aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIvan Vecera <cera@cera.cz>2017-01-31 14:01:31 -0500
committerDavid S. Miller <davem@davemloft.net>2017-02-01 11:11:41 -0500
commit4993b39ab04b083ff6ee1147e7e7f120feb6bf7f (patch)
tree8cdbd97a79c66c6a730c79dac5727135cbe95e76 /drivers
parent90427ef5d2a4b9a24079889bf16afdcdaebc4240 (diff)
be2net: fix initial MAC setting
Recent commit 34393529163a ("be2net: fix MAC addr setting on privileged BE3 VFs") allows privileged BE3 VFs to set its MAC address during initialization. Although the initial MAC for such VFs is already programmed by parent PF the subsequent setting performed by VF is OK, but in certain cases (after fresh boot) this command in VF can fail. The MAC should be initialized only when: 1) no MAC is programmed (always except BE3 VFs during first init) 2) programmed MAC is different from requested (e.g. MAC is set when interface is down). In this case the initial MAC programmed by PF needs to be deleted. The adapter->dev_mac contains MAC address currently programmed in HW so it should be zeroed when the MAC is deleted from HW and should not be filled when MAC is set when interface is down in be_mac_addr_set() as no programming is performed in this case. Example of failure without the fix (immediately after fresh boot): # ip link set eth0 up <- eth0 is BE3 PF be2net 0000:01:00.0 eth0: Link is Up # echo 1 > /sys/class/net/eth0/device/sriov_numvfs <- Create 1 VF ... be2net 0000:01:04.0: Emulex OneConnect(be3): VF port 0 # ip link set eth8 up <- eth8 is created privileged VF be2net 0000:01:04.0: opcode 59-1 failed:status 1-76 RTNETLINK answers: Input/output error # echo 0 > /sys/class/net/eth0/device/sriov_numvfs <- Delete VF iommu: Removing device 0000:01:04.0 from group 33 ... # echo 1 > /sys/class/net/eth0/device/sriov_numvfs <- Create it again iommu: Removing device 0000:01:04.0 from group 33 ... # ip link set eth8 up be2net 0000:01:04.0 eth8: Link is Up Initialization is now OK. v2 - Corrected the comment and condition check suggested by Suresh & Harsha Fixes: 34393529163a ("be2net: fix MAC addr setting on privileged BE3 VFs") Cc: Sathya Perla <sathya.perla@broadcom.com> Cc: Ajit Khaparde <ajit.khaparde@broadcom.com> Cc: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Cc: Somnath Kotur <somnath.kotur@broadcom.com> Signed-off-by: Ivan Vecera <cera@cera.cz> Acked-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 1a7f8ad7b9c6..cd49a54c538d 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -362,8 +362,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
362 status = -EPERM; 362 status = -EPERM;
363 goto err; 363 goto err;
364 } 364 }
365done: 365
366 /* Remember currently programmed MAC */
366 ether_addr_copy(adapter->dev_mac, addr->sa_data); 367 ether_addr_copy(adapter->dev_mac, addr->sa_data);
368done:
367 ether_addr_copy(netdev->dev_addr, addr->sa_data); 369 ether_addr_copy(netdev->dev_addr, addr->sa_data);
368 dev_info(dev, "MAC address changed to %pM\n", addr->sa_data); 370 dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
369 return 0; 371 return 0;
@@ -3618,8 +3620,10 @@ static void be_disable_if_filters(struct be_adapter *adapter)
3618{ 3620{
3619 /* Don't delete MAC on BE3 VFs without FILTMGMT privilege */ 3621 /* Don't delete MAC on BE3 VFs without FILTMGMT privilege */
3620 if (!BEx_chip(adapter) || !be_virtfn(adapter) || 3622 if (!BEx_chip(adapter) || !be_virtfn(adapter) ||
3621 check_privilege(adapter, BE_PRIV_FILTMGMT)) 3623 check_privilege(adapter, BE_PRIV_FILTMGMT)) {
3622 be_dev_mac_del(adapter, adapter->pmac_id[0]); 3624 be_dev_mac_del(adapter, adapter->pmac_id[0]);
3625 eth_zero_addr(adapter->dev_mac);
3626 }
3623 3627
3624 be_clear_uc_list(adapter); 3628 be_clear_uc_list(adapter);
3625 be_clear_mc_list(adapter); 3629 be_clear_mc_list(adapter);
@@ -3773,12 +3777,27 @@ static int be_enable_if_filters(struct be_adapter *adapter)
3773 if (status) 3777 if (status)
3774 return status; 3778 return status;
3775 3779
3776 /* Don't add MAC on BE3 VFs without FILTMGMT privilege */ 3780 /* Normally this condition usually true as the ->dev_mac is zeroed.
3777 if (!BEx_chip(adapter) || !be_virtfn(adapter) || 3781 * But on BE3 VFs the initial MAC is pre-programmed by PF and
3778 check_privilege(adapter, BE_PRIV_FILTMGMT)) { 3782 * subsequent be_dev_mac_add() can fail (after fresh boot)
3783 */
3784 if (!ether_addr_equal(adapter->dev_mac, adapter->netdev->dev_addr)) {
3785 int old_pmac_id = -1;
3786
3787 /* Remember old programmed MAC if any - can happen on BE3 VF */
3788 if (!is_zero_ether_addr(adapter->dev_mac))
3789 old_pmac_id = adapter->pmac_id[0];
3790
3779 status = be_dev_mac_add(adapter, adapter->netdev->dev_addr); 3791 status = be_dev_mac_add(adapter, adapter->netdev->dev_addr);
3780 if (status) 3792 if (status)
3781 return status; 3793 return status;
3794
3795 /* Delete the old programmed MAC as we successfully programmed
3796 * a new MAC
3797 */
3798 if (old_pmac_id >= 0 && old_pmac_id != adapter->pmac_id[0])
3799 be_dev_mac_del(adapter, old_pmac_id);
3800
3782 ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr); 3801 ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr);
3783 } 3802 }
3784 3803
@@ -4552,6 +4571,10 @@ static int be_mac_setup(struct be_adapter *adapter)
4552 4571
4553 memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); 4572 memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
4554 memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); 4573 memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
4574
4575 /* Initial MAC for BE3 VFs is already programmed by PF */
4576 if (BEx_chip(adapter) && be_virtfn(adapter))
4577 memcpy(adapter->dev_mac, mac, ETH_ALEN);
4555 } 4578 }
4556 4579
4557 return 0; 4580 return 0;