xref: /linux/drivers/infiniband/hw/hns/hns_roce_bond.c (revision b37ad2e290fc52e575572b04803a4f93f584df6c)
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