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
hns_roce_get_hrdev_by_netdev(struct net_device * net_dev)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
get_upper_dev_from_ndev(struct net_device * net_dev)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
get_netdev_bond_slave_id(struct net_device * net_dev,struct hns_roce_bond_group * bond_grp)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
hns_roce_get_bond_grp(struct net_device * net_dev,u8 bus_num)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
hns_roce_set_bond_netdev(struct hns_roce_bond_group * bond_grp,struct hns_roce_dev * hr_dev)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
hns_roce_bond_is_active(struct hns_roce_dev * hr_dev)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
hns_roce_bond_get_active_slave(struct hns_roce_bond_group * bond_grp)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
hns_roce_recover_bond(struct hns_roce_bond_group * bond_grp,struct hns_roce_dev * hr_dev)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
hns_roce_slave_uninit(struct hns_roce_bond_group * bond_grp,u8 func_idx)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
switch_main_dev(struct hns_roce_bond_group * bond_grp,u8 main_func_idx)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
hns_roce_slave_init(struct hns_roce_bond_group * bond_grp,u8 func_idx,bool need_switch)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
alloc_die_info(int bus_num)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
dealloc_die_info(struct hns_roce_die_info * die_info,u8 bus_num)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
alloc_bond_id(struct hns_roce_bond_group * bond_grp)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
remove_bond_id(int bus_num,u8 bond_id)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
hns_roce_set_bond(struct hns_roce_bond_group * bond_grp)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
hns_roce_clear_bond(struct hns_roce_bond_group * bond_grp)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
hns_roce_slave_changestate(struct hns_roce_bond_group * bond_grp)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
hns_roce_slave_change_num(struct hns_roce_bond_group * bond_grp)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
hns_roce_bond_info_update_nolock(struct hns_roce_bond_group * bond_grp,struct net_device * upper_dev)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
is_dev_bond_supported(struct hns_roce_bond_group * bond_grp,struct net_device * net_dev)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
check_slave_support(struct hns_roce_bond_group * bond_grp,struct net_device * upper_dev)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
hns_roce_bond_work(struct work_struct * work)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
hns_roce_attach_bond_grp(struct hns_roce_bond_group * bond_grp,struct hns_roce_dev * hr_dev,struct net_device * upper_dev)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
hns_roce_detach_bond_grp(struct hns_roce_bond_group * bond_grp)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
hns_roce_cleanup_bond(struct hns_roce_bond_group * bond_grp)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
lowerstate_event_filter(struct hns_roce_bond_group * bond_grp,struct net_device * net_dev)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
lowerstate_event_setting(struct hns_roce_bond_group * bond_grp,struct netdev_notifier_changelowerstate_info * info)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
hns_roce_bond_lowerstate_event(struct hns_roce_bond_group * bond_grp,struct netdev_notifier_changelowerstate_info * info)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
is_bond_setting_supported(struct netdev_lag_upper_info * bond_info)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
upper_event_setting(struct hns_roce_bond_group * bond_grp,struct netdev_notifier_changeupper_info * info)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
check_unlinking_bond_support(struct hns_roce_bond_group * bond_grp)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
check_linking_bond_support(struct netdev_lag_upper_info * bond_info,struct hns_roce_bond_group * bond_grp,struct net_device * upper_dev)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
check_bond_support(struct hns_roce_bond_group * bond_grp,struct net_device * upper_dev,struct netdev_notifier_changeupper_info * info)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
upper_event_filter(struct netdev_notifier_changeupper_info * info,struct hns_roce_bond_group * bond_grp,struct net_device * net_dev)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
hns_roce_bond_upper_event(struct hns_roce_bond_group * bond_grp,struct netdev_notifier_changeupper_info * info)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
hns_roce_bond_event(struct notifier_block * self,unsigned long event,void * ptr)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
hns_roce_alloc_bond_grp(struct hns_roce_dev * hr_dev)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
hns_roce_dealloc_bond_grp(void)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
hns_roce_bond_init(struct hns_roce_dev * hr_dev)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
hns_roce_bond_suspend(struct hnae3_handle * handle)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
hns_roce_bond_resume(struct hnae3_handle * handle)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