1b37ad2e2SJunxian Huang // SPDX-License-Identifier: GPL-2.0+ 2b37ad2e2SJunxian Huang /* 3b37ad2e2SJunxian Huang * Copyright (c) 2025 Hisilicon Limited. 4b37ad2e2SJunxian Huang */ 5b37ad2e2SJunxian Huang 6b37ad2e2SJunxian Huang #include "hns_roce_device.h" 7b37ad2e2SJunxian Huang #include "hns_roce_hw_v2.h" 8b37ad2e2SJunxian Huang #include "hns_roce_bond.h" 9b37ad2e2SJunxian Huang 10b37ad2e2SJunxian Huang static DEFINE_XARRAY(roce_bond_xa); 11b37ad2e2SJunxian Huang 12*d31d410bSJunxian Huang static struct hns_roce_dev *hns_roce_get_hrdev_by_netdev(struct net_device *net_dev) 13*d31d410bSJunxian Huang { 14*d31d410bSJunxian Huang struct ib_device *ibdev = 15*d31d410bSJunxian Huang ib_device_get_by_netdev(net_dev, RDMA_DRIVER_HNS); 16*d31d410bSJunxian Huang 17*d31d410bSJunxian Huang if (!ibdev) 18*d31d410bSJunxian Huang return NULL; 19*d31d410bSJunxian Huang 20*d31d410bSJunxian Huang return container_of(ibdev, struct hns_roce_dev, ib_dev); 21*d31d410bSJunxian Huang } 22*d31d410bSJunxian Huang 23b37ad2e2SJunxian Huang static struct net_device *get_upper_dev_from_ndev(struct net_device *net_dev) 24b37ad2e2SJunxian Huang { 25b37ad2e2SJunxian Huang struct net_device *upper_dev; 26b37ad2e2SJunxian Huang 27b37ad2e2SJunxian Huang rcu_read_lock(); 28b37ad2e2SJunxian Huang upper_dev = netdev_master_upper_dev_get_rcu(net_dev); 29b37ad2e2SJunxian Huang dev_hold(upper_dev); 30b37ad2e2SJunxian Huang rcu_read_unlock(); 31b37ad2e2SJunxian Huang 32b37ad2e2SJunxian Huang return upper_dev; 33b37ad2e2SJunxian Huang } 34b37ad2e2SJunxian Huang 35b37ad2e2SJunxian Huang static int get_netdev_bond_slave_id(struct net_device *net_dev, 36b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp) 37b37ad2e2SJunxian Huang { 38b37ad2e2SJunxian Huang int i; 39b37ad2e2SJunxian Huang 40b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) 41b37ad2e2SJunxian Huang if (net_dev == bond_grp->bond_func_info[i].net_dev) 42b37ad2e2SJunxian Huang return i; 43b37ad2e2SJunxian Huang 44b37ad2e2SJunxian Huang return -ENOENT; 45b37ad2e2SJunxian Huang } 46b37ad2e2SJunxian Huang 47b37ad2e2SJunxian Huang struct hns_roce_bond_group *hns_roce_get_bond_grp(struct net_device *net_dev, 48b37ad2e2SJunxian Huang u8 bus_num) 49b37ad2e2SJunxian Huang { 50b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 51b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 52b37ad2e2SJunxian Huang struct net_device *upper_dev = NULL; 53b37ad2e2SJunxian Huang int i; 54b37ad2e2SJunxian Huang 55b37ad2e2SJunxian Huang if (!die_info) 56b37ad2e2SJunxian Huang return NULL; 57b37ad2e2SJunxian Huang 58b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 59b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 60b37ad2e2SJunxian Huang if (!bond_grp) 61b37ad2e2SJunxian Huang continue; 62b37ad2e2SJunxian Huang if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 63b37ad2e2SJunxian Huang return bond_grp; 64b37ad2e2SJunxian Huang if (bond_grp->upper_dev) { 65b37ad2e2SJunxian Huang upper_dev = get_upper_dev_from_ndev(net_dev); 66b37ad2e2SJunxian Huang if (bond_grp->upper_dev == upper_dev) { 67b37ad2e2SJunxian Huang dev_put(upper_dev); 68b37ad2e2SJunxian Huang return bond_grp; 69b37ad2e2SJunxian Huang } 70b37ad2e2SJunxian Huang dev_put(upper_dev); 71b37ad2e2SJunxian Huang } 72b37ad2e2SJunxian Huang } 73b37ad2e2SJunxian Huang 74b37ad2e2SJunxian Huang return NULL; 75b37ad2e2SJunxian Huang } 76b37ad2e2SJunxian Huang 77b37ad2e2SJunxian Huang static struct hns_roce_die_info *alloc_die_info(int bus_num) 78b37ad2e2SJunxian Huang { 79b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 80b37ad2e2SJunxian Huang int ret; 81b37ad2e2SJunxian Huang 82b37ad2e2SJunxian Huang die_info = kzalloc(sizeof(*die_info), GFP_KERNEL); 83b37ad2e2SJunxian Huang if (!die_info) 84b37ad2e2SJunxian Huang return NULL; 85b37ad2e2SJunxian Huang 86b37ad2e2SJunxian Huang ret = xa_err(xa_store(&roce_bond_xa, bus_num, die_info, GFP_KERNEL)); 87b37ad2e2SJunxian Huang if (ret) { 88b37ad2e2SJunxian Huang kfree(die_info); 89b37ad2e2SJunxian Huang return NULL; 90b37ad2e2SJunxian Huang } 91b37ad2e2SJunxian Huang 92b37ad2e2SJunxian Huang return die_info; 93b37ad2e2SJunxian Huang } 94b37ad2e2SJunxian Huang 95b37ad2e2SJunxian Huang static void dealloc_die_info(struct hns_roce_die_info *die_info, u8 bus_num) 96b37ad2e2SJunxian Huang { 97b37ad2e2SJunxian Huang xa_erase(&roce_bond_xa, bus_num); 98b37ad2e2SJunxian Huang kfree(die_info); 99b37ad2e2SJunxian Huang } 100b37ad2e2SJunxian Huang 101b37ad2e2SJunxian Huang static int alloc_bond_id(struct hns_roce_bond_group *bond_grp) 102b37ad2e2SJunxian Huang { 103b37ad2e2SJunxian Huang u8 bus_num = bond_grp->bus_num; 104b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 105b37ad2e2SJunxian Huang int i; 106b37ad2e2SJunxian Huang 107b37ad2e2SJunxian Huang if (!die_info) { 108b37ad2e2SJunxian Huang die_info = alloc_die_info(bus_num); 109b37ad2e2SJunxian Huang if (!die_info) 110b37ad2e2SJunxian Huang return -ENOMEM; 111b37ad2e2SJunxian Huang } 112b37ad2e2SJunxian Huang 113b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 114b37ad2e2SJunxian Huang if (die_info->bond_id_mask & BOND_ID(i)) 115b37ad2e2SJunxian Huang continue; 116b37ad2e2SJunxian Huang 117b37ad2e2SJunxian Huang die_info->bond_id_mask |= BOND_ID(i); 118b37ad2e2SJunxian Huang die_info->bgrps[i] = bond_grp; 119b37ad2e2SJunxian Huang bond_grp->bond_id = i; 120b37ad2e2SJunxian Huang 121b37ad2e2SJunxian Huang return 0; 122b37ad2e2SJunxian Huang } 123b37ad2e2SJunxian Huang 124b37ad2e2SJunxian Huang return -ENOSPC; 125b37ad2e2SJunxian Huang } 126b37ad2e2SJunxian Huang 127b37ad2e2SJunxian Huang static int remove_bond_id(int bus_num, u8 bond_id) 128b37ad2e2SJunxian Huang { 129b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 130b37ad2e2SJunxian Huang 131b37ad2e2SJunxian Huang if (bond_id >= ROCE_BOND_NUM_MAX) 132b37ad2e2SJunxian Huang return -EINVAL; 133b37ad2e2SJunxian Huang 134b37ad2e2SJunxian Huang if (!die_info) 135b37ad2e2SJunxian Huang return -ENODEV; 136b37ad2e2SJunxian Huang 137b37ad2e2SJunxian Huang die_info->bond_id_mask &= ~BOND_ID(bond_id); 138b37ad2e2SJunxian Huang die_info->bgrps[bond_id] = NULL; 139b37ad2e2SJunxian Huang if (!die_info->bond_id_mask) 140b37ad2e2SJunxian Huang dealloc_die_info(die_info, bus_num); 141b37ad2e2SJunxian Huang 142b37ad2e2SJunxian Huang return 0; 143b37ad2e2SJunxian Huang } 144b37ad2e2SJunxian Huang 145*d31d410bSJunxian Huang static bool is_dev_bond_supported(struct hns_roce_bond_group *bond_grp, 146*d31d410bSJunxian Huang struct net_device *net_dev) 147*d31d410bSJunxian Huang { 148*d31d410bSJunxian Huang struct hns_roce_dev *hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 149*d31d410bSJunxian Huang bool ret = true; 150*d31d410bSJunxian Huang 151*d31d410bSJunxian Huang if (!hr_dev) { 152*d31d410bSJunxian Huang if (bond_grp && 153*d31d410bSJunxian Huang get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 154*d31d410bSJunxian Huang return true; 155*d31d410bSJunxian Huang else 156*d31d410bSJunxian Huang return false; 157*d31d410bSJunxian Huang } 158*d31d410bSJunxian Huang 159*d31d410bSJunxian Huang if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_BOND)) { 160*d31d410bSJunxian Huang ret = false; 161*d31d410bSJunxian Huang goto out; 162*d31d410bSJunxian Huang } 163*d31d410bSJunxian Huang 164*d31d410bSJunxian Huang if (hr_dev->is_vf || pci_num_vf(hr_dev->pci_dev) > 0) { 165*d31d410bSJunxian Huang ret = false; 166*d31d410bSJunxian Huang goto out; 167*d31d410bSJunxian Huang } 168*d31d410bSJunxian Huang 169*d31d410bSJunxian Huang if (bond_grp->bus_num != get_hr_bus_num(hr_dev)) 170*d31d410bSJunxian Huang ret = false; 171*d31d410bSJunxian Huang 172*d31d410bSJunxian Huang out: 173*d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 174*d31d410bSJunxian Huang return ret; 175*d31d410bSJunxian Huang } 176*d31d410bSJunxian Huang 177*d31d410bSJunxian Huang static bool check_slave_support(struct hns_roce_bond_group *bond_grp, 178*d31d410bSJunxian Huang struct net_device *upper_dev) 179*d31d410bSJunxian Huang { 180*d31d410bSJunxian Huang struct net_device *net_dev; 181*d31d410bSJunxian Huang u8 slave_num = 0; 182*d31d410bSJunxian Huang 183*d31d410bSJunxian Huang rcu_read_lock(); 184*d31d410bSJunxian Huang for_each_netdev_in_bond_rcu(upper_dev, net_dev) { 185*d31d410bSJunxian Huang if (is_dev_bond_supported(bond_grp, net_dev)) { 186*d31d410bSJunxian Huang slave_num++; 187*d31d410bSJunxian Huang continue; 188*d31d410bSJunxian Huang } 189*d31d410bSJunxian Huang rcu_read_unlock(); 190*d31d410bSJunxian Huang return false; 191*d31d410bSJunxian Huang } 192*d31d410bSJunxian Huang rcu_read_unlock(); 193*d31d410bSJunxian Huang 194*d31d410bSJunxian Huang return (slave_num > 1 && slave_num <= ROCE_BOND_FUNC_MAX); 195*d31d410bSJunxian Huang } 196*d31d410bSJunxian Huang 197*d31d410bSJunxian Huang static void hns_roce_attach_bond_grp(struct hns_roce_bond_group *bond_grp, 198*d31d410bSJunxian Huang struct hns_roce_dev *hr_dev, 199*d31d410bSJunxian Huang struct net_device *upper_dev) 200*d31d410bSJunxian Huang { 201*d31d410bSJunxian Huang bond_grp->upper_dev = upper_dev; 202*d31d410bSJunxian Huang bond_grp->main_hr_dev = hr_dev; 203*d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_BONDED; 204*d31d410bSJunxian Huang bond_grp->bond_ready = false; 205*d31d410bSJunxian Huang } 206*d31d410bSJunxian Huang 207*d31d410bSJunxian Huang static bool lowerstate_event_filter(struct hns_roce_bond_group *bond_grp, 208*d31d410bSJunxian Huang struct net_device *net_dev) 209*d31d410bSJunxian Huang { 210*d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp_tmp; 211*d31d410bSJunxian Huang 212*d31d410bSJunxian Huang bond_grp_tmp = hns_roce_get_bond_grp(net_dev, bond_grp->bus_num); 213*d31d410bSJunxian Huang return bond_grp_tmp == bond_grp; 214*d31d410bSJunxian Huang } 215*d31d410bSJunxian Huang 216*d31d410bSJunxian Huang static void lowerstate_event_setting(struct hns_roce_bond_group *bond_grp, 217*d31d410bSJunxian Huang struct netdev_notifier_changelowerstate_info *info) 218*d31d410bSJunxian Huang { 219*d31d410bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 220*d31d410bSJunxian Huang 221*d31d410bSJunxian Huang if (bond_grp->bond_ready && 222*d31d410bSJunxian Huang bond_grp->bond_state == HNS_ROCE_BOND_IS_BONDED) 223*d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_SLAVE_CHANGESTATE; 224*d31d410bSJunxian Huang 225*d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 226*d31d410bSJunxian Huang } 227*d31d410bSJunxian Huang 228*d31d410bSJunxian Huang static bool hns_roce_bond_lowerstate_event(struct hns_roce_bond_group *bond_grp, 229*d31d410bSJunxian Huang struct netdev_notifier_changelowerstate_info *info) 230*d31d410bSJunxian Huang { 231*d31d410bSJunxian Huang struct net_device *net_dev = 232*d31d410bSJunxian Huang netdev_notifier_info_to_dev((struct netdev_notifier_info *)info); 233*d31d410bSJunxian Huang 234*d31d410bSJunxian Huang if (!netif_is_lag_port(net_dev)) 235*d31d410bSJunxian Huang return false; 236*d31d410bSJunxian Huang 237*d31d410bSJunxian Huang if (!lowerstate_event_filter(bond_grp, net_dev)) 238*d31d410bSJunxian Huang return false; 239*d31d410bSJunxian Huang 240*d31d410bSJunxian Huang lowerstate_event_setting(bond_grp, info); 241*d31d410bSJunxian Huang 242*d31d410bSJunxian Huang return true; 243*d31d410bSJunxian Huang } 244*d31d410bSJunxian Huang 245*d31d410bSJunxian Huang static bool is_bond_setting_supported(struct netdev_lag_upper_info *bond_info) 246*d31d410bSJunxian Huang { 247*d31d410bSJunxian Huang if (!bond_info) 248*d31d410bSJunxian Huang return false; 249*d31d410bSJunxian Huang 250*d31d410bSJunxian Huang if (bond_info->tx_type != NETDEV_LAG_TX_TYPE_ACTIVEBACKUP && 251*d31d410bSJunxian Huang bond_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) 252*d31d410bSJunxian Huang return false; 253*d31d410bSJunxian Huang 254*d31d410bSJunxian Huang if (bond_info->tx_type == NETDEV_LAG_TX_TYPE_HASH && 255*d31d410bSJunxian Huang bond_info->hash_type > NETDEV_LAG_HASH_L23) 256*d31d410bSJunxian Huang return false; 257*d31d410bSJunxian Huang 258*d31d410bSJunxian Huang return true; 259*d31d410bSJunxian Huang } 260*d31d410bSJunxian Huang 261*d31d410bSJunxian Huang static void upper_event_setting(struct hns_roce_bond_group *bond_grp, 262*d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 263*d31d410bSJunxian Huang { 264*d31d410bSJunxian Huang struct netdev_lag_upper_info *bond_upper_info = NULL; 265*d31d410bSJunxian Huang bool slave_inc = info->linking; 266*d31d410bSJunxian Huang 267*d31d410bSJunxian Huang if (slave_inc) 268*d31d410bSJunxian Huang bond_upper_info = info->upper_info; 269*d31d410bSJunxian Huang 270*d31d410bSJunxian Huang if (bond_upper_info) { 271*d31d410bSJunxian Huang bond_grp->tx_type = bond_upper_info->tx_type; 272*d31d410bSJunxian Huang bond_grp->hash_type = bond_upper_info->hash_type; 273*d31d410bSJunxian Huang } 274*d31d410bSJunxian Huang } 275*d31d410bSJunxian Huang 276*d31d410bSJunxian Huang static bool check_unlinking_bond_support(struct hns_roce_bond_group *bond_grp) 277*d31d410bSJunxian Huang { 278*d31d410bSJunxian Huang struct net_device *net_dev; 279*d31d410bSJunxian Huang u8 slave_num = 0; 280*d31d410bSJunxian Huang 281*d31d410bSJunxian Huang rcu_read_lock(); 282*d31d410bSJunxian Huang for_each_netdev_in_bond_rcu(bond_grp->upper_dev, net_dev) { 283*d31d410bSJunxian Huang if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 284*d31d410bSJunxian Huang slave_num++; 285*d31d410bSJunxian Huang } 286*d31d410bSJunxian Huang rcu_read_unlock(); 287*d31d410bSJunxian Huang 288*d31d410bSJunxian Huang return (slave_num > 1); 289*d31d410bSJunxian Huang } 290*d31d410bSJunxian Huang 291*d31d410bSJunxian Huang static bool check_linking_bond_support(struct netdev_lag_upper_info *bond_info, 292*d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp, 293*d31d410bSJunxian Huang struct net_device *upper_dev) 294*d31d410bSJunxian Huang { 295*d31d410bSJunxian Huang if (!is_bond_setting_supported(bond_info)) 296*d31d410bSJunxian Huang return false; 297*d31d410bSJunxian Huang 298*d31d410bSJunxian Huang return check_slave_support(bond_grp, upper_dev); 299*d31d410bSJunxian Huang } 300*d31d410bSJunxian Huang 301*d31d410bSJunxian Huang static enum bond_support_type 302*d31d410bSJunxian Huang check_bond_support(struct hns_roce_bond_group *bond_grp, 303*d31d410bSJunxian Huang struct net_device *upper_dev, 304*d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 305*d31d410bSJunxian Huang { 306*d31d410bSJunxian Huang bool bond_grp_exist = false; 307*d31d410bSJunxian Huang bool support; 308*d31d410bSJunxian Huang 309*d31d410bSJunxian Huang if (upper_dev == bond_grp->upper_dev) 310*d31d410bSJunxian Huang bond_grp_exist = true; 311*d31d410bSJunxian Huang 312*d31d410bSJunxian Huang if (!info->linking && !bond_grp_exist) 313*d31d410bSJunxian Huang return BOND_NOT_SUPPORT; 314*d31d410bSJunxian Huang 315*d31d410bSJunxian Huang if (info->linking) 316*d31d410bSJunxian Huang support = check_linking_bond_support(info->upper_info, bond_grp, 317*d31d410bSJunxian Huang upper_dev); 318*d31d410bSJunxian Huang else 319*d31d410bSJunxian Huang support = check_unlinking_bond_support(bond_grp); 320*d31d410bSJunxian Huang 321*d31d410bSJunxian Huang if (support) 322*d31d410bSJunxian Huang return BOND_SUPPORT; 323*d31d410bSJunxian Huang 324*d31d410bSJunxian Huang return bond_grp_exist ? BOND_EXISTING_NOT_SUPPORT : BOND_NOT_SUPPORT; 325*d31d410bSJunxian Huang } 326*d31d410bSJunxian Huang 327*d31d410bSJunxian Huang static bool upper_event_filter(struct netdev_notifier_changeupper_info *info, 328*d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp, 329*d31d410bSJunxian Huang struct net_device *net_dev) 330*d31d410bSJunxian Huang { 331*d31d410bSJunxian Huang struct net_device *upper_dev = info->upper_dev; 332*d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp_tmp; 333*d31d410bSJunxian Huang struct hns_roce_dev *hr_dev; 334*d31d410bSJunxian Huang bool ret = true; 335*d31d410bSJunxian Huang u8 bus_num; 336*d31d410bSJunxian Huang 337*d31d410bSJunxian Huang if (!info->linking || 338*d31d410bSJunxian Huang bond_grp->bond_state != HNS_ROCE_BOND_NOT_ATTACHED) 339*d31d410bSJunxian Huang return bond_grp->upper_dev == upper_dev; 340*d31d410bSJunxian Huang 341*d31d410bSJunxian Huang hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 342*d31d410bSJunxian Huang if (!hr_dev) 343*d31d410bSJunxian Huang return false; 344*d31d410bSJunxian Huang 345*d31d410bSJunxian Huang bus_num = get_hr_bus_num(hr_dev); 346*d31d410bSJunxian Huang if (bond_grp->bus_num != bus_num) { 347*d31d410bSJunxian Huang ret = false; 348*d31d410bSJunxian Huang goto out; 349*d31d410bSJunxian Huang } 350*d31d410bSJunxian Huang 351*d31d410bSJunxian Huang bond_grp_tmp = hns_roce_get_bond_grp(net_dev, bus_num); 352*d31d410bSJunxian Huang if (bond_grp_tmp && bond_grp_tmp != bond_grp) 353*d31d410bSJunxian Huang ret = false; 354*d31d410bSJunxian Huang out: 355*d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 356*d31d410bSJunxian Huang return ret; 357*d31d410bSJunxian Huang } 358*d31d410bSJunxian Huang 359*d31d410bSJunxian Huang static bool hns_roce_bond_upper_event(struct hns_roce_bond_group *bond_grp, 360*d31d410bSJunxian Huang struct netdev_notifier_changeupper_info *info) 361*d31d410bSJunxian Huang { 362*d31d410bSJunxian Huang struct net_device *net_dev = 363*d31d410bSJunxian Huang netdev_notifier_info_to_dev((struct netdev_notifier_info *)info); 364*d31d410bSJunxian Huang struct net_device *upper_dev = info->upper_dev; 365*d31d410bSJunxian Huang enum bond_support_type support = BOND_SUPPORT; 366*d31d410bSJunxian Huang struct hns_roce_dev *hr_dev; 367*d31d410bSJunxian Huang int slave_id; 368*d31d410bSJunxian Huang 369*d31d410bSJunxian Huang if (!upper_dev || !netif_is_lag_master(upper_dev)) 370*d31d410bSJunxian Huang return false; 371*d31d410bSJunxian Huang 372*d31d410bSJunxian Huang if (!upper_event_filter(info, bond_grp, net_dev)) 373*d31d410bSJunxian Huang return false; 374*d31d410bSJunxian Huang 375*d31d410bSJunxian Huang mutex_lock(&bond_grp->bond_mutex); 376*d31d410bSJunxian Huang support = check_bond_support(bond_grp, upper_dev, info); 377*d31d410bSJunxian Huang if (support == BOND_NOT_SUPPORT) { 378*d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 379*d31d410bSJunxian Huang return false; 380*d31d410bSJunxian Huang } 381*d31d410bSJunxian Huang 382*d31d410bSJunxian Huang if (bond_grp->bond_state == HNS_ROCE_BOND_NOT_ATTACHED) { 383*d31d410bSJunxian Huang hr_dev = hns_roce_get_hrdev_by_netdev(net_dev); 384*d31d410bSJunxian Huang if (!hr_dev) { 385*d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 386*d31d410bSJunxian Huang return false; 387*d31d410bSJunxian Huang } 388*d31d410bSJunxian Huang hns_roce_attach_bond_grp(bond_grp, hr_dev, upper_dev); 389*d31d410bSJunxian Huang ib_device_put(&hr_dev->ib_dev); 390*d31d410bSJunxian Huang } 391*d31d410bSJunxian Huang 392*d31d410bSJunxian Huang /* In the case of netdev being unregistered, the roce 393*d31d410bSJunxian Huang * instance shouldn't be inited. 394*d31d410bSJunxian Huang */ 395*d31d410bSJunxian Huang if (net_dev->reg_state >= NETREG_UNREGISTERING) { 396*d31d410bSJunxian Huang slave_id = get_netdev_bond_slave_id(net_dev, bond_grp); 397*d31d410bSJunxian Huang if (slave_id >= 0) { 398*d31d410bSJunxian Huang bond_grp->bond_func_info[slave_id].net_dev = NULL; 399*d31d410bSJunxian Huang bond_grp->bond_func_info[slave_id].handle = NULL; 400*d31d410bSJunxian Huang } 401*d31d410bSJunxian Huang } 402*d31d410bSJunxian Huang 403*d31d410bSJunxian Huang if (support == BOND_SUPPORT) { 404*d31d410bSJunxian Huang bond_grp->bond_ready = true; 405*d31d410bSJunxian Huang if (bond_grp->bond_state != HNS_ROCE_BOND_NOT_BONDED) 406*d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_SLAVE_CHANGE_NUM; 407*d31d410bSJunxian Huang } 408*d31d410bSJunxian Huang mutex_unlock(&bond_grp->bond_mutex); 409*d31d410bSJunxian Huang if (support == BOND_SUPPORT) 410*d31d410bSJunxian Huang upper_event_setting(bond_grp, info); 411*d31d410bSJunxian Huang 412*d31d410bSJunxian Huang return true; 413*d31d410bSJunxian Huang } 414*d31d410bSJunxian Huang 415*d31d410bSJunxian Huang static int hns_roce_bond_event(struct notifier_block *self, 416*d31d410bSJunxian Huang unsigned long event, void *ptr) 417*d31d410bSJunxian Huang { 418*d31d410bSJunxian Huang struct hns_roce_bond_group *bond_grp = 419*d31d410bSJunxian Huang container_of(self, struct hns_roce_bond_group, bond_nb); 420*d31d410bSJunxian Huang bool changed = false; 421*d31d410bSJunxian Huang 422*d31d410bSJunxian Huang if (event == NETDEV_CHANGEUPPER) 423*d31d410bSJunxian Huang changed = hns_roce_bond_upper_event(bond_grp, ptr); 424*d31d410bSJunxian Huang if (event == NETDEV_CHANGELOWERSTATE) 425*d31d410bSJunxian Huang changed = hns_roce_bond_lowerstate_event(bond_grp, ptr); 426*d31d410bSJunxian Huang 427*d31d410bSJunxian Huang return NOTIFY_DONE; 428*d31d410bSJunxian Huang } 429*d31d410bSJunxian Huang 430b37ad2e2SJunxian Huang int hns_roce_alloc_bond_grp(struct hns_roce_dev *hr_dev) 431b37ad2e2SJunxian Huang { 432b37ad2e2SJunxian Huang struct hns_roce_bond_group *bgrps[ROCE_BOND_NUM_MAX]; 433b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 434b37ad2e2SJunxian Huang u8 bus_num = get_hr_bus_num(hr_dev); 435b37ad2e2SJunxian Huang int ret; 436b37ad2e2SJunxian Huang int i; 437b37ad2e2SJunxian Huang 438b37ad2e2SJunxian Huang if (xa_load(&roce_bond_xa, bus_num)) 439b37ad2e2SJunxian Huang return 0; 440b37ad2e2SJunxian Huang 441b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 442b37ad2e2SJunxian Huang bond_grp = kvzalloc(sizeof(*bond_grp), GFP_KERNEL); 443b37ad2e2SJunxian Huang if (!bond_grp) { 444b37ad2e2SJunxian Huang ret = -ENOMEM; 445b37ad2e2SJunxian Huang goto mem_err; 446b37ad2e2SJunxian Huang } 447b37ad2e2SJunxian Huang 448*d31d410bSJunxian Huang mutex_init(&bond_grp->bond_mutex); 449*d31d410bSJunxian Huang 450*d31d410bSJunxian Huang bond_grp->bond_ready = false; 451*d31d410bSJunxian Huang bond_grp->bond_state = HNS_ROCE_BOND_NOT_ATTACHED; 452b37ad2e2SJunxian Huang bond_grp->bus_num = bus_num; 453b37ad2e2SJunxian Huang 454b37ad2e2SJunxian Huang ret = alloc_bond_id(bond_grp); 455b37ad2e2SJunxian Huang if (ret) { 456b37ad2e2SJunxian Huang dev_err(hr_dev->dev, 457b37ad2e2SJunxian Huang "failed to alloc bond ID, ret = %d.\n", ret); 458b37ad2e2SJunxian Huang goto alloc_id_err; 459b37ad2e2SJunxian Huang } 460b37ad2e2SJunxian Huang 461*d31d410bSJunxian Huang bond_grp->bond_nb.notifier_call = hns_roce_bond_event; 462*d31d410bSJunxian Huang ret = register_netdevice_notifier(&bond_grp->bond_nb); 463*d31d410bSJunxian Huang if (ret) { 464*d31d410bSJunxian Huang ibdev_err(&hr_dev->ib_dev, 465*d31d410bSJunxian Huang "failed to register bond nb, ret = %d.\n", ret); 466*d31d410bSJunxian Huang goto register_nb_err; 467*d31d410bSJunxian Huang } 468b37ad2e2SJunxian Huang bgrps[i] = bond_grp; 469b37ad2e2SJunxian Huang } 470b37ad2e2SJunxian Huang 471b37ad2e2SJunxian Huang return 0; 472b37ad2e2SJunxian Huang 473*d31d410bSJunxian Huang register_nb_err: 474*d31d410bSJunxian Huang remove_bond_id(bond_grp->bus_num, bond_grp->bond_id); 475b37ad2e2SJunxian Huang alloc_id_err: 476*d31d410bSJunxian Huang mutex_destroy(&bond_grp->bond_mutex); 477b37ad2e2SJunxian Huang kvfree(bond_grp); 478b37ad2e2SJunxian Huang mem_err: 479b37ad2e2SJunxian Huang for (i--; i >= 0; i--) { 480*d31d410bSJunxian Huang unregister_netdevice_notifier(&bgrps[i]->bond_nb); 481b37ad2e2SJunxian Huang remove_bond_id(bgrps[i]->bus_num, bgrps[i]->bond_id); 482*d31d410bSJunxian Huang mutex_destroy(&bgrps[i]->bond_mutex); 483b37ad2e2SJunxian Huang kvfree(bgrps[i]); 484b37ad2e2SJunxian Huang } 485b37ad2e2SJunxian Huang return ret; 486b37ad2e2SJunxian Huang } 487b37ad2e2SJunxian Huang 488b37ad2e2SJunxian Huang void hns_roce_dealloc_bond_grp(void) 489b37ad2e2SJunxian Huang { 490b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 491b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 492b37ad2e2SJunxian Huang unsigned long id; 493b37ad2e2SJunxian Huang int i; 494b37ad2e2SJunxian Huang 495b37ad2e2SJunxian Huang xa_for_each(&roce_bond_xa, id, die_info) { 496b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 497b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 498b37ad2e2SJunxian Huang if (!bond_grp) 499b37ad2e2SJunxian Huang continue; 500*d31d410bSJunxian Huang unregister_netdevice_notifier(&bond_grp->bond_nb); 501b37ad2e2SJunxian Huang remove_bond_id(bond_grp->bus_num, bond_grp->bond_id); 502*d31d410bSJunxian Huang mutex_destroy(&bond_grp->bond_mutex); 503b37ad2e2SJunxian Huang kvfree(bond_grp); 504b37ad2e2SJunxian Huang } 505b37ad2e2SJunxian Huang } 506b37ad2e2SJunxian Huang } 507