| From foo@baz Wed Dec 6 17:39:55 CET 2017 |
| From: Ivan Vecera <cera@cera.cz> |
| Date: Tue, 31 Jan 2017 20:01:31 +0100 |
| Subject: be2net: fix initial MAC setting |
| |
| From: Ivan Vecera <cera@cera.cz> |
| |
| |
| [ Upstream commit 4993b39ab04b083ff6ee1147e7e7f120feb6bf7f ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/emulex/benet/be_main.c | 33 +++++++++++++++++++++++----- |
| 1 file changed, 28 insertions(+), 5 deletions(-) |
| |
| --- 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_de |
| status = -EPERM; |
| goto err; |
| } |
| -done: |
| + |
| + /* Remember currently programmed MAC */ |
| ether_addr_copy(adapter->dev_mac, addr->sa_data); |
| +done: |
| ether_addr_copy(netdev->dev_addr, addr->sa_data); |
| dev_info(dev, "MAC address changed to %pM\n", addr->sa_data); |
| return 0; |
| @@ -3635,8 +3637,10 @@ static void be_disable_if_filters(struct |
| { |
| /* Don't delete MAC on BE3 VFs without FILTMGMT privilege */ |
| if (!BEx_chip(adapter) || !be_virtfn(adapter) || |
| - check_privilege(adapter, BE_PRIV_FILTMGMT)) |
| + check_privilege(adapter, BE_PRIV_FILTMGMT)) { |
| be_dev_mac_del(adapter, adapter->pmac_id[0]); |
| + eth_zero_addr(adapter->dev_mac); |
| + } |
| |
| be_clear_uc_list(adapter); |
| be_clear_mc_list(adapter); |
| @@ -3790,12 +3794,27 @@ static int be_enable_if_filters(struct b |
| if (status) |
| return status; |
| |
| - /* Don't add MAC on BE3 VFs without FILTMGMT privilege */ |
| - if (!BEx_chip(adapter) || !be_virtfn(adapter) || |
| - check_privilege(adapter, BE_PRIV_FILTMGMT)) { |
| + /* Normally this condition usually true as the ->dev_mac is zeroed. |
| + * But on BE3 VFs the initial MAC is pre-programmed by PF and |
| + * subsequent be_dev_mac_add() can fail (after fresh boot) |
| + */ |
| + if (!ether_addr_equal(adapter->dev_mac, adapter->netdev->dev_addr)) { |
| + int old_pmac_id = -1; |
| + |
| + /* Remember old programmed MAC if any - can happen on BE3 VF */ |
| + if (!is_zero_ether_addr(adapter->dev_mac)) |
| + old_pmac_id = adapter->pmac_id[0]; |
| + |
| status = be_dev_mac_add(adapter, adapter->netdev->dev_addr); |
| if (status) |
| return status; |
| + |
| + /* Delete the old programmed MAC as we successfully programmed |
| + * a new MAC |
| + */ |
| + if (old_pmac_id >= 0 && old_pmac_id != adapter->pmac_id[0]) |
| + be_dev_mac_del(adapter, old_pmac_id); |
| + |
| ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr); |
| } |
| |
| @@ -4569,6 +4588,10 @@ static int be_mac_setup(struct be_adapte |
| |
| memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); |
| memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); |
| + |
| + /* Initial MAC for BE3 VFs is already programmed by PF */ |
| + if (BEx_chip(adapter) && be_virtfn(adapter)) |
| + memcpy(adapter->dev_mac, mac, ETH_ALEN); |
| } |
| |
| return 0; |