* i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
* @vsi: the PF Main VSI - inappropriate for any other VSI
* @macaddr: the MAC address
+ *
+ * Some older firmware configurations set up a default promiscuous VLAN
+ * filter that needs to be removed.
**/
-static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
+static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
{
struct i40e_aqc_remove_macvlan_element_data element;
struct i40e_pf *pf = vsi->back;
/* Only appropriate for the PF main VSI */
if (vsi->type != I40E_VSI_MAIN)
- return;
+ return -EINVAL;
+ memset(&element, 0, sizeof(element));
ether_addr_copy(element.mac_addr, macaddr);
element.vlan_tag = 0;
element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
if (aq_ret)
- dev_err(&pf->pdev->dev, "Could not remove default MAC-VLAN\n");
+ return -ENOENT;
+
+ return 0;
}
/**
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
+ struct i40e_pf *pf = vsi->back;
+ struct i40e_hw *hw = &pf->hw;
struct sockaddr *addr = p;
struct i40e_mac_filter *f;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- netdev_info(netdev, "set mac address=%pM\n", addr->sa_data);
+ if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) {
+ netdev_info(netdev, "already using mac address %pM\n",
+ addr->sa_data);
+ return 0;
+ }
if (test_bit(__I40E_DOWN, &vsi->back->state) ||
test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
return -EADDRNOTAVAIL;
+ if (ether_addr_equal(hw->mac.addr, addr->sa_data))
+ netdev_info(netdev, "returning to hw mac address %pM\n",
+ hw->mac.addr);
+ else
+ netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
+
if (vsi->type == I40E_VSI_MAIN) {
i40e_status ret;
ret = i40e_aq_mac_address_write(&vsi->back->hw,
}
}
- f = i40e_find_mac(vsi, addr->sa_data, false, true);
- if (!f) {
- /* In order to be sure to not drop any packets, add the
- * new address first then delete the old one.
- */
- f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
- false, false);
- if (!f)
- return -ENOMEM;
+ if (ether_addr_equal(netdev->dev_addr, hw->mac.addr)) {
+ struct i40e_aqc_remove_macvlan_element_data element;
- i40e_sync_vsi_filters(vsi);
+ memset(&element, 0, sizeof(element));
+ ether_addr_copy(element.mac_addr, netdev->dev_addr);
+ element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+ i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+ } else {
i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY,
false, false);
- i40e_sync_vsi_filters(vsi);
}
- f->is_laa = true;
- if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
- ether_addr_copy(netdev->dev_addr, addr->sa_data);
+ if (ether_addr_equal(addr->sa_data, hw->mac.addr)) {
+ struct i40e_aqc_add_macvlan_element_data element;
+
+ memset(&element, 0, sizeof(element));
+ ether_addr_copy(element.mac_addr, hw->mac.addr);
+ element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+ i40e_aq_add_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+ } else {
+ f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
+ false, false);
+ if (f)
+ f->is_laa = true;
+ }
+
+ i40e_sync_vsi_filters(vsi);
+ ether_addr_copy(netdev->dev_addr, addr->sa_data);
return 0;
}
kfree(add_list);
add_list = NULL;
- if (add_happened && (!aq_ret)) {
- /* do nothing */;
- } else if (add_happened && (aq_ret)) {
+ if (add_happened && aq_ret &&
+ pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) {
dev_info(&pf->pdev->dev,
"add filter failed, err %d, aq_err %d\n",
aq_ret, pf->hw.aq.asq_last_status);
if (vsi->type == I40E_VSI_MAIN) {
SET_NETDEV_DEV(netdev, &pf->pdev->dev);
ether_addr_copy(mac_addr, hw->mac.perm_addr);
- /* The following two steps are necessary to prevent reception
- * of tagged packets - by default the NVM loads a MAC-VLAN
- * filter that will accept any tagged packet. This is to
- * prevent that during normal operations until a specific
- * VLAN tag filter has been set.
+ /* The following steps are necessary to prevent reception
+ * of tagged packets - some older NVM configurations load a
+ * default a MAC-VLAN filter that accepts any tagged packet
+ * which must be replaced by a normal filter.
*/
- i40e_rm_default_mac_filter(vsi, mac_addr);
- i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true);
+ if (!i40e_rm_default_mac_filter(vsi, mac_addr))
+ i40e_add_filter(vsi, mac_addr,
+ I40E_VLAN_ANY, false, true);
} else {
/* relate the VSI_VMDQ name to the VSI_MAIN name */
snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
f_count++;
if (f->is_laa && vsi->type == I40E_VSI_MAIN) {
- i40e_aq_mac_address_write(&vsi->back->hw,
+ struct i40e_aqc_remove_macvlan_element_data element;
+
+ memset(&element, 0, sizeof(element));
+ ether_addr_copy(element.mac_addr, f->macaddr);
+ element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+ ret = i40e_aq_remove_macvlan(hw, vsi->seid,
+ &element, 1, NULL);
+ if (ret) {
+ /* some older FW has a different default */
+ element.flags |=
+ I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
+ i40e_aq_remove_macvlan(hw, vsi->seid,
+ &element, 1, NULL);
+ }
+
+ i40e_aq_mac_address_write(hw,
I40E_AQC_WRITE_TYPE_LAA_WOL,
f->macaddr, NULL);
}