xref: /linux/fs/smb/smbdirect/devices.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*1249c01aSStefan Metzmacher // SPDX-License-Identifier: GPL-2.0-or-later
2*1249c01aSStefan Metzmacher /*
3*1249c01aSStefan Metzmacher  *   Copyright (C) 2017, Microsoft Corporation.
4*1249c01aSStefan Metzmacher  *   Copyright (C) 2018, LG Electronics.
5*1249c01aSStefan Metzmacher  *   Copyright (c) 2025 Stefan Metzmacher
6*1249c01aSStefan Metzmacher  */
7*1249c01aSStefan Metzmacher 
8*1249c01aSStefan Metzmacher #include "internal.h"
9*1249c01aSStefan Metzmacher 
10*1249c01aSStefan Metzmacher static u8 smbdirect_ib_device_rdma_capable_node_type(struct ib_device *ib_dev)
11*1249c01aSStefan Metzmacher {
12*1249c01aSStefan Metzmacher 	if (!smbdirect_frwr_is_supported(&ib_dev->attrs))
13*1249c01aSStefan Metzmacher 		return RDMA_NODE_UNSPECIFIED;
14*1249c01aSStefan Metzmacher 
15*1249c01aSStefan Metzmacher 	switch (ib_dev->node_type) {
16*1249c01aSStefan Metzmacher 	case RDMA_NODE_IB_CA: /* Infiniband, RoCE v1 and v2 */
17*1249c01aSStefan Metzmacher 	case RDMA_NODE_RNIC:  /* iWarp */
18*1249c01aSStefan Metzmacher 		return ib_dev->node_type;
19*1249c01aSStefan Metzmacher 	}
20*1249c01aSStefan Metzmacher 
21*1249c01aSStefan Metzmacher 	return RDMA_NODE_UNSPECIFIED;
22*1249c01aSStefan Metzmacher }
23*1249c01aSStefan Metzmacher 
24*1249c01aSStefan Metzmacher static int smbdirect_ib_client_add(struct ib_device *ib_dev)
25*1249c01aSStefan Metzmacher {
26*1249c01aSStefan Metzmacher 	u8 node_type = smbdirect_ib_device_rdma_capable_node_type(ib_dev);
27*1249c01aSStefan Metzmacher 	struct smbdirect_device *sdev;
28*1249c01aSStefan Metzmacher 	const char *node_str;
29*1249c01aSStefan Metzmacher 	const char *action;
30*1249c01aSStefan Metzmacher 	u32 pidx;
31*1249c01aSStefan Metzmacher 
32*1249c01aSStefan Metzmacher 	switch (node_type) {
33*1249c01aSStefan Metzmacher 	case RDMA_NODE_IB_CA:
34*1249c01aSStefan Metzmacher 		node_str = "IB_CA";
35*1249c01aSStefan Metzmacher 		action = "added";
36*1249c01aSStefan Metzmacher 		break;
37*1249c01aSStefan Metzmacher 	case RDMA_NODE_RNIC:
38*1249c01aSStefan Metzmacher 		node_str = "RNIC";
39*1249c01aSStefan Metzmacher 		action = "added";
40*1249c01aSStefan Metzmacher 		break;
41*1249c01aSStefan Metzmacher 	case RDMA_NODE_UNSPECIFIED:
42*1249c01aSStefan Metzmacher 		node_str = "UNSPECIFIED";
43*1249c01aSStefan Metzmacher 		action = "ignored";
44*1249c01aSStefan Metzmacher 		break;
45*1249c01aSStefan Metzmacher 	default:
46*1249c01aSStefan Metzmacher 		node_str = "UNKNOWN";
47*1249c01aSStefan Metzmacher 		action = "ignored";
48*1249c01aSStefan Metzmacher 		node_type = RDMA_NODE_UNSPECIFIED;
49*1249c01aSStefan Metzmacher 		break;
50*1249c01aSStefan Metzmacher 	}
51*1249c01aSStefan Metzmacher 
52*1249c01aSStefan Metzmacher 	pr_info("ib_dev[%.*s]: %s: %s %s=%u %s=0x%llx %s=0x%llx %s=0x%llx\n",
53*1249c01aSStefan Metzmacher 		IB_DEVICE_NAME_MAX,
54*1249c01aSStefan Metzmacher 		ib_dev->name,
55*1249c01aSStefan Metzmacher 		action,
56*1249c01aSStefan Metzmacher 		node_str,
57*1249c01aSStefan Metzmacher 		"max_fast_reg_page_list_len",
58*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_fast_reg_page_list_len,
59*1249c01aSStefan Metzmacher 		"device_cap_flags",
60*1249c01aSStefan Metzmacher 		ib_dev->attrs.device_cap_flags,
61*1249c01aSStefan Metzmacher 		"kernel_cap_flags",
62*1249c01aSStefan Metzmacher 		ib_dev->attrs.kernel_cap_flags,
63*1249c01aSStefan Metzmacher 		"page_size_cap",
64*1249c01aSStefan Metzmacher 		ib_dev->attrs.page_size_cap);
65*1249c01aSStefan Metzmacher 
66*1249c01aSStefan Metzmacher 	if (node_type == RDMA_NODE_UNSPECIFIED)
67*1249c01aSStefan Metzmacher 		return 0;
68*1249c01aSStefan Metzmacher 
69*1249c01aSStefan Metzmacher 	pr_info("ib_dev[%.*s]: %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u\n",
70*1249c01aSStefan Metzmacher 		IB_DEVICE_NAME_MAX,
71*1249c01aSStefan Metzmacher 		ib_dev->name,
72*1249c01aSStefan Metzmacher 		"num_ports",
73*1249c01aSStefan Metzmacher 		rdma_end_port(ib_dev),
74*1249c01aSStefan Metzmacher 		"max_qp_rd_atom",
75*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_qp_rd_atom,
76*1249c01aSStefan Metzmacher 		"max_qp_init_rd_atom",
77*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_qp_init_rd_atom,
78*1249c01aSStefan Metzmacher 		"max_sgl_rd",
79*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_sgl_rd,
80*1249c01aSStefan Metzmacher 		"max_sge_rd",
81*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_sge_rd,
82*1249c01aSStefan Metzmacher 		"max_cqe",
83*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_cqe,
84*1249c01aSStefan Metzmacher 		"max_qp_wr",
85*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_qp_wr,
86*1249c01aSStefan Metzmacher 		"max_send_sge",
87*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_send_sge,
88*1249c01aSStefan Metzmacher 		"max_recv_sge",
89*1249c01aSStefan Metzmacher 		ib_dev->attrs.max_recv_sge);
90*1249c01aSStefan Metzmacher 
91*1249c01aSStefan Metzmacher 	rdma_for_each_port(ib_dev, pidx) {
92*1249c01aSStefan Metzmacher 		const struct ib_port_immutable *ib_pi =
93*1249c01aSStefan Metzmacher 			ib_port_immutable_read(ib_dev, pidx);
94*1249c01aSStefan Metzmacher 		u32 core_cap_flags = ib_pi ? ib_pi->core_cap_flags : 0;
95*1249c01aSStefan Metzmacher 
96*1249c01aSStefan Metzmacher 		pr_info("ib_dev[%.*s]PORT[%u]: %s=%u %s=%u %s=%u %s=%u %s=%u %s=0x%x\n",
97*1249c01aSStefan Metzmacher 			IB_DEVICE_NAME_MAX,
98*1249c01aSStefan Metzmacher 			ib_dev->name,
99*1249c01aSStefan Metzmacher 			pidx,
100*1249c01aSStefan Metzmacher 			"iwarp",
101*1249c01aSStefan Metzmacher 			rdma_protocol_iwarp(ib_dev, pidx),
102*1249c01aSStefan Metzmacher 			"ib",
103*1249c01aSStefan Metzmacher 			rdma_protocol_ib(ib_dev, pidx),
104*1249c01aSStefan Metzmacher 			"roce",
105*1249c01aSStefan Metzmacher 			rdma_protocol_roce(ib_dev, pidx),
106*1249c01aSStefan Metzmacher 			"v1",
107*1249c01aSStefan Metzmacher 			rdma_protocol_roce_eth_encap(ib_dev, pidx),
108*1249c01aSStefan Metzmacher 			"v2",
109*1249c01aSStefan Metzmacher 			rdma_protocol_roce_udp_encap(ib_dev, pidx),
110*1249c01aSStefan Metzmacher 			"core_cap_flags",
111*1249c01aSStefan Metzmacher 			core_cap_flags);
112*1249c01aSStefan Metzmacher 	}
113*1249c01aSStefan Metzmacher 
114*1249c01aSStefan Metzmacher 	sdev = kzalloc_obj(*sdev);
115*1249c01aSStefan Metzmacher 	if (!sdev)
116*1249c01aSStefan Metzmacher 		return -ENOMEM;
117*1249c01aSStefan Metzmacher 	sdev->ib_dev = ib_dev;
118*1249c01aSStefan Metzmacher 	snprintf(sdev->ib_name, ARRAY_SIZE(sdev->ib_name), "%.*s",
119*1249c01aSStefan Metzmacher 		 IB_DEVICE_NAME_MAX, ib_dev->name);
120*1249c01aSStefan Metzmacher 
121*1249c01aSStefan Metzmacher 	write_lock(&smbdirect_globals.devices.lock);
122*1249c01aSStefan Metzmacher 	list_add(&sdev->list, &smbdirect_globals.devices.list);
123*1249c01aSStefan Metzmacher 	write_unlock(&smbdirect_globals.devices.lock);
124*1249c01aSStefan Metzmacher 
125*1249c01aSStefan Metzmacher 	return 0;
126*1249c01aSStefan Metzmacher }
127*1249c01aSStefan Metzmacher 
128*1249c01aSStefan Metzmacher static void smbdirect_ib_client_remove(struct ib_device *ib_dev, void *client_data)
129*1249c01aSStefan Metzmacher {
130*1249c01aSStefan Metzmacher 	struct smbdirect_device *sdev, *tmp;
131*1249c01aSStefan Metzmacher 
132*1249c01aSStefan Metzmacher 	write_lock(&smbdirect_globals.devices.lock);
133*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(sdev, tmp, &smbdirect_globals.devices.list, list) {
134*1249c01aSStefan Metzmacher 		if (sdev->ib_dev == ib_dev) {
135*1249c01aSStefan Metzmacher 			list_del(&sdev->list);
136*1249c01aSStefan Metzmacher 			pr_info("ib_dev[%.*s] removed\n",
137*1249c01aSStefan Metzmacher 				IB_DEVICE_NAME_MAX, sdev->ib_name);
138*1249c01aSStefan Metzmacher 			kfree(sdev);
139*1249c01aSStefan Metzmacher 			break;
140*1249c01aSStefan Metzmacher 		}
141*1249c01aSStefan Metzmacher 	}
142*1249c01aSStefan Metzmacher 	write_unlock(&smbdirect_globals.devices.lock);
143*1249c01aSStefan Metzmacher }
144*1249c01aSStefan Metzmacher 
145*1249c01aSStefan Metzmacher static void smbdirect_ib_client_rename(struct ib_device *ib_dev, void *client_data)
146*1249c01aSStefan Metzmacher {
147*1249c01aSStefan Metzmacher 	struct smbdirect_device *sdev;
148*1249c01aSStefan Metzmacher 
149*1249c01aSStefan Metzmacher 	write_lock(&smbdirect_globals.devices.lock);
150*1249c01aSStefan Metzmacher 	list_for_each_entry(sdev, &smbdirect_globals.devices.list, list) {
151*1249c01aSStefan Metzmacher 		if (sdev->ib_dev == ib_dev) {
152*1249c01aSStefan Metzmacher 			pr_info("ib_dev[%.*s] renamed to [%.*s]\n",
153*1249c01aSStefan Metzmacher 				IB_DEVICE_NAME_MAX, sdev->ib_name,
154*1249c01aSStefan Metzmacher 				IB_DEVICE_NAME_MAX, ib_dev->name);
155*1249c01aSStefan Metzmacher 			snprintf(sdev->ib_name, ARRAY_SIZE(sdev->ib_name), "%.*s",
156*1249c01aSStefan Metzmacher 				 IB_DEVICE_NAME_MAX, ib_dev->name);
157*1249c01aSStefan Metzmacher 			break;
158*1249c01aSStefan Metzmacher 		}
159*1249c01aSStefan Metzmacher 	}
160*1249c01aSStefan Metzmacher 	write_unlock(&smbdirect_globals.devices.lock);
161*1249c01aSStefan Metzmacher }
162*1249c01aSStefan Metzmacher 
163*1249c01aSStefan Metzmacher static struct ib_client smbdirect_ib_client = {
164*1249c01aSStefan Metzmacher 	.name	= "smbdirect_ib_client",
165*1249c01aSStefan Metzmacher 	.add	= smbdirect_ib_client_add,
166*1249c01aSStefan Metzmacher 	.remove	= smbdirect_ib_client_remove,
167*1249c01aSStefan Metzmacher 	.rename	= smbdirect_ib_client_rename,
168*1249c01aSStefan Metzmacher };
169*1249c01aSStefan Metzmacher 
170*1249c01aSStefan Metzmacher static u8 smbdirect_netdev_find_rdma_capable_node_type(struct net_device *netdev)
171*1249c01aSStefan Metzmacher {
172*1249c01aSStefan Metzmacher 	struct smbdirect_device *sdev;
173*1249c01aSStefan Metzmacher 	u8 node_type = RDMA_NODE_UNSPECIFIED;
174*1249c01aSStefan Metzmacher 
175*1249c01aSStefan Metzmacher 	read_lock(&smbdirect_globals.devices.lock);
176*1249c01aSStefan Metzmacher 	list_for_each_entry(sdev, &smbdirect_globals.devices.list, list) {
177*1249c01aSStefan Metzmacher 		u32 pi;
178*1249c01aSStefan Metzmacher 
179*1249c01aSStefan Metzmacher 		rdma_for_each_port(sdev->ib_dev, pi) {
180*1249c01aSStefan Metzmacher 			struct net_device *ndev;
181*1249c01aSStefan Metzmacher 
182*1249c01aSStefan Metzmacher 			ndev = ib_device_get_netdev(sdev->ib_dev, pi);
183*1249c01aSStefan Metzmacher 			if (!ndev)
184*1249c01aSStefan Metzmacher 				continue;
185*1249c01aSStefan Metzmacher 
186*1249c01aSStefan Metzmacher 			if (ndev == netdev) {
187*1249c01aSStefan Metzmacher 				dev_put(ndev);
188*1249c01aSStefan Metzmacher 				node_type = sdev->ib_dev->node_type;
189*1249c01aSStefan Metzmacher 				goto out;
190*1249c01aSStefan Metzmacher 			}
191*1249c01aSStefan Metzmacher 			dev_put(ndev);
192*1249c01aSStefan Metzmacher 		}
193*1249c01aSStefan Metzmacher 	}
194*1249c01aSStefan Metzmacher out:
195*1249c01aSStefan Metzmacher 	read_unlock(&smbdirect_globals.devices.lock);
196*1249c01aSStefan Metzmacher 
197*1249c01aSStefan Metzmacher 	if (node_type == RDMA_NODE_UNSPECIFIED) {
198*1249c01aSStefan Metzmacher 		struct ib_device *ibdev;
199*1249c01aSStefan Metzmacher 
200*1249c01aSStefan Metzmacher 		ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN);
201*1249c01aSStefan Metzmacher 		if (ibdev) {
202*1249c01aSStefan Metzmacher 			node_type = smbdirect_ib_device_rdma_capable_node_type(ibdev);
203*1249c01aSStefan Metzmacher 			ib_device_put(ibdev);
204*1249c01aSStefan Metzmacher 		}
205*1249c01aSStefan Metzmacher 	}
206*1249c01aSStefan Metzmacher 
207*1249c01aSStefan Metzmacher 	return node_type;
208*1249c01aSStefan Metzmacher }
209*1249c01aSStefan Metzmacher 
210*1249c01aSStefan Metzmacher /*
211*1249c01aSStefan Metzmacher  * Returns RDMA_NODE_UNSPECIFIED when the netdev has
212*1249c01aSStefan Metzmacher  * no support for smbdirect capable rdma.
213*1249c01aSStefan Metzmacher  *
214*1249c01aSStefan Metzmacher  * Otherwise RDMA_NODE_RNIC is returned for iwarp devices
215*1249c01aSStefan Metzmacher  * and RDMA_NODE_IB_CA or Infiniband and RoCE (v1 and v2)
216*1249c01aSStefan Metzmacher  */
217*1249c01aSStefan Metzmacher u8 smbdirect_netdev_rdma_capable_node_type(struct net_device *netdev)
218*1249c01aSStefan Metzmacher {
219*1249c01aSStefan Metzmacher 	struct net_device *lower_dev;
220*1249c01aSStefan Metzmacher 	struct list_head *iter;
221*1249c01aSStefan Metzmacher 	u8 node_type = RDMA_NODE_UNSPECIFIED;
222*1249c01aSStefan Metzmacher 
223*1249c01aSStefan Metzmacher 	node_type = smbdirect_netdev_find_rdma_capable_node_type(netdev);
224*1249c01aSStefan Metzmacher 	if (node_type != RDMA_NODE_UNSPECIFIED)
225*1249c01aSStefan Metzmacher 		return node_type;
226*1249c01aSStefan Metzmacher 
227*1249c01aSStefan Metzmacher 	/* check if netdev is bridge or VLAN */
228*1249c01aSStefan Metzmacher 	if (netif_is_bridge_master(netdev) || netdev->priv_flags & IFF_802_1Q_VLAN)
229*1249c01aSStefan Metzmacher 		netdev_for_each_lower_dev(netdev, lower_dev, iter) {
230*1249c01aSStefan Metzmacher 			node_type = smbdirect_netdev_find_rdma_capable_node_type(lower_dev);
231*1249c01aSStefan Metzmacher 			if (node_type != RDMA_NODE_UNSPECIFIED)
232*1249c01aSStefan Metzmacher 				return node_type;
233*1249c01aSStefan Metzmacher 		}
234*1249c01aSStefan Metzmacher 
235*1249c01aSStefan Metzmacher 	/* check if netdev is IPoIB safely without layer violation */
236*1249c01aSStefan Metzmacher 	if (netdev->type == ARPHRD_INFINIBAND)
237*1249c01aSStefan Metzmacher 		return RDMA_NODE_IB_CA;
238*1249c01aSStefan Metzmacher 
239*1249c01aSStefan Metzmacher 	return RDMA_NODE_UNSPECIFIED;
240*1249c01aSStefan Metzmacher }
241*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_netdev_rdma_capable_node_type);
242*1249c01aSStefan Metzmacher 
243*1249c01aSStefan Metzmacher __init int smbdirect_devices_init(void)
244*1249c01aSStefan Metzmacher {
245*1249c01aSStefan Metzmacher 	int ret;
246*1249c01aSStefan Metzmacher 
247*1249c01aSStefan Metzmacher 	rwlock_init(&smbdirect_globals.devices.lock);
248*1249c01aSStefan Metzmacher 	INIT_LIST_HEAD(&smbdirect_globals.devices.list);
249*1249c01aSStefan Metzmacher 
250*1249c01aSStefan Metzmacher 	ret = ib_register_client(&smbdirect_ib_client);
251*1249c01aSStefan Metzmacher 	if (ret) {
252*1249c01aSStefan Metzmacher 		pr_crit("failed to ib_register_client: %d %1pe\n",
253*1249c01aSStefan Metzmacher 			ret, SMBDIRECT_DEBUG_ERR_PTR(ret));
254*1249c01aSStefan Metzmacher 		return ret;
255*1249c01aSStefan Metzmacher 	}
256*1249c01aSStefan Metzmacher 
257*1249c01aSStefan Metzmacher 	return 0;
258*1249c01aSStefan Metzmacher }
259*1249c01aSStefan Metzmacher 
260*1249c01aSStefan Metzmacher __exit void smbdirect_devices_exit(void)
261*1249c01aSStefan Metzmacher {
262*1249c01aSStefan Metzmacher 	struct smbdirect_device *sdev, *tmp;
263*1249c01aSStefan Metzmacher 
264*1249c01aSStefan Metzmacher 	/*
265*1249c01aSStefan Metzmacher 	 * On exist we just cleanup so that
266*1249c01aSStefan Metzmacher 	 * smbdirect_ib_client_remove() won't
267*1249c01aSStefan Metzmacher 	 * print removals of devices.
268*1249c01aSStefan Metzmacher 	 */
269*1249c01aSStefan Metzmacher 	write_lock(&smbdirect_globals.devices.lock);
270*1249c01aSStefan Metzmacher 	list_for_each_entry_safe(sdev, tmp, &smbdirect_globals.devices.list, list) {
271*1249c01aSStefan Metzmacher 		list_del(&sdev->list);
272*1249c01aSStefan Metzmacher 		kfree(sdev);
273*1249c01aSStefan Metzmacher 	}
274*1249c01aSStefan Metzmacher 	write_unlock(&smbdirect_globals.devices.lock);
275*1249c01aSStefan Metzmacher 
276*1249c01aSStefan Metzmacher 	ib_unregister_client(&smbdirect_ib_client);
277*1249c01aSStefan Metzmacher }
278