diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 99 |
1 files changed, 70 insertions, 29 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 172f7561643a..3216aa5e705e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c | |||
@@ -1239,8 +1239,11 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr, | |||
1239 | * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM | 1239 | * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM |
1240 | * @vsi: the PF Main VSI - inappropriate for any other VSI | 1240 | * @vsi: the PF Main VSI - inappropriate for any other VSI |
1241 | * @macaddr: the MAC address | 1241 | * @macaddr: the MAC address |
1242 | * | ||
1243 | * Some older firmware configurations set up a default promiscuous VLAN | ||
1244 | * filter that needs to be removed. | ||
1242 | **/ | 1245 | **/ |
1243 | static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) | 1246 | static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) |
1244 | { | 1247 | { |
1245 | struct i40e_aqc_remove_macvlan_element_data element; | 1248 | struct i40e_aqc_remove_macvlan_element_data element; |
1246 | struct i40e_pf *pf = vsi->back; | 1249 | struct i40e_pf *pf = vsi->back; |
@@ -1248,15 +1251,18 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) | |||
1248 | 1251 | ||
1249 | /* Only appropriate for the PF main VSI */ | 1252 | /* Only appropriate for the PF main VSI */ |
1250 | if (vsi->type != I40E_VSI_MAIN) | 1253 | if (vsi->type != I40E_VSI_MAIN) |
1251 | return; | 1254 | return -EINVAL; |
1252 | 1255 | ||
1256 | memset(&element, 0, sizeof(element)); | ||
1253 | ether_addr_copy(element.mac_addr, macaddr); | 1257 | ether_addr_copy(element.mac_addr, macaddr); |
1254 | element.vlan_tag = 0; | 1258 | element.vlan_tag = 0; |
1255 | element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | | 1259 | element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | |
1256 | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; | 1260 | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; |
1257 | aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); | 1261 | aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); |
1258 | if (aq_ret) | 1262 | if (aq_ret) |
1259 | dev_err(&pf->pdev->dev, "Could not remove default MAC-VLAN\n"); | 1263 | return -ENOENT; |
1264 | |||
1265 | return 0; | ||
1260 | } | 1266 | } |
1261 | 1267 | ||
1262 | /** | 1268 | /** |
@@ -1385,18 +1391,30 @@ static int i40e_set_mac(struct net_device *netdev, void *p) | |||
1385 | { | 1391 | { |
1386 | struct i40e_netdev_priv *np = netdev_priv(netdev); | 1392 | struct i40e_netdev_priv *np = netdev_priv(netdev); |
1387 | struct i40e_vsi *vsi = np->vsi; | 1393 | struct i40e_vsi *vsi = np->vsi; |
1394 | struct i40e_pf *pf = vsi->back; | ||
1395 | struct i40e_hw *hw = &pf->hw; | ||
1388 | struct sockaddr *addr = p; | 1396 | struct sockaddr *addr = p; |
1389 | struct i40e_mac_filter *f; | 1397 | struct i40e_mac_filter *f; |
1390 | 1398 | ||
1391 | if (!is_valid_ether_addr(addr->sa_data)) | 1399 | if (!is_valid_ether_addr(addr->sa_data)) |
1392 | return -EADDRNOTAVAIL; | 1400 | return -EADDRNOTAVAIL; |
1393 | 1401 | ||
1394 | netdev_info(netdev, "set mac address=%pM\n", addr->sa_data); | 1402 | if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) { |
1403 | netdev_info(netdev, "already using mac address %pM\n", | ||
1404 | addr->sa_data); | ||
1405 | return 0; | ||
1406 | } | ||
1395 | 1407 | ||
1396 | if (test_bit(__I40E_DOWN, &vsi->back->state) || | 1408 | if (test_bit(__I40E_DOWN, &vsi->back->state) || |
1397 | test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) | 1409 | test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state)) |
1398 | return -EADDRNOTAVAIL; | 1410 | return -EADDRNOTAVAIL; |
1399 | 1411 | ||
1412 | if (ether_addr_equal(hw->mac.addr, addr->sa_data)) | ||
1413 | netdev_info(netdev, "returning to hw mac address %pM\n", | ||
1414 | hw->mac.addr); | ||
1415 | else | ||
1416 | netdev_info(netdev, "set new mac address %pM\n", addr->sa_data); | ||
1417 | |||
1400 | if (vsi->type == I40E_VSI_MAIN) { | 1418 | if (vsi->type == I40E_VSI_MAIN) { |
1401 | i40e_status ret; | 1419 | i40e_status ret; |
1402 | ret = i40e_aq_mac_address_write(&vsi->back->hw, | 1420 | ret = i40e_aq_mac_address_write(&vsi->back->hw, |
@@ -1410,25 +1428,34 @@ static int i40e_set_mac(struct net_device *netdev, void *p) | |||
1410 | } | 1428 | } |
1411 | } | 1429 | } |
1412 | 1430 | ||
1413 | f = i40e_find_mac(vsi, addr->sa_data, false, true); | 1431 | if (ether_addr_equal(netdev->dev_addr, hw->mac.addr)) { |
1414 | if (!f) { | 1432 | struct i40e_aqc_remove_macvlan_element_data element; |
1415 | /* In order to be sure to not drop any packets, add the | ||
1416 | * new address first then delete the old one. | ||
1417 | */ | ||
1418 | f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, | ||
1419 | false, false); | ||
1420 | if (!f) | ||
1421 | return -ENOMEM; | ||
1422 | 1433 | ||
1423 | i40e_sync_vsi_filters(vsi); | 1434 | memset(&element, 0, sizeof(element)); |
1435 | ether_addr_copy(element.mac_addr, netdev->dev_addr); | ||
1436 | element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; | ||
1437 | i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); | ||
1438 | } else { | ||
1424 | i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, | 1439 | i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, |
1425 | false, false); | 1440 | false, false); |
1426 | i40e_sync_vsi_filters(vsi); | ||
1427 | } | 1441 | } |
1428 | 1442 | ||
1429 | f->is_laa = true; | 1443 | if (ether_addr_equal(addr->sa_data, hw->mac.addr)) { |
1430 | if (!ether_addr_equal(netdev->dev_addr, addr->sa_data)) | 1444 | struct i40e_aqc_add_macvlan_element_data element; |
1431 | ether_addr_copy(netdev->dev_addr, addr->sa_data); | 1445 | |
1446 | memset(&element, 0, sizeof(element)); | ||
1447 | ether_addr_copy(element.mac_addr, hw->mac.addr); | ||
1448 | element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH); | ||
1449 | i40e_aq_add_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); | ||
1450 | } else { | ||
1451 | f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, | ||
1452 | false, false); | ||
1453 | if (f) | ||
1454 | f->is_laa = true; | ||
1455 | } | ||
1456 | |||
1457 | i40e_sync_vsi_filters(vsi); | ||
1458 | ether_addr_copy(netdev->dev_addr, addr->sa_data); | ||
1432 | 1459 | ||
1433 | return 0; | 1460 | return 0; |
1434 | } | 1461 | } |
@@ -1796,9 +1823,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) | |||
1796 | kfree(add_list); | 1823 | kfree(add_list); |
1797 | add_list = NULL; | 1824 | add_list = NULL; |
1798 | 1825 | ||
1799 | if (add_happened && (!aq_ret)) { | 1826 | if (add_happened && aq_ret && |
1800 | /* do nothing */; | 1827 | pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) { |
1801 | } else if (add_happened && (aq_ret)) { | ||
1802 | dev_info(&pf->pdev->dev, | 1828 | dev_info(&pf->pdev->dev, |
1803 | "add filter failed, err %d, aq_err %d\n", | 1829 | "add filter failed, err %d, aq_err %d\n", |
1804 | aq_ret, pf->hw.aq.asq_last_status); | 1830 | aq_ret, pf->hw.aq.asq_last_status); |
@@ -7512,14 +7538,14 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) | |||
7512 | if (vsi->type == I40E_VSI_MAIN) { | 7538 | if (vsi->type == I40E_VSI_MAIN) { |
7513 | SET_NETDEV_DEV(netdev, &pf->pdev->dev); | 7539 | SET_NETDEV_DEV(netdev, &pf->pdev->dev); |
7514 | ether_addr_copy(mac_addr, hw->mac.perm_addr); | 7540 | ether_addr_copy(mac_addr, hw->mac.perm_addr); |
7515 | /* The following two steps are necessary to prevent reception | 7541 | /* The following steps are necessary to prevent reception |
7516 | * of tagged packets - by default the NVM loads a MAC-VLAN | 7542 | * of tagged packets - some older NVM configurations load a |
7517 | * filter that will accept any tagged packet. This is to | 7543 | * default a MAC-VLAN filter that accepts any tagged packet |
7518 | * prevent that during normal operations until a specific | 7544 | * which must be replaced by a normal filter. |
7519 | * VLAN tag filter has been set. | ||
7520 | */ | 7545 | */ |
7521 | i40e_rm_default_mac_filter(vsi, mac_addr); | 7546 | if (!i40e_rm_default_mac_filter(vsi, mac_addr)) |
7522 | i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true); | 7547 | i40e_add_filter(vsi, mac_addr, |
7548 | I40E_VLAN_ANY, false, true); | ||
7523 | } else { | 7549 | } else { |
7524 | /* relate the VSI_VMDQ name to the VSI_MAIN name */ | 7550 | /* relate the VSI_VMDQ name to the VSI_MAIN name */ |
7525 | snprintf(netdev->name, IFNAMSIZ, "%sv%%d", | 7551 | snprintf(netdev->name, IFNAMSIZ, "%sv%%d", |
@@ -7735,7 +7761,22 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) | |||
7735 | f_count++; | 7761 | f_count++; |
7736 | 7762 | ||
7737 | if (f->is_laa && vsi->type == I40E_VSI_MAIN) { | 7763 | if (f->is_laa && vsi->type == I40E_VSI_MAIN) { |
7738 | i40e_aq_mac_address_write(&vsi->back->hw, | 7764 | struct i40e_aqc_remove_macvlan_element_data element; |
7765 | |||
7766 | memset(&element, 0, sizeof(element)); | ||
7767 | ether_addr_copy(element.mac_addr, f->macaddr); | ||
7768 | element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; | ||
7769 | ret = i40e_aq_remove_macvlan(hw, vsi->seid, | ||
7770 | &element, 1, NULL); | ||
7771 | if (ret) { | ||
7772 | /* some older FW has a different default */ | ||
7773 | element.flags |= | ||
7774 | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; | ||
7775 | i40e_aq_remove_macvlan(hw, vsi->seid, | ||
7776 | &element, 1, NULL); | ||
7777 | } | ||
7778 | |||
7779 | i40e_aq_mac_address_write(hw, | ||
7739 | I40E_AQC_WRITE_TYPE_LAA_WOL, | 7780 | I40E_AQC_WRITE_TYPE_LAA_WOL, |
7740 | f->macaddr, NULL); | 7781 | f->macaddr, NULL); |
7741 | } | 7782 | } |