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