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
ucaps_devnode(const struct device * dev,umode_t * mode)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 /**
50 * ib_cleanup_ucaps - cleanup all API resources and class.
51 *
52 * This is called once, when removing the ib_uverbs module.
53 */
ib_cleanup_ucaps(void)54 void ib_cleanup_ucaps(void)
55 {
56 mutex_lock(&ucaps_mutex);
57 if (!ucaps_class_is_registered) {
58 mutex_unlock(&ucaps_mutex);
59 return;
60 }
61
62 for (int i = RDMA_UCAP_FIRST; i < RDMA_UCAP_MAX; i++)
63 WARN_ON(ucaps_list[i]);
64
65 class_unregister(&ucaps_class);
66 ucaps_class_is_registered = false;
67 unregister_chrdev_region(ucaps_base_dev, RDMA_UCAP_MAX);
68 mutex_unlock(&ucaps_mutex);
69 }
70
get_ucap_from_devt(dev_t devt,u64 * idx_mask)71 static int get_ucap_from_devt(dev_t devt, u64 *idx_mask)
72 {
73 for (int type = RDMA_UCAP_FIRST; type < RDMA_UCAP_MAX; type++) {
74 if (ucaps_list[type] && ucaps_list[type]->dev.devt == devt) {
75 *idx_mask |= 1 << type;
76 return 0;
77 }
78 }
79
80 return -EINVAL;
81 }
82
get_devt_from_fd(unsigned int fd,dev_t * ret_dev)83 static int get_devt_from_fd(unsigned int fd, dev_t *ret_dev)
84 {
85 struct file *file;
86
87 file = fget(fd);
88 if (!file)
89 return -EBADF;
90
91 *ret_dev = file_inode(file)->i_rdev;
92 fput(file);
93 return 0;
94 }
95
96 /**
97 * ib_ucaps_init - Initialization required before ucap creation.
98 *
99 * Return: 0 on success, or a negative errno value on failure
100 */
ib_ucaps_init(void)101 static int ib_ucaps_init(void)
102 {
103 int ret = 0;
104
105 if (ucaps_class_is_registered)
106 return ret;
107
108 ret = class_register(&ucaps_class);
109 if (ret)
110 return ret;
111
112 ret = alloc_chrdev_region(&ucaps_base_dev, 0, RDMA_UCAP_MAX,
113 ucaps_class.name);
114 if (ret < 0) {
115 class_unregister(&ucaps_class);
116 return ret;
117 }
118
119 ucaps_class_is_registered = true;
120
121 return 0;
122 }
123
ucap_dev_release(struct device * device)124 static void ucap_dev_release(struct device *device)
125 {
126 struct ib_ucap *ucap = container_of(device, struct ib_ucap, dev);
127
128 kfree(ucap);
129 }
130
131 /**
132 * ib_create_ucap - Add a ucap character device
133 * @type: UCAP type
134 *
135 * Creates a ucap character device in the /dev/infiniband directory. By default,
136 * the device has root-only read-write access.
137 *
138 * A driver may call this multiple times with the same UCAP type. A reference
139 * count tracks creations and deletions.
140 *
141 * Return: 0 on success, or a negative errno value on failure
142 */
ib_create_ucap(enum rdma_user_cap type)143 int ib_create_ucap(enum rdma_user_cap type)
144 {
145 struct ib_ucap *ucap;
146 int ret;
147
148 if (type >= RDMA_UCAP_MAX)
149 return -EINVAL;
150
151 mutex_lock(&ucaps_mutex);
152 ret = ib_ucaps_init();
153 if (ret)
154 goto unlock;
155
156 ucap = ucaps_list[type];
157 if (ucap) {
158 kref_get(&ucap->ref);
159 mutex_unlock(&ucaps_mutex);
160 return 0;
161 }
162
163 ucap = kzalloc(sizeof(*ucap), GFP_KERNEL);
164 if (!ucap) {
165 ret = -ENOMEM;
166 goto unlock;
167 }
168
169 device_initialize(&ucap->dev);
170 ucap->dev.class = &ucaps_class;
171 ucap->dev.devt = MKDEV(MAJOR(ucaps_base_dev), type);
172 ucap->dev.release = ucap_dev_release;
173 ret = dev_set_name(&ucap->dev, "%s", ucap_names[type]);
174 if (ret)
175 goto err_device;
176
177 cdev_init(&ucap->cdev, &ucaps_cdev_fops);
178 ucap->cdev.owner = THIS_MODULE;
179
180 ret = cdev_device_add(&ucap->cdev, &ucap->dev);
181 if (ret)
182 goto err_device;
183
184 kref_init(&ucap->ref);
185 ucaps_list[type] = ucap;
186 mutex_unlock(&ucaps_mutex);
187
188 return 0;
189
190 err_device:
191 put_device(&ucap->dev);
192 unlock:
193 mutex_unlock(&ucaps_mutex);
194 return ret;
195 }
196 EXPORT_SYMBOL(ib_create_ucap);
197
ib_release_ucap(struct kref * ref)198 static void ib_release_ucap(struct kref *ref)
199 {
200 struct ib_ucap *ucap = container_of(ref, struct ib_ucap, ref);
201 enum rdma_user_cap type;
202
203 for (type = RDMA_UCAP_FIRST; type < RDMA_UCAP_MAX; type++) {
204 if (ucaps_list[type] == ucap)
205 break;
206 }
207 WARN_ON(type == RDMA_UCAP_MAX);
208
209 ucaps_list[type] = NULL;
210 cdev_device_del(&ucap->cdev, &ucap->dev);
211 put_device(&ucap->dev);
212 }
213
214 /**
215 * ib_remove_ucap - Remove a ucap character device
216 * @type: User cap type
217 *
218 * Removes the ucap character device according to type. The device is completely
219 * removed from the filesystem when its reference count reaches 0.
220 */
ib_remove_ucap(enum rdma_user_cap type)221 void ib_remove_ucap(enum rdma_user_cap type)
222 {
223 struct ib_ucap *ucap;
224
225 mutex_lock(&ucaps_mutex);
226 ucap = ucaps_list[type];
227 if (WARN_ON(!ucap))
228 goto end;
229
230 kref_put(&ucap->ref, ib_release_ucap);
231 end:
232 mutex_unlock(&ucaps_mutex);
233 }
234 EXPORT_SYMBOL(ib_remove_ucap);
235
236 /**
237 * ib_get_ucaps - Get bitmask of ucap types from file descriptors
238 * @fds: Array of file descriptors
239 * @fd_count: Number of file descriptors in the array
240 * @idx_mask: Bitmask to be updated based on the ucaps in the fd list
241 *
242 * Given an array of file descriptors, this function returns a bitmask of
243 * the ucaps where a bit is set if an FD for that ucap type was in the array.
244 *
245 * Return: 0 on success, or a negative errno value on failure
246 */
ib_get_ucaps(int * fds,int fd_count,uint64_t * idx_mask)247 int ib_get_ucaps(int *fds, int fd_count, uint64_t *idx_mask)
248 {
249 int ret = 0;
250 dev_t dev;
251
252 *idx_mask = 0;
253 mutex_lock(&ucaps_mutex);
254 for (int i = 0; i < fd_count; i++) {
255 ret = get_devt_from_fd(fds[i], &dev);
256 if (ret)
257 goto end;
258
259 ret = get_ucap_from_devt(dev, idx_mask);
260 if (ret)
261 goto end;
262 }
263
264 end:
265 mutex_unlock(&ucaps_mutex);
266 return ret;
267 }
268