1*b37ad2e2SJunxian Huang // SPDX-License-Identifier: GPL-2.0+ 2*b37ad2e2SJunxian Huang /* 3*b37ad2e2SJunxian Huang * Copyright (c) 2025 Hisilicon Limited. 4*b37ad2e2SJunxian Huang */ 5*b37ad2e2SJunxian Huang 6*b37ad2e2SJunxian Huang #include "hns_roce_device.h" 7*b37ad2e2SJunxian Huang #include "hns_roce_hw_v2.h" 8*b37ad2e2SJunxian Huang #include "hns_roce_bond.h" 9*b37ad2e2SJunxian Huang 10*b37ad2e2SJunxian Huang static DEFINE_XARRAY(roce_bond_xa); 11*b37ad2e2SJunxian Huang 12*b37ad2e2SJunxian Huang static struct net_device *get_upper_dev_from_ndev(struct net_device *net_dev) 13*b37ad2e2SJunxian Huang { 14*b37ad2e2SJunxian Huang struct net_device *upper_dev; 15*b37ad2e2SJunxian Huang 16*b37ad2e2SJunxian Huang rcu_read_lock(); 17*b37ad2e2SJunxian Huang upper_dev = netdev_master_upper_dev_get_rcu(net_dev); 18*b37ad2e2SJunxian Huang dev_hold(upper_dev); 19*b37ad2e2SJunxian Huang rcu_read_unlock(); 20*b37ad2e2SJunxian Huang 21*b37ad2e2SJunxian Huang return upper_dev; 22*b37ad2e2SJunxian Huang } 23*b37ad2e2SJunxian Huang 24*b37ad2e2SJunxian Huang static int get_netdev_bond_slave_id(struct net_device *net_dev, 25*b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp) 26*b37ad2e2SJunxian Huang { 27*b37ad2e2SJunxian Huang int i; 28*b37ad2e2SJunxian Huang 29*b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_FUNC_MAX; i++) 30*b37ad2e2SJunxian Huang if (net_dev == bond_grp->bond_func_info[i].net_dev) 31*b37ad2e2SJunxian Huang return i; 32*b37ad2e2SJunxian Huang 33*b37ad2e2SJunxian Huang return -ENOENT; 34*b37ad2e2SJunxian Huang } 35*b37ad2e2SJunxian Huang 36*b37ad2e2SJunxian Huang struct hns_roce_bond_group *hns_roce_get_bond_grp(struct net_device *net_dev, 37*b37ad2e2SJunxian Huang u8 bus_num) 38*b37ad2e2SJunxian Huang { 39*b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 40*b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 41*b37ad2e2SJunxian Huang struct net_device *upper_dev = NULL; 42*b37ad2e2SJunxian Huang int i; 43*b37ad2e2SJunxian Huang 44*b37ad2e2SJunxian Huang if (!die_info) 45*b37ad2e2SJunxian Huang return NULL; 46*b37ad2e2SJunxian Huang 47*b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 48*b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 49*b37ad2e2SJunxian Huang if (!bond_grp) 50*b37ad2e2SJunxian Huang continue; 51*b37ad2e2SJunxian Huang if (get_netdev_bond_slave_id(net_dev, bond_grp) >= 0) 52*b37ad2e2SJunxian Huang return bond_grp; 53*b37ad2e2SJunxian Huang if (bond_grp->upper_dev) { 54*b37ad2e2SJunxian Huang upper_dev = get_upper_dev_from_ndev(net_dev); 55*b37ad2e2SJunxian Huang if (bond_grp->upper_dev == upper_dev) { 56*b37ad2e2SJunxian Huang dev_put(upper_dev); 57*b37ad2e2SJunxian Huang return bond_grp; 58*b37ad2e2SJunxian Huang } 59*b37ad2e2SJunxian Huang dev_put(upper_dev); 60*b37ad2e2SJunxian Huang } 61*b37ad2e2SJunxian Huang } 62*b37ad2e2SJunxian Huang 63*b37ad2e2SJunxian Huang return NULL; 64*b37ad2e2SJunxian Huang } 65*b37ad2e2SJunxian Huang 66*b37ad2e2SJunxian Huang static struct hns_roce_die_info *alloc_die_info(int bus_num) 67*b37ad2e2SJunxian Huang { 68*b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 69*b37ad2e2SJunxian Huang int ret; 70*b37ad2e2SJunxian Huang 71*b37ad2e2SJunxian Huang die_info = kzalloc(sizeof(*die_info), GFP_KERNEL); 72*b37ad2e2SJunxian Huang if (!die_info) 73*b37ad2e2SJunxian Huang return NULL; 74*b37ad2e2SJunxian Huang 75*b37ad2e2SJunxian Huang ret = xa_err(xa_store(&roce_bond_xa, bus_num, die_info, GFP_KERNEL)); 76*b37ad2e2SJunxian Huang if (ret) { 77*b37ad2e2SJunxian Huang kfree(die_info); 78*b37ad2e2SJunxian Huang return NULL; 79*b37ad2e2SJunxian Huang } 80*b37ad2e2SJunxian Huang 81*b37ad2e2SJunxian Huang return die_info; 82*b37ad2e2SJunxian Huang } 83*b37ad2e2SJunxian Huang 84*b37ad2e2SJunxian Huang static void dealloc_die_info(struct hns_roce_die_info *die_info, u8 bus_num) 85*b37ad2e2SJunxian Huang { 86*b37ad2e2SJunxian Huang xa_erase(&roce_bond_xa, bus_num); 87*b37ad2e2SJunxian Huang kfree(die_info); 88*b37ad2e2SJunxian Huang } 89*b37ad2e2SJunxian Huang 90*b37ad2e2SJunxian Huang static int alloc_bond_id(struct hns_roce_bond_group *bond_grp) 91*b37ad2e2SJunxian Huang { 92*b37ad2e2SJunxian Huang u8 bus_num = bond_grp->bus_num; 93*b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 94*b37ad2e2SJunxian Huang int i; 95*b37ad2e2SJunxian Huang 96*b37ad2e2SJunxian Huang if (!die_info) { 97*b37ad2e2SJunxian Huang die_info = alloc_die_info(bus_num); 98*b37ad2e2SJunxian Huang if (!die_info) 99*b37ad2e2SJunxian Huang return -ENOMEM; 100*b37ad2e2SJunxian Huang } 101*b37ad2e2SJunxian Huang 102*b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 103*b37ad2e2SJunxian Huang if (die_info->bond_id_mask & BOND_ID(i)) 104*b37ad2e2SJunxian Huang continue; 105*b37ad2e2SJunxian Huang 106*b37ad2e2SJunxian Huang die_info->bond_id_mask |= BOND_ID(i); 107*b37ad2e2SJunxian Huang die_info->bgrps[i] = bond_grp; 108*b37ad2e2SJunxian Huang bond_grp->bond_id = i; 109*b37ad2e2SJunxian Huang 110*b37ad2e2SJunxian Huang return 0; 111*b37ad2e2SJunxian Huang } 112*b37ad2e2SJunxian Huang 113*b37ad2e2SJunxian Huang return -ENOSPC; 114*b37ad2e2SJunxian Huang } 115*b37ad2e2SJunxian Huang 116*b37ad2e2SJunxian Huang static int remove_bond_id(int bus_num, u8 bond_id) 117*b37ad2e2SJunxian Huang { 118*b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info = xa_load(&roce_bond_xa, bus_num); 119*b37ad2e2SJunxian Huang 120*b37ad2e2SJunxian Huang if (bond_id >= ROCE_BOND_NUM_MAX) 121*b37ad2e2SJunxian Huang return -EINVAL; 122*b37ad2e2SJunxian Huang 123*b37ad2e2SJunxian Huang if (!die_info) 124*b37ad2e2SJunxian Huang return -ENODEV; 125*b37ad2e2SJunxian Huang 126*b37ad2e2SJunxian Huang die_info->bond_id_mask &= ~BOND_ID(bond_id); 127*b37ad2e2SJunxian Huang die_info->bgrps[bond_id] = NULL; 128*b37ad2e2SJunxian Huang if (!die_info->bond_id_mask) 129*b37ad2e2SJunxian Huang dealloc_die_info(die_info, bus_num); 130*b37ad2e2SJunxian Huang 131*b37ad2e2SJunxian Huang return 0; 132*b37ad2e2SJunxian Huang } 133*b37ad2e2SJunxian Huang 134*b37ad2e2SJunxian Huang int hns_roce_alloc_bond_grp(struct hns_roce_dev *hr_dev) 135*b37ad2e2SJunxian Huang { 136*b37ad2e2SJunxian Huang struct hns_roce_bond_group *bgrps[ROCE_BOND_NUM_MAX]; 137*b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 138*b37ad2e2SJunxian Huang u8 bus_num = get_hr_bus_num(hr_dev); 139*b37ad2e2SJunxian Huang int ret; 140*b37ad2e2SJunxian Huang int i; 141*b37ad2e2SJunxian Huang 142*b37ad2e2SJunxian Huang if (xa_load(&roce_bond_xa, bus_num)) 143*b37ad2e2SJunxian Huang return 0; 144*b37ad2e2SJunxian Huang 145*b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 146*b37ad2e2SJunxian Huang bond_grp = kvzalloc(sizeof(*bond_grp), GFP_KERNEL); 147*b37ad2e2SJunxian Huang if (!bond_grp) { 148*b37ad2e2SJunxian Huang ret = -ENOMEM; 149*b37ad2e2SJunxian Huang goto mem_err; 150*b37ad2e2SJunxian Huang } 151*b37ad2e2SJunxian Huang 152*b37ad2e2SJunxian Huang bond_grp->bus_num = bus_num; 153*b37ad2e2SJunxian Huang 154*b37ad2e2SJunxian Huang ret = alloc_bond_id(bond_grp); 155*b37ad2e2SJunxian Huang if (ret) { 156*b37ad2e2SJunxian Huang dev_err(hr_dev->dev, 157*b37ad2e2SJunxian Huang "failed to alloc bond ID, ret = %d.\n", ret); 158*b37ad2e2SJunxian Huang goto alloc_id_err; 159*b37ad2e2SJunxian Huang } 160*b37ad2e2SJunxian Huang 161*b37ad2e2SJunxian Huang bgrps[i] = bond_grp; 162*b37ad2e2SJunxian Huang } 163*b37ad2e2SJunxian Huang 164*b37ad2e2SJunxian Huang return 0; 165*b37ad2e2SJunxian Huang 166*b37ad2e2SJunxian Huang alloc_id_err: 167*b37ad2e2SJunxian Huang kvfree(bond_grp); 168*b37ad2e2SJunxian Huang mem_err: 169*b37ad2e2SJunxian Huang for (i--; i >= 0; i--) { 170*b37ad2e2SJunxian Huang remove_bond_id(bgrps[i]->bus_num, bgrps[i]->bond_id); 171*b37ad2e2SJunxian Huang kvfree(bgrps[i]); 172*b37ad2e2SJunxian Huang } 173*b37ad2e2SJunxian Huang return ret; 174*b37ad2e2SJunxian Huang } 175*b37ad2e2SJunxian Huang 176*b37ad2e2SJunxian Huang void hns_roce_dealloc_bond_grp(void) 177*b37ad2e2SJunxian Huang { 178*b37ad2e2SJunxian Huang struct hns_roce_bond_group *bond_grp; 179*b37ad2e2SJunxian Huang struct hns_roce_die_info *die_info; 180*b37ad2e2SJunxian Huang unsigned long id; 181*b37ad2e2SJunxian Huang int i; 182*b37ad2e2SJunxian Huang 183*b37ad2e2SJunxian Huang xa_for_each(&roce_bond_xa, id, die_info) { 184*b37ad2e2SJunxian Huang for (i = 0; i < ROCE_BOND_NUM_MAX; i++) { 185*b37ad2e2SJunxian Huang bond_grp = die_info->bgrps[i]; 186*b37ad2e2SJunxian Huang if (!bond_grp) 187*b37ad2e2SJunxian Huang continue; 188*b37ad2e2SJunxian Huang remove_bond_id(bond_grp->bus_num, bond_grp->bond_id); 189*b37ad2e2SJunxian Huang kvfree(bond_grp); 190*b37ad2e2SJunxian Huang } 191*b37ad2e2SJunxian Huang } 192*b37ad2e2SJunxian Huang } 193