1b37ad2e2SJunxian Huang // SPDX-License-Identifier: GPL-2.0+ 2b37ad2e2SJunxian Huang /* 3b37ad2e2SJunxian Huang * Copyright (c) 2025 Hisilicon Limited. 4b37ad2e2SJunxian Huang */ 5b37ad2e2SJunxian Huang 65d91677bSJunxian Huang #include <net/lag.h> 7d9023e46SJunxian Huang #include <net/bonding.h> 8b37ad2e2SJunxian Huang #include "hns_roce_device.h" 9b37ad2e2SJunxian Huang #include "hns_roce_hw_v2.h" 10b37ad2e2SJunxian Huang #include "hns_roce_bond.h" 11b37ad2e2SJunxian Huang 12b37ad2e2SJunxian Huang static DEFINE_XARRAY(roce_bond_xa); 13b37ad2e2SJunxian Huang 14d31d410bSJunxian Huang static struct hns_roce_dev *hns_roce_get_hrdev_by_netdev(struct net_device *net_dev) 15d31d410bSJunxian Huang { 16d31d410bSJunxian Huang struct ib_device *ibdev = 17d31d410bSJunxian Huang ib_device_get_by_netdev(net_dev, RDMA_DRIVER_HNS); 18d31d410bSJunxian Huang 19d31d410bSJunxian Huang if (!ibdev) 20d31d410bSJunxian Huang return NULL; 21d31d410bSJunxian Huang 22d31d410bSJunxian Huang return container_of(ibdev, struct hns_roce_dev, ib_dev); 23d31d410bSJunxian Huang } 24d31d410bSJunxian Huang 25b37ad2e2SJunxian Huang static struct net_device *get_upper_dev_from_ndev(struct net_device *net_dev) 26b37ad2e2SJunxian Huang { 27b37ad2e2SJunxian Huang struct net_device *upper_dev; 28b37ad2e2SJunxian Huang 29b37ad2e2SJunxian Huang rcu_read_lock(); 30b37ad2e2SJunxian Huang upper_dev = netdev_master_upper_dev_get_rcu(net_dev); 31b37ad2e2SJunxian Huang dev_hold(upper_dev); 32b37ad2e2SJunxian Huang rcu_read_unlock(); 33b37ad2e2SJunxian Huang 34b37ad2e2SJunxian Huang return upper_dev; 35b37ad2e2SJunxian Huang } 36b37ad2e2SJunxian Huang 37b37ad2e2SJunxian Huang static int get_netdev_bond_slave_id(struct net_device *net_dev, 38b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp) 39b37ad2e2SJunxian Huang { 40b37ad2e2SJunxian Huang int i; 41b37ad2e2SJunxian Huang 42b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) 43b37ad2e2SJunxian Huang if (net_dev == bond_grp->bond_func_info[i].net_dev) 44b37ad2e2SJunxian Huang return i; 45b37ad2e2SJunxian Huang 46b37ad2e2SJunxian Huang return -ENOENT; 47b37ad2e2SJunxian Huang } 48b37ad2e2SJunxian Huang 49b37ad2e2SJunxian Huang struct hns_roce_bond_group *hns_roce_get_bond_grp(struct net_device *net_dev, 50b37ad2e2SJunxian Huang u8 bus_num) 51b37ad2e2SJunxian Huang { 52b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 53b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 54b37ad2e2SJunxian Huang struct net_device *upper_dev = NULL; 55b37ad2e2SJunxian Huang int i; 56b37ad2e2SJunxian Huang 57b37ad2e2SJunxian Huang if (!die_info) 58b37ad2e2SJunxian Huang return NULL; 59b37ad2e2SJunxian Huang 60b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 61b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 62b37ad2e2SJunxian Huang if (!bond_grp) 63b37ad2e2SJunxian Huang continue; 64b37ad2e2SJunxian Huang if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 65b37ad2e2SJunxian Huang return bond_grp; 66b37ad2e2SJunxian Huang if (bond_grp->upper_dev) { 67b37ad2e2SJunxian Huang upper_dev = get_upper_dev_from_ndev(net_dev); 68b37ad2e2SJunxian Huang if (bond_grp->upper_dev == upper_dev) { 69b37ad2e2SJunxian Huang dev_put(upper_dev); 70b37ad2e2SJunxian Huang return bond_grp; 71b37ad2e2SJunxian Huang } 72b37ad2e2SJunxian Huang dev_put(upper_dev); 73b37ad2e2SJunxian Huang } 74b37ad2e2SJunxian Huang } 75b37ad2e2SJunxian Huang 76b37ad2e2SJunxian Huang return NULL; 77b37ad2e2SJunxian Huang } 78b37ad2e2SJunxian Huang 79d9023e46SJunxian Huang static int hns_roce_set_bond_netdev(struct hns_roce_bond_group *bond_grp, 80d9023e46SJunxian Huang struct hns_roce_dev *hr_dev) 81d9023e46SJunxian Huang { 82d9023e46SJunxian Huang struct net_device *active_dev; 83d9023e46SJunxian Huang struct net_device *old_dev; 84d9023e46SJunxian Huang int i, ret = 0; 85d9023e46SJunxian Huang 86d9023e46SJunxian Huang if (bond_grp->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { 87d9023e46SJunxian Huang rcu_read_lock(); 88d9023e46SJunxian Huang active_dev = 89d9023e46SJunxian Huang bond_option_active_slave_get_rcu(netdev_priv(bond_grp->upper_dev)); 90d9023e46SJunxian Huang rcu_read_unlock(); 91d9023e46SJunxian Huang } else { 92d9023e46SJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 93d9023e46SJunxian Huang active_dev = bond_grp->bond_func_info[i].net_dev; 94d9023e46SJunxian Huang if (active_dev && 95d9023e46SJunxian Huang ib_get_curr_port_state(active_dev) == IB_PORT_ACTIVE) 96d9023e46SJunxian Huang break; 97d9023e46SJunxian Huang } 98d9023e46SJunxian Huang } 99d9023e46SJunxian Huang 100d9023e46SJunxian Huang if (!active_dev || i == ROCE_BOND_FUNC_MAX) 101d9023e46SJunxian Huang active_dev = get_hr_netdev(hr_dev, 0); 102d9023e46SJunxian Huang 103d9023e46SJunxian Huang old_dev = ib_device_get_netdev(&hr_dev->ib_dev, 1); 104d9023e46SJunxian Huang if (old_dev == active_dev) 105d9023e46SJunxian Huang goto out; 106d9023e46SJunxian Huang 107d9023e46SJunxian Huang ret = ib_device_set_netdev(&hr_dev->ib_dev, active_dev, 1); 108d9023e46SJunxian Huang if (ret) { 109d9023e46SJunxian Huang dev_err(hr_dev->dev, "failed to set netdev for bond.\n"); 110d9023e46SJunxian Huang goto out; 111d9023e46SJunxian Huang } 112d9023e46SJunxian Huang 113d9023e46SJunxian Huang if (bond_grp->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { 114d9023e46SJunxian Huang if (old_dev) 115d9023e46SJunxian Huang roce_del_all_netdev_gids(&hr_dev->ib_dev, 1, old_dev); 116d9023e46SJunxian Huang rdma_roce_rescan_port(&hr_dev->ib_dev, 1); 117d9023e46SJunxian Huang } 118d9023e46SJunxian Huang out: 119d9023e46SJunxian Huang dev_put(old_dev); 120d9023e46SJunxian Huang return ret; 121d9023e46SJunxian Huang } 122d9023e46SJunxian Huang 123d9023e46SJunxian Huang bool hns_roce_bond_is_active(struct hns_roce_dev *hr_dev) 124d9023e46SJunxian Huang { 125d9023e46SJunxian Huang struct net_device *net_dev = get_hr_netdev(hr_dev, 0); 126d9023e46SJunxian Huang struct hns_roce_bond_group *bond_grp; 127d9023e46SJunxian Huang u8 bus_num = get_hr_bus_num(hr_dev); 128d9023e46SJunxian Huang 129d9023e46SJunxian Huang bond_grp = hns_roce_get_bond_grp(net_dev, bus_num); 130d9023e46SJunxian Huang if (bond_grp && bond_grp->bond_state != HNS_ROCE_BOND_NOT_BONDED && 131d9023e46SJunxian Huang bond_grp->bond_state != HNS_ROCE_BOND_NOT_ATTACHED) 132d9023e46SJunxian Huang return true; 133d9023e46SJunxian Huang 134d9023e46SJunxian Huang return false; 135d9023e46SJunxian Huang } 136d9023e46SJunxian Huang 1375d91677bSJunxian Huang static void hns_roce_bond_get_active_slave(struct hns_roce_bond_group *bond_grp) 1385d91677bSJunxian Huang { 1395d91677bSJunxian Huang struct net_device *net_dev; 1405d91677bSJunxian Huang u32 active_slave_map = 0; 1415d91677bSJunxian Huang u8 active_slave_num = 0; 1425d91677bSJunxian Huang bool active; 1435d91677bSJunxian Huang u8 i; 1445d91677bSJunxian Huang 1455d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 1465d91677bSJunxian Huang net_dev = bond_grp->bond_func_info[i].net_dev; 1475d91677bSJunxian Huang if (!net_dev || !(bond_grp->slave_map & (1U << i))) 1485d91677bSJunxian Huang continue; 1495d91677bSJunxian Huang 1505d91677bSJunxian Huang active = (bond_grp->tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) ? 1515d91677bSJunxian Huang net_lag_port_dev_txable(net_dev) : 1525d91677bSJunxian Huang (ib_get_curr_port_state(net_dev) == IB_PORT_ACTIVE); 1535d91677bSJunxian Huang if (active) { 1545d91677bSJunxian Huang active_slave_num++; 1555d91677bSJunxian Huang active_slave_map |= (1U << i); 1565d91677bSJunxian Huang } 1575d91677bSJunxian Huang } 1585d91677bSJunxian Huang 1595d91677bSJunxian Huang bond_grp->active_slave_num = active_slave_num; 1605d91677bSJunxian Huang bond_grp->active_slave_map = active_slave_map; 1615d91677bSJunxian Huang } 1625d91677bSJunxian Huang 163*d70f30ceSJunxian Huang static int hns_roce_recover_bond(struct hns_roce_bond_group *bond_grp, 164*d70f30ceSJunxian Huang struct hns_roce_dev *hr_dev) 165*d70f30ceSJunxian Huang { 166*d70f30ceSJunxian Huang bond_grp->main_hr_dev = hr_dev; 167*d70f30ceSJunxian Huang hns_roce_bond_get_active_slave(bond_grp); 168*d70f30ceSJunxian Huang 169*d70f30ceSJunxian Huang return hns_roce_cmd_bond(bond_grp, HNS_ROCE_SET_BOND); 170*d70f30ceSJunxian Huang } 171*d70f30ceSJunxian Huang 172d9023e46SJunxian Huang static void hns_roce_slave_uninit(struct hns_roce_bond_group *bond_grp, 173d9023e46SJunxian Huang u8 func_idx) 174d9023e46SJunxian Huang { 175d9023e46SJunxian Huang struct hnae3_handle *handle; 176d9023e46SJunxian Huang 177d9023e46SJunxian Huang handle = bond_grp->bond_func_info[func_idx].handle; 178d9023e46SJunxian Huang if (handle->priv) 179d9023e46SJunxian Huang hns_roce_bond_uninit_client(bond_grp, func_idx); 180d9023e46SJunxian Huang } 181d9023e46SJunxian Huang 182d9023e46SJunxian Huang static struct hns_roce_dev 183d9023e46SJunxian Huang *hns_roce_slave_init(struct hns_roce_bond_group *bond_grp, 184d9023e46SJunxian Huang u8 func_idx, bool need_switch); 185d9023e46SJunxian Huang 186d9023e46SJunxian Huang static int switch_main_dev(struct hns_roce_bond_group *bond_grp, 187d9023e46SJunxian Huang u8 main_func_idx) 188d9023e46SJunxian Huang { 189d9023e46SJunxian Huang struct hns_roce_dev *hr_dev; 190d9023e46SJunxian Huang struct net_device *net_dev; 191d9023e46SJunxian Huang u8 i; 192d9023e46SJunxian Huang 193d9023e46SJunxian Huang bond_grp->main_hr_dev = NULL; 194d9023e46SJunxian Huang hns_roce_bond_uninit_client(bond_grp, main_func_idx); 195d9023e46SJunxian Huang 196d9023e46SJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 197d9023e46SJunxian Huang net_dev = bond_grp->bond_func_info[i].net_dev; 198d9023e46SJunxian Huang if ((bond_grp->slave_map & (1U << i)) && net_dev) { 199d9023e46SJunxian Huang /* In case this slave is still being registered as 200d9023e46SJunxian Huang * a non-bonded PF, uninit it first and then re-init 201d9023e46SJunxian Huang * it as the main device. 202d9023e46SJunxian Huang */ 203d9023e46SJunxian Huang hns_roce_slave_uninit(bond_grp, i); 204d9023e46SJunxian Huang hr_dev = hns_roce_slave_init(bond_grp, i, false); 205d9023e46SJunxian Huang if (hr_dev) { 206d9023e46SJunxian Huang bond_grp->main_hr_dev = hr_dev; 207d9023e46SJunxian Huang break; 208d9023e46SJunxian Huang } 209d9023e46SJunxian Huang } 210d9023e46SJunxian Huang } 211d9023e46SJunxian Huang 212d9023e46SJunxian Huang if (!bond_grp->main_hr_dev) 213d9023e46SJunxian Huang return -ENODEV; 214d9023e46SJunxian Huang 215d9023e46SJunxian Huang return 0; 216d9023e46SJunxian Huang } 217d9023e46SJunxian Huang 218d9023e46SJunxian Huang static struct hns_roce_dev 219d9023e46SJunxian Huang *hns_roce_slave_init(struct hns_roce_bond_group *bond_grp, 220d9023e46SJunxian Huang u8 func_idx, bool need_switch) 221d9023e46SJunxian Huang { 222d9023e46SJunxian Huang struct hns_roce_dev *hr_dev = NULL; 223d9023e46SJunxian Huang struct hnae3_handle *handle; 224d9023e46SJunxian Huang u8 main_func_idx; 225d9023e46SJunxian Huang int ret; 226d9023e46SJunxian Huang 227d9023e46SJunxian Huang if (need_switch) { 228d9023e46SJunxian Huang main_func_idx = PCI_FUNC(bond_grp->main_hr_dev->pci_dev->devfn); 229d9023e46SJunxian Huang if (func_idx == main_func_idx) { 230d9023e46SJunxian Huang ret = switch_main_dev(bond_grp, main_func_idx); 231d9023e46SJunxian Huang if (ret == -ENODEV) 232d9023e46SJunxian Huang return NULL; 233d9023e46SJunxian Huang } 234d9023e46SJunxian Huang } 235d9023e46SJunxian Huang 236d9023e46SJunxian Huang handle = bond_grp->bond_func_info[func_idx].handle; 237d9023e46SJunxian Huang if (handle) { 238d9023e46SJunxian Huang if (handle->priv) 239d9023e46SJunxian Huang return handle->priv; 240d9023e46SJunxian Huang /* Prevent this device from being initialized as a bond device */ 241d9023e46SJunxian Huang if (need_switch) 242d9023e46SJunxian Huang bond_grp->bond_func_info[func_idx].net_dev = NULL; 243d9023e46SJunxian Huang hr_dev = hns_roce_bond_init_client(bond_grp, func_idx); 244d9023e46SJunxian Huang if (!hr_dev) 245d9023e46SJunxian Huang BOND_ERR_LOG("failed to init slave %u.\n", func_idx); 246d9023e46SJunxian Huang } 247d9023e46SJunxian Huang 248d9023e46SJunxian Huang return hr_dev; 249d9023e46SJunxian Huang } 250d9023e46SJunxian Huang 251b37ad2e2SJunxian Huang static struct hns_roce_die_info *alloc_die_info(int bus_num) 252b37ad2e2SJunxian Huang { 253b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 254b37ad2e2SJunxian Huang int ret; 255b37ad2e2SJunxian Huang 256b37ad2e2SJunxian Huang die_info = kzalloc(sizeof(*die_info), GFP_KERNEL); 257b37ad2e2SJunxian Huang if (!die_info) 258b37ad2e2SJunxian Huang return NULL; 259b37ad2e2SJunxian Huang 260b37ad2e2SJunxian Huang ret = xa_err(xa_store(&roce_bond_xa, bus_num, die_info, GFP_KERNEL)); 261b37ad2e2SJunxian Huang if (ret) { 262b37ad2e2SJunxian Huang kfree(die_info); 263b37ad2e2SJunxian Huang return NULL; 264b37ad2e2SJunxian Huang } 265b37ad2e2SJunxian Huang 2665d91677bSJunxian Huang mutex_init(&die_info->die_mutex); 2675d91677bSJunxian Huang 268b37ad2e2SJunxian Huang return die_info; 269b37ad2e2SJunxian Huang } 270b37ad2e2SJunxian Huang 271b37ad2e2SJunxian Huang static void dealloc_die_info(struct hns_roce_die_info *die_info, u8 bus_num) 272b37ad2e2SJunxian Huang { 2735d91677bSJunxian Huang mutex_destroy(&die_info->die_mutex); 274b37ad2e2SJunxian Huang xa_erase(&roce_bond_xa, bus_num); 275b37ad2e2SJunxian Huang kfree(die_info); 276b37ad2e2SJunxian Huang } 277b37ad2e2SJunxian Huang 278b37ad2e2SJunxian Huang static int alloc_bond_id(struct hns_roce_bond_group *bond_grp) 279b37ad2e2SJunxian Huang { 280b37ad2e2SJunxian Huang u8 bus_num = bond_grp->bus_num; 281b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 282b37ad2e2SJunxian Huang int i; 283b37ad2e2SJunxian Huang 284b37ad2e2SJunxian Huang if (!die_info) { 285b37ad2e2SJunxian Huang die_info = alloc_die_info(bus_num); 286b37ad2e2SJunxian Huang if (!die_info) 287b37ad2e2SJunxian Huang return -ENOMEM; 288b37ad2e2SJunxian Huang } 289b37ad2e2SJunxian Huang 290b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 291b37ad2e2SJunxian Huang if (die_info->bond_id_mask & BOND_ID(i)) 292b37ad2e2SJunxian Huang continue; 293b37ad2e2SJunxian Huang 294b37ad2e2SJunxian Huang die_info->bond_id_mask |= BOND_ID(i); 295b37ad2e2SJunxian Huang die_info->bgrps[i] = bond_grp; 296b37ad2e2SJunxian Huang bond_grp->bond_id = i; 297b37ad2e2SJunxian Huang 298b37ad2e2SJunxian Huang return 0; 299b37ad2e2SJunxian Huang } 300b37ad2e2SJunxian Huang 301b37ad2e2SJunxian Huang return -ENOSPC; 302b37ad2e2SJunxian Huang } 303b37ad2e2SJunxian Huang 304b37ad2e2SJunxian Huang static int remove_bond_id(int bus_num, u8 bond_id) 305b37ad2e2SJunxian Huang { 306b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 307b37ad2e2SJunxian Huang 308b37ad2e2SJunxian Huang if (bond_id >= ROCE_BOND_NUM_MAX) 309b37ad2e2SJunxian Huang return -EINVAL; 310b37ad2e2SJunxian Huang 311b37ad2e2SJunxian Huang if (!die_info) 312b37ad2e2SJunxian Huang return -ENODEV; 313b37ad2e2SJunxian Huang 314b37ad2e2SJunxian Huang die_info->bond_id_mask &= ~BOND_ID(bond_id); 315b37ad2e2SJunxian Huang die_info->bgrps[bond_id] = NULL; 316b37ad2e2SJunxian Huang if (!die_info->bond_id_mask) 317b37ad2e2SJunxian Huang dealloc_die_info(die_info, bus_num); 318b37ad2e2SJunxian Huang 319b37ad2e2SJunxian Huang return 0; 320b37ad2e2SJunxian Huang } 321b37ad2e2SJunxian Huang 3225d91677bSJunxian Huang static void hns_roce_set_bond(struct hns_roce_bond_group *bond_grp) 3235d91677bSJunxian Huang { 3245d91677bSJunxian Huang struct hns_roce_dev *hr_dev; 3255d91677bSJunxian Huang int ret; 3265d91677bSJunxian Huang int i; 3275d91677bSJunxian Huang 3285d91677bSJunxian Huang for (i = ROCE_BOND_FUNC_MAX - 1; i >= 0; i--) { 3295d91677bSJunxian Huang if (bond_grp->slave_map & (1 << i)) 3305d91677bSJunxian Huang hns_roce_slave_uninit(bond_grp, i); 3315d91677bSJunxian Huang } 3325d91677bSJunxian Huang 3335d91677bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 3345d91677bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_IS_BONDED; 3355d91677bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 3365d91677bSJunxian Huang bond_grp->main_hr_dev = NULL; 3375d91677bSJunxian Huang 3385d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 3395d91677bSJunxian Huang if (bond_grp->slave_map & (1 << i)) { 3405d91677bSJunxian Huang hr_dev = hns_roce_slave_init(bond_grp, i, false); 3415d91677bSJunxian Huang if (hr_dev) { 3425d91677bSJunxian Huang bond_grp->main_hr_dev = hr_dev; 3435d91677bSJunxian Huang break; 3445d91677bSJunxian Huang } 3455d91677bSJunxian Huang } 3465d91677bSJunxian Huang } 3475d91677bSJunxian Huang 3485d91677bSJunxian Huang if (!bond_grp->main_hr_dev) { 3495d91677bSJunxian Huang ret = -ENODEV; 3505d91677bSJunxian Huang goto out; 3515d91677bSJunxian Huang } 3525d91677bSJunxian Huang 3535d91677bSJunxian Huang hns_roce_bond_get_active_slave(bond_grp); 3545d91677bSJunxian Huang 3555d91677bSJunxian Huang ret = hns_roce_cmd_bond(bond_grp, HNS_ROCE_SET_BOND); 3565d91677bSJunxian Huang 3575d91677bSJunxian Huang out: 3585d91677bSJunxian Huang if (ret) { 3595d91677bSJunxian Huang BOND_ERR_LOG("failed to set RoCE bond, ret = %d.\n", ret); 3605d91677bSJunxian Huang hns_roce_cleanup_bond(bond_grp); 3615d91677bSJunxian Huang } else { 3625d91677bSJunxian Huang ibdev_info(&bond_grp->main_hr_dev->ib_dev, 3635d91677bSJunxian Huang "RoCE set bond finished!\n"); 3645d91677bSJunxian Huang } 3655d91677bSJunxian Huang } 3665d91677bSJunxian Huang 3675d91677bSJunxian Huang static void hns_roce_clear_bond(struct hns_roce_bond_group *bond_grp) 3685d91677bSJunxian Huang { 3695d91677bSJunxian Huang u8 main_func_idx = PCI_FUNC(bond_grp->main_hr_dev->pci_dev->devfn); 3705d91677bSJunxian Huang struct hns_roce_dev *hr_dev; 3715d91677bSJunxian Huang u8 i; 3725d91677bSJunxian Huang 3735d91677bSJunxian Huang if (bond_grp->bond_state == HNS_ROCE_BOND_NOT_BONDED) 3745d91677bSJunxian Huang goto out; 3755d91677bSJunxian Huang 3765d91677bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_BONDED; 3775d91677bSJunxian Huang bond_grp->main_hr_dev = NULL; 3785d91677bSJunxian Huang 3795d91677bSJunxian Huang hns_roce_slave_uninit(bond_grp, main_func_idx); 3805d91677bSJunxian Huang 3815d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 3825d91677bSJunxian Huang hr_dev = hns_roce_slave_init(bond_grp, i, false); 3835d91677bSJunxian Huang if (hr_dev) 3845d91677bSJunxian Huang bond_grp->main_hr_dev = hr_dev; 3855d91677bSJunxian Huang } 3865d91677bSJunxian Huang 3875d91677bSJunxian Huang out: 3885d91677bSJunxian Huang hns_roce_cleanup_bond(bond_grp); 3895d91677bSJunxian Huang } 3905d91677bSJunxian Huang 3915d91677bSJunxian Huang static void hns_roce_slave_changestate(struct hns_roce_bond_group *bond_grp) 3925d91677bSJunxian Huang { 3935d91677bSJunxian Huang int ret; 3945d91677bSJunxian Huang 3955d91677bSJunxian Huang hns_roce_bond_get_active_slave(bond_grp); 3965d91677bSJunxian Huang 3975d91677bSJunxian Huang ret = hns_roce_cmd_bond(bond_grp, HNS_ROCE_CHANGE_BOND); 3985d91677bSJunxian Huang 3995d91677bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 4005d91677bSJunxian Huang if (bond_grp->bond_state == HNS_ROCE_BOND_SLAVE_CHANGESTATE) 4015d91677bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_IS_BONDED; 4025d91677bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 4035d91677bSJunxian Huang 4045d91677bSJunxian Huang if (ret) 4055d91677bSJunxian Huang ibdev_err(&bond_grp->main_hr_dev->ib_dev, 4065d91677bSJunxian Huang "failed to change RoCE bond slave state, ret = %d.\n", 4075d91677bSJunxian Huang ret); 4085d91677bSJunxian Huang else 4095d91677bSJunxian Huang ibdev_info(&bond_grp->main_hr_dev->ib_dev, 4105d91677bSJunxian Huang "RoCE slave changestate finished!\n"); 4115d91677bSJunxian Huang } 4125d91677bSJunxian Huang 4135d91677bSJunxian Huang static void hns_roce_slave_change_num(struct hns_roce_bond_group *bond_grp) 4145d91677bSJunxian Huang { 4155d91677bSJunxian Huang int ret; 4165d91677bSJunxian Huang u8 i; 4175d91677bSJunxian Huang 4185d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) { 4195d91677bSJunxian Huang if (bond_grp->slave_map & (1U << i)) { 4205d91677bSJunxian Huang if (i == PCI_FUNC(bond_grp->main_hr_dev->pci_dev->devfn)) 4215d91677bSJunxian Huang continue; 4225d91677bSJunxian Huang hns_roce_slave_uninit(bond_grp, i); 4235d91677bSJunxian Huang } else { 4245d91677bSJunxian Huang hns_roce_slave_init(bond_grp, i, true); 4255d91677bSJunxian Huang if (!bond_grp->main_hr_dev) { 4265d91677bSJunxian Huang ret = -ENODEV; 4275d91677bSJunxian Huang goto out; 4285d91677bSJunxian Huang } 4295d91677bSJunxian Huang bond_grp->bond_func_info[i].net_dev = NULL; 4305d91677bSJunxian Huang bond_grp->bond_func_info[i].handle = NULL; 4315d91677bSJunxian Huang } 4325d91677bSJunxian Huang } 4335d91677bSJunxian Huang 4345d91677bSJunxian Huang hns_roce_bond_get_active_slave(bond_grp); 4355d91677bSJunxian Huang 4365d91677bSJunxian Huang ret = hns_roce_cmd_bond(bond_grp, HNS_ROCE_CHANGE_BOND); 4375d91677bSJunxian Huang 4385d91677bSJunxian Huang out: 4395d91677bSJunxian Huang if (ret) { 4405d91677bSJunxian Huang BOND_ERR_LOG("failed to change RoCE bond slave num, ret = %d.\n", ret); 4415d91677bSJunxian Huang hns_roce_cleanup_bond(bond_grp); 4425d91677bSJunxian Huang } else { 4435d91677bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 4445d91677bSJunxian Huang if (bond_grp->bond_state == HNS_ROCE_BOND_SLAVE_CHANGE_NUM) 4455d91677bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_IS_BONDED; 4465d91677bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 4475d91677bSJunxian Huang ibdev_info(&bond_grp->main_hr_dev->ib_dev, 4485d91677bSJunxian Huang "RoCE slave change num finished!\n"); 4495d91677bSJunxian Huang } 4505d91677bSJunxian Huang } 4515d91677bSJunxian Huang 4525d91677bSJunxian Huang static void hns_roce_bond_info_update_nolock(struct hns_roce_bond_group *bond_grp, 4535d91677bSJunxian Huang struct net_device *upper_dev) 4545d91677bSJunxian Huang { 4555d91677bSJunxian Huang struct hns_roce_v2_priv *priv; 4565d91677bSJunxian Huang struct hns_roce_dev *hr_dev; 4575d91677bSJunxian Huang struct net_device *net_dev; 4585d91677bSJunxian Huang int func_idx; 4595d91677bSJunxian Huang 4605d91677bSJunxian Huang bond_grp->slave_map = 0; 4615d91677bSJunxian Huang rcu_read_lock(); 4625d91677bSJunxian Huang for_each_netdev_in_bond_rcu(upper_dev, net_dev) { 4635d91677bSJunxian Huang func_idx = get_netdev_bond_slave_id(net_dev, bond_grp); 4645d91677bSJunxian Huang if (func_idx < 0) { 4655d91677bSJunxian Huang hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 4665d91677bSJunxian Huang if (!hr_dev) 4675d91677bSJunxian Huang continue; 4685d91677bSJunxian Huang func_idx = PCI_FUNC(hr_dev->pci_dev->devfn); 4695d91677bSJunxian Huang if (!bond_grp->bond_func_info[func_idx].net_dev) { 4705d91677bSJunxian Huang priv = hr_dev->priv; 4715d91677bSJunxian Huang bond_grp->bond_func_info[func_idx].net_dev = 4725d91677bSJunxian Huang net_dev; 4735d91677bSJunxian Huang bond_grp->bond_func_info[func_idx].handle = 4745d91677bSJunxian Huang priv->handle; 4755d91677bSJunxian Huang } 4765d91677bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 4775d91677bSJunxian Huang } 4785d91677bSJunxian Huang 4795d91677bSJunxian Huang bond_grp->slave_map |= (1 << func_idx); 4805d91677bSJunxian Huang } 4815d91677bSJunxian Huang rcu_read_unlock(); 4825d91677bSJunxian Huang } 4835d91677bSJunxian Huang 484d31d410bSJunxian Huang static bool is_dev_bond_supported(struct hns_roce_bond_group *bond_grp, 485d31d410bSJunxian Huang struct net_device *net_dev) 486d31d410bSJunxian Huang { 487d31d410bSJunxian Huang struct hns_roce_dev *hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 488d31d410bSJunxian Huang bool ret = true; 489d31d410bSJunxian Huang 490d31d410bSJunxian Huang if (!hr_dev) { 491d31d410bSJunxian Huang if (bond_grp && 492d31d410bSJunxian Huang get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 493d31d410bSJunxian Huang return true; 494d31d410bSJunxian Huang else 495d31d410bSJunxian Huang return false; 496d31d410bSJunxian Huang } 497d31d410bSJunxian Huang 498d31d410bSJunxian Huang if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_BOND)) { 499d31d410bSJunxian Huang ret = false; 500d31d410bSJunxian Huang goto out; 501d31d410bSJunxian Huang } 502d31d410bSJunxian Huang 503d31d410bSJunxian Huang if (hr_dev->is_vf || pci_num_vf(hr_dev->pci_dev) > 0) { 504d31d410bSJunxian Huang ret = false; 505d31d410bSJunxian Huang goto out; 506d31d410bSJunxian Huang } 507d31d410bSJunxian Huang 508d31d410bSJunxian Huang if (bond_grp->bus_num != get_hr_bus_num(hr_dev)) 509d31d410bSJunxian Huang ret = false; 510d31d410bSJunxian Huang 511d31d410bSJunxian Huang out: 512d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 513d31d410bSJunxian Huang return ret; 514d31d410bSJunxian Huang } 515d31d410bSJunxian Huang 516d31d410bSJunxian Huang static bool check_slave_support(struct hns_roce_bond_group *bond_grp, 517d31d410bSJunxian Huang struct net_device *upper_dev) 518d31d410bSJunxian Huang { 519d31d410bSJunxian Huang struct net_device *net_dev; 520d31d410bSJunxian Huang u8 slave_num = 0; 521d31d410bSJunxian Huang 522d31d410bSJunxian Huang rcu_read_lock(); 523d31d410bSJunxian Huang for_each_netdev_in_bond_rcu(upper_dev, net_dev) { 524d31d410bSJunxian Huang if (is_dev_bond_supported(bond_grp, net_dev)) { 525d31d410bSJunxian Huang slave_num++; 526d31d410bSJunxian Huang continue; 527d31d410bSJunxian Huang } 528d31d410bSJunxian Huang rcu_read_unlock(); 529d31d410bSJunxian Huang return false; 530d31d410bSJunxian Huang } 531d31d410bSJunxian Huang rcu_read_unlock(); 532d31d410bSJunxian Huang 533d31d410bSJunxian Huang return (slave_num > 1 && slave_num <= ROCE_BOND_FUNC_MAX); 534d31d410bSJunxian Huang } 535d31d410bSJunxian Huang 5365d91677bSJunxian Huang static void hns_roce_bond_work(struct work_struct *work) 5375d91677bSJunxian Huang { 5385d91677bSJunxian Huang struct delayed_work *delayed_work = to_delayed_work(work); 5395d91677bSJunxian Huang struct hns_roce_bond_group *bond_grp = 5405d91677bSJunxian Huang container_of(delayed_work, struct hns_roce_bond_group, 5415d91677bSJunxian Huang bond_work); 5425d91677bSJunxian Huang enum hns_roce_bond_state bond_state; 5435d91677bSJunxian Huang bool bond_ready; 5445d91677bSJunxian Huang 5455d91677bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 5465d91677bSJunxian Huang bond_ready = check_slave_support(bond_grp, bond_grp->upper_dev); 5475d91677bSJunxian Huang hns_roce_bond_info_update_nolock(bond_grp, bond_grp->upper_dev); 5485d91677bSJunxian Huang bond_state = bond_grp->bond_state; 5495d91677bSJunxian Huang bond_grp->bond_ready = bond_ready; 5505d91677bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 5515d91677bSJunxian Huang 5525d91677bSJunxian Huang ibdev_info(&bond_grp->main_hr_dev->ib_dev, 5535d91677bSJunxian Huang "bond work: bond_ready - %d, bond_state - %d.\n", 5545d91677bSJunxian Huang bond_ready, bond_state); 5555d91677bSJunxian Huang 5565d91677bSJunxian Huang if (!bond_ready) { 5575d91677bSJunxian Huang hns_roce_clear_bond(bond_grp); 5585d91677bSJunxian Huang return; 5595d91677bSJunxian Huang } 5605d91677bSJunxian Huang 5615d91677bSJunxian Huang switch (bond_state) { 5625d91677bSJunxian Huang case HNS_ROCE_BOND_NOT_BONDED: 5635d91677bSJunxian Huang hns_roce_set_bond(bond_grp); 5645d91677bSJunxian Huang /* In set_bond flow, we don't need to set bond netdev here as 5655d91677bSJunxian Huang * it has been done when bond_grp->main_hr_dev is registered. 5665d91677bSJunxian Huang */ 5675d91677bSJunxian Huang return; 5685d91677bSJunxian Huang case HNS_ROCE_BOND_SLAVE_CHANGESTATE: 5695d91677bSJunxian Huang hns_roce_slave_changestate(bond_grp); 5705d91677bSJunxian Huang break; 5715d91677bSJunxian Huang case HNS_ROCE_BOND_SLAVE_CHANGE_NUM: 5725d91677bSJunxian Huang hns_roce_slave_change_num(bond_grp); 5735d91677bSJunxian Huang break; 5745d91677bSJunxian Huang default: 5755d91677bSJunxian Huang return; 5765d91677bSJunxian Huang } 5775d91677bSJunxian Huang hns_roce_set_bond_netdev(bond_grp, bond_grp->main_hr_dev); 5785d91677bSJunxian Huang } 5795d91677bSJunxian Huang 580d31d410bSJunxian Huang static void hns_roce_attach_bond_grp(struct hns_roce_bond_group *bond_grp, 581d31d410bSJunxian Huang struct hns_roce_dev *hr_dev, 582d31d410bSJunxian Huang struct net_device *upper_dev) 583d31d410bSJunxian Huang { 584d31d410bSJunxian Huang bond_grp->upper_dev = upper_dev; 585d31d410bSJunxian Huang bond_grp->main_hr_dev = hr_dev; 586d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_BONDED; 587d31d410bSJunxian Huang bond_grp->bond_ready = false; 588d31d410bSJunxian Huang } 589d31d410bSJunxian Huang 590d9023e46SJunxian Huang static void hns_roce_detach_bond_grp(struct hns_roce_bond_group *bond_grp) 591d9023e46SJunxian Huang { 592d9023e46SJunxian Huang mutex_lock(&bond_grp->bond_mutex); 593d9023e46SJunxian Huang 5945d91677bSJunxian Huang cancel_delayed_work(&bond_grp->bond_work); 595d9023e46SJunxian Huang bond_grp->upper_dev = NULL; 596d9023e46SJunxian Huang bond_grp->main_hr_dev = NULL; 597d9023e46SJunxian Huang bond_grp->bond_ready = false; 598d9023e46SJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_ATTACHED; 599d9023e46SJunxian Huang bond_grp->slave_map = 0; 600d9023e46SJunxian Huang memset(bond_grp->bond_func_info, 0, sizeof(bond_grp->bond_func_info)); 601d9023e46SJunxian Huang 602d9023e46SJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 603d9023e46SJunxian Huang } 604d9023e46SJunxian Huang 605d9023e46SJunxian Huang void hns_roce_cleanup_bond(struct hns_roce_bond_group *bond_grp) 606d9023e46SJunxian Huang { 607d9023e46SJunxian Huang int ret; 608d9023e46SJunxian Huang 609d9023e46SJunxian Huang ret = bond_grp->main_hr_dev ? 610d9023e46SJunxian Huang hns_roce_cmd_bond(bond_grp, HNS_ROCE_CLEAR_BOND) : -EIO; 611d9023e46SJunxian Huang if (ret) 612d9023e46SJunxian Huang BOND_ERR_LOG("failed to clear RoCE bond, ret = %d.\n", ret); 613d9023e46SJunxian Huang else 614d9023e46SJunxian Huang ibdev_info(&bond_grp->main_hr_dev->ib_dev, 615d9023e46SJunxian Huang "RoCE clear bond finished!\n"); 616d9023e46SJunxian Huang 617d9023e46SJunxian Huang hns_roce_detach_bond_grp(bond_grp); 618d9023e46SJunxian Huang } 619d9023e46SJunxian Huang 620d31d410bSJunxian Huang static bool lowerstate_event_filter(struct hns_roce_bond_group *bond_grp, 621d31d410bSJunxian Huang struct net_device *net_dev) 622d31d410bSJunxian Huang { 623d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp_tmp; 624d31d410bSJunxian Huang 625d31d410bSJunxian Huang bond_grp_tmp = hns_roce_get_bond_grp(net_dev, bond_grp->bus_num); 626d31d410bSJunxian Huang return bond_grp_tmp == bond_grp; 627d31d410bSJunxian Huang } 628d31d410bSJunxian Huang 629d31d410bSJunxian Huang static void lowerstate_event_setting(struct hns_roce_bond_group *bond_grp, 630d31d410bSJunxian Huang struct netdev_notifier_changelowerstate_info *info) 631d31d410bSJunxian Huang { 632d31d410bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 633d31d410bSJunxian Huang 634d31d410bSJunxian Huang if (bond_grp->bond_ready && 635d31d410bSJunxian Huang bond_grp->bond_state == HNS_ROCE_BOND_IS_BONDED) 636d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_SLAVE_CHANGESTATE; 637d31d410bSJunxian Huang 638d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 639d31d410bSJunxian Huang } 640d31d410bSJunxian Huang 641d31d410bSJunxian Huang static bool hns_roce_bond_lowerstate_event(struct hns_roce_bond_group *bond_grp, 642d31d410bSJunxian Huang struct netdev_notifier_changelowerstate_info *info) 643d31d410bSJunxian Huang { 644d31d410bSJunxian Huang struct net_device *net_dev = 645d31d410bSJunxian Huang netdev_notifier_info_to_dev((struct netdev_notifier_info *)info); 646d31d410bSJunxian Huang 647d31d410bSJunxian Huang if (!netif_is_lag_port(net_dev)) 648d31d410bSJunxian Huang return false; 649d31d410bSJunxian Huang 650d31d410bSJunxian Huang if (!lowerstate_event_filter(bond_grp, net_dev)) 651d31d410bSJunxian Huang return false; 652d31d410bSJunxian Huang 653d31d410bSJunxian Huang lowerstate_event_setting(bond_grp, info); 654d31d410bSJunxian Huang 655d31d410bSJunxian Huang return true; 656d31d410bSJunxian Huang } 657d31d410bSJunxian Huang 658d31d410bSJunxian Huang static bool is_bond_setting_supported(struct netdev_lag_upper_info *bond_info) 659d31d410bSJunxian Huang { 660d31d410bSJunxian Huang if (!bond_info) 661d31d410bSJunxian Huang return false; 662d31d410bSJunxian Huang 663d31d410bSJunxian Huang if (bond_info->tx_type != NETDEV_LAG_TX_TYPE_ACTIVEBACKUP && 664d31d410bSJunxian Huang bond_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) 665d31d410bSJunxian Huang return false; 666d31d410bSJunxian Huang 667d31d410bSJunxian Huang if (bond_info->tx_type == NETDEV_LAG_TX_TYPE_HASH && 668d31d410bSJunxian Huang bond_info->hash_type > NETDEV_LAG_HASH_L23) 669d31d410bSJunxian Huang return false; 670d31d410bSJunxian Huang 671d31d410bSJunxian Huang return true; 672d31d410bSJunxian Huang } 673d31d410bSJunxian Huang 674d31d410bSJunxian Huang static void upper_event_setting(struct hns_roce_bond_group *bond_grp, 675d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 676d31d410bSJunxian Huang { 677d31d410bSJunxian Huang struct netdev_lag_upper_info *bond_upper_info = NULL; 678d31d410bSJunxian Huang bool slave_inc = info->linking; 679d31d410bSJunxian Huang 680d31d410bSJunxian Huang if (slave_inc) 681d31d410bSJunxian Huang bond_upper_info = info->upper_info; 682d31d410bSJunxian Huang 683d31d410bSJunxian Huang if (bond_upper_info) { 684d31d410bSJunxian Huang bond_grp->tx_type = bond_upper_info->tx_type; 685d31d410bSJunxian Huang bond_grp->hash_type = bond_upper_info->hash_type; 686d31d410bSJunxian Huang } 687d31d410bSJunxian Huang } 688d31d410bSJunxian Huang 689d31d410bSJunxian Huang static bool check_unlinking_bond_support(struct hns_roce_bond_group *bond_grp) 690d31d410bSJunxian Huang { 691d31d410bSJunxian Huang struct net_device *net_dev; 692d31d410bSJunxian Huang u8 slave_num = 0; 693d31d410bSJunxian Huang 694d31d410bSJunxian Huang rcu_read_lock(); 695d31d410bSJunxian Huang for_each_netdev_in_bond_rcu(bond_grp->upper_dev, net_dev) { 696d31d410bSJunxian Huang if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 697d31d410bSJunxian Huang slave_num++; 698d31d410bSJunxian Huang } 699d31d410bSJunxian Huang rcu_read_unlock(); 700d31d410bSJunxian Huang 701d31d410bSJunxian Huang return (slave_num > 1); 702d31d410bSJunxian Huang } 703d31d410bSJunxian Huang 704d31d410bSJunxian Huang static bool check_linking_bond_support(struct netdev_lag_upper_info *bond_info, 705d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp, 706d31d410bSJunxian Huang struct net_device *upper_dev) 707d31d410bSJunxian Huang { 708d31d410bSJunxian Huang if (!is_bond_setting_supported(bond_info)) 709d31d410bSJunxian Huang return false; 710d31d410bSJunxian Huang 711d31d410bSJunxian Huang return check_slave_support(bond_grp, upper_dev); 712d31d410bSJunxian Huang } 713d31d410bSJunxian Huang 714d31d410bSJunxian Huang static enum bond_support_type 715d31d410bSJunxian Huang check_bond_support(struct hns_roce_bond_group *bond_grp, 716d31d410bSJunxian Huang struct net_device *upper_dev, 717d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 718d31d410bSJunxian Huang { 719d31d410bSJunxian Huang bool bond_grp_exist = false; 720d31d410bSJunxian Huang bool support; 721d31d410bSJunxian Huang 722d31d410bSJunxian Huang if (upper_dev == bond_grp->upper_dev) 723d31d410bSJunxian Huang bond_grp_exist = true; 724d31d410bSJunxian Huang 725d31d410bSJunxian Huang if (!info->linking && !bond_grp_exist) 726d31d410bSJunxian Huang return BOND_NOT_SUPPORT; 727d31d410bSJunxian Huang 728d31d410bSJunxian Huang if (info->linking) 729d31d410bSJunxian Huang support = check_linking_bond_support(info->upper_info, bond_grp, 730d31d410bSJunxian Huang upper_dev); 731d31d410bSJunxian Huang else 732d31d410bSJunxian Huang support = check_unlinking_bond_support(bond_grp); 733d31d410bSJunxian Huang 734d31d410bSJunxian Huang if (support) 735d31d410bSJunxian Huang return BOND_SUPPORT; 736d31d410bSJunxian Huang 737d31d410bSJunxian Huang return bond_grp_exist ? BOND_EXISTING_NOT_SUPPORT : BOND_NOT_SUPPORT; 738d31d410bSJunxian Huang } 739d31d410bSJunxian Huang 740d31d410bSJunxian Huang static bool upper_event_filter(struct netdev_notifier_changeupper_info *info, 741d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp, 742d31d410bSJunxian Huang struct net_device *net_dev) 743d31d410bSJunxian Huang { 744d31d410bSJunxian Huang struct net_device *upper_dev = info->upper_dev; 745d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp_tmp; 746d31d410bSJunxian Huang struct hns_roce_dev *hr_dev; 747d31d410bSJunxian Huang bool ret = true; 748d31d410bSJunxian Huang u8 bus_num; 749d31d410bSJunxian Huang 750d31d410bSJunxian Huang if (!info->linking || 751d31d410bSJunxian Huang bond_grp->bond_state != HNS_ROCE_BOND_NOT_ATTACHED) 752d31d410bSJunxian Huang return bond_grp->upper_dev == upper_dev; 753d31d410bSJunxian Huang 754d31d410bSJunxian Huang hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 755d31d410bSJunxian Huang if (!hr_dev) 756d31d410bSJunxian Huang return false; 757d31d410bSJunxian Huang 758d31d410bSJunxian Huang bus_num = get_hr_bus_num(hr_dev); 759d31d410bSJunxian Huang if (bond_grp->bus_num != bus_num) { 760d31d410bSJunxian Huang ret = false; 761d31d410bSJunxian Huang goto out; 762d31d410bSJunxian Huang } 763d31d410bSJunxian Huang 764d31d410bSJunxian Huang bond_grp_tmp = hns_roce_get_bond_grp(net_dev, bus_num); 765d31d410bSJunxian Huang if (bond_grp_tmp && bond_grp_tmp != bond_grp) 766d31d410bSJunxian Huang ret = false; 767d31d410bSJunxian Huang out: 768d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 769d31d410bSJunxian Huang return ret; 770d31d410bSJunxian Huang } 771d31d410bSJunxian Huang 772d31d410bSJunxian Huang static bool hns_roce_bond_upper_event(struct hns_roce_bond_group *bond_grp, 773d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 774d31d410bSJunxian Huang { 775d31d410bSJunxian Huang struct net_device *net_dev = 776d31d410bSJunxian Huang netdev_notifier_info_to_dev((struct netdev_notifier_info *)info); 777d31d410bSJunxian Huang struct net_device *upper_dev = info->upper_dev; 778d31d410bSJunxian Huang enum bond_support_type support = BOND_SUPPORT; 779d31d410bSJunxian Huang struct hns_roce_dev *hr_dev; 780d31d410bSJunxian Huang int slave_id; 781d31d410bSJunxian Huang 782d31d410bSJunxian Huang if (!upper_dev || !netif_is_lag_master(upper_dev)) 783d31d410bSJunxian Huang return false; 784d31d410bSJunxian Huang 785d31d410bSJunxian Huang if (!upper_event_filter(info, bond_grp, net_dev)) 786d31d410bSJunxian Huang return false; 787d31d410bSJunxian Huang 788d31d410bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 789d31d410bSJunxian Huang support = check_bond_support(bond_grp, upper_dev, info); 790d31d410bSJunxian Huang if (support == BOND_NOT_SUPPORT) { 791d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 792d31d410bSJunxian Huang return false; 793d31d410bSJunxian Huang } 794d31d410bSJunxian Huang 795d31d410bSJunxian Huang if (bond_grp->bond_state == HNS_ROCE_BOND_NOT_ATTACHED) { 796d31d410bSJunxian Huang hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 797d31d410bSJunxian Huang if (!hr_dev) { 798d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 799d31d410bSJunxian Huang return false; 800d31d410bSJunxian Huang } 801d31d410bSJunxian Huang hns_roce_attach_bond_grp(bond_grp, hr_dev, upper_dev); 802d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 803d31d410bSJunxian Huang } 804d31d410bSJunxian Huang 805d31d410bSJunxian Huang /* In the case of netdev being unregistered, the roce 806d31d410bSJunxian Huang * instance shouldn't be inited. 807d31d410bSJunxian Huang */ 808d31d410bSJunxian Huang if (net_dev->reg_state >= NETREG_UNREGISTERING) { 809d31d410bSJunxian Huang slave_id = get_netdev_bond_slave_id(net_dev, bond_grp); 810d31d410bSJunxian Huang if (slave_id >= 0) { 811d31d410bSJunxian Huang bond_grp->bond_func_info[slave_id].net_dev = NULL; 812d31d410bSJunxian Huang bond_grp->bond_func_info[slave_id].handle = NULL; 813d31d410bSJunxian Huang } 814d31d410bSJunxian Huang } 815d31d410bSJunxian Huang 816d31d410bSJunxian Huang if (support == BOND_SUPPORT) { 817d31d410bSJunxian Huang bond_grp->bond_ready = true; 818d31d410bSJunxian Huang if (bond_grp->bond_state != HNS_ROCE_BOND_NOT_BONDED) 819d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_SLAVE_CHANGE_NUM; 820d31d410bSJunxian Huang } 821d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 822d31d410bSJunxian Huang if (support == BOND_SUPPORT) 823d31d410bSJunxian Huang upper_event_setting(bond_grp, info); 824d31d410bSJunxian Huang 825d31d410bSJunxian Huang return true; 826d31d410bSJunxian Huang } 827d31d410bSJunxian Huang 828d31d410bSJunxian Huang static int hns_roce_bond_event(struct notifier_block *self, 829d31d410bSJunxian Huang unsigned long event, void *ptr) 830d31d410bSJunxian Huang { 831d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp = 832d31d410bSJunxian Huang container_of(self, struct hns_roce_bond_group, bond_nb); 833d31d410bSJunxian Huang bool changed = false; 834d31d410bSJunxian Huang 835d31d410bSJunxian Huang if (event == NETDEV_CHANGEUPPER) 836d31d410bSJunxian Huang changed = hns_roce_bond_upper_event(bond_grp, ptr); 837d31d410bSJunxian Huang if (event == NETDEV_CHANGELOWERSTATE) 838d31d410bSJunxian Huang changed = hns_roce_bond_lowerstate_event(bond_grp, ptr); 839d31d410bSJunxian Huang 8405d91677bSJunxian Huang if (changed) 8415d91677bSJunxian Huang schedule_delayed_work(&bond_grp->bond_work, HZ); 8425d91677bSJunxian Huang 843d31d410bSJunxian Huang return NOTIFY_DONE; 844d31d410bSJunxian Huang } 845d31d410bSJunxian Huang 846b37ad2e2SJunxian Huang int hns_roce_alloc_bond_grp(struct hns_roce_dev *hr_dev) 847b37ad2e2SJunxian Huang { 848b37ad2e2SJunxian Huang struct hns_roce_bond_group *bgrps[ROCE_BOND_NUM_MAX]; 849b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 850b37ad2e2SJunxian Huang u8 bus_num = get_hr_bus_num(hr_dev); 851b37ad2e2SJunxian Huang int ret; 852b37ad2e2SJunxian Huang int i; 853b37ad2e2SJunxian Huang 854b37ad2e2SJunxian Huang if (xa_load(&roce_bond_xa, bus_num)) 855b37ad2e2SJunxian Huang return 0; 856b37ad2e2SJunxian Huang 857b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 858b37ad2e2SJunxian Huang bond_grp = kvzalloc(sizeof(*bond_grp), GFP_KERNEL); 859b37ad2e2SJunxian Huang if (!bond_grp) { 860b37ad2e2SJunxian Huang ret = -ENOMEM; 861b37ad2e2SJunxian Huang goto mem_err; 862b37ad2e2SJunxian Huang } 863b37ad2e2SJunxian Huang 864d31d410bSJunxian Huang mutex_init(&bond_grp->bond_mutex); 8655d91677bSJunxian Huang INIT_DELAYED_WORK(&bond_grp->bond_work, hns_roce_bond_work); 866d31d410bSJunxian Huang 867d31d410bSJunxian Huang bond_grp->bond_ready = false; 868d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_ATTACHED; 869b37ad2e2SJunxian Huang bond_grp->bus_num = bus_num; 870b37ad2e2SJunxian Huang 871b37ad2e2SJunxian Huang ret = alloc_bond_id(bond_grp); 872b37ad2e2SJunxian Huang if (ret) { 873b37ad2e2SJunxian Huang dev_err(hr_dev->dev, 874b37ad2e2SJunxian Huang "failed to alloc bond ID, ret = %d.\n", ret); 875b37ad2e2SJunxian Huang goto alloc_id_err; 876b37ad2e2SJunxian Huang } 877b37ad2e2SJunxian Huang 878d31d410bSJunxian Huang bond_grp->bond_nb.notifier_call = hns_roce_bond_event; 879d31d410bSJunxian Huang ret = register_netdevice_notifier(&bond_grp->bond_nb); 880d31d410bSJunxian Huang if (ret) { 881d31d410bSJunxian Huang ibdev_err(&hr_dev->ib_dev, 882d31d410bSJunxian Huang "failed to register bond nb, ret = %d.\n", ret); 883d31d410bSJunxian Huang goto register_nb_err; 884d31d410bSJunxian Huang } 885b37ad2e2SJunxian Huang bgrps[i] = bond_grp; 886b37ad2e2SJunxian Huang } 887b37ad2e2SJunxian Huang 888b37ad2e2SJunxian Huang return 0; 889b37ad2e2SJunxian Huang 890d31d410bSJunxian Huang register_nb_err: 891d31d410bSJunxian Huang remove_bond_id(bond_grp->bus_num, bond_grp->bond_id); 892b37ad2e2SJunxian Huang alloc_id_err: 893d31d410bSJunxian Huang mutex_destroy(&bond_grp->bond_mutex); 894b37ad2e2SJunxian Huang kvfree(bond_grp); 895b37ad2e2SJunxian Huang mem_err: 896b37ad2e2SJunxian Huang for (i--; i >= 0; i--) { 897d31d410bSJunxian Huang unregister_netdevice_notifier(&bgrps[i]->bond_nb); 8985d91677bSJunxian Huang cancel_delayed_work_sync(&bgrps[i]->bond_work); 899b37ad2e2SJunxian Huang remove_bond_id(bgrps[i]->bus_num, bgrps[i]->bond_id); 900d31d410bSJunxian Huang mutex_destroy(&bgrps[i]->bond_mutex); 901b37ad2e2SJunxian Huang kvfree(bgrps[i]); 902b37ad2e2SJunxian Huang } 903b37ad2e2SJunxian Huang return ret; 904b37ad2e2SJunxian Huang } 905b37ad2e2SJunxian Huang 906b37ad2e2SJunxian Huang void hns_roce_dealloc_bond_grp(void) 907b37ad2e2SJunxian Huang { 908b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 909b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 910b37ad2e2SJunxian Huang unsigned long id; 911b37ad2e2SJunxian Huang int i; 912b37ad2e2SJunxian Huang 913b37ad2e2SJunxian Huang xa_for_each(&roce_bond_xa, id, die_info) { 914b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 915b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 916b37ad2e2SJunxian Huang if (!bond_grp) 917b37ad2e2SJunxian Huang continue; 918d31d410bSJunxian Huang unregister_netdevice_notifier(&bond_grp->bond_nb); 9195d91677bSJunxian Huang cancel_delayed_work_sync(&bond_grp->bond_work); 920b37ad2e2SJunxian Huang remove_bond_id(bond_grp->bus_num, bond_grp->bond_id); 921d31d410bSJunxian Huang mutex_destroy(&bond_grp->bond_mutex); 922b37ad2e2SJunxian Huang kvfree(bond_grp); 923b37ad2e2SJunxian Huang } 924b37ad2e2SJunxian Huang } 925b37ad2e2SJunxian Huang } 926d9023e46SJunxian Huang 927d9023e46SJunxian Huang int hns_roce_bond_init(struct hns_roce_dev *hr_dev) 928d9023e46SJunxian Huang { 929d9023e46SJunxian Huang struct net_device *net_dev = get_hr_netdev(hr_dev, 0); 930*d70f30ceSJunxian Huang struct hns_roce_v2_priv *priv = hr_dev->priv; 931d9023e46SJunxian Huang struct hns_roce_bond_group *bond_grp; 932d9023e46SJunxian Huang u8 bus_num = get_hr_bus_num(hr_dev); 933*d70f30ceSJunxian Huang int ret; 934d9023e46SJunxian Huang 935d9023e46SJunxian Huang bond_grp = hns_roce_get_bond_grp(net_dev, bus_num); 936d9023e46SJunxian Huang 937*d70f30ceSJunxian Huang if (priv->handle->rinfo.reset_state == HNS_ROCE_STATE_RST_INIT) { 938*d70f30ceSJunxian Huang ret = hns_roce_recover_bond(bond_grp, hr_dev); 939*d70f30ceSJunxian Huang if (ret) { 940*d70f30ceSJunxian Huang dev_err(hr_dev->dev, 941*d70f30ceSJunxian Huang "failed to recover RoCE bond, ret = %d.\n", ret); 942*d70f30ceSJunxian Huang return ret; 943*d70f30ceSJunxian Huang } 944*d70f30ceSJunxian Huang } 945*d70f30ceSJunxian Huang 946d9023e46SJunxian Huang return hns_roce_set_bond_netdev(bond_grp, hr_dev); 947d9023e46SJunxian Huang } 9485d91677bSJunxian Huang 9495d91677bSJunxian Huang void hns_roce_bond_suspend(struct hnae3_handle *handle) 9505d91677bSJunxian Huang { 9515d91677bSJunxian Huang u8 bus_num = handle->pdev->bus->number; 9525d91677bSJunxian Huang struct hns_roce_bond_group *bond_grp; 9535d91677bSJunxian Huang struct hns_roce_die_info *die_info; 9545d91677bSJunxian Huang int i; 9555d91677bSJunxian Huang 9565d91677bSJunxian Huang die_info = xa_load(&roce_bond_xa, bus_num); 9575d91677bSJunxian Huang if (!die_info) 9585d91677bSJunxian Huang return; 9595d91677bSJunxian Huang 9605d91677bSJunxian Huang mutex_lock(&die_info->die_mutex); 9615d91677bSJunxian Huang 9625d91677bSJunxian Huang /* 9635d91677bSJunxian Huang * Avoid duplicated processing when calling this function 9645d91677bSJunxian Huang * multiple times. 9655d91677bSJunxian Huang */ 9665d91677bSJunxian Huang if (die_info->suspend_cnt) 9675d91677bSJunxian Huang goto out; 9685d91677bSJunxian Huang 9695d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 9705d91677bSJunxian Huang bond_grp = die_info->bgrps[i]; 9715d91677bSJunxian Huang if (!bond_grp) 9725d91677bSJunxian Huang continue; 9735d91677bSJunxian Huang unregister_netdevice_notifier(&bond_grp->bond_nb); 9745d91677bSJunxian Huang cancel_delayed_work_sync(&bond_grp->bond_work); 9755d91677bSJunxian Huang } 9765d91677bSJunxian Huang 9775d91677bSJunxian Huang out: 9785d91677bSJunxian Huang die_info->suspend_cnt++; 9795d91677bSJunxian Huang mutex_unlock(&die_info->die_mutex); 9805d91677bSJunxian Huang } 9815d91677bSJunxian Huang 9825d91677bSJunxian Huang void hns_roce_bond_resume(struct hnae3_handle *handle) 9835d91677bSJunxian Huang { 9845d91677bSJunxian Huang u8 bus_num = handle->pdev->bus->number; 9855d91677bSJunxian Huang struct hns_roce_bond_group *bond_grp; 9865d91677bSJunxian Huang struct hns_roce_die_info *die_info; 9875d91677bSJunxian Huang int i, ret; 9885d91677bSJunxian Huang 9895d91677bSJunxian Huang die_info = xa_load(&roce_bond_xa, bus_num); 9905d91677bSJunxian Huang if (!die_info) 9915d91677bSJunxian Huang return; 9925d91677bSJunxian Huang 9935d91677bSJunxian Huang mutex_lock(&die_info->die_mutex); 9945d91677bSJunxian Huang 9955d91677bSJunxian Huang die_info->suspend_cnt--; 9965d91677bSJunxian Huang if (die_info->suspend_cnt) 9975d91677bSJunxian Huang goto out; 9985d91677bSJunxian Huang 9995d91677bSJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 10005d91677bSJunxian Huang bond_grp = die_info->bgrps[i]; 10015d91677bSJunxian Huang if (!bond_grp) 10025d91677bSJunxian Huang continue; 10035d91677bSJunxian Huang ret = register_netdevice_notifier(&bond_grp->bond_nb); 10045d91677bSJunxian Huang if (ret) 10055d91677bSJunxian Huang dev_err(&handle->pdev->dev, 10065d91677bSJunxian Huang "failed to resume bond notifier(bus_num = %u, id = %u), ret = %d.\n", 10075d91677bSJunxian Huang bus_num, bond_grp->bond_id, ret); 10085d91677bSJunxian Huang } 10095d91677bSJunxian Huang 10105d91677bSJunxian Huang out: 10115d91677bSJunxian Huang mutex_unlock(&die_info->die_mutex); 10125d91677bSJunxian Huang } 1013