1 /*
2 * Copyright (c) 2012 Mellanox Technologies, Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32 #define _GNU_SOURCE
33 #include <config.h>
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <sys/mman.h>
40 #include <pthread.h>
41 #include <string.h>
42 #include <sched.h>
43 #include <sys/param.h>
44 #include <sys/cpuset.h>
45
46 #include "mlx5.h"
47 #include "mlx5-abi.h"
48
49 #ifndef PCI_VENDOR_ID_MELLANOX
50 #define PCI_VENDOR_ID_MELLANOX 0x15b3
51 #endif
52
53 #ifndef CPU_OR
54 #define CPU_OR(x, y, z) do {} while (0)
55 #endif
56
57 #ifndef CPU_EQUAL
58 #define CPU_EQUAL(x, y) 1
59 #endif
60
61
62 #define HCA(v, d) \
63 { .vendor = PCI_VENDOR_ID_##v, \
64 .device = d }
65
66 static struct {
67 unsigned vendor;
68 unsigned device;
69 } hca_table[] = {
70 /*
71 * PCI IDs must match mlx5_core_pci_table in
72 * sys/dev/mlx5/mlx5_core/mlx5_main.c so userspace loads for every
73 * mlx5 device the kernel probes.
74 */
75 HCA(MELLANOX, 4113), /* MT4113 Connect-IB */
76 HCA(MELLANOX, 4114), /* Connect-IB Virtual Function */
77 HCA(MELLANOX, 4115), /* ConnectX-4 */
78 HCA(MELLANOX, 4116), /* ConnectX-4 Virtual Function */
79 HCA(MELLANOX, 4117), /* ConnectX-4LX */
80 HCA(MELLANOX, 4118), /* ConnectX-4LX Virtual Function */
81 HCA(MELLANOX, 4119), /* ConnectX-5, PCIe 3.0 */
82 HCA(MELLANOX, 4120), /* ConnectX-5 Virtual Function */
83 HCA(MELLANOX, 4121), /* ConnectX-5 Ex */
84 HCA(MELLANOX, 4122), /* ConnectX-5 Ex VF */
85 HCA(MELLANOX, 4123), /* ConnectX-6 */
86 HCA(MELLANOX, 4124), /* ConnectX-6 VF */
87 HCA(MELLANOX, 4125), /* ConnectX-6 DX */
88 HCA(MELLANOX, 4126), /* ConnectX family mlx5Gen Virtual Function */
89 HCA(MELLANOX, 4127), /* ConnectX-6 LX */
90 HCA(MELLANOX, 4128),
91 HCA(MELLANOX, 4129), /* ConnectX-7 */
92 HCA(MELLANOX, 4130),
93 HCA(MELLANOX, 4131), /* ConnectX-8 */
94 HCA(MELLANOX, 4132),
95 HCA(MELLANOX, 4133), /* ConnectX-9 */
96 HCA(MELLANOX, 4134),
97 HCA(MELLANOX, 4135),
98 HCA(MELLANOX, 4136),
99 HCA(MELLANOX, 4137),
100 HCA(MELLANOX, 4138),
101 HCA(MELLANOX, 4139),
102 HCA(MELLANOX, 4140),
103 HCA(MELLANOX, 4141),
104 HCA(MELLANOX, 4142),
105 HCA(MELLANOX, 4143),
106 HCA(MELLANOX, 4144),
107 HCA(MELLANOX, 41682), /* BlueField integrated ConnectX-5 network controller */
108 HCA(MELLANOX, 41683), /* BlueField integrated ConnectX-5 network controller VF */
109 HCA(MELLANOX, 41686), /* BlueField-2 integrated ConnectX-6 Dx network controller */
110 HCA(MELLANOX, 41692), /* BlueField-3 integrated ConnectX-7 network controller */
111 HCA(MELLANOX, 41695), /* BlueField-4 integrated ConnectX-8 network controller */
112 };
113
114 uint32_t mlx5_debug_mask = 0;
115 int mlx5_freeze_on_error_cqe;
116
117 static struct ibv_context_ops mlx5_ctx_ops = {
118 .query_device = mlx5_query_device,
119 .query_port = mlx5_query_port,
120 .alloc_pd = mlx5_alloc_pd,
121 .dealloc_pd = mlx5_free_pd,
122 .reg_mr = mlx5_reg_mr,
123 .rereg_mr = mlx5_rereg_mr,
124 .dereg_mr = mlx5_dereg_mr,
125 .alloc_mw = mlx5_alloc_mw,
126 .dealloc_mw = mlx5_dealloc_mw,
127 .bind_mw = mlx5_bind_mw,
128 .create_cq = mlx5_create_cq,
129 .poll_cq = mlx5_poll_cq,
130 .req_notify_cq = mlx5_arm_cq,
131 .cq_event = mlx5_cq_event,
132 .resize_cq = mlx5_resize_cq,
133 .destroy_cq = mlx5_destroy_cq,
134 .create_srq = mlx5_create_srq,
135 .modify_srq = mlx5_modify_srq,
136 .query_srq = mlx5_query_srq,
137 .destroy_srq = mlx5_destroy_srq,
138 .post_srq_recv = mlx5_post_srq_recv,
139 .create_qp = mlx5_create_qp,
140 .query_qp = mlx5_query_qp,
141 .modify_qp = mlx5_modify_qp,
142 .destroy_qp = mlx5_destroy_qp,
143 .post_send = mlx5_post_send,
144 .post_recv = mlx5_post_recv,
145 .create_ah = mlx5_create_ah,
146 .destroy_ah = mlx5_destroy_ah,
147 .attach_mcast = mlx5_attach_mcast,
148 .detach_mcast = mlx5_detach_mcast
149 };
150
read_number_from_line(const char * line,int * value)151 static int read_number_from_line(const char *line, int *value)
152 {
153 const char *ptr;
154
155 ptr = strchr(line, ':');
156 if (!ptr)
157 return 1;
158
159 ++ptr;
160
161 *value = atoi(ptr);
162 return 0;
163 }
164 /**
165 * The function looks for the first free user-index in all the
166 * user-index tables. If all are used, returns -1, otherwise
167 * a valid user-index.
168 * In case the reference count of the table is zero, it means the
169 * table is not in use and wasn't allocated yet, therefore the
170 * mlx5_store_uidx allocates the table, and increment the reference
171 * count on the table.
172 */
get_free_uidx(struct mlx5_context * ctx)173 static int32_t get_free_uidx(struct mlx5_context *ctx)
174 {
175 int32_t tind;
176 int32_t i;
177
178 for (tind = 0; tind < MLX5_UIDX_TABLE_SIZE; tind++) {
179 if (ctx->uidx_table[tind].refcnt < MLX5_UIDX_TABLE_MASK)
180 break;
181 }
182
183 if (tind == MLX5_UIDX_TABLE_SIZE)
184 return -1;
185
186 if (!ctx->uidx_table[tind].refcnt)
187 return tind << MLX5_UIDX_TABLE_SHIFT;
188
189 for (i = 0; i < MLX5_UIDX_TABLE_MASK + 1; i++) {
190 if (!ctx->uidx_table[tind].table[i])
191 break;
192 }
193
194 return (tind << MLX5_UIDX_TABLE_SHIFT) | i;
195 }
196
mlx5_store_uidx(struct mlx5_context * ctx,void * rsc)197 int32_t mlx5_store_uidx(struct mlx5_context *ctx, void *rsc)
198 {
199 int32_t tind;
200 int32_t ret = -1;
201 int32_t uidx;
202
203 pthread_mutex_lock(&ctx->uidx_table_mutex);
204 uidx = get_free_uidx(ctx);
205 if (uidx < 0)
206 goto out;
207
208 tind = uidx >> MLX5_UIDX_TABLE_SHIFT;
209
210 if (!ctx->uidx_table[tind].refcnt) {
211 ctx->uidx_table[tind].table = calloc(MLX5_UIDX_TABLE_MASK + 1,
212 sizeof(struct mlx5_resource *));
213 if (!ctx->uidx_table[tind].table)
214 goto out;
215 }
216
217 ++ctx->uidx_table[tind].refcnt;
218 ctx->uidx_table[tind].table[uidx & MLX5_UIDX_TABLE_MASK] = rsc;
219 ret = uidx;
220
221 out:
222 pthread_mutex_unlock(&ctx->uidx_table_mutex);
223 return ret;
224 }
225
mlx5_clear_uidx(struct mlx5_context * ctx,uint32_t uidx)226 void mlx5_clear_uidx(struct mlx5_context *ctx, uint32_t uidx)
227 {
228 int tind = uidx >> MLX5_UIDX_TABLE_SHIFT;
229
230 pthread_mutex_lock(&ctx->uidx_table_mutex);
231
232 if (!--ctx->uidx_table[tind].refcnt)
233 free(ctx->uidx_table[tind].table);
234 else
235 ctx->uidx_table[tind].table[uidx & MLX5_UIDX_TABLE_MASK] = NULL;
236
237 pthread_mutex_unlock(&ctx->uidx_table_mutex);
238 }
239
mlx5_is_sandy_bridge(int * num_cores)240 static int mlx5_is_sandy_bridge(int *num_cores)
241 {
242 char line[128];
243 FILE *fd;
244 int rc = 0;
245 int cur_cpu_family = -1;
246 int cur_cpu_model = -1;
247
248 fd = fopen("/proc/cpuinfo", "r");
249 if (!fd)
250 return 0;
251
252 *num_cores = 0;
253
254 while (fgets(line, 128, fd)) {
255 int value;
256
257 /* if this is information on new processor */
258 if (!strncmp(line, "processor", 9)) {
259 ++*num_cores;
260
261 cur_cpu_family = -1;
262 cur_cpu_model = -1;
263 } else if (!strncmp(line, "cpu family", 10)) {
264 if ((cur_cpu_family < 0) && (!read_number_from_line(line, &value)))
265 cur_cpu_family = value;
266 } else if (!strncmp(line, "model", 5)) {
267 if ((cur_cpu_model < 0) && (!read_number_from_line(line, &value)))
268 cur_cpu_model = value;
269 }
270
271 /* if this is a Sandy Bridge CPU */
272 if ((cur_cpu_family == 6) &&
273 (cur_cpu_model == 0x2A || (cur_cpu_model == 0x2D) ))
274 rc = 1;
275 }
276
277 fclose(fd);
278 return rc;
279 }
280
281 /*
282 man cpuset
283
284 This format displays each 32-bit word in hexadecimal (using ASCII characters "0" - "9" and "a" - "f"); words
285 are filled with leading zeros, if required. For masks longer than one word, a comma separator is used between
286 words. Words are displayed in big-endian order, which has the most significant bit first. The hex digits
287 within a word are also in big-endian order.
288
289 The number of 32-bit words displayed is the minimum number needed to display all bits of the bitmask, based on
290 the size of the bitmask.
291
292 Examples of the Mask Format:
293
294 00000001 # just bit 0 set
295 40000000,00000000,00000000 # just bit 94 set
296 000000ff,00000000 # bits 32-39 set
297 00000000,000E3862 # 1,5,6,11-13,17-19 set
298
299 A mask with bits 0, 1, 2, 4, 8, 16, 32, and 64 set displays as:
300
301 00000001,00000001,00010117
302
303 The first "1" is for bit 64, the second for bit 32, the third for bit 16, the fourth for bit 8, the fifth for
304 bit 4, and the "7" is for bits 2, 1, and 0.
305 */
mlx5_local_cpu_set(struct ibv_device * ibdev,cpuset_t * cpu_set)306 static void mlx5_local_cpu_set(struct ibv_device *ibdev, cpuset_t *cpu_set)
307 {
308 char *p, buf[1024];
309 char *env_value;
310 uint32_t word;
311 int i, k;
312
313 env_value = getenv("MLX5_LOCAL_CPUS");
314 if (env_value)
315 strncpy(buf, env_value, sizeof(buf));
316 else {
317 char fname[MAXPATHLEN];
318
319 snprintf(fname, MAXPATHLEN, "/sys/class/infiniband/%s",
320 ibv_get_device_name(ibdev));
321
322 if (ibv_read_sysfs_file(fname, "device/local_cpus", buf, sizeof(buf))) {
323 fprintf(stderr, PFX "Warning: can not get local cpu set: failed to open %s\n", fname);
324 return;
325 }
326 }
327
328 p = strrchr(buf, ',');
329 if (!p)
330 p = buf;
331
332 i = 0;
333 do {
334 if (*p == ',') {
335 *p = 0;
336 p ++;
337 }
338
339 word = strtoul(p, NULL, 16);
340
341 for (k = 0; word; ++k, word >>= 1)
342 if (word & 1)
343 CPU_SET(k+i, cpu_set);
344
345 if (p == buf)
346 break;
347
348 p = strrchr(buf, ',');
349 if (!p)
350 p = buf;
351
352 i += 32;
353 } while (i < CPU_SETSIZE);
354 }
355
mlx5_enable_sandy_bridge_fix(struct ibv_device * ibdev)356 static int mlx5_enable_sandy_bridge_fix(struct ibv_device *ibdev)
357 {
358 cpuset_t my_cpus, dev_local_cpus, result_set;
359 int stall_enable;
360 int ret;
361 int num_cores;
362
363 if (!mlx5_is_sandy_bridge(&num_cores))
364 return 0;
365
366 /* by default enable stall on sandy bridge arch */
367 stall_enable = 1;
368
369 /*
370 * check if app is bound to cpu set that is inside
371 * of device local cpu set. Disable stalling if true
372 */
373
374 /* use static cpu set - up to CPU_SETSIZE (1024) cpus/node */
375 CPU_ZERO(&my_cpus);
376 CPU_ZERO(&dev_local_cpus);
377 CPU_ZERO(&result_set);
378 ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
379 sizeof(my_cpus), &my_cpus);
380 if (ret == -1) {
381 if (errno == EINVAL)
382 fprintf(stderr, PFX "Warning: my cpu set is too small\n");
383 else
384 fprintf(stderr, PFX "Warning: failed to get my cpu set\n");
385 goto out;
386 }
387
388 /* get device local cpu set */
389 mlx5_local_cpu_set(ibdev, &dev_local_cpus);
390
391 /* check if my cpu set is in dev cpu */
392 #if __FreeBSD_version < 1400046
393 CPU_OR(&result_set, &my_cpus);
394 CPU_OR(&result_set, &dev_local_cpus);
395 #else
396 CPU_OR(&result_set, &my_cpus, &dev_local_cpus);
397 #endif
398 stall_enable = CPU_EQUAL(&result_set, &dev_local_cpus) ? 0 : 1;
399
400 out:
401 return stall_enable;
402 }
403
mlx5_read_env(struct ibv_device * ibdev,struct mlx5_context * ctx)404 static void mlx5_read_env(struct ibv_device *ibdev, struct mlx5_context *ctx)
405 {
406 char *env_value;
407
408 env_value = getenv("MLX5_STALL_CQ_POLL");
409 if (env_value)
410 /* check if cq stall is enforced by user */
411 ctx->stall_enable = (strcmp(env_value, "0")) ? 1 : 0;
412 else
413 /* autodetect if we need to do cq polling */
414 ctx->stall_enable = mlx5_enable_sandy_bridge_fix(ibdev);
415
416 env_value = getenv("MLX5_STALL_NUM_LOOP");
417 if (env_value)
418 mlx5_stall_num_loop = atoi(env_value);
419
420 env_value = getenv("MLX5_STALL_CQ_POLL_MIN");
421 if (env_value)
422 mlx5_stall_cq_poll_min = atoi(env_value);
423
424 env_value = getenv("MLX5_STALL_CQ_POLL_MAX");
425 if (env_value)
426 mlx5_stall_cq_poll_max = atoi(env_value);
427
428 env_value = getenv("MLX5_STALL_CQ_INC_STEP");
429 if (env_value)
430 mlx5_stall_cq_inc_step = atoi(env_value);
431
432 env_value = getenv("MLX5_STALL_CQ_DEC_STEP");
433 if (env_value)
434 mlx5_stall_cq_dec_step = atoi(env_value);
435
436 ctx->stall_adaptive_enable = 0;
437 ctx->stall_cycles = 0;
438
439 if (mlx5_stall_num_loop < 0) {
440 ctx->stall_adaptive_enable = 1;
441 ctx->stall_cycles = mlx5_stall_cq_poll_min;
442 }
443
444 }
445
get_total_uuars(int page_size)446 static int get_total_uuars(int page_size)
447 {
448 int size = MLX5_DEF_TOT_UUARS;
449 int uuars_in_page;
450 char *env;
451
452 env = getenv("MLX5_TOTAL_UUARS");
453 if (env)
454 size = atoi(env);
455
456 if (size < 1)
457 return -EINVAL;
458
459 uuars_in_page = page_size / MLX5_ADAPTER_PAGE_SIZE * MLX5_NUM_NON_FP_BFREGS_PER_UAR;
460 size = max(uuars_in_page, size);
461 size = align(size, MLX5_NUM_NON_FP_BFREGS_PER_UAR);
462 if (size > MLX5_MAX_BFREGS)
463 return -ENOMEM;
464
465 return size;
466 }
467
open_debug_file(struct mlx5_context * ctx)468 static void open_debug_file(struct mlx5_context *ctx)
469 {
470 char *env;
471
472 env = getenv("MLX5_DEBUG_FILE");
473 if (!env) {
474 ctx->dbg_fp = stderr;
475 return;
476 }
477
478 ctx->dbg_fp = fopen(env, "aw+");
479 if (!ctx->dbg_fp) {
480 fprintf(stderr, "Failed opening debug file %s, using stderr\n", env);
481 ctx->dbg_fp = stderr;
482 return;
483 }
484 }
485
close_debug_file(struct mlx5_context * ctx)486 static void close_debug_file(struct mlx5_context *ctx)
487 {
488 if (ctx->dbg_fp && ctx->dbg_fp != stderr)
489 fclose(ctx->dbg_fp);
490 }
491
set_debug_mask(void)492 static void set_debug_mask(void)
493 {
494 char *env;
495
496 env = getenv("MLX5_DEBUG_MASK");
497 if (env)
498 mlx5_debug_mask = strtol(env, NULL, 0);
499 }
500
set_freeze_on_error(void)501 static void set_freeze_on_error(void)
502 {
503 char *env;
504
505 env = getenv("MLX5_FREEZE_ON_ERROR_CQE");
506 if (env)
507 mlx5_freeze_on_error_cqe = strtol(env, NULL, 0);
508 }
509
get_always_bf(void)510 static int get_always_bf(void)
511 {
512 char *env;
513
514 env = getenv("MLX5_POST_SEND_PREFER_BF");
515 if (!env)
516 return 1;
517
518 return strcmp(env, "0") ? 1 : 0;
519 }
520
get_shut_up_bf(void)521 static int get_shut_up_bf(void)
522 {
523 char *env;
524
525 env = getenv("MLX5_SHUT_UP_BF");
526 if (!env)
527 return 0;
528
529 return strcmp(env, "0") ? 1 : 0;
530 }
531
get_num_low_lat_uuars(int tot_uuars)532 static int get_num_low_lat_uuars(int tot_uuars)
533 {
534 char *env;
535 int num = 4;
536
537 env = getenv("MLX5_NUM_LOW_LAT_UUARS");
538 if (env)
539 num = atoi(env);
540
541 if (num < 0)
542 return -EINVAL;
543
544 num = max(num, tot_uuars - MLX5_MED_BFREGS_TSHOLD);
545 return num;
546 }
547
548 /* The library allocates an array of uuar contexts. The one in index zero does
549 * not to execersize odd/even policy so it can avoid a lock but it may not use
550 * blue flame. The upper ones, low_lat_uuars can use blue flame with no lock
551 * since they are assigned to one QP only. The rest can use blue flame but since
552 * they are shared they need a lock
553 */
need_uuar_lock(struct mlx5_context * ctx,int uuarn)554 static int need_uuar_lock(struct mlx5_context *ctx, int uuarn)
555 {
556 if (uuarn == 0 || mlx5_single_threaded)
557 return 0;
558
559 if (uuarn >= (ctx->tot_uuars - ctx->low_lat_uuars) * 2)
560 return 0;
561
562 return 1;
563 }
564
single_threaded_app(void)565 static int single_threaded_app(void)
566 {
567
568 char *env;
569
570 env = getenv("MLX5_SINGLE_THREADED");
571 if (env)
572 return strcmp(env, "1") ? 0 : 1;
573
574 return 0;
575 }
576
mlx5_cmd_get_context(struct mlx5_context * context,struct mlx5_alloc_ucontext * req,size_t req_len,struct mlx5_alloc_ucontext_resp * resp,size_t resp_len)577 static int mlx5_cmd_get_context(struct mlx5_context *context,
578 struct mlx5_alloc_ucontext *req,
579 size_t req_len,
580 struct mlx5_alloc_ucontext_resp *resp,
581 size_t resp_len)
582 {
583 if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
584 req_len, &resp->ibv_resp, resp_len))
585 return 0;
586
587 /* The ibv_cmd_get_context fails in older kernels when passing
588 * a request length that the kernel doesn't know.
589 * To avoid breaking compatibility of new libmlx5 and older
590 * kernels, when ibv_cmd_get_context fails with the full
591 * request length, we try once again with the legacy length.
592 * We repeat this process while reducing requested size based
593 * on the feature input size. To avoid this in the future, we
594 * will remove the check in kernel that requires fields unknown
595 * to the kernel to be cleared. This will require that any new
596 * feature that involves extending struct mlx5_alloc_ucontext
597 * will be accompanied by an indication in the form of one or
598 * more fields in struct mlx5_alloc_ucontext_resp. If the
599 * response value can be interpreted as feature not supported
600 * when the returned value is zero, this will suffice to
601 * indicate to the library that the request was ignored by the
602 * kernel, either because it is unaware or because it decided
603 * to do so. If zero is a valid response, we will add a new
604 * field that indicates whether the request was handled.
605 */
606 if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
607 offsetof(struct mlx5_alloc_ucontext, lib_caps),
608 &resp->ibv_resp, resp_len))
609 return 0;
610
611 return ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
612 offsetof(struct mlx5_alloc_ucontext,
613 cqe_version),
614 &resp->ibv_resp, resp_len);
615 }
616
mlx5_map_internal_clock(struct mlx5_device * mdev,struct ibv_context * ibv_ctx)617 static int mlx5_map_internal_clock(struct mlx5_device *mdev,
618 struct ibv_context *ibv_ctx)
619 {
620 struct mlx5_context *context = to_mctx(ibv_ctx);
621 void *hca_clock_page;
622 off_t offset = 0;
623
624 set_command(MLX5_MMAP_GET_CORE_CLOCK_CMD, &offset);
625 hca_clock_page = mmap(NULL, mdev->page_size,
626 PROT_READ, MAP_SHARED, ibv_ctx->cmd_fd,
627 mdev->page_size * offset);
628
629 if (hca_clock_page == MAP_FAILED) {
630 fprintf(stderr, PFX
631 "Warning: Timestamp available,\n"
632 "but failed to mmap() hca core clock page.\n");
633 return -1;
634 }
635
636 context->hca_core_clock = hca_clock_page +
637 (context->core_clock.offset & (mdev->page_size - 1));
638 return 0;
639 }
640
mlx5dv_query_device(struct ibv_context * ctx_in,struct mlx5dv_context * attrs_out)641 int mlx5dv_query_device(struct ibv_context *ctx_in,
642 struct mlx5dv_context *attrs_out)
643 {
644 struct mlx5_context *mctx = to_mctx(ctx_in);
645 uint64_t comp_mask_out = 0;
646
647 attrs_out->version = 0;
648 attrs_out->flags = 0;
649
650 if (mctx->cqe_version == MLX5_CQE_VERSION_V1)
651 attrs_out->flags |= MLX5DV_CONTEXT_FLAGS_CQE_V1;
652
653 if (mctx->vendor_cap_flags & MLX5_VENDOR_CAP_FLAGS_MPW_ALLOWED)
654 attrs_out->flags |= MLX5DV_CONTEXT_FLAGS_MPW_ALLOWED;
655
656 if (attrs_out->comp_mask & MLX5DV_CONTEXT_MASK_CQE_COMPRESION) {
657 attrs_out->cqe_comp_caps = mctx->cqe_comp_caps;
658 comp_mask_out |= MLX5DV_CONTEXT_MASK_CQE_COMPRESION;
659 }
660
661 if (mctx->vendor_cap_flags & MLX5_VENDOR_CAP_FLAGS_ENHANCED_MPW)
662 attrs_out->flags |= MLX5DV_CONTEXT_FLAGS_ENHANCED_MPW;
663
664 if (attrs_out->comp_mask & MLX5DV_CONTEXT_MASK_SWP) {
665 attrs_out->sw_parsing_caps = mctx->sw_parsing_caps;
666 comp_mask_out |= MLX5DV_CONTEXT_MASK_SWP;
667 }
668
669 if (attrs_out->comp_mask & MLX5DV_CONTEXT_MASK_STRIDING_RQ) {
670 attrs_out->striding_rq_caps = mctx->striding_rq_caps;
671 comp_mask_out |= MLX5DV_CONTEXT_MASK_STRIDING_RQ;
672 }
673
674 if (attrs_out->comp_mask & MLX5DV_CONTEXT_MASK_TUNNEL_OFFLOADS) {
675 attrs_out->tunnel_offloads_caps = mctx->tunnel_offloads_caps;
676 comp_mask_out |= MLX5DV_CONTEXT_MASK_TUNNEL_OFFLOADS;
677 }
678
679 attrs_out->comp_mask = comp_mask_out;
680
681 return 0;
682 }
683
mlx5dv_get_qp(struct ibv_qp * qp_in,struct mlx5dv_qp * qp_out)684 static int mlx5dv_get_qp(struct ibv_qp *qp_in,
685 struct mlx5dv_qp *qp_out)
686 {
687 struct mlx5_qp *mqp = to_mqp(qp_in);
688 uint64_t mask_out = 0;
689
690 qp_out->dbrec = mqp->db;
691
692 if (mqp->sq_buf_size)
693 /* IBV_QPT_RAW_PACKET */
694 qp_out->sq.buf = (void *)((uintptr_t)mqp->sq_buf.buf);
695 else
696 qp_out->sq.buf = (void *)((uintptr_t)mqp->buf.buf + mqp->sq.offset);
697 qp_out->sq.wqe_cnt = mqp->sq.wqe_cnt;
698 qp_out->sq.stride = 1 << mqp->sq.wqe_shift;
699
700 qp_out->rq.buf = (void *)((uintptr_t)mqp->buf.buf + mqp->rq.offset);
701 qp_out->rq.wqe_cnt = mqp->rq.wqe_cnt;
702 qp_out->rq.stride = 1 << mqp->rq.wqe_shift;
703
704 qp_out->bf.reg = mqp->bf->reg;
705
706 if (qp_out->comp_mask & MLX5DV_QP_MASK_UAR_MMAP_OFFSET) {
707 qp_out->uar_mmap_offset = mqp->bf->uar_mmap_offset;
708 mask_out |= MLX5DV_QP_MASK_UAR_MMAP_OFFSET;
709 }
710
711 if (mqp->bf->uuarn > 0)
712 qp_out->bf.size = mqp->bf->buf_size;
713 else
714 qp_out->bf.size = 0;
715
716 qp_out->comp_mask = mask_out;
717
718 return 0;
719 }
720
mlx5dv_get_cq(struct ibv_cq * cq_in,struct mlx5dv_cq * cq_out)721 static int mlx5dv_get_cq(struct ibv_cq *cq_in,
722 struct mlx5dv_cq *cq_out)
723 {
724 struct mlx5_cq *mcq = to_mcq(cq_in);
725 struct mlx5_context *mctx = to_mctx(cq_in->context);
726
727 cq_out->comp_mask = 0;
728 cq_out->cqn = mcq->cqn;
729 cq_out->cqe_cnt = mcq->ibv_cq.cqe + 1;
730 cq_out->cqe_size = mcq->cqe_sz;
731 cq_out->buf = mcq->active_buf->buf;
732 cq_out->dbrec = mcq->dbrec;
733 cq_out->cq_uar = mctx->uar[0];
734
735 mcq->flags |= MLX5_CQ_FLAGS_DV_OWNED;
736
737 return 0;
738 }
739
mlx5dv_get_rwq(struct ibv_wq * wq_in,struct mlx5dv_rwq * rwq_out)740 static int mlx5dv_get_rwq(struct ibv_wq *wq_in,
741 struct mlx5dv_rwq *rwq_out)
742 {
743 struct mlx5_rwq *mrwq = to_mrwq(wq_in);
744
745 rwq_out->comp_mask = 0;
746 rwq_out->buf = mrwq->pbuff;
747 rwq_out->dbrec = mrwq->recv_db;
748 rwq_out->wqe_cnt = mrwq->rq.wqe_cnt;
749 rwq_out->stride = 1 << mrwq->rq.wqe_shift;
750
751 return 0;
752 }
753
mlx5dv_get_srq(struct ibv_srq * srq_in,struct mlx5dv_srq * srq_out)754 static int mlx5dv_get_srq(struct ibv_srq *srq_in,
755 struct mlx5dv_srq *srq_out)
756 {
757 struct mlx5_srq *msrq;
758
759 msrq = container_of(srq_in, struct mlx5_srq, vsrq.srq);
760
761 srq_out->comp_mask = 0;
762 srq_out->buf = msrq->buf.buf;
763 srq_out->dbrec = msrq->db;
764 srq_out->stride = 1 << msrq->wqe_shift;
765 srq_out->head = msrq->head;
766 srq_out->tail = msrq->tail;
767
768 return 0;
769 }
770
_mlx5dv_init_obj(struct mlx5dv_obj * obj,uint64_t obj_type)771 static int _mlx5dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type)
772 {
773 int ret = 0;
774
775 if (obj_type & MLX5DV_OBJ_QP)
776 ret = mlx5dv_get_qp(obj->qp.in, obj->qp.out);
777 if (!ret && (obj_type & MLX5DV_OBJ_CQ))
778 ret = mlx5dv_get_cq(obj->cq.in, obj->cq.out);
779 if (!ret && (obj_type & MLX5DV_OBJ_SRQ))
780 ret = mlx5dv_get_srq(obj->srq.in, obj->srq.out);
781 if (!ret && (obj_type & MLX5DV_OBJ_RWQ))
782 ret = mlx5dv_get_rwq(obj->rwq.in, obj->rwq.out);
783
784 return ret;
785 }
786
787 /*
788 * mlx5dv_init_obj is exported with two ABI versions so that binaries linked
789 * against the historical symbol keep working after the mlx5dv_cq UAR field was
790 * revised. The current implementation (MLX5_1.2) leaves mlx5dv_cq.cq_uar set
791 * to the CQ's UAR register (a 'void *'). The MLX5_1.0 compat wrapper restores
792 * the historical 'void **' value at that location.
793 */
794 int mlx5dv_init_obj_1_2(struct mlx5dv_obj *obj, uint64_t obj_type);
795 int mlx5dv_init_obj_1_0(struct mlx5dv_obj *obj, uint64_t obj_type);
796
mlx5dv_init_obj_1_2(struct mlx5dv_obj * obj,uint64_t obj_type)797 int mlx5dv_init_obj_1_2(struct mlx5dv_obj *obj, uint64_t obj_type)
798 {
799 return _mlx5dv_init_obj(obj, obj_type);
800 }
801
mlx5dv_init_obj_1_0(struct mlx5dv_obj * obj,uint64_t obj_type)802 int mlx5dv_init_obj_1_0(struct mlx5dv_obj *obj, uint64_t obj_type)
803 {
804 int ret;
805
806 ret = _mlx5dv_init_obj(obj, obj_type);
807 if (!ret && (obj_type & MLX5DV_OBJ_CQ)) {
808 /* ABI version 1.0 returns the 'void **' at this location. */
809 obj->cq.out->cq_uar = to_mctx(obj->cq.in->context)->uar;
810 }
811 return ret;
812 }
813
814 __asm__(".symver mlx5dv_init_obj_1_2, mlx5dv_init_obj@@MLX5_1.2");
815 __asm__(".symver mlx5dv_init_obj_1_0, mlx5dv_init_obj@MLX5_1.0");
816
mlx5dv_set_context_attr(struct ibv_context * ibv_ctx,enum mlx5dv_set_ctx_attr_type type,void * attr)817 int mlx5dv_set_context_attr(struct ibv_context *ibv_ctx,
818 enum mlx5dv_set_ctx_attr_type type, void *attr)
819 {
820 struct mlx5_context *ctx = to_mctx(ibv_ctx);
821
822 switch (type) {
823 case MLX5DV_CTX_ATTR_BUF_ALLOCATORS:
824 ctx->extern_alloc = *((struct mlx5dv_ctx_allocators *)attr);
825 break;
826 default:
827 return ENOTSUP;
828 }
829
830 return 0;
831 }
832
adjust_uar_info(struct mlx5_device * mdev,struct mlx5_context * context,struct mlx5_alloc_ucontext_resp resp)833 static void adjust_uar_info(struct mlx5_device *mdev,
834 struct mlx5_context *context,
835 struct mlx5_alloc_ucontext_resp resp)
836 {
837 if (!resp.log_uar_size && !resp.num_uars_per_page) {
838 /* old kernel */
839 context->uar_size = mdev->page_size;
840 context->num_uars_per_page = 1;
841 return;
842 }
843
844 context->uar_size = 1 << resp.log_uar_size;
845 context->num_uars_per_page = resp.num_uars_per_page;
846 }
847
get_uar_mmap_offset(int idx,int page_size)848 static off_t get_uar_mmap_offset(int idx, int page_size)
849 {
850 off_t offset = 0;
851
852 set_command(MLX5_MMAP_GET_REGULAR_PAGES_CMD, &offset);
853 set_index(idx, &offset);
854 return offset * page_size;
855 }
856
mlx5_init_context(struct verbs_device * vdev,struct ibv_context * ctx,int cmd_fd)857 static int mlx5_init_context(struct verbs_device *vdev,
858 struct ibv_context *ctx, int cmd_fd)
859 {
860 struct mlx5_context *context;
861 struct mlx5_alloc_ucontext req;
862 struct mlx5_alloc_ucontext_resp resp;
863 int i;
864 int page_size;
865 int tot_uuars;
866 int low_lat_uuars;
867 int gross_uuars;
868 int j;
869 off_t offset;
870 struct mlx5_device *mdev;
871 struct verbs_context *v_ctx;
872 struct ibv_port_attr port_attr;
873 struct ibv_device_attr_ex device_attr;
874 int k;
875 int bfi;
876 int num_sys_page_map;
877
878 mdev = to_mdev(&vdev->device);
879 v_ctx = verbs_get_ctx(ctx);
880 page_size = mdev->page_size;
881 mlx5_single_threaded = single_threaded_app();
882
883 context = to_mctx(ctx);
884 context->ibv_ctx.cmd_fd = cmd_fd;
885
886 open_debug_file(context);
887 set_debug_mask();
888 set_freeze_on_error();
889 if (gethostname(context->hostname, sizeof(context->hostname)))
890 strcpy(context->hostname, "host_unknown");
891
892 tot_uuars = get_total_uuars(page_size);
893 if (tot_uuars < 0) {
894 errno = -tot_uuars;
895 goto err_free;
896 }
897
898 low_lat_uuars = get_num_low_lat_uuars(tot_uuars);
899 if (low_lat_uuars < 0) {
900 errno = -low_lat_uuars;
901 goto err_free;
902 }
903
904 if (low_lat_uuars > tot_uuars - 1) {
905 errno = ENOMEM;
906 goto err_free;
907 }
908
909 memset(&req, 0, sizeof(req));
910 memset(&resp, 0, sizeof(resp));
911
912 req.total_num_uuars = tot_uuars;
913 req.num_low_latency_uuars = low_lat_uuars;
914 req.cqe_version = MLX5_CQE_VERSION_V1;
915 req.lib_caps |= MLX5_LIB_CAP_4K_UAR;
916
917 if (mlx5_cmd_get_context(context, &req, sizeof(req), &resp,
918 sizeof(resp)))
919 goto err_free;
920
921 context->max_num_qps = resp.qp_tab_size;
922 context->bf_reg_size = resp.bf_reg_size;
923 context->tot_uuars = resp.tot_uuars;
924 context->low_lat_uuars = low_lat_uuars;
925 context->cache_line_size = resp.cache_line_size;
926 context->max_sq_desc_sz = resp.max_sq_desc_sz;
927 context->max_rq_desc_sz = resp.max_rq_desc_sz;
928 context->max_send_wqebb = resp.max_send_wqebb;
929 context->num_ports = resp.num_ports;
930 context->max_recv_wr = resp.max_recv_wr;
931 context->max_srq_recv_wr = resp.max_srq_recv_wr;
932
933 context->cqe_version = resp.cqe_version;
934 if (context->cqe_version) {
935 if (context->cqe_version == MLX5_CQE_VERSION_V1)
936 mlx5_ctx_ops.poll_cq = mlx5_poll_cq_v1;
937 else
938 goto err_free;
939 }
940
941 adjust_uar_info(mdev, context, resp);
942
943 gross_uuars = context->tot_uuars / MLX5_NUM_NON_FP_BFREGS_PER_UAR * NUM_BFREGS_PER_UAR;
944 context->bfs = calloc(gross_uuars, sizeof(*context->bfs));
945 if (!context->bfs) {
946 errno = ENOMEM;
947 goto err_free;
948 }
949
950 context->cmds_supp_uhw = resp.cmds_supp_uhw;
951 context->vendor_cap_flags = 0;
952
953 if (pthread_mutex_init(&context->qp_table_mutex, NULL))
954 goto err_free_bf;
955 if (pthread_mutex_init(&context->srq_table_mutex, NULL))
956 goto err_qp_table_mutex;
957 if (pthread_mutex_init(&context->uidx_table_mutex, NULL))
958 goto err_srq_table_mutex;
959 for (i = 0; i < MLX5_QP_TABLE_SIZE; ++i)
960 context->qp_table[i].refcnt = 0;
961
962 for (i = 0; i < MLX5_QP_TABLE_SIZE; ++i)
963 context->uidx_table[i].refcnt = 0;
964
965 context->db_list = NULL;
966
967 if (pthread_mutex_init(&context->db_list_mutex, NULL))
968 goto err_uidx_table_mutex;
969
970 num_sys_page_map = context->tot_uuars / (context->num_uars_per_page * MLX5_NUM_NON_FP_BFREGS_PER_UAR);
971 for (i = 0; i < num_sys_page_map; ++i) {
972 offset = get_uar_mmap_offset(i, page_size);
973 context->uar[i] = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED,
974 cmd_fd, offset);
975 if (context->uar[i] == MAP_FAILED) {
976 context->uar[i] = NULL;
977 goto err_db_list_mutex;
978 }
979 }
980
981 for (i = 0; i < num_sys_page_map; i++) {
982 for (j = 0; j < context->num_uars_per_page; j++) {
983 for (k = 0; k < NUM_BFREGS_PER_UAR; k++) {
984 bfi = (i * context->num_uars_per_page + j) * NUM_BFREGS_PER_UAR + k;
985 context->bfs[bfi].reg = context->uar[i] + MLX5_ADAPTER_PAGE_SIZE * j +
986 MLX5_BF_OFFSET + k * context->bf_reg_size;
987 context->bfs[bfi].need_lock = need_uuar_lock(context, bfi);
988 if (mlx5_spinlock_init(&context->bfs[bfi].lock))
989 goto err_bfs_spl;
990 context->bfs[bfi].offset = 0;
991 if (bfi)
992 context->bfs[bfi].buf_size = context->bf_reg_size / 2;
993 context->bfs[bfi].uuarn = bfi;
994 context->bfs[bfi].uar_mmap_offset = get_uar_mmap_offset(i, page_size);
995 }
996 }
997 }
998 context->hca_core_clock = NULL;
999 if (resp.response_length + sizeof(resp.ibv_resp) >=
1000 offsetof(struct mlx5_alloc_ucontext_resp, hca_core_clock_offset) +
1001 sizeof(resp.hca_core_clock_offset) &&
1002 resp.comp_mask & MLX5_IB_ALLOC_UCONTEXT_RESP_MASK_CORE_CLOCK_OFFSET) {
1003 context->core_clock.offset = resp.hca_core_clock_offset;
1004 mlx5_map_internal_clock(mdev, ctx);
1005 }
1006
1007 if (mlx5_spinlock_init(&context->lock32))
1008 goto err_bfs_spl;
1009
1010 context->prefer_bf = get_always_bf();
1011 context->shut_up_bf = get_shut_up_bf();
1012 mlx5_read_env(&vdev->device, context);
1013
1014 if (mlx5_spinlock_init(&context->hugetlb_lock))
1015 goto err_32_spl;
1016 TAILQ_INIT(&context->hugetlb_list);
1017
1018 context->ibv_ctx.ops = mlx5_ctx_ops;
1019
1020 verbs_set_ctx_op(v_ctx, create_qp_ex, mlx5_create_qp_ex);
1021 verbs_set_ctx_op(v_ctx, open_xrcd, mlx5_open_xrcd);
1022 verbs_set_ctx_op(v_ctx, close_xrcd, mlx5_close_xrcd);
1023 verbs_set_ctx_op(v_ctx, create_srq_ex, mlx5_create_srq_ex);
1024 verbs_set_ctx_op(v_ctx, get_srq_num, mlx5_get_srq_num);
1025 verbs_set_ctx_op(v_ctx, query_device_ex, mlx5_query_device_ex);
1026 verbs_set_ctx_op(v_ctx, query_rt_values, mlx5_query_rt_values);
1027 verbs_set_ctx_op(v_ctx, ibv_create_flow, ibv_cmd_create_flow);
1028 verbs_set_ctx_op(v_ctx, ibv_destroy_flow, ibv_cmd_destroy_flow);
1029 verbs_set_ctx_op(v_ctx, create_cq_ex, mlx5_create_cq_ex);
1030 verbs_set_ctx_op(v_ctx, create_wq, mlx5_create_wq);
1031 verbs_set_ctx_op(v_ctx, modify_wq, mlx5_modify_wq);
1032 verbs_set_ctx_op(v_ctx, destroy_wq, mlx5_destroy_wq);
1033 verbs_set_ctx_op(v_ctx, create_rwq_ind_table, mlx5_create_rwq_ind_table);
1034 verbs_set_ctx_op(v_ctx, destroy_rwq_ind_table, mlx5_destroy_rwq_ind_table);
1035
1036 memset(&device_attr, 0, sizeof(device_attr));
1037 if (!mlx5_query_device_ex(ctx, NULL, &device_attr,
1038 sizeof(struct ibv_device_attr_ex))) {
1039 context->cached_device_cap_flags =
1040 device_attr.orig_attr.device_cap_flags;
1041 context->atomic_cap = device_attr.orig_attr.atomic_cap;
1042 context->cached_tso_caps = device_attr.tso_caps;
1043 }
1044
1045 for (j = 0; j < min(MLX5_MAX_PORTS_NUM, context->num_ports); ++j) {
1046 memset(&port_attr, 0, sizeof(port_attr));
1047 if (!mlx5_query_port(ctx, j + 1, &port_attr))
1048 context->cached_link_layer[j] = port_attr.link_layer;
1049 }
1050
1051 return 0;
1052
1053 err_32_spl:
1054 mlx5_spinlock_destroy(&context->lock32);
1055
1056 err_bfs_spl:
1057 for (i = 0; i < num_sys_page_map; i++) {
1058 for (j = 0; j < context->num_uars_per_page; j++) {
1059 for (k = 0; k < NUM_BFREGS_PER_UAR; k++) {
1060 bfi = (i * context->num_uars_per_page + j) * NUM_BFREGS_PER_UAR + k;
1061 mlx5_spinlock_destroy(&context->bfs[bfi].lock);
1062 }
1063 }
1064 }
1065
1066 err_db_list_mutex:
1067 pthread_mutex_destroy(&context->db_list_mutex);
1068
1069 err_uidx_table_mutex:
1070 pthread_mutex_destroy(&context->uidx_table_mutex);
1071
1072 err_srq_table_mutex:
1073 pthread_mutex_destroy(&context->srq_table_mutex);
1074
1075 err_qp_table_mutex:
1076 pthread_mutex_destroy(&context->qp_table_mutex);
1077
1078 err_free_bf:
1079 free(context->bfs);
1080
1081 err_free:
1082 for (i = 0; i < MLX5_MAX_UARS; ++i) {
1083 if (context->uar[i])
1084 munmap(context->uar[i], page_size);
1085 }
1086 close_debug_file(context);
1087 return errno;
1088 }
1089
mlx5_cleanup_context(struct verbs_device * device,struct ibv_context * ibctx)1090 static void mlx5_cleanup_context(struct verbs_device *device,
1091 struct ibv_context *ibctx)
1092 {
1093 struct mlx5_context *context = to_mctx(ibctx);
1094 int page_size = to_mdev(ibctx->device)->page_size;
1095 int i;
1096 int j;
1097 int k;
1098 int bfi;
1099 int num_sys_page_map;
1100
1101 num_sys_page_map = context->tot_uuars / (context->num_uars_per_page * MLX5_NUM_NON_FP_BFREGS_PER_UAR);
1102 for (i = 0; i < num_sys_page_map; i++) {
1103 for (j = 0; j < context->num_uars_per_page; j++) {
1104 for (k = 0; k < NUM_BFREGS_PER_UAR; k++) {
1105 bfi = (i * context->num_uars_per_page + j) * NUM_BFREGS_PER_UAR + k;
1106 mlx5_spinlock_destroy(&context->bfs[bfi].lock);
1107 }
1108 }
1109 }
1110 mlx5_spinlock_destroy(&context->hugetlb_lock);
1111 mlx5_spinlock_destroy(&context->lock32);
1112 pthread_mutex_destroy(&context->db_list_mutex);
1113 pthread_mutex_destroy(&context->uidx_table_mutex);
1114 pthread_mutex_destroy(&context->srq_table_mutex);
1115 pthread_mutex_destroy(&context->qp_table_mutex);
1116
1117 free(context->bfs);
1118 for (i = 0; i < MLX5_MAX_UARS; ++i) {
1119 if (context->uar[i])
1120 munmap(context->uar[i], page_size);
1121 }
1122 if (context->hca_core_clock)
1123 munmap(context->hca_core_clock - context->core_clock.offset,
1124 page_size);
1125 close_debug_file(context);
1126 }
1127
1128 static struct verbs_device_ops mlx5_dev_ops = {
1129 .init_context = mlx5_init_context,
1130 .uninit_context = mlx5_cleanup_context,
1131 };
1132
mlx5_driver_init(const char * uverbs_sys_path,int abi_version)1133 static struct verbs_device *mlx5_driver_init(const char *uverbs_sys_path,
1134 int abi_version)
1135 {
1136 char value[8];
1137 struct mlx5_device *dev;
1138 unsigned vendor, device;
1139 int i;
1140
1141 if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor",
1142 value, sizeof value) < 0)
1143 return NULL;
1144 sscanf(value, "%i", &vendor);
1145
1146 if (ibv_read_sysfs_file(uverbs_sys_path, "device/device",
1147 value, sizeof value) < 0)
1148 return NULL;
1149 sscanf(value, "%i", &device);
1150
1151 for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i)
1152 if (vendor == hca_table[i].vendor &&
1153 device == hca_table[i].device)
1154 goto found;
1155
1156 return NULL;
1157
1158 found:
1159 if (abi_version < MLX5_UVERBS_MIN_ABI_VERSION ||
1160 abi_version > MLX5_UVERBS_MAX_ABI_VERSION) {
1161 fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported "
1162 "(min supported %d, max supported %d)\n",
1163 abi_version, uverbs_sys_path,
1164 MLX5_UVERBS_MIN_ABI_VERSION,
1165 MLX5_UVERBS_MAX_ABI_VERSION);
1166 return NULL;
1167 }
1168
1169 dev = calloc(1, sizeof *dev);
1170 if (!dev) {
1171 fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n",
1172 uverbs_sys_path);
1173 return NULL;
1174 }
1175
1176 dev->page_size = sysconf(_SC_PAGESIZE);
1177 dev->driver_abi_ver = abi_version;
1178
1179 dev->verbs_dev.ops = &mlx5_dev_ops;
1180 dev->verbs_dev.sz = sizeof(*dev);
1181 dev->verbs_dev.size_of_context = sizeof(struct mlx5_context) -
1182 sizeof(struct ibv_context);
1183
1184 return &dev->verbs_dev;
1185 }
1186
mlx5_register_driver(void)1187 static __attribute__((constructor)) void mlx5_register_driver(void)
1188 {
1189 verbs_register_driver("mlx5", mlx5_driver_init);
1190 }
1191