xref: /freebsd/contrib/ofed/libmlx5/mlx5.c (revision 4b32c67bbfdbbd8ae557f18324a7c115668ca01a)
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