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