From: Junxian Huang huangjunxian6@hisilicon.com
driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6ZAIM
---------------------------------------------------------------
Support dispatching IB event for RoCE bonding. After setting bond, IB_EVENT_PORT_ERR is dispatched in the following situation: 1. bond0 becomes link down; 2. all slaves become link down (as it will lead to a link-down of the upper device).
IB_EVENT_PORT_ACTIVE is dispatched in the following situation: 1. bond0 becomes link up; 2. one slave becomes link up when all slaves were link down (as it will lead to a link-up of the upper device).
Signed-off-by: Junxian Huang huangjunxian6@hisilicon.com --- drivers/infiniband/hw/hns/hns_roce_bond.c | 17 +++++++++-------- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 10 ++++++++++ drivers/infiniband/hw/hns/hns_roce_main.c | 18 ++++++++++++------ 3 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_bond.c b/drivers/infiniband/hw/hns/hns_roce_bond.c index 1d0b47b390c2..92ddbe61a41b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_bond.c +++ b/drivers/infiniband/hw/hns/hns_roce_bond.c @@ -136,17 +136,18 @@ struct net_device *hns_roce_get_bond_netdev(struct hns_roce_dev *hr_dev) if (bond_grp->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { net_dev = bond_grp->bond_func_info[i].net_dev; - if (net_dev && is_active_slave(net_dev, bond_grp)) - break; - } - } else { - for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { - net_dev = bond_grp->bond_func_info[i].net_dev; - if (net_dev && get_port_state(net_dev) == IB_PORT_ACTIVE) - break; + if (net_dev && is_active_slave(net_dev, bond_grp) && + get_port_state(net_dev) == IB_PORT_ACTIVE) + goto out; } }
+ for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { + net_dev = bond_grp->bond_func_info[i].net_dev; + if (net_dev && get_port_state(net_dev) == IB_PORT_ACTIVE) + break; + } + out: mutex_unlock(&bond_grp->bond_mutex);
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index b417bfc43a11..812d96d2d3d9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -7570,6 +7570,7 @@ static void hns_roce_hw_v2_link_status_change(struct hnae3_handle *handle, { struct net_device *netdev = handle->rinfo.netdev; struct hns_roce_dev *hr_dev = handle->priv; + struct hns_roce_bond_group *bond_grp; struct ib_event event; unsigned long flags; u8 phy_port; @@ -7577,6 +7578,15 @@ static void hns_roce_hw_v2_link_status_change(struct hnae3_handle *handle, if (linkup || !hr_dev) return;
+ /* For bond device, the link status depends on the upper netdev, + * and the upper device's link status depends on all the slaves' + * netdev but not only one. So bond device cannot get a correct + * link status from this path. + */ + bond_grp = hns_roce_get_bond_grp(hr_dev); + if (bond_grp) + return; + for (phy_port = 0; phy_port < hr_dev->caps.num_ports; phy_port++) if (netdev == hr_dev->iboe.netdevs[phy_port]) break; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 075d31d7f00c..101614aed9c7 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -131,17 +131,16 @@ static enum ib_port_state get_upper_port_state(struct hns_roce_dev *hr_dev) return IB_PORT_ACTIVE; }
-static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, - unsigned long dev_event) +static int handle_en_event(struct net_device *netdev, + struct hns_roce_dev *hr_dev, + u32 port, unsigned long dev_event) { struct device *dev = hr_dev->dev; enum ib_port_state port_state; - struct net_device *netdev; struct ib_event event; unsigned long flags; int ret = 0;
- netdev = hr_dev->iboe.netdevs[port]; if (!netdev) { dev_err(dev, "Can't find netdev on port(%u)!\n", port); return -ENODEV; @@ -189,17 +188,24 @@ static int hns_roce_netdev_event(struct notifier_block *self, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct hns_roce_bond_group *bond_grp; struct hns_roce_ib_iboe *iboe = NULL; struct hns_roce_dev *hr_dev = NULL; + struct net_device *upper = NULL; int ret; u8 port;
hr_dev = container_of(self, struct hns_roce_dev, iboe.nb); iboe = &hr_dev->iboe; + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_BOND) { + bond_grp = hns_roce_get_bond_grp(hr_dev); + upper = bond_grp ? bond_grp->upper_dev : NULL; + }
for (port = 0; port < hr_dev->caps.num_ports; port++) { - if (dev == iboe->netdevs[port]) { - ret = handle_en_event(hr_dev, port, event); + if ((!upper && dev == iboe->netdevs[port]) || + (upper && dev == upper)) { + ret = handle_en_event(dev, hr_dev, port, event); if (ret) return NOTIFY_DONE; break;