Commit | Line | Data |
---|---|---|
a8b92ca1 YH |
1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* | |
3 | * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. | |
4 | */ | |
5 | ||
6 | #include <rdma/ib_user_verbs.h> | |
7 | #include <rdma/ib_verbs.h> | |
8 | #include <rdma/uverbs_types.h> | |
9 | #include <rdma/uverbs_ioctl.h> | |
10 | #include <rdma/mlx5_user_ioctl_cmds.h> | |
11 | #include <rdma/ib_umem.h> | |
12 | #include <linux/mlx5/driver.h> | |
13 | #include <linux/mlx5/fs.h> | |
14 | #include "mlx5_ib.h" | |
15 | ||
8aa8c95c YH |
16 | #define UVERBS_MODULE_NAME mlx5_ib |
17 | #include <rdma/uverbs_named_ioctl.h> | |
18 | ||
7efce369 YH |
19 | #define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in) |
20 | struct devx_obj { | |
21 | struct mlx5_core_dev *mdev; | |
22 | u32 obj_id; | |
23 | u32 dinlen; /* destroy inbox length */ | |
24 | u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW]; | |
25 | }; | |
26 | ||
aeae9457 YH |
27 | struct devx_umem { |
28 | struct mlx5_core_dev *mdev; | |
29 | struct ib_umem *umem; | |
30 | u32 page_offset; | |
31 | int page_shift; | |
32 | int ncont; | |
33 | u32 dinlen; | |
34 | u32 dinbox[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)]; | |
35 | }; | |
36 | ||
37 | struct devx_umem_reg_cmd { | |
38 | void *in; | |
39 | u32 inlen; | |
40 | u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; | |
41 | }; | |
42 | ||
8aa8c95c YH |
43 | static struct mlx5_ib_ucontext *devx_ufile2uctx(struct ib_uverbs_file *file) |
44 | { | |
45 | return to_mucontext(ib_uverbs_get_ucontext(file)); | |
46 | } | |
47 | ||
a8b92ca1 YH |
48 | int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *context) |
49 | { | |
50 | u32 in[MLX5_ST_SZ_DW(create_uctx_in)] = {0}; | |
51 | u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; | |
52 | u64 general_obj_types; | |
a8b92ca1 YH |
53 | void *hdr; |
54 | int err; | |
55 | ||
a8b92ca1 YH |
56 | hdr = MLX5_ADDR_OF(create_uctx_in, in, hdr); |
57 | ||
58 | general_obj_types = MLX5_CAP_GEN_64(dev->mdev, general_obj_types); | |
59 | if (!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_UCTX) || | |
60 | !(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_UMEM)) | |
61 | return -EINVAL; | |
62 | ||
63 | if (!capable(CAP_NET_RAW)) | |
64 | return -EPERM; | |
65 | ||
66 | MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); | |
67 | MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_UCTX); | |
68 | ||
69 | err = mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out)); | |
70 | if (err) | |
71 | return err; | |
72 | ||
73 | context->devx_uid = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); | |
74 | return 0; | |
75 | } | |
76 | ||
77 | void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, | |
78 | struct mlx5_ib_ucontext *context) | |
79 | { | |
80 | u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {0}; | |
81 | u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; | |
82 | ||
83 | MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); | |
84 | MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_UCTX); | |
85 | MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, context->devx_uid); | |
86 | ||
87 | mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, sizeof(out)); | |
88 | } | |
8aa8c95c | 89 | |
e662e14d YH |
90 | static int devx_is_valid_obj_id(struct devx_obj *obj, const void *in) |
91 | { | |
92 | u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); | |
93 | u32 obj_id; | |
94 | ||
95 | switch (opcode) { | |
96 | case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: | |
97 | case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: | |
98 | obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id); | |
99 | break; | |
100 | case MLX5_CMD_OP_QUERY_MKEY: | |
101 | obj_id = MLX5_GET(query_mkey_in, in, mkey_index); | |
102 | break; | |
103 | case MLX5_CMD_OP_QUERY_CQ: | |
104 | obj_id = MLX5_GET(query_cq_in, in, cqn); | |
105 | break; | |
106 | case MLX5_CMD_OP_MODIFY_CQ: | |
107 | obj_id = MLX5_GET(modify_cq_in, in, cqn); | |
108 | break; | |
109 | case MLX5_CMD_OP_QUERY_SQ: | |
110 | obj_id = MLX5_GET(query_sq_in, in, sqn); | |
111 | break; | |
112 | case MLX5_CMD_OP_MODIFY_SQ: | |
113 | obj_id = MLX5_GET(modify_sq_in, in, sqn); | |
114 | break; | |
115 | case MLX5_CMD_OP_QUERY_RQ: | |
116 | obj_id = MLX5_GET(query_rq_in, in, rqn); | |
117 | break; | |
118 | case MLX5_CMD_OP_MODIFY_RQ: | |
119 | obj_id = MLX5_GET(modify_rq_in, in, rqn); | |
120 | break; | |
121 | case MLX5_CMD_OP_QUERY_RMP: | |
122 | obj_id = MLX5_GET(query_rmp_in, in, rmpn); | |
123 | break; | |
124 | case MLX5_CMD_OP_MODIFY_RMP: | |
125 | obj_id = MLX5_GET(modify_rmp_in, in, rmpn); | |
126 | break; | |
127 | case MLX5_CMD_OP_QUERY_RQT: | |
128 | obj_id = MLX5_GET(query_rqt_in, in, rqtn); | |
129 | break; | |
130 | case MLX5_CMD_OP_MODIFY_RQT: | |
131 | obj_id = MLX5_GET(modify_rqt_in, in, rqtn); | |
132 | break; | |
133 | case MLX5_CMD_OP_QUERY_TIR: | |
134 | obj_id = MLX5_GET(query_tir_in, in, tirn); | |
135 | break; | |
136 | case MLX5_CMD_OP_MODIFY_TIR: | |
137 | obj_id = MLX5_GET(modify_tir_in, in, tirn); | |
138 | break; | |
139 | case MLX5_CMD_OP_QUERY_TIS: | |
140 | obj_id = MLX5_GET(query_tis_in, in, tisn); | |
141 | break; | |
142 | case MLX5_CMD_OP_MODIFY_TIS: | |
143 | obj_id = MLX5_GET(modify_tis_in, in, tisn); | |
144 | break; | |
145 | case MLX5_CMD_OP_QUERY_FLOW_TABLE: | |
146 | obj_id = MLX5_GET(query_flow_table_in, in, table_id); | |
147 | break; | |
148 | case MLX5_CMD_OP_MODIFY_FLOW_TABLE: | |
149 | obj_id = MLX5_GET(modify_flow_table_in, in, table_id); | |
150 | break; | |
151 | case MLX5_CMD_OP_QUERY_FLOW_GROUP: | |
152 | obj_id = MLX5_GET(query_flow_group_in, in, group_id); | |
153 | break; | |
154 | case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY: | |
155 | obj_id = MLX5_GET(query_fte_in, in, flow_index); | |
156 | break; | |
157 | case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: | |
158 | obj_id = MLX5_GET(set_fte_in, in, flow_index); | |
159 | break; | |
160 | case MLX5_CMD_OP_QUERY_Q_COUNTER: | |
161 | obj_id = MLX5_GET(query_q_counter_in, in, counter_set_id); | |
162 | break; | |
163 | case MLX5_CMD_OP_QUERY_FLOW_COUNTER: | |
164 | obj_id = MLX5_GET(query_flow_counter_in, in, flow_counter_id); | |
165 | break; | |
166 | case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT: | |
167 | obj_id = MLX5_GET(general_obj_in_cmd_hdr, in, obj_id); | |
168 | break; | |
169 | case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT: | |
170 | obj_id = MLX5_GET(query_scheduling_element_in, in, | |
171 | scheduling_element_id); | |
172 | break; | |
173 | case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT: | |
174 | obj_id = MLX5_GET(modify_scheduling_element_in, in, | |
175 | scheduling_element_id); | |
176 | break; | |
177 | case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: | |
178 | obj_id = MLX5_GET(add_vxlan_udp_dport_in, in, vxlan_udp_port); | |
179 | break; | |
180 | case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY: | |
181 | obj_id = MLX5_GET(query_l2_table_entry_in, in, table_index); | |
182 | break; | |
183 | case MLX5_CMD_OP_SET_L2_TABLE_ENTRY: | |
184 | obj_id = MLX5_GET(set_l2_table_entry_in, in, table_index); | |
185 | break; | |
186 | case MLX5_CMD_OP_QUERY_QP: | |
187 | obj_id = MLX5_GET(query_qp_in, in, qpn); | |
188 | break; | |
189 | case MLX5_CMD_OP_RST2INIT_QP: | |
190 | obj_id = MLX5_GET(rst2init_qp_in, in, qpn); | |
191 | break; | |
192 | case MLX5_CMD_OP_INIT2RTR_QP: | |
193 | obj_id = MLX5_GET(init2rtr_qp_in, in, qpn); | |
194 | break; | |
195 | case MLX5_CMD_OP_RTR2RTS_QP: | |
196 | obj_id = MLX5_GET(rtr2rts_qp_in, in, qpn); | |
197 | break; | |
198 | case MLX5_CMD_OP_RTS2RTS_QP: | |
199 | obj_id = MLX5_GET(rts2rts_qp_in, in, qpn); | |
200 | break; | |
201 | case MLX5_CMD_OP_SQERR2RTS_QP: | |
202 | obj_id = MLX5_GET(sqerr2rts_qp_in, in, qpn); | |
203 | break; | |
204 | case MLX5_CMD_OP_2ERR_QP: | |
205 | obj_id = MLX5_GET(qp_2err_in, in, qpn); | |
206 | break; | |
207 | case MLX5_CMD_OP_2RST_QP: | |
208 | obj_id = MLX5_GET(qp_2rst_in, in, qpn); | |
209 | break; | |
210 | case MLX5_CMD_OP_QUERY_DCT: | |
211 | obj_id = MLX5_GET(query_dct_in, in, dctn); | |
212 | break; | |
213 | case MLX5_CMD_OP_QUERY_XRQ: | |
214 | obj_id = MLX5_GET(query_xrq_in, in, xrqn); | |
215 | break; | |
216 | case MLX5_CMD_OP_QUERY_XRC_SRQ: | |
217 | obj_id = MLX5_GET(query_xrc_srq_in, in, xrc_srqn); | |
218 | break; | |
219 | case MLX5_CMD_OP_ARM_XRC_SRQ: | |
220 | obj_id = MLX5_GET(arm_xrc_srq_in, in, xrc_srqn); | |
221 | break; | |
222 | case MLX5_CMD_OP_QUERY_SRQ: | |
223 | obj_id = MLX5_GET(query_srq_in, in, srqn); | |
224 | break; | |
225 | case MLX5_CMD_OP_ARM_RQ: | |
226 | obj_id = MLX5_GET(arm_rq_in, in, srq_number); | |
227 | break; | |
228 | case MLX5_CMD_OP_DRAIN_DCT: | |
229 | case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION: | |
230 | obj_id = MLX5_GET(drain_dct_in, in, dctn); | |
231 | break; | |
232 | case MLX5_CMD_OP_ARM_XRQ: | |
233 | obj_id = MLX5_GET(arm_xrq_in, in, xrqn); | |
234 | break; | |
235 | default: | |
236 | return false; | |
237 | } | |
238 | ||
239 | if (obj_id == obj->obj_id) | |
240 | return true; | |
241 | ||
242 | return false; | |
243 | } | |
244 | ||
7efce369 YH |
245 | static bool devx_is_obj_create_cmd(const void *in) |
246 | { | |
247 | u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); | |
248 | ||
249 | switch (opcode) { | |
250 | case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: | |
251 | case MLX5_CMD_OP_CREATE_MKEY: | |
252 | case MLX5_CMD_OP_CREATE_CQ: | |
253 | case MLX5_CMD_OP_ALLOC_PD: | |
254 | case MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN: | |
255 | case MLX5_CMD_OP_CREATE_RMP: | |
256 | case MLX5_CMD_OP_CREATE_SQ: | |
257 | case MLX5_CMD_OP_CREATE_RQ: | |
258 | case MLX5_CMD_OP_CREATE_RQT: | |
259 | case MLX5_CMD_OP_CREATE_TIR: | |
260 | case MLX5_CMD_OP_CREATE_TIS: | |
261 | case MLX5_CMD_OP_ALLOC_Q_COUNTER: | |
262 | case MLX5_CMD_OP_CREATE_FLOW_TABLE: | |
263 | case MLX5_CMD_OP_CREATE_FLOW_GROUP: | |
264 | case MLX5_CMD_OP_ALLOC_FLOW_COUNTER: | |
265 | case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: | |
266 | case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: | |
267 | case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT: | |
268 | case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: | |
269 | case MLX5_CMD_OP_SET_L2_TABLE_ENTRY: | |
270 | case MLX5_CMD_OP_CREATE_QP: | |
271 | case MLX5_CMD_OP_CREATE_SRQ: | |
272 | case MLX5_CMD_OP_CREATE_XRC_SRQ: | |
273 | case MLX5_CMD_OP_CREATE_DCT: | |
274 | case MLX5_CMD_OP_CREATE_XRQ: | |
275 | case MLX5_CMD_OP_ATTACH_TO_MCG: | |
276 | case MLX5_CMD_OP_ALLOC_XRCD: | |
277 | return true; | |
278 | case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: | |
279 | { | |
280 | u16 op_mod = MLX5_GET(set_fte_in, in, op_mod); | |
281 | if (op_mod == 0) | |
282 | return true; | |
283 | return false; | |
284 | } | |
285 | default: | |
286 | return false; | |
287 | } | |
288 | } | |
289 | ||
e662e14d YH |
290 | static bool devx_is_obj_modify_cmd(const void *in) |
291 | { | |
292 | u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); | |
293 | ||
294 | switch (opcode) { | |
295 | case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: | |
296 | case MLX5_CMD_OP_MODIFY_CQ: | |
297 | case MLX5_CMD_OP_MODIFY_RMP: | |
298 | case MLX5_CMD_OP_MODIFY_SQ: | |
299 | case MLX5_CMD_OP_MODIFY_RQ: | |
300 | case MLX5_CMD_OP_MODIFY_RQT: | |
301 | case MLX5_CMD_OP_MODIFY_TIR: | |
302 | case MLX5_CMD_OP_MODIFY_TIS: | |
303 | case MLX5_CMD_OP_MODIFY_FLOW_TABLE: | |
304 | case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT: | |
305 | case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: | |
306 | case MLX5_CMD_OP_SET_L2_TABLE_ENTRY: | |
307 | case MLX5_CMD_OP_RST2INIT_QP: | |
308 | case MLX5_CMD_OP_INIT2RTR_QP: | |
309 | case MLX5_CMD_OP_RTR2RTS_QP: | |
310 | case MLX5_CMD_OP_RTS2RTS_QP: | |
311 | case MLX5_CMD_OP_SQERR2RTS_QP: | |
312 | case MLX5_CMD_OP_2ERR_QP: | |
313 | case MLX5_CMD_OP_2RST_QP: | |
314 | case MLX5_CMD_OP_ARM_XRC_SRQ: | |
315 | case MLX5_CMD_OP_ARM_RQ: | |
316 | case MLX5_CMD_OP_DRAIN_DCT: | |
317 | case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION: | |
318 | case MLX5_CMD_OP_ARM_XRQ: | |
319 | return true; | |
320 | case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: | |
321 | { | |
322 | u16 op_mod = MLX5_GET(set_fte_in, in, op_mod); | |
323 | ||
324 | if (op_mod == 1) | |
325 | return true; | |
326 | return false; | |
327 | } | |
328 | default: | |
329 | return false; | |
330 | } | |
331 | } | |
332 | ||
333 | static bool devx_is_obj_query_cmd(const void *in) | |
334 | { | |
335 | u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); | |
336 | ||
337 | switch (opcode) { | |
338 | case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: | |
339 | case MLX5_CMD_OP_QUERY_MKEY: | |
340 | case MLX5_CMD_OP_QUERY_CQ: | |
341 | case MLX5_CMD_OP_QUERY_RMP: | |
342 | case MLX5_CMD_OP_QUERY_SQ: | |
343 | case MLX5_CMD_OP_QUERY_RQ: | |
344 | case MLX5_CMD_OP_QUERY_RQT: | |
345 | case MLX5_CMD_OP_QUERY_TIR: | |
346 | case MLX5_CMD_OP_QUERY_TIS: | |
347 | case MLX5_CMD_OP_QUERY_Q_COUNTER: | |
348 | case MLX5_CMD_OP_QUERY_FLOW_TABLE: | |
349 | case MLX5_CMD_OP_QUERY_FLOW_GROUP: | |
350 | case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY: | |
351 | case MLX5_CMD_OP_QUERY_FLOW_COUNTER: | |
352 | case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT: | |
353 | case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT: | |
354 | case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY: | |
355 | case MLX5_CMD_OP_QUERY_QP: | |
356 | case MLX5_CMD_OP_QUERY_SRQ: | |
357 | case MLX5_CMD_OP_QUERY_XRC_SRQ: | |
358 | case MLX5_CMD_OP_QUERY_DCT: | |
359 | case MLX5_CMD_OP_QUERY_XRQ: | |
360 | return true; | |
361 | default: | |
362 | return false; | |
363 | } | |
364 | } | |
365 | ||
366 | static bool devx_is_general_cmd(void *in) | |
8aa8c95c YH |
367 | { |
368 | u16 opcode = MLX5_GET(general_obj_in_cmd_hdr, in, opcode); | |
369 | ||
370 | switch (opcode) { | |
371 | case MLX5_CMD_OP_QUERY_HCA_CAP: | |
372 | case MLX5_CMD_OP_QUERY_VPORT_STATE: | |
373 | case MLX5_CMD_OP_QUERY_ADAPTER: | |
374 | case MLX5_CMD_OP_QUERY_ISSI: | |
375 | case MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT: | |
376 | case MLX5_CMD_OP_QUERY_ROCE_ADDRESS: | |
377 | case MLX5_CMD_OP_QUERY_VNIC_ENV: | |
378 | case MLX5_CMD_OP_QUERY_VPORT_COUNTER: | |
379 | case MLX5_CMD_OP_GET_DROPPED_PACKET_LOG: | |
380 | case MLX5_CMD_OP_NOP: | |
381 | case MLX5_CMD_OP_QUERY_CONG_STATUS: | |
382 | case MLX5_CMD_OP_QUERY_CONG_PARAMS: | |
383 | case MLX5_CMD_OP_QUERY_CONG_STATISTICS: | |
384 | return true; | |
385 | default: | |
386 | return false; | |
387 | } | |
388 | } | |
389 | ||
f6fe01b7 YH |
390 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_EQN)(struct ib_device *ib_dev, |
391 | struct ib_uverbs_file *file, | |
392 | struct uverbs_attr_bundle *attrs) | |
393 | { | |
394 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
395 | int user_vector; | |
396 | int dev_eqn; | |
397 | unsigned int irqn; | |
398 | int err; | |
399 | ||
400 | if (uverbs_copy_from(&user_vector, attrs, | |
401 | MLX5_IB_ATTR_DEVX_QUERY_EQN_USER_VEC)) | |
402 | return -EFAULT; | |
403 | ||
404 | err = mlx5_vector2eqn(dev->mdev, user_vector, &dev_eqn, &irqn); | |
405 | if (err < 0) | |
406 | return err; | |
407 | ||
408 | if (uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_QUERY_EQN_DEV_EQN, | |
409 | &dev_eqn, sizeof(dev_eqn))) | |
410 | return -EFAULT; | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
7c043e90 YH |
415 | /* |
416 | *Security note: | |
417 | * The hardware protection mechanism works like this: Each device object that | |
418 | * is subject to UAR doorbells (QP/SQ/CQ) gets a UAR ID (called uar_page in | |
419 | * the device specification manual) upon its creation. Then upon doorbell, | |
420 | * hardware fetches the object context for which the doorbell was rang, and | |
421 | * validates that the UAR through which the DB was rang matches the UAR ID | |
422 | * of the object. | |
423 | * If no match the doorbell is silently ignored by the hardware. Of course, | |
424 | * the user cannot ring a doorbell on a UAR that was not mapped to it. | |
425 | * Now in devx, as the devx kernel does not manipulate the QP/SQ/CQ command | |
426 | * mailboxes (except tagging them with UID), we expose to the user its UAR | |
427 | * ID, so it can embed it in these objects in the expected specification | |
428 | * format. So the only thing the user can do is hurt itself by creating a | |
429 | * QP/SQ/CQ with a UAR ID other than his, and then in this case other users | |
430 | * may ring a doorbell on its objects. | |
431 | * The consequence of that will be that another user can schedule a QP/SQ | |
432 | * of the buggy user for execution (just insert it to the hardware schedule | |
433 | * queue or arm its CQ for event generation), no further harm is expected. | |
434 | */ | |
435 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_QUERY_UAR)(struct ib_device *ib_dev, | |
436 | struct ib_uverbs_file *file, | |
437 | struct uverbs_attr_bundle *attrs) | |
438 | { | |
439 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
440 | u32 user_idx; | |
441 | s32 dev_idx; | |
442 | ||
443 | if (uverbs_copy_from(&user_idx, attrs, | |
444 | MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX)) | |
445 | return -EFAULT; | |
446 | ||
447 | dev_idx = bfregn_to_uar_index(to_mdev(ib_dev), | |
448 | &c->bfregi, user_idx, true); | |
449 | if (dev_idx < 0) | |
450 | return dev_idx; | |
451 | ||
452 | if (uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_QUERY_UAR_DEV_IDX, | |
453 | &dev_idx, sizeof(dev_idx))) | |
454 | return -EFAULT; | |
455 | ||
456 | return 0; | |
457 | } | |
458 | ||
8aa8c95c YH |
459 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(struct ib_device *ib_dev, |
460 | struct ib_uverbs_file *file, | |
461 | struct uverbs_attr_bundle *attrs) | |
462 | { | |
463 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
464 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
7efce369 YH |
465 | void *cmd_in = uverbs_attr_get_alloced_ptr( |
466 | attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN); | |
8aa8c95c YH |
467 | int cmd_out_len = uverbs_attr_get_len(attrs, |
468 | MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT); | |
469 | void *cmd_out; | |
470 | int err; | |
471 | ||
472 | if (!c->devx_uid) | |
473 | return -EPERM; | |
474 | ||
475 | /* Only white list of some general HCA commands are allowed for this method. */ | |
476 | if (!devx_is_general_cmd(cmd_in)) | |
477 | return -EINVAL; | |
478 | ||
479 | cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); | |
480 | if (!cmd_out) | |
481 | return -ENOMEM; | |
482 | ||
483 | MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); | |
484 | err = mlx5_cmd_exec(dev->mdev, cmd_in, | |
485 | uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_IN), | |
486 | cmd_out, cmd_out_len); | |
487 | if (err) | |
488 | goto other_cmd_free; | |
489 | ||
490 | err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, cmd_out, cmd_out_len); | |
491 | ||
492 | other_cmd_free: | |
493 | kvfree(cmd_out); | |
494 | return err; | |
495 | } | |
496 | ||
7efce369 YH |
497 | static void devx_obj_build_destroy_cmd(void *in, void *out, void *din, |
498 | u32 *dinlen, | |
499 | u32 *obj_id) | |
500 | { | |
501 | u16 obj_type = MLX5_GET(general_obj_in_cmd_hdr, in, obj_type); | |
502 | u16 uid = MLX5_GET(general_obj_in_cmd_hdr, in, uid); | |
503 | ||
504 | *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); | |
505 | *dinlen = MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr); | |
506 | ||
507 | MLX5_SET(general_obj_in_cmd_hdr, din, obj_id, *obj_id); | |
508 | MLX5_SET(general_obj_in_cmd_hdr, din, uid, uid); | |
509 | ||
510 | switch (MLX5_GET(general_obj_in_cmd_hdr, in, opcode)) { | |
511 | case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: | |
512 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); | |
513 | MLX5_SET(general_obj_in_cmd_hdr, din, obj_type, obj_type); | |
514 | break; | |
515 | ||
516 | case MLX5_CMD_OP_CREATE_MKEY: | |
517 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_MKEY); | |
518 | break; | |
519 | case MLX5_CMD_OP_CREATE_CQ: | |
520 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_CQ); | |
521 | break; | |
522 | case MLX5_CMD_OP_ALLOC_PD: | |
523 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DEALLOC_PD); | |
524 | break; | |
525 | case MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN: | |
526 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
527 | MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN); | |
528 | break; | |
529 | case MLX5_CMD_OP_CREATE_RMP: | |
530 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_RMP); | |
531 | break; | |
532 | case MLX5_CMD_OP_CREATE_SQ: | |
533 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_SQ); | |
534 | break; | |
535 | case MLX5_CMD_OP_CREATE_RQ: | |
536 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_RQ); | |
537 | break; | |
538 | case MLX5_CMD_OP_CREATE_RQT: | |
539 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_RQT); | |
540 | break; | |
541 | case MLX5_CMD_OP_CREATE_TIR: | |
542 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_TIR); | |
543 | break; | |
544 | case MLX5_CMD_OP_CREATE_TIS: | |
545 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_TIS); | |
546 | break; | |
547 | case MLX5_CMD_OP_ALLOC_Q_COUNTER: | |
548 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
549 | MLX5_CMD_OP_DEALLOC_Q_COUNTER); | |
550 | break; | |
551 | case MLX5_CMD_OP_CREATE_FLOW_TABLE: | |
552 | *dinlen = MLX5_ST_SZ_BYTES(destroy_flow_table_in); | |
553 | *obj_id = MLX5_GET(create_flow_table_out, out, table_id); | |
554 | MLX5_SET(destroy_flow_table_in, din, other_vport, | |
555 | MLX5_GET(create_flow_table_in, in, other_vport)); | |
556 | MLX5_SET(destroy_flow_table_in, din, vport_number, | |
557 | MLX5_GET(create_flow_table_in, in, vport_number)); | |
558 | MLX5_SET(destroy_flow_table_in, din, table_type, | |
559 | MLX5_GET(create_flow_table_in, in, table_type)); | |
560 | MLX5_SET(destroy_flow_table_in, din, table_id, *obj_id); | |
561 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
562 | MLX5_CMD_OP_DESTROY_FLOW_TABLE); | |
563 | break; | |
564 | case MLX5_CMD_OP_CREATE_FLOW_GROUP: | |
565 | *dinlen = MLX5_ST_SZ_BYTES(destroy_flow_group_in); | |
566 | *obj_id = MLX5_GET(create_flow_group_out, out, group_id); | |
567 | MLX5_SET(destroy_flow_group_in, din, other_vport, | |
568 | MLX5_GET(create_flow_group_in, in, other_vport)); | |
569 | MLX5_SET(destroy_flow_group_in, din, vport_number, | |
570 | MLX5_GET(create_flow_group_in, in, vport_number)); | |
571 | MLX5_SET(destroy_flow_group_in, din, table_type, | |
572 | MLX5_GET(create_flow_group_in, in, table_type)); | |
573 | MLX5_SET(destroy_flow_group_in, din, table_id, | |
574 | MLX5_GET(create_flow_group_in, in, table_id)); | |
575 | MLX5_SET(destroy_flow_group_in, din, group_id, *obj_id); | |
576 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
577 | MLX5_CMD_OP_DESTROY_FLOW_GROUP); | |
578 | break; | |
579 | case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY: | |
580 | *dinlen = MLX5_ST_SZ_BYTES(delete_fte_in); | |
581 | *obj_id = MLX5_GET(set_fte_in, in, flow_index); | |
582 | MLX5_SET(delete_fte_in, din, other_vport, | |
583 | MLX5_GET(set_fte_in, in, other_vport)); | |
584 | MLX5_SET(delete_fte_in, din, vport_number, | |
585 | MLX5_GET(set_fte_in, in, vport_number)); | |
586 | MLX5_SET(delete_fte_in, din, table_type, | |
587 | MLX5_GET(set_fte_in, in, table_type)); | |
588 | MLX5_SET(delete_fte_in, din, table_id, | |
589 | MLX5_GET(set_fte_in, in, table_id)); | |
590 | MLX5_SET(delete_fte_in, din, flow_index, *obj_id); | |
591 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
592 | MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); | |
593 | break; | |
594 | case MLX5_CMD_OP_ALLOC_FLOW_COUNTER: | |
595 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
596 | MLX5_CMD_OP_DEALLOC_FLOW_COUNTER); | |
597 | break; | |
598 | case MLX5_CMD_OP_ALLOC_ENCAP_HEADER: | |
599 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
600 | MLX5_CMD_OP_DEALLOC_ENCAP_HEADER); | |
601 | break; | |
602 | case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT: | |
603 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
604 | MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT); | |
605 | break; | |
606 | case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT: | |
607 | *dinlen = MLX5_ST_SZ_BYTES(destroy_scheduling_element_in); | |
608 | *obj_id = MLX5_GET(create_scheduling_element_out, out, | |
609 | scheduling_element_id); | |
610 | MLX5_SET(destroy_scheduling_element_in, din, | |
611 | scheduling_hierarchy, | |
612 | MLX5_GET(create_scheduling_element_in, in, | |
613 | scheduling_hierarchy)); | |
614 | MLX5_SET(destroy_scheduling_element_in, din, | |
615 | scheduling_element_id, *obj_id); | |
616 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
617 | MLX5_CMD_OP_DESTROY_SCHEDULING_ELEMENT); | |
618 | break; | |
619 | case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT: | |
620 | *dinlen = MLX5_ST_SZ_BYTES(delete_vxlan_udp_dport_in); | |
621 | *obj_id = MLX5_GET(add_vxlan_udp_dport_in, in, vxlan_udp_port); | |
622 | MLX5_SET(delete_vxlan_udp_dport_in, din, vxlan_udp_port, *obj_id); | |
623 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
624 | MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT); | |
625 | break; | |
626 | case MLX5_CMD_OP_SET_L2_TABLE_ENTRY: | |
627 | *dinlen = MLX5_ST_SZ_BYTES(delete_l2_table_entry_in); | |
628 | *obj_id = MLX5_GET(set_l2_table_entry_in, in, table_index); | |
629 | MLX5_SET(delete_l2_table_entry_in, din, table_index, *obj_id); | |
630 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
631 | MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY); | |
632 | break; | |
633 | case MLX5_CMD_OP_CREATE_QP: | |
634 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_QP); | |
635 | break; | |
636 | case MLX5_CMD_OP_CREATE_SRQ: | |
637 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_SRQ); | |
638 | break; | |
639 | case MLX5_CMD_OP_CREATE_XRC_SRQ: | |
640 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, | |
641 | MLX5_CMD_OP_DESTROY_XRC_SRQ); | |
642 | break; | |
643 | case MLX5_CMD_OP_CREATE_DCT: | |
644 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_DCT); | |
645 | break; | |
646 | case MLX5_CMD_OP_CREATE_XRQ: | |
647 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DESTROY_XRQ); | |
648 | break; | |
649 | case MLX5_CMD_OP_ATTACH_TO_MCG: | |
650 | *dinlen = MLX5_ST_SZ_BYTES(detach_from_mcg_in); | |
651 | MLX5_SET(detach_from_mcg_in, din, qpn, | |
652 | MLX5_GET(attach_to_mcg_in, in, qpn)); | |
653 | memcpy(MLX5_ADDR_OF(detach_from_mcg_in, din, multicast_gid), | |
654 | MLX5_ADDR_OF(attach_to_mcg_in, in, multicast_gid), | |
655 | MLX5_FLD_SZ_BYTES(attach_to_mcg_in, multicast_gid)); | |
656 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DETACH_FROM_MCG); | |
657 | break; | |
658 | case MLX5_CMD_OP_ALLOC_XRCD: | |
659 | MLX5_SET(general_obj_in_cmd_hdr, din, opcode, MLX5_CMD_OP_DEALLOC_XRCD); | |
660 | break; | |
661 | default: | |
662 | /* The entry must match to one of the devx_is_obj_create_cmd */ | |
663 | WARN_ON(true); | |
664 | break; | |
665 | } | |
666 | } | |
667 | ||
668 | static int devx_obj_cleanup(struct ib_uobject *uobject, | |
669 | enum rdma_remove_reason why) | |
670 | { | |
671 | u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; | |
672 | struct devx_obj *obj = uobject->object; | |
673 | int ret; | |
674 | ||
675 | ret = mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out, sizeof(out)); | |
1c77483e | 676 | if (ib_is_destroy_retryable(ret, why, uobject)) |
7efce369 YH |
677 | return ret; |
678 | ||
679 | kfree(obj); | |
680 | return ret; | |
681 | } | |
682 | ||
7efce369 YH |
683 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(struct ib_device *ib_dev, |
684 | struct ib_uverbs_file *file, | |
685 | struct uverbs_attr_bundle *attrs) | |
686 | { | |
687 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
688 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
689 | void *cmd_in = uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN); | |
690 | int cmd_out_len = uverbs_attr_get_len(attrs, | |
691 | MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT); | |
692 | void *cmd_out; | |
693 | struct ib_uobject *uobj; | |
694 | struct devx_obj *obj; | |
695 | int err; | |
696 | ||
697 | if (!c->devx_uid) | |
698 | return -EPERM; | |
699 | ||
700 | if (!devx_is_obj_create_cmd(cmd_in)) | |
701 | return -EINVAL; | |
702 | ||
703 | obj = kzalloc(sizeof(struct devx_obj), GFP_KERNEL); | |
704 | if (!obj) | |
705 | return -ENOMEM; | |
706 | ||
707 | cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); | |
708 | if (!cmd_out) { | |
709 | err = -ENOMEM; | |
710 | goto obj_free; | |
711 | } | |
712 | ||
713 | MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); | |
714 | err = mlx5_cmd_exec(dev->mdev, cmd_in, | |
715 | uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN), | |
716 | cmd_out, cmd_out_len); | |
717 | if (err) | |
718 | goto cmd_free; | |
719 | ||
720 | uobj = uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_HANDLE); | |
721 | uobj->object = obj; | |
722 | obj->mdev = dev->mdev; | |
723 | devx_obj_build_destroy_cmd(cmd_in, cmd_out, obj->dinbox, &obj->dinlen, &obj->obj_id); | |
724 | WARN_ON(obj->dinlen > MLX5_MAX_DESTROY_INBOX_SIZE_DW * sizeof(u32)); | |
725 | ||
726 | err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, cmd_out, cmd_out_len); | |
727 | if (err) | |
728 | goto cmd_free; | |
729 | ||
730 | kvfree(cmd_out); | |
731 | return 0; | |
732 | ||
733 | cmd_free: | |
734 | kvfree(cmd_out); | |
735 | obj_free: | |
736 | kfree(obj); | |
737 | return err; | |
738 | } | |
739 | ||
e662e14d YH |
740 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_MODIFY)(struct ib_device *ib_dev, |
741 | struct ib_uverbs_file *file, | |
742 | struct uverbs_attr_bundle *attrs) | |
743 | { | |
744 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
745 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
746 | void *cmd_in = uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN); | |
747 | int cmd_out_len = uverbs_attr_get_len(attrs, | |
748 | MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT); | |
749 | struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, | |
750 | MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE); | |
751 | void *cmd_out; | |
752 | int err; | |
753 | ||
754 | if (!c->devx_uid) | |
755 | return -EPERM; | |
756 | ||
757 | if (!devx_is_obj_modify_cmd(cmd_in)) | |
758 | return -EINVAL; | |
759 | ||
760 | if (!devx_is_valid_obj_id(uobj->object, cmd_in)) | |
761 | return -EINVAL; | |
762 | ||
763 | cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); | |
764 | if (!cmd_out) | |
765 | return -ENOMEM; | |
766 | ||
767 | MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); | |
768 | err = mlx5_cmd_exec(dev->mdev, cmd_in, | |
769 | uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN), | |
770 | cmd_out, cmd_out_len); | |
771 | if (err) | |
772 | goto other_cmd_free; | |
773 | ||
774 | err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT, | |
775 | cmd_out, cmd_out_len); | |
776 | ||
777 | other_cmd_free: | |
778 | kvfree(cmd_out); | |
779 | return err; | |
780 | } | |
781 | ||
782 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(struct ib_device *ib_dev, | |
783 | struct ib_uverbs_file *file, | |
784 | struct uverbs_attr_bundle *attrs) | |
785 | { | |
786 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
787 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
788 | void *cmd_in = uverbs_attr_get_alloced_ptr(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN); | |
789 | int cmd_out_len = uverbs_attr_get_len(attrs, | |
790 | MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT); | |
791 | struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, | |
792 | MLX5_IB_ATTR_DEVX_OBJ_QUERY_HANDLE); | |
793 | void *cmd_out; | |
794 | int err; | |
795 | ||
796 | if (!c->devx_uid) | |
797 | return -EPERM; | |
798 | ||
799 | if (!devx_is_obj_query_cmd(cmd_in)) | |
800 | return -EINVAL; | |
801 | ||
802 | if (!devx_is_valid_obj_id(uobj->object, cmd_in)) | |
803 | return -EINVAL; | |
804 | ||
805 | cmd_out = kvzalloc(cmd_out_len, GFP_KERNEL); | |
806 | if (!cmd_out) | |
807 | return -ENOMEM; | |
808 | ||
809 | MLX5_SET(general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); | |
810 | err = mlx5_cmd_exec(dev->mdev, cmd_in, | |
811 | uverbs_attr_get_len(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN), | |
812 | cmd_out, cmd_out_len); | |
813 | if (err) | |
814 | goto other_cmd_free; | |
815 | ||
816 | err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, cmd_out, cmd_out_len); | |
817 | ||
818 | other_cmd_free: | |
819 | kvfree(cmd_out); | |
820 | return err; | |
821 | } | |
822 | ||
aeae9457 YH |
823 | static int devx_umem_get(struct mlx5_ib_dev *dev, struct ib_ucontext *ucontext, |
824 | struct uverbs_attr_bundle *attrs, | |
825 | struct devx_umem *obj) | |
826 | { | |
827 | u64 addr; | |
828 | size_t size; | |
829 | int access; | |
830 | int npages; | |
831 | int err; | |
832 | u32 page_mask; | |
833 | ||
834 | if (uverbs_copy_from(&addr, attrs, MLX5_IB_ATTR_DEVX_UMEM_REG_ADDR) || | |
835 | uverbs_copy_from(&size, attrs, MLX5_IB_ATTR_DEVX_UMEM_REG_LEN) || | |
836 | uverbs_copy_from(&access, attrs, MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS)) | |
837 | return -EFAULT; | |
838 | ||
839 | err = ib_check_mr_access(access); | |
840 | if (err) | |
841 | return err; | |
842 | ||
843 | obj->umem = ib_umem_get(ucontext, addr, size, access, 0); | |
844 | if (IS_ERR(obj->umem)) | |
845 | return PTR_ERR(obj->umem); | |
846 | ||
847 | mlx5_ib_cont_pages(obj->umem, obj->umem->address, | |
848 | MLX5_MKEY_PAGE_SHIFT_MASK, &npages, | |
849 | &obj->page_shift, &obj->ncont, NULL); | |
850 | ||
851 | if (!npages) { | |
852 | ib_umem_release(obj->umem); | |
853 | return -EINVAL; | |
854 | } | |
855 | ||
856 | page_mask = (1 << obj->page_shift) - 1; | |
857 | obj->page_offset = obj->umem->address & page_mask; | |
858 | ||
859 | return 0; | |
860 | } | |
861 | ||
862 | static int devx_umem_reg_cmd_alloc(struct devx_umem *obj, | |
863 | struct devx_umem_reg_cmd *cmd) | |
864 | { | |
865 | cmd->inlen = MLX5_ST_SZ_BYTES(create_umem_in) + | |
866 | (MLX5_ST_SZ_BYTES(mtt) * obj->ncont); | |
867 | cmd->in = kvzalloc(cmd->inlen, GFP_KERNEL); | |
868 | return cmd->in ? 0 : -ENOMEM; | |
869 | } | |
870 | ||
871 | static void devx_umem_reg_cmd_free(struct devx_umem_reg_cmd *cmd) | |
872 | { | |
873 | kvfree(cmd->in); | |
874 | } | |
875 | ||
876 | static void devx_umem_reg_cmd_build(struct mlx5_ib_dev *dev, | |
877 | struct devx_umem *obj, | |
878 | struct devx_umem_reg_cmd *cmd) | |
879 | { | |
880 | void *umem; | |
881 | __be64 *mtt; | |
882 | ||
883 | umem = MLX5_ADDR_OF(create_umem_in, cmd->in, umem); | |
884 | mtt = (__be64 *)MLX5_ADDR_OF(umem, umem, mtt); | |
885 | ||
886 | MLX5_SET(general_obj_in_cmd_hdr, cmd->in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); | |
887 | MLX5_SET(general_obj_in_cmd_hdr, cmd->in, obj_type, MLX5_OBJ_TYPE_UMEM); | |
888 | MLX5_SET64(umem, umem, num_of_mtt, obj->ncont); | |
889 | MLX5_SET(umem, umem, log_page_size, obj->page_shift - | |
890 | MLX5_ADAPTER_PAGE_SHIFT); | |
891 | MLX5_SET(umem, umem, page_offset, obj->page_offset); | |
892 | mlx5_ib_populate_pas(dev, obj->umem, obj->page_shift, mtt, | |
893 | (obj->umem->writable ? MLX5_IB_MTT_WRITE : 0) | | |
894 | MLX5_IB_MTT_READ); | |
895 | } | |
896 | ||
897 | static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_UMEM_REG)(struct ib_device *ib_dev, | |
898 | struct ib_uverbs_file *file, | |
899 | struct uverbs_attr_bundle *attrs) | |
900 | { | |
901 | struct mlx5_ib_ucontext *c = devx_ufile2uctx(file); | |
902 | struct mlx5_ib_dev *dev = to_mdev(ib_dev); | |
903 | struct devx_umem_reg_cmd cmd; | |
904 | struct devx_umem *obj; | |
905 | struct ib_uobject *uobj; | |
906 | u32 obj_id; | |
907 | int err; | |
908 | ||
909 | if (!c->devx_uid) | |
910 | return -EPERM; | |
911 | ||
912 | uobj = uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE); | |
913 | obj = kzalloc(sizeof(struct devx_umem), GFP_KERNEL); | |
914 | if (!obj) | |
915 | return -ENOMEM; | |
916 | ||
917 | err = devx_umem_get(dev, &c->ibucontext, attrs, obj); | |
918 | if (err) | |
919 | goto err_obj_free; | |
920 | ||
921 | err = devx_umem_reg_cmd_alloc(obj, &cmd); | |
922 | if (err) | |
923 | goto err_umem_release; | |
924 | ||
925 | devx_umem_reg_cmd_build(dev, obj, &cmd); | |
926 | ||
927 | MLX5_SET(general_obj_in_cmd_hdr, cmd.in, uid, c->devx_uid); | |
928 | err = mlx5_cmd_exec(dev->mdev, cmd.in, cmd.inlen, cmd.out, | |
929 | sizeof(cmd.out)); | |
930 | if (err) | |
931 | goto err_umem_reg_cmd_free; | |
932 | ||
933 | obj->mdev = dev->mdev; | |
934 | uobj->object = obj; | |
935 | devx_obj_build_destroy_cmd(cmd.in, cmd.out, obj->dinbox, &obj->dinlen, &obj_id); | |
936 | err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID, &obj_id, sizeof(obj_id)); | |
937 | if (err) | |
938 | goto err_umem_destroy; | |
939 | ||
940 | devx_umem_reg_cmd_free(&cmd); | |
941 | ||
942 | return 0; | |
943 | ||
944 | err_umem_destroy: | |
945 | mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, cmd.out, sizeof(cmd.out)); | |
946 | err_umem_reg_cmd_free: | |
947 | devx_umem_reg_cmd_free(&cmd); | |
948 | err_umem_release: | |
949 | ib_umem_release(obj->umem); | |
950 | err_obj_free: | |
951 | kfree(obj); | |
952 | return err; | |
953 | } | |
954 | ||
aeae9457 YH |
955 | static int devx_umem_cleanup(struct ib_uobject *uobject, |
956 | enum rdma_remove_reason why) | |
957 | { | |
958 | struct devx_umem *obj = uobject->object; | |
959 | u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; | |
960 | int err; | |
961 | ||
962 | err = mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out, sizeof(out)); | |
1c77483e | 963 | if (ib_is_destroy_retryable(err, why, uobject)) |
aeae9457 YH |
964 | return err; |
965 | ||
966 | ib_umem_release(obj->umem); | |
967 | kfree(obj); | |
968 | return 0; | |
969 | } | |
970 | ||
9a119cd5 JG |
971 | DECLARE_UVERBS_NAMED_METHOD( |
972 | MLX5_IB_METHOD_DEVX_UMEM_REG, | |
973 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE, | |
974 | MLX5_IB_OBJECT_DEVX_UMEM, | |
975 | UVERBS_ACCESS_NEW, | |
83bb4442 | 976 | UA_MANDATORY), |
9a119cd5 JG |
977 | UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_ADDR, |
978 | UVERBS_ATTR_TYPE(u64), | |
83bb4442 | 979 | UA_MANDATORY), |
9a119cd5 JG |
980 | UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_LEN, |
981 | UVERBS_ATTR_TYPE(u64), | |
83bb4442 | 982 | UA_MANDATORY), |
9a119cd5 JG |
983 | UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS, |
984 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 985 | UA_MANDATORY), |
9a119cd5 JG |
986 | UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID, |
987 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 988 | UA_MANDATORY)); |
9a119cd5 | 989 | |
528922af | 990 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
9a119cd5 JG |
991 | MLX5_IB_METHOD_DEVX_UMEM_DEREG, |
992 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_UMEM_DEREG_HANDLE, | |
993 | MLX5_IB_OBJECT_DEVX_UMEM, | |
994 | UVERBS_ACCESS_DESTROY, | |
83bb4442 | 995 | UA_MANDATORY)); |
9a119cd5 JG |
996 | |
997 | DECLARE_UVERBS_NAMED_METHOD( | |
998 | MLX5_IB_METHOD_DEVX_QUERY_EQN, | |
999 | UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_EQN_USER_VEC, | |
1000 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 1001 | UA_MANDATORY), |
9a119cd5 JG |
1002 | UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_QUERY_EQN_DEV_EQN, |
1003 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 1004 | UA_MANDATORY)); |
9a119cd5 JG |
1005 | |
1006 | DECLARE_UVERBS_NAMED_METHOD( | |
1007 | MLX5_IB_METHOD_DEVX_QUERY_UAR, | |
1008 | UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX, | |
1009 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 1010 | UA_MANDATORY), |
9a119cd5 JG |
1011 | UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_QUERY_UAR_DEV_IDX, |
1012 | UVERBS_ATTR_TYPE(u32), | |
83bb4442 | 1013 | UA_MANDATORY)); |
9a119cd5 JG |
1014 | |
1015 | DECLARE_UVERBS_NAMED_METHOD( | |
1016 | MLX5_IB_METHOD_DEVX_OTHER, | |
1017 | UVERBS_ATTR_PTR_IN( | |
1018 | MLX5_IB_ATTR_DEVX_OTHER_CMD_IN, | |
1019 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), | |
83bb4442 | 1020 | UA_MANDATORY, |
83bb4442 | 1021 | UA_ALLOC_AND_COPY), |
9a119cd5 JG |
1022 | UVERBS_ATTR_PTR_OUT( |
1023 | MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, | |
1024 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_out_cmd_hdr)), | |
540cd692 | 1025 | UA_MANDATORY)); |
9a119cd5 JG |
1026 | |
1027 | DECLARE_UVERBS_NAMED_METHOD( | |
1028 | MLX5_IB_METHOD_DEVX_OBJ_CREATE, | |
1029 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_CREATE_HANDLE, | |
1030 | MLX5_IB_OBJECT_DEVX_OBJ, | |
1031 | UVERBS_ACCESS_NEW, | |
83bb4442 | 1032 | UA_MANDATORY), |
9a119cd5 JG |
1033 | UVERBS_ATTR_PTR_IN( |
1034 | MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN, | |
1035 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), | |
83bb4442 | 1036 | UA_MANDATORY, |
83bb4442 | 1037 | UA_ALLOC_AND_COPY), |
9a119cd5 JG |
1038 | UVERBS_ATTR_PTR_OUT( |
1039 | MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, | |
1040 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_out_cmd_hdr)), | |
540cd692 | 1041 | UA_MANDATORY)); |
9a119cd5 | 1042 | |
528922af | 1043 | DECLARE_UVERBS_NAMED_METHOD_DESTROY( |
9a119cd5 JG |
1044 | MLX5_IB_METHOD_DEVX_OBJ_DESTROY, |
1045 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_DESTROY_HANDLE, | |
1046 | MLX5_IB_OBJECT_DEVX_OBJ, | |
1047 | UVERBS_ACCESS_DESTROY, | |
83bb4442 | 1048 | UA_MANDATORY)); |
9a119cd5 JG |
1049 | |
1050 | DECLARE_UVERBS_NAMED_METHOD( | |
1051 | MLX5_IB_METHOD_DEVX_OBJ_MODIFY, | |
1052 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE, | |
1053 | MLX5_IB_OBJECT_DEVX_OBJ, | |
1054 | UVERBS_ACCESS_WRITE, | |
83bb4442 | 1055 | UA_MANDATORY), |
9a119cd5 JG |
1056 | UVERBS_ATTR_PTR_IN( |
1057 | MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN, | |
1058 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), | |
83bb4442 | 1059 | UA_MANDATORY, |
83bb4442 | 1060 | UA_ALLOC_AND_COPY), |
9a119cd5 JG |
1061 | UVERBS_ATTR_PTR_OUT( |
1062 | MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT, | |
1063 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_out_cmd_hdr)), | |
540cd692 | 1064 | UA_MANDATORY)); |
9a119cd5 JG |
1065 | |
1066 | DECLARE_UVERBS_NAMED_METHOD( | |
1067 | MLX5_IB_METHOD_DEVX_OBJ_QUERY, | |
1068 | UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_QUERY_HANDLE, | |
1069 | MLX5_IB_OBJECT_DEVX_OBJ, | |
1070 | UVERBS_ACCESS_READ, | |
83bb4442 | 1071 | UA_MANDATORY), |
9a119cd5 JG |
1072 | UVERBS_ATTR_PTR_IN( |
1073 | MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN, | |
1074 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), | |
83bb4442 | 1075 | UA_MANDATORY, |
83bb4442 | 1076 | UA_ALLOC_AND_COPY), |
9a119cd5 JG |
1077 | UVERBS_ATTR_PTR_OUT( |
1078 | MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, | |
1079 | UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_out_cmd_hdr)), | |
540cd692 | 1080 | UA_MANDATORY)); |
e662e14d | 1081 | |
6c61d2a5 | 1082 | DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, |
9a119cd5 JG |
1083 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER), |
1084 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR), | |
1085 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_EQN)); | |
8aa8c95c | 1086 | |
6c61d2a5 | 1087 | DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, |
9a119cd5 JG |
1088 | UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup), |
1089 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_CREATE), | |
1090 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY), | |
1091 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_MODIFY), | |
1092 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY)); | |
7efce369 | 1093 | |
6c61d2a5 | 1094 | DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM, |
9a119cd5 JG |
1095 | UVERBS_TYPE_ALLOC_IDR(devx_umem_cleanup), |
1096 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_REG), | |
1097 | &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG)); | |
aeae9457 | 1098 | |
6c61d2a5 | 1099 | DECLARE_UVERBS_OBJECT_TREE(devx_objects, |
9a119cd5 JG |
1100 | &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX), |
1101 | &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ), | |
1102 | &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM)); | |
c59450c4 YH |
1103 | |
1104 | const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void) | |
1105 | { | |
1106 | return &devx_objects; | |
1107 | } |