xref: /linux/drivers/infiniband/core/ucaps.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved
4  */
5 
6 #include <linux/kref.h>
7 #include <linux/cdev.h>
8 #include <linux/mutex.h>
9 #include <linux/file.h>
10 #include <linux/fs.h>
11 #include <rdma/ib_ucaps.h>
12 
13 #define RDMA_UCAP_FIRST RDMA_UCAP_MLX5_CTRL_LOCAL
14 
15 static DEFINE_MUTEX(ucaps_mutex);
16 static struct ib_ucap *ucaps_list[RDMA_UCAP_MAX];
17 static bool ucaps_class_is_registered;
18 static dev_t ucaps_base_dev;
19 
20 struct ib_ucap {
21 	struct cdev cdev;
22 	struct device dev;
23 	struct kref ref;
24 };
25 
26 static const char *ucap_names[RDMA_UCAP_MAX] = {
27 	[RDMA_UCAP_MLX5_CTRL_LOCAL] = "mlx5_perm_ctrl_local",
28 	[RDMA_UCAP_MLX5_CTRL_OTHER_VHCA] = "mlx5_perm_ctrl_other_vhca"
29 };
30 
31 static char *ucaps_devnode(const struct device *dev, umode_t *mode)
32 {
33 	if (mode)
34 		*mode = 0600;
35 
36 	return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
37 }
38 
39 static const struct class ucaps_class = {
40 	.name = "infiniband_ucaps",
41 	.devnode = ucaps_devnode,
42 };
43 
44 static const struct file_operations ucaps_cdev_fops = {
45 	.owner = THIS_MODULE,
46 	.open = simple_open,
47 };
48 
49 static __exit void ib_cleanup_ucaps(void)
50 {
51 	mutex_lock(&ucaps_mutex);
52 	if (!ucaps_class_is_registered) {
53 		mutex_unlock(&ucaps_mutex);
54 		return;
55 	}
56 
57 	for (int i = RDMA_UCAP_FIRST; i < RDMA_UCAP_MAX; i++)
58 		WARN_ON(ucaps_list[i]);
59 
60 	class_unregister(&ucaps_class);
61 	ucaps_class_is_registered = false;
62 	unregister_chrdev_region(ucaps_base_dev, RDMA_UCAP_MAX);
63 	mutex_unlock(&ucaps_mutex);
64 }
65 
66 static int get_ucap_from_devt(dev_t devt, u64 *idx_mask)
67 {
68 	for (int type = RDMA_UCAP_FIRST; type < RDMA_UCAP_MAX; type++) {
69 		if (ucaps_list[type] && ucaps_list[type]->dev.devt == devt) {
70 			*idx_mask |= 1 << type;
71 			return 0;
72 		}
73 	}
74 
75 	return -EINVAL;
76 }
77 
78 static int get_devt_from_fd(unsigned int fd, dev_t *ret_dev)
79 {
80 	CLASS(fd, f)(fd);
81 
82 	if (fd_empty(f) || fd_file(f)->f_op != &ucaps_cdev_fops)
83 		return -EBADF;
84 
85 	*ret_dev = file_inode(fd_file(f))->i_rdev;
86 	return 0;
87 }
88 
89 /**
90  * ib_ucaps_init - Initialization required before ucap creation.
91  *
92  * Return: 0 on success, or a negative errno value on failure
93  */
94 static int ib_ucaps_init(void)
95 {
96 	int ret = 0;
97 
98 	if (ucaps_class_is_registered)
99 		return ret;
100 
101 	ret = class_register(&ucaps_class);
102 	if (ret)
103 		return ret;
104 
105 	ret = alloc_chrdev_region(&ucaps_base_dev, 0, RDMA_UCAP_MAX,
106 				  ucaps_class.name);
107 	if (ret < 0) {
108 		class_unregister(&ucaps_class);
109 		return ret;
110 	}
111 
112 	ucaps_class_is_registered = true;
113 
114 	return 0;
115 }
116 
117 static void ucap_dev_release(struct device *device)
118 {
119 	struct ib_ucap *ucap = container_of(device, struct ib_ucap, dev);
120 
121 	kfree(ucap);
122 }
123 
124 /**
125  * ib_create_ucap - Add a ucap character device
126  * @type: UCAP type
127  *
128  * Creates a ucap character device in the /dev/infiniband directory. By default,
129  * the device has root-only read-write access.
130  *
131  * A driver may call this multiple times with the same UCAP type. A reference
132  * count tracks creations and deletions.
133  *
134  * Return: 0 on success, or a negative errno value on failure
135  */
136 int ib_create_ucap(enum rdma_user_cap type)
137 {
138 	struct ib_ucap *ucap;
139 	int ret;
140 
141 	if (type >= RDMA_UCAP_MAX)
142 		return -EINVAL;
143 
144 	mutex_lock(&ucaps_mutex);
145 	ret = ib_ucaps_init();
146 	if (ret)
147 		goto unlock;
148 
149 	ucap = ucaps_list[type];
150 	if (ucap) {
151 		kref_get(&ucap->ref);
152 		mutex_unlock(&ucaps_mutex);
153 		return 0;
154 	}
155 
156 	ucap = kzalloc_obj(*ucap);
157 	if (!ucap) {
158 		ret = -ENOMEM;
159 		goto unlock;
160 	}
161 
162 	device_initialize(&ucap->dev);
163 	ucap->dev.class = &ucaps_class;
164 	ucap->dev.devt = MKDEV(MAJOR(ucaps_base_dev), type);
165 	ucap->dev.release = ucap_dev_release;
166 	ret = dev_set_name(&ucap->dev, "%s", ucap_names[type]);
167 	if (ret)
168 		goto err_device;
169 
170 	cdev_init(&ucap->cdev, &ucaps_cdev_fops);
171 	ucap->cdev.owner = THIS_MODULE;
172 
173 	ret = cdev_device_add(&ucap->cdev, &ucap->dev);
174 	if (ret)
175 		goto err_device;
176 
177 	kref_init(&ucap->ref);
178 	ucaps_list[type] = ucap;
179 	mutex_unlock(&ucaps_mutex);
180 
181 	return 0;
182 
183 err_device:
184 	put_device(&ucap->dev);
185 unlock:
186 	mutex_unlock(&ucaps_mutex);
187 	return ret;
188 }
189 EXPORT_SYMBOL(ib_create_ucap);
190 
191 static void ib_release_ucap(struct kref *ref)
192 {
193 	struct ib_ucap *ucap = container_of(ref, struct ib_ucap, ref);
194 	enum rdma_user_cap type;
195 
196 	for (type = RDMA_UCAP_FIRST; type < RDMA_UCAP_MAX; type++) {
197 		if (ucaps_list[type] == ucap)
198 			break;
199 	}
200 	WARN_ON(type == RDMA_UCAP_MAX);
201 
202 	ucaps_list[type] = NULL;
203 	cdev_device_del(&ucap->cdev, &ucap->dev);
204 	put_device(&ucap->dev);
205 }
206 
207 /**
208  * ib_remove_ucap - Remove a ucap character device
209  * @type: User cap type
210  *
211  * Removes the ucap character device according to type. The device is completely
212  * removed from the filesystem when its reference count reaches 0.
213  */
214 void ib_remove_ucap(enum rdma_user_cap type)
215 {
216 	struct ib_ucap *ucap;
217 
218 	mutex_lock(&ucaps_mutex);
219 	ucap = ucaps_list[type];
220 	if (WARN_ON(!ucap))
221 		goto end;
222 
223 	kref_put(&ucap->ref, ib_release_ucap);
224 end:
225 	mutex_unlock(&ucaps_mutex);
226 }
227 EXPORT_SYMBOL(ib_remove_ucap);
228 
229 /**
230  * ib_get_ucaps - Get bitmask of ucap types from file descriptors
231  * @fds: Array of file descriptors
232  * @fd_count: Number of file descriptors in the array
233  * @idx_mask: Bitmask to be updated based on the ucaps in the fd list
234  *
235  * Given an array of file descriptors, this function returns a bitmask of
236  * the ucaps where a bit is set if an FD for that ucap type was in the array.
237  *
238  * Return: 0 on success, or a negative errno value on failure
239  */
240 int ib_get_ucaps(int *fds, int fd_count, uint64_t *idx_mask)
241 {
242 	int ret = 0;
243 	dev_t dev;
244 
245 	*idx_mask = 0;
246 	mutex_lock(&ucaps_mutex);
247 	for (int i = 0; i < fd_count; i++) {
248 		ret = get_devt_from_fd(fds[i], &dev);
249 		if (ret)
250 			goto end;
251 
252 		ret = get_ucap_from_devt(dev, idx_mask);
253 		if (ret)
254 			goto end;
255 	}
256 
257 end:
258 	mutex_unlock(&ucaps_mutex);
259 	return ret;
260 }
261 EXPORT_SYMBOL_NS_GPL(ib_get_ucaps, "rdma_core");
262 
263 module_exit(ib_cleanup_ucaps);
264