xref: /dpdk/drivers/common/mlx5/mlx5_common.c (revision 9ad3a41ab2a10db0059e1decdbf3ec038f348e08)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2019 Mellanox Technologies, Ltd
3  */
4 
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdio.h>
8 
9 #include <rte_errno.h>
10 #include <rte_mempool.h>
11 #include <rte_class.h>
12 #include <rte_malloc.h>
13 #include <rte_eal_paging.h>
14 
15 #include "mlx5_common.h"
16 #include "mlx5_common_os.h"
17 #include "mlx5_common_mp.h"
18 #include "mlx5_common_log.h"
19 #include "mlx5_common_defs.h"
20 #include "mlx5_common_private.h"
21 
22 uint8_t haswell_broadwell_cpu;
23 
24 /* Driver type key for new device global syntax. */
25 #define MLX5_DRIVER_KEY "driver"
26 
27 /* Enable extending memsegs when creating a MR. */
28 #define MLX5_MR_EXT_MEMSEG_EN "mr_ext_memseg_en"
29 
30 /* Device parameter to configure implicit registration of mempool memory. */
31 #define MLX5_MR_MEMPOOL_REG_EN "mr_mempool_reg_en"
32 
33 /* The default memory allocator used in PMD. */
34 #define MLX5_SYS_MEM_EN "sys_mem_en"
35 
36 /*
37  * Device parameter to force doorbell register mapping
38  * to non-cached region eliminating the extra write memory barrier.
39  * Deprecated, ignored (Name changed to sq_db_nc).
40  */
41 #define MLX5_TX_DB_NC "tx_db_nc"
42 
43 /*
44  * Device parameter to force doorbell register mapping
45  * to non-cached region eliminating the extra write memory barrier.
46  */
47 #define MLX5_SQ_DB_NC "sq_db_nc"
48 
49 /* In case this is an x86_64 intel processor to check if
50  * we should use relaxed ordering.
51  */
52 #ifdef RTE_ARCH_X86_64
53 /**
54  * This function returns processor identification and feature information
55  * into the registers.
56  *
57  * @param eax, ebx, ecx, edx
58  *		Pointers to the registers that will hold cpu information.
59  * @param level
60  *		The main category of information returned.
61  */
62 static inline void mlx5_cpu_id(unsigned int level,
63 				unsigned int *eax, unsigned int *ebx,
64 				unsigned int *ecx, unsigned int *edx)
65 {
66 	__asm__("cpuid\n\t"
67 		: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
68 		: "0" (level));
69 }
70 #endif
71 
72 RTE_LOG_REGISTER_DEFAULT(mlx5_common_logtype, NOTICE)
73 
74 /* Head of list of drivers. */
75 static TAILQ_HEAD(mlx5_drivers, mlx5_class_driver) drivers_list =
76 				TAILQ_HEAD_INITIALIZER(drivers_list);
77 
78 /* Head of devices. */
79 static TAILQ_HEAD(mlx5_devices, mlx5_common_device) devices_list =
80 				TAILQ_HEAD_INITIALIZER(devices_list);
81 static pthread_mutex_t devices_list_lock;
82 
83 static const struct {
84 	const char *name;
85 	unsigned int drv_class;
86 } mlx5_classes[] = {
87 	{ .name = "vdpa", .drv_class = MLX5_CLASS_VDPA },
88 	{ .name = "eth", .drv_class = MLX5_CLASS_ETH },
89 	/* Keep class "net" for backward compatibility. */
90 	{ .name = "net", .drv_class = MLX5_CLASS_ETH },
91 	{ .name = "regex", .drv_class = MLX5_CLASS_REGEX },
92 	{ .name = "compress", .drv_class = MLX5_CLASS_COMPRESS },
93 	{ .name = "crypto", .drv_class = MLX5_CLASS_CRYPTO },
94 };
95 
96 static int
97 class_name_to_value(const char *class_name)
98 {
99 	unsigned int i;
100 
101 	for (i = 0; i < RTE_DIM(mlx5_classes); i++) {
102 		if (strcmp(class_name, mlx5_classes[i].name) == 0)
103 			return mlx5_classes[i].drv_class;
104 	}
105 	return -EINVAL;
106 }
107 
108 static struct mlx5_class_driver *
109 driver_get(uint32_t class)
110 {
111 	struct mlx5_class_driver *driver;
112 
113 	TAILQ_FOREACH(driver, &drivers_list, next) {
114 		if ((uint32_t)driver->drv_class == class)
115 			return driver;
116 	}
117 	return NULL;
118 }
119 
120 int
121 mlx5_kvargs_process(struct mlx5_kvargs_ctrl *mkvlist, const char *const keys[],
122 		    arg_handler_t handler, void *opaque_arg)
123 {
124 	const struct rte_kvargs_pair *pair;
125 	uint32_t i, j;
126 
127 	MLX5_ASSERT(mkvlist && mkvlist->kvlist);
128 	/* Process parameters. */
129 	for (i = 0; i < mkvlist->kvlist->count; i++) {
130 		pair = &mkvlist->kvlist->pairs[i];
131 		for (j = 0; keys[j] != NULL; ++j) {
132 			if (strcmp(pair->key, keys[j]) != 0)
133 				continue;
134 			if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
135 				return -1;
136 			mkvlist->is_used[i] = true;
137 			break;
138 		}
139 	}
140 	return 0;
141 }
142 
143 /**
144  * Prepare a mlx5 kvargs control.
145  *
146  * @param[out] mkvlist
147  *   Pointer to mlx5 kvargs control.
148  * @param[in] devargs
149  *   The input string containing the key/value associations.
150  *
151  * @return
152  *   0 on success, a negative errno value otherwise and rte_errno is set.
153  */
154 static int
155 mlx5_kvargs_prepare(struct mlx5_kvargs_ctrl *mkvlist,
156 		    const struct rte_devargs *devargs)
157 {
158 	struct rte_kvargs *kvlist;
159 	uint32_t i;
160 
161 	if (devargs == NULL)
162 		return 0;
163 	kvlist = rte_kvargs_parse(devargs->args, NULL);
164 	if (kvlist == NULL) {
165 		rte_errno = EINVAL;
166 		return -rte_errno;
167 	}
168 	/*
169 	 * rte_kvargs_parse enable key without value, in mlx5 PMDs we disable
170 	 * this syntax.
171 	 */
172 	for (i = 0; i < kvlist->count; i++) {
173 		const struct rte_kvargs_pair *pair = &kvlist->pairs[i];
174 		if (pair->value == NULL || *(pair->value) == '\0') {
175 			DRV_LOG(ERR, "Key %s is missing value.", pair->key);
176 			rte_kvargs_free(kvlist);
177 			rte_errno = EINVAL;
178 			return -rte_errno;
179 		}
180 	}
181 	/* Makes sure all devargs used array is false. */
182 	memset(mkvlist, 0, sizeof(*mkvlist));
183 	mkvlist->kvlist = kvlist;
184 	DRV_LOG(DEBUG, "Parse successfully %u devargs.",
185 		mkvlist->kvlist->count);
186 	return 0;
187 }
188 
189 /**
190  * Release a mlx5 kvargs control.
191  *
192  * @param[out] mkvlist
193  *   Pointer to mlx5 kvargs control.
194  */
195 static void
196 mlx5_kvargs_release(struct mlx5_kvargs_ctrl *mkvlist)
197 {
198 	if (mkvlist == NULL)
199 		return;
200 	rte_kvargs_free(mkvlist->kvlist);
201 	memset(mkvlist, 0, sizeof(*mkvlist));
202 }
203 
204 /**
205  * Validate device arguments list.
206  * It report about the first unknown parameter.
207  *
208  * @param[in] mkvlist
209  *   Pointer to mlx5 kvargs control.
210  *
211  * @return
212  *   0 on success, a negative errno value otherwise and rte_errno is set.
213  */
214 static int
215 mlx5_kvargs_validate(struct mlx5_kvargs_ctrl *mkvlist)
216 {
217 	uint32_t i;
218 
219 	/* Secondary process should not handle devargs. */
220 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
221 		return 0;
222 	if (mkvlist == NULL)
223 		return 0;
224 	for (i = 0; i < mkvlist->kvlist->count; i++) {
225 		if (mkvlist->is_used[i] == 0) {
226 			DRV_LOG(ERR, "Key \"%s\" "
227 				"is unknown for the provided classes.",
228 				mkvlist->kvlist->pairs[i].key);
229 			rte_errno = EINVAL;
230 			return -rte_errno;
231 		}
232 	}
233 	return 0;
234 }
235 
236 /**
237  * Verify and store value for devargs.
238  *
239  * @param[in] key
240  *   Key argument to verify.
241  * @param[in] val
242  *   Value associated with key.
243  * @param opaque
244  *   User data.
245  *
246  * @return
247  *   0 on success, a negative errno value otherwise and rte_errno is set.
248  */
249 static int
250 mlx5_common_args_check_handler(const char *key, const char *val, void *opaque)
251 {
252 	struct mlx5_common_dev_config *config = opaque;
253 	signed long tmp;
254 
255 	if (strcmp(MLX5_DRIVER_KEY, key) == 0 ||
256 	    strcmp(RTE_DEVARGS_KEY_CLASS, key) == 0)
257 		return 0;
258 	errno = 0;
259 	tmp = strtol(val, NULL, 0);
260 	if (errno) {
261 		rte_errno = errno;
262 		DRV_LOG(WARNING, "%s: \"%s\" is an invalid integer.", key, val);
263 		return -rte_errno;
264 	}
265 	if (strcmp(key, MLX5_TX_DB_NC) == 0)
266 		DRV_LOG(WARNING,
267 			"%s: deprecated parameter, converted to queue_db_nc",
268 			key);
269 	if (strcmp(key, MLX5_SQ_DB_NC) == 0 ||
270 	    strcmp(key, MLX5_TX_DB_NC) == 0) {
271 		if (tmp != MLX5_SQ_DB_CACHED &&
272 		    tmp != MLX5_SQ_DB_NCACHED &&
273 		    tmp != MLX5_SQ_DB_HEURISTIC) {
274 			DRV_LOG(ERR,
275 				"Invalid Send Queue doorbell mapping parameter.");
276 			rte_errno = EINVAL;
277 			return -rte_errno;
278 		}
279 		config->dbnc = tmp;
280 	} else if (strcmp(key, MLX5_MR_EXT_MEMSEG_EN) == 0) {
281 		config->mr_ext_memseg_en = !!tmp;
282 	} else if (strcmp(key, MLX5_MR_MEMPOOL_REG_EN) == 0) {
283 		config->mr_mempool_reg_en = !!tmp;
284 	} else if (strcmp(key, MLX5_SYS_MEM_EN) == 0) {
285 		config->sys_mem_en = !!tmp;
286 	}
287 	return 0;
288 }
289 
290 /**
291  * Parse common device parameters.
292  *
293  * @param devargs
294  *   Device arguments structure.
295  * @param config
296  *   Pointer to device configuration structure.
297  *
298  * @return
299  *   0 on success, a negative errno value otherwise and rte_errno is set.
300  */
301 static int
302 mlx5_common_config_get(struct mlx5_kvargs_ctrl *mkvlist,
303 		       struct mlx5_common_dev_config *config)
304 {
305 	const char **params = (const char *[]){
306 		RTE_DEVARGS_KEY_CLASS,
307 		MLX5_DRIVER_KEY,
308 		MLX5_TX_DB_NC,
309 		MLX5_SQ_DB_NC,
310 		MLX5_MR_EXT_MEMSEG_EN,
311 		MLX5_SYS_MEM_EN,
312 		MLX5_MR_MEMPOOL_REG_EN,
313 		NULL,
314 	};
315 	int ret = 0;
316 
317 	if (mkvlist == NULL)
318 		return 0;
319 	/* Set defaults. */
320 	config->mr_ext_memseg_en = 1;
321 	config->mr_mempool_reg_en = 1;
322 	config->sys_mem_en = 0;
323 	config->dbnc = MLX5_ARG_UNSET;
324 	/* Process common parameters. */
325 	ret = mlx5_kvargs_process(mkvlist, params,
326 				  mlx5_common_args_check_handler, config);
327 	if (ret) {
328 		rte_errno = EINVAL;
329 		ret = -rte_errno;
330 	}
331 	DRV_LOG(DEBUG, "mr_ext_memseg_en is %u.", config->mr_ext_memseg_en);
332 	DRV_LOG(DEBUG, "mr_mempool_reg_en is %u.", config->mr_mempool_reg_en);
333 	DRV_LOG(DEBUG, "sys_mem_en is %u.", config->sys_mem_en);
334 	DRV_LOG(DEBUG, "Send Queue doorbell mapping parameter is %d.",
335 		config->dbnc);
336 	return ret;
337 }
338 
339 static int
340 devargs_class_handler(__rte_unused const char *key,
341 		      const char *class_names, void *opaque)
342 {
343 	int *ret = opaque;
344 	int class_val;
345 	char *scratch;
346 	char *found;
347 	char *refstr = NULL;
348 
349 	*ret = 0;
350 	scratch = strdup(class_names);
351 	if (scratch == NULL) {
352 		*ret = -ENOMEM;
353 		return *ret;
354 	}
355 	found = strtok_r(scratch, ":", &refstr);
356 	if (found == NULL)
357 		/* Empty string. */
358 		goto err;
359 	do {
360 		/* Extract each individual class name. Multiple
361 		 * classes can be supplied as class=net:regex:foo:bar.
362 		 */
363 		class_val = class_name_to_value(found);
364 		/* Check if its a valid class. */
365 		if (class_val < 0) {
366 			*ret = -EINVAL;
367 			goto err;
368 		}
369 		*ret |= class_val;
370 		found = strtok_r(NULL, ":", &refstr);
371 	} while (found != NULL);
372 err:
373 	free(scratch);
374 	if (*ret < 0)
375 		DRV_LOG(ERR, "Invalid mlx5 class options: %s.\n", class_names);
376 	return *ret;
377 }
378 
379 static int
380 parse_class_options(const struct rte_devargs *devargs,
381 		    struct mlx5_kvargs_ctrl *mkvlist)
382 {
383 	int ret = 0;
384 
385 	if (devargs == NULL)
386 		return 0;
387 	if (devargs->cls != NULL && devargs->cls->name != NULL)
388 		/* Global syntax, only one class type. */
389 		return class_name_to_value(devargs->cls->name);
390 	/* Legacy devargs support multiple classes. */
391 	rte_kvargs_process(mkvlist->kvlist, RTE_DEVARGS_KEY_CLASS,
392 			   devargs_class_handler, &ret);
393 	return ret;
394 }
395 
396 static const unsigned int mlx5_class_invalid_combinations[] = {
397 	MLX5_CLASS_ETH | MLX5_CLASS_VDPA,
398 	/* New class combination should be added here. */
399 };
400 
401 static int
402 is_valid_class_combination(uint32_t user_classes)
403 {
404 	unsigned int i;
405 
406 	/* Verify if user specified unsupported combination. */
407 	for (i = 0; i < RTE_DIM(mlx5_class_invalid_combinations); i++) {
408 		if ((mlx5_class_invalid_combinations[i] & user_classes) ==
409 		    mlx5_class_invalid_combinations[i])
410 			return -EINVAL;
411 	}
412 	/* Not found any invalid class combination. */
413 	return 0;
414 }
415 
416 static bool
417 mlx5_bus_match(const struct mlx5_class_driver *drv,
418 	       const struct rte_device *dev)
419 {
420 	if (mlx5_dev_is_pci(dev))
421 		return mlx5_dev_pci_match(drv, dev);
422 	return true;
423 }
424 
425 static struct mlx5_common_device *
426 to_mlx5_device(const struct rte_device *rte_dev)
427 {
428 	struct mlx5_common_device *cdev;
429 
430 	TAILQ_FOREACH(cdev, &devices_list, next) {
431 		if (rte_dev == cdev->dev)
432 			return cdev;
433 	}
434 	return NULL;
435 }
436 
437 int
438 mlx5_dev_to_pci_str(const struct rte_device *dev, char *addr, size_t size)
439 {
440 	struct rte_pci_addr pci_addr = { 0 };
441 	int ret;
442 
443 	if (mlx5_dev_is_pci(dev)) {
444 		/* Input might be <BDF>, format PCI address to <DBDF>. */
445 		ret = rte_pci_addr_parse(dev->name, &pci_addr);
446 		if (ret != 0)
447 			return -ENODEV;
448 		rte_pci_device_name(&pci_addr, addr, size);
449 		return 0;
450 	}
451 #ifdef RTE_EXEC_ENV_LINUX
452 	return mlx5_auxiliary_get_pci_str(RTE_DEV_TO_AUXILIARY_CONST(dev),
453 			addr, size);
454 #else
455 	rte_errno = ENODEV;
456 	return -rte_errno;
457 #endif
458 }
459 
460 /**
461  * Register the mempool for the protection domain.
462  *
463  * @param cdev
464  *   Pointer to the mlx5 common device.
465  * @param mp
466  *   Mempool being registered.
467  *
468  * @return
469  *   0 on success, (-1) on failure and rte_errno is set.
470  */
471 static int
472 mlx5_dev_mempool_register(struct mlx5_common_device *cdev,
473 			  struct rte_mempool *mp, bool is_extmem)
474 {
475 	return mlx5_mr_mempool_register(cdev, mp, is_extmem);
476 }
477 
478 /**
479  * Unregister the mempool from the protection domain.
480  *
481  * @param cdev
482  *   Pointer to the mlx5 common device.
483  * @param mp
484  *   Mempool being unregistered.
485  */
486 void
487 mlx5_dev_mempool_unregister(struct mlx5_common_device *cdev,
488 			    struct rte_mempool *mp)
489 {
490 	if (mlx5_mr_mempool_unregister(cdev, mp) < 0)
491 		DRV_LOG(WARNING, "Failed to unregister mempool %s for PD %p: %s",
492 			mp->name, cdev->pd, rte_strerror(rte_errno));
493 }
494 
495 /**
496  * rte_mempool_walk() callback to register mempools for the protection domain.
497  *
498  * @param mp
499  *   The mempool being walked.
500  * @param arg
501  *   Pointer to the device shared context.
502  */
503 static void
504 mlx5_dev_mempool_register_cb(struct rte_mempool *mp, void *arg)
505 {
506 	struct mlx5_common_device *cdev = arg;
507 	int ret;
508 
509 	ret = mlx5_dev_mempool_register(cdev, mp, false);
510 	if (ret < 0 && rte_errno != EEXIST)
511 		DRV_LOG(ERR,
512 			"Failed to register existing mempool %s for PD %p: %s",
513 			mp->name, cdev->pd, rte_strerror(rte_errno));
514 }
515 
516 /**
517  * rte_mempool_walk() callback to unregister mempools
518  * from the protection domain.
519  *
520  * @param mp
521  *   The mempool being walked.
522  * @param arg
523  *   Pointer to the device shared context.
524  */
525 static void
526 mlx5_dev_mempool_unregister_cb(struct rte_mempool *mp, void *arg)
527 {
528 	mlx5_dev_mempool_unregister((struct mlx5_common_device *)arg, mp);
529 }
530 
531 /**
532  * Mempool life cycle callback for mlx5 common devices.
533  *
534  * @param event
535  *   Mempool life cycle event.
536  * @param mp
537  *   Associated mempool.
538  * @param arg
539  *   Pointer to a device shared context.
540  */
541 static void
542 mlx5_dev_mempool_event_cb(enum rte_mempool_event event, struct rte_mempool *mp,
543 			  void *arg)
544 {
545 	struct mlx5_common_device *cdev = arg;
546 
547 	switch (event) {
548 	case RTE_MEMPOOL_EVENT_READY:
549 		if (mlx5_dev_mempool_register(cdev, mp, false) < 0)
550 			DRV_LOG(ERR,
551 				"Failed to register new mempool %s for PD %p: %s",
552 				mp->name, cdev->pd, rte_strerror(rte_errno));
553 		break;
554 	case RTE_MEMPOOL_EVENT_DESTROY:
555 		mlx5_dev_mempool_unregister(cdev, mp);
556 		break;
557 	}
558 }
559 
560 int
561 mlx5_dev_mempool_subscribe(struct mlx5_common_device *cdev)
562 {
563 	int ret = 0;
564 
565 	if (!cdev->config.mr_mempool_reg_en)
566 		return 0;
567 	rte_rwlock_write_lock(&cdev->mr_scache.mprwlock);
568 	if (cdev->mr_scache.mp_cb_registered)
569 		goto exit;
570 	/* Callback for this device may be already registered. */
571 	ret = rte_mempool_event_callback_register(mlx5_dev_mempool_event_cb,
572 						  cdev);
573 	if (ret != 0 && rte_errno != EEXIST)
574 		goto exit;
575 	/* Register mempools only once for this device. */
576 	if (ret == 0)
577 		rte_mempool_walk(mlx5_dev_mempool_register_cb, cdev);
578 	ret = 0;
579 	cdev->mr_scache.mp_cb_registered = 1;
580 exit:
581 	rte_rwlock_write_unlock(&cdev->mr_scache.mprwlock);
582 	return ret;
583 }
584 
585 static void
586 mlx5_dev_mempool_unsubscribe(struct mlx5_common_device *cdev)
587 {
588 	int ret;
589 
590 	if (!cdev->mr_scache.mp_cb_registered ||
591 	    !cdev->config.mr_mempool_reg_en)
592 		return;
593 	/* Stop watching for mempool events and unregister all mempools. */
594 	ret = rte_mempool_event_callback_unregister(mlx5_dev_mempool_event_cb,
595 						    cdev);
596 	if (ret == 0)
597 		rte_mempool_walk(mlx5_dev_mempool_unregister_cb, cdev);
598 }
599 
600 /**
601  * Callback for memory event.
602  *
603  * @param event_type
604  *   Memory event type.
605  * @param addr
606  *   Address of memory.
607  * @param len
608  *   Size of memory.
609  */
610 static void
611 mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr,
612 		     size_t len, void *arg __rte_unused)
613 {
614 	struct mlx5_common_device *cdev;
615 
616 	/* Must be called from the primary process. */
617 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
618 	switch (event_type) {
619 	case RTE_MEM_EVENT_FREE:
620 		pthread_mutex_lock(&devices_list_lock);
621 		/* Iterate all the existing mlx5 devices. */
622 		TAILQ_FOREACH(cdev, &devices_list, next)
623 			mlx5_free_mr_by_addr(&cdev->mr_scache,
624 					     mlx5_os_get_ctx_device_name
625 								    (cdev->ctx),
626 					     addr, len);
627 		pthread_mutex_unlock(&devices_list_lock);
628 		break;
629 	case RTE_MEM_EVENT_ALLOC:
630 	default:
631 		break;
632 	}
633 }
634 
635 /**
636  * Uninitialize all HW global of device context.
637  *
638  * @param cdev
639  *   Pointer to mlx5 device structure.
640  *
641  * @return
642  *   0 on success, a negative errno value otherwise and rte_errno is set.
643  */
644 static void
645 mlx5_dev_hw_global_release(struct mlx5_common_device *cdev)
646 {
647 	if (cdev->pd != NULL) {
648 		claim_zero(mlx5_os_dealloc_pd(cdev->pd));
649 		cdev->pd = NULL;
650 	}
651 	if (cdev->ctx != NULL) {
652 		claim_zero(mlx5_glue->close_device(cdev->ctx));
653 		cdev->ctx = NULL;
654 	}
655 }
656 
657 /**
658  * Initialize all HW global of device context.
659  *
660  * @param cdev
661  *   Pointer to mlx5 device structure.
662  * @param classes
663  *   Chosen classes come from user device arguments.
664  *
665  * @return
666  *   0 on success, a negative errno value otherwise and rte_errno is set.
667  */
668 static int
669 mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes)
670 {
671 	int ret;
672 
673 	/* Create context device */
674 	ret = mlx5_os_open_device(cdev, classes);
675 	if (ret < 0)
676 		return ret;
677 	/* Allocate Protection Domain object and extract its pdn. */
678 	ret = mlx5_os_pd_create(cdev);
679 	if (ret)
680 		goto error;
681 	/* All actions taken below are relevant only when DevX is supported */
682 	if (cdev->config.devx == 0)
683 		return 0;
684 	/* Query HCA attributes. */
685 	ret = mlx5_devx_cmd_query_hca_attr(cdev->ctx, &cdev->config.hca_attr);
686 	if (ret) {
687 		DRV_LOG(ERR, "Unable to read HCA capabilities.");
688 		rte_errno = ENOTSUP;
689 		goto error;
690 	}
691 	return 0;
692 error:
693 	mlx5_dev_hw_global_release(cdev);
694 	return ret;
695 }
696 
697 static void
698 mlx5_common_dev_release(struct mlx5_common_device *cdev)
699 {
700 	pthread_mutex_lock(&devices_list_lock);
701 	TAILQ_REMOVE(&devices_list, cdev, next);
702 	pthread_mutex_unlock(&devices_list_lock);
703 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
704 		if (TAILQ_EMPTY(&devices_list))
705 			rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB",
706 							  NULL);
707 		mlx5_dev_mempool_unsubscribe(cdev);
708 		mlx5_mr_release_cache(&cdev->mr_scache);
709 		mlx5_dev_hw_global_release(cdev);
710 	}
711 	rte_free(cdev);
712 }
713 
714 static struct mlx5_common_device *
715 mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes,
716 		       struct mlx5_kvargs_ctrl *mkvlist)
717 {
718 	struct mlx5_common_device *cdev;
719 	int ret;
720 
721 	cdev = rte_zmalloc("mlx5_common_device", sizeof(*cdev), 0);
722 	if (!cdev) {
723 		DRV_LOG(ERR, "Device allocation failure.");
724 		rte_errno = ENOMEM;
725 		return NULL;
726 	}
727 	cdev->dev = eal_dev;
728 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
729 		goto exit;
730 	/* Parse device parameters. */
731 	ret = mlx5_common_config_get(mkvlist, &cdev->config);
732 	if (ret < 0) {
733 		DRV_LOG(ERR, "Failed to process device arguments: %s",
734 			strerror(rte_errno));
735 		rte_free(cdev);
736 		return NULL;
737 	}
738 	mlx5_malloc_mem_select(cdev->config.sys_mem_en);
739 	/* Initialize all HW global of device context. */
740 	ret = mlx5_dev_hw_global_prepare(cdev, classes);
741 	if (ret) {
742 		DRV_LOG(ERR, "Failed to initialize device context.");
743 		rte_free(cdev);
744 		return NULL;
745 	}
746 	/* Initialize global MR cache resources and update its functions. */
747 	ret = mlx5_mr_create_cache(&cdev->mr_scache, eal_dev->numa_node);
748 	if (ret) {
749 		DRV_LOG(ERR, "Failed to initialize global MR share cache.");
750 		mlx5_dev_hw_global_release(cdev);
751 		rte_free(cdev);
752 		return NULL;
753 	}
754 	/* Register callback function for global shared MR cache management. */
755 	if (TAILQ_EMPTY(&devices_list))
756 		rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
757 						mlx5_mr_mem_event_cb, NULL);
758 exit:
759 	pthread_mutex_lock(&devices_list_lock);
760 	TAILQ_INSERT_HEAD(&devices_list, cdev, next);
761 	pthread_mutex_unlock(&devices_list_lock);
762 	return cdev;
763 }
764 
765 /**
766  * Validate common devargs when probing again.
767  *
768  * When common device probing again, it cannot change its configurations.
769  * If user ask non compatible configurations in devargs, it is error.
770  * This function checks the match between:
771  *  - Common device configurations requested by probe again devargs.
772  *  - Existing common device configurations.
773  *
774  * @param cdev
775  *   Pointer to mlx5 device structure.
776  * @param mkvlist
777  *   Pointer to mlx5 kvargs control, can be NULL if there is no devargs.
778  *
779  * @return
780  *   0 on success, a negative errno value otherwise and rte_errno is set.
781  */
782 static int
783 mlx5_common_probe_again_args_validate(struct mlx5_common_device *cdev,
784 				      struct mlx5_kvargs_ctrl *mkvlist)
785 {
786 	struct mlx5_common_dev_config *config;
787 	int ret;
788 
789 	/* Secondary process should not handle devargs. */
790 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
791 		return 0;
792 	/* Probe again doesn't have to generate devargs. */
793 	if (mkvlist == NULL)
794 		return 0;
795 	config = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE,
796 			     sizeof(struct mlx5_common_dev_config),
797 			     RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
798 	if (config == NULL) {
799 		rte_errno = -ENOMEM;
800 		return -rte_errno;
801 	}
802 	/*
803 	 * Creates a temporary common configure structure according to new
804 	 * devargs attached in probing again.
805 	 */
806 	ret = mlx5_common_config_get(mkvlist, config);
807 	if (ret) {
808 		DRV_LOG(ERR, "Failed to process device configure: %s",
809 			strerror(rte_errno));
810 		mlx5_free(config);
811 		return ret;
812 	}
813 	/*
814 	 * Checks the match between the temporary structure and the existing
815 	 * common device structure.
816 	 */
817 	if (cdev->config.mr_ext_memseg_en ^ config->mr_ext_memseg_en) {
818 		DRV_LOG(ERR, "\"mr_ext_memseg_en\" "
819 			"configuration mismatch for device %s.",
820 			cdev->dev->name);
821 		goto error;
822 	}
823 	if (cdev->config.mr_mempool_reg_en ^ config->mr_mempool_reg_en) {
824 		DRV_LOG(ERR, "\"mr_mempool_reg_en\" "
825 			"configuration mismatch for device %s.",
826 			cdev->dev->name);
827 		goto error;
828 	}
829 	if (cdev->config.sys_mem_en ^ config->sys_mem_en) {
830 		DRV_LOG(ERR,
831 			"\"sys_mem_en\" configuration mismatch for device %s.",
832 			cdev->dev->name);
833 		goto error;
834 	}
835 	if (cdev->config.dbnc ^ config->dbnc) {
836 		DRV_LOG(ERR, "\"dbnc\" configuration mismatch for device %s.",
837 			cdev->dev->name);
838 		goto error;
839 	}
840 	mlx5_free(config);
841 	return 0;
842 error:
843 	mlx5_free(config);
844 	rte_errno = EINVAL;
845 	return -rte_errno;
846 }
847 
848 static int
849 drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes)
850 {
851 	struct mlx5_class_driver *driver;
852 	int local_ret = -ENODEV;
853 	unsigned int i = 0;
854 	int ret = 0;
855 
856 	while (enabled_classes) {
857 		driver = driver_get(RTE_BIT64(i));
858 		if (driver != NULL) {
859 			local_ret = driver->remove(cdev);
860 			if (local_ret == 0)
861 				cdev->classes_loaded &= ~RTE_BIT64(i);
862 			else if (ret == 0)
863 				ret = local_ret;
864 		}
865 		enabled_classes &= ~RTE_BIT64(i);
866 		i++;
867 	}
868 	if (local_ret != 0 && ret == 0)
869 		ret = local_ret;
870 	return ret;
871 }
872 
873 static int
874 drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes,
875 	      struct mlx5_kvargs_ctrl *mkvlist)
876 {
877 	struct mlx5_class_driver *driver;
878 	uint32_t enabled_classes = 0;
879 	bool already_loaded;
880 	int ret = -EINVAL;
881 
882 	TAILQ_FOREACH(driver, &drivers_list, next) {
883 		if ((driver->drv_class & user_classes) == 0)
884 			continue;
885 		if (!mlx5_bus_match(driver, cdev->dev))
886 			continue;
887 		already_loaded = cdev->classes_loaded & driver->drv_class;
888 		if (already_loaded && driver->probe_again == 0) {
889 			DRV_LOG(ERR, "Device %s is already probed",
890 				cdev->dev->name);
891 			ret = -EEXIST;
892 			goto probe_err;
893 		}
894 		ret = driver->probe(cdev, mkvlist);
895 		if (ret < 0) {
896 			DRV_LOG(ERR, "Failed to load driver %s",
897 				driver->name);
898 			goto probe_err;
899 		}
900 		enabled_classes |= driver->drv_class;
901 	}
902 	if (!ret) {
903 		cdev->classes_loaded |= enabled_classes;
904 		return 0;
905 	}
906 probe_err:
907 	/*
908 	 * Need to remove only drivers which were not probed before this probe
909 	 * instance, but have already been probed before this failure.
910 	 */
911 	enabled_classes &= ~cdev->classes_loaded;
912 	drivers_remove(cdev, enabled_classes);
913 	return ret;
914 }
915 
916 int
917 mlx5_common_dev_probe(struct rte_device *eal_dev)
918 {
919 	struct mlx5_common_device *cdev;
920 	struct mlx5_kvargs_ctrl mkvlist;
921 	struct mlx5_kvargs_ctrl *mkvlist_p = NULL;
922 	uint32_t classes = 0;
923 	bool new_device = false;
924 	int ret;
925 
926 	DRV_LOG(INFO, "probe device \"%s\".", eal_dev->name);
927 	if (eal_dev->devargs != NULL)
928 		mkvlist_p = &mkvlist;
929 	ret = mlx5_kvargs_prepare(mkvlist_p, eal_dev->devargs);
930 	if (ret < 0) {
931 		DRV_LOG(ERR, "Unsupported device arguments: %s",
932 			eal_dev->devargs->args);
933 		return ret;
934 	}
935 	ret = parse_class_options(eal_dev->devargs, mkvlist_p);
936 	if (ret < 0) {
937 		DRV_LOG(ERR, "Unsupported mlx5 class type: %s",
938 			eal_dev->devargs->args);
939 		goto class_err;
940 	}
941 	classes = ret;
942 	if (classes == 0)
943 		/* Default to net class. */
944 		classes = MLX5_CLASS_ETH;
945 	/*
946 	 * MLX5 common driver supports probing again in two scenarios:
947 	 * - Add new driver under existing common device (regardless of the
948 	 *   driver's own support in probing again).
949 	 * - Transfer the probing again support of the drivers themselves.
950 	 *
951 	 * In both scenarios it uses in the existing device. here it looks for
952 	 * device that match to rte device, if it exists, the request classes
953 	 * were probed with this device.
954 	 */
955 	cdev = to_mlx5_device(eal_dev);
956 	if (!cdev) {
957 		/* It isn't probing again, creates a new device. */
958 		cdev = mlx5_common_dev_create(eal_dev, classes, mkvlist_p);
959 		if (!cdev) {
960 			ret = -ENOMEM;
961 			goto class_err;
962 		}
963 		new_device = true;
964 	} else {
965 		/* It is probing again, validate common devargs match. */
966 		ret = mlx5_common_probe_again_args_validate(cdev, mkvlist_p);
967 		if (ret) {
968 			DRV_LOG(ERR,
969 				"Probe again parameters aren't compatible : %s",
970 				strerror(rte_errno));
971 			goto class_err;
972 		}
973 	}
974 	/*
975 	 * Validate combination here.
976 	 * For new device, the classes_loaded field is 0 and it check only
977 	 * the classes given as user device arguments.
978 	 */
979 	ret = is_valid_class_combination(classes | cdev->classes_loaded);
980 	if (ret != 0) {
981 		DRV_LOG(ERR, "Unsupported mlx5 classes combination.");
982 		goto class_err;
983 	}
984 	ret = drivers_probe(cdev, classes, mkvlist_p);
985 	if (ret)
986 		goto class_err;
987 	/*
988 	 * Validate that all devargs have been used, unused key -> unknown Key.
989 	 * When probe again validate is failed, the added drivers aren't removed
990 	 * here but when device is released.
991 	 */
992 	ret = mlx5_kvargs_validate(mkvlist_p);
993 	if (ret)
994 		goto class_err;
995 	mlx5_kvargs_release(mkvlist_p);
996 	return 0;
997 class_err:
998 	if (new_device) {
999 		/*
1000 		 * For new device, classes_loaded is always 0 before
1001 		 * drivers_probe function.
1002 		 */
1003 		if (cdev->classes_loaded)
1004 			drivers_remove(cdev, cdev->classes_loaded);
1005 		mlx5_common_dev_release(cdev);
1006 	}
1007 	mlx5_kvargs_release(mkvlist_p);
1008 	return ret;
1009 }
1010 
1011 int
1012 mlx5_common_dev_remove(struct rte_device *eal_dev)
1013 {
1014 	struct mlx5_common_device *cdev;
1015 	int ret;
1016 
1017 	cdev = to_mlx5_device(eal_dev);
1018 	if (!cdev)
1019 		return -ENODEV;
1020 	/* Matching device found, cleanup and unload drivers. */
1021 	ret = drivers_remove(cdev, cdev->classes_loaded);
1022 	if (ret == 0)
1023 		mlx5_common_dev_release(cdev);
1024 	return ret;
1025 }
1026 
1027 /**
1028  * Callback to DMA map external memory to a device.
1029  *
1030  * @param rte_dev
1031  *   Pointer to the generic device.
1032  * @param addr
1033  *   Starting virtual address of memory to be mapped.
1034  * @param iova
1035  *   Starting IOVA address of memory to be mapped.
1036  * @param len
1037  *   Length of memory segment being mapped.
1038  *
1039  * @return
1040  *   0 on success, negative value on error.
1041  */
1042 int
1043 mlx5_common_dev_dma_map(struct rte_device *rte_dev, void *addr,
1044 			uint64_t iova __rte_unused, size_t len)
1045 {
1046 	struct mlx5_common_device *dev;
1047 	struct mlx5_mr *mr;
1048 
1049 	dev = to_mlx5_device(rte_dev);
1050 	if (!dev) {
1051 		DRV_LOG(WARNING,
1052 			"Unable to find matching mlx5 device to device %s",
1053 			rte_dev->name);
1054 		rte_errno = ENODEV;
1055 		return -1;
1056 	}
1057 	mr = mlx5_create_mr_ext(dev->pd, (uintptr_t)addr, len,
1058 				SOCKET_ID_ANY, dev->mr_scache.reg_mr_cb);
1059 	if (!mr) {
1060 		DRV_LOG(WARNING, "Device %s unable to DMA map", rte_dev->name);
1061 		rte_errno = EINVAL;
1062 		return -1;
1063 	}
1064 	rte_rwlock_write_lock(&dev->mr_scache.rwlock);
1065 	LIST_INSERT_HEAD(&dev->mr_scache.mr_list, mr, mr);
1066 	/* Insert to the global cache table. */
1067 	mlx5_mr_insert_cache(&dev->mr_scache, mr);
1068 	rte_rwlock_write_unlock(&dev->mr_scache.rwlock);
1069 	return 0;
1070 }
1071 
1072 /**
1073  * Callback to DMA unmap external memory to a device.
1074  *
1075  * @param rte_dev
1076  *   Pointer to the generic device.
1077  * @param addr
1078  *   Starting virtual address of memory to be unmapped.
1079  * @param iova
1080  *   Starting IOVA address of memory to be unmapped.
1081  * @param len
1082  *   Length of memory segment being unmapped.
1083  *
1084  * @return
1085  *   0 on success, negative value on error.
1086  */
1087 int
1088 mlx5_common_dev_dma_unmap(struct rte_device *rte_dev, void *addr,
1089 			  uint64_t iova __rte_unused, size_t len __rte_unused)
1090 {
1091 	struct mlx5_common_device *dev;
1092 	struct mr_cache_entry entry;
1093 	struct mlx5_mr *mr;
1094 
1095 	dev = to_mlx5_device(rte_dev);
1096 	if (!dev) {
1097 		DRV_LOG(WARNING,
1098 			"Unable to find matching mlx5 device to device %s.",
1099 			rte_dev->name);
1100 		rte_errno = ENODEV;
1101 		return -1;
1102 	}
1103 	rte_rwlock_read_lock(&dev->mr_scache.rwlock);
1104 	mr = mlx5_mr_lookup_list(&dev->mr_scache, &entry, (uintptr_t)addr);
1105 	if (!mr) {
1106 		rte_rwlock_read_unlock(&dev->mr_scache.rwlock);
1107 		DRV_LOG(WARNING,
1108 			"Address 0x%" PRIxPTR " wasn't registered to device %s",
1109 			(uintptr_t)addr, rte_dev->name);
1110 		rte_errno = EINVAL;
1111 		return -1;
1112 	}
1113 	LIST_REMOVE(mr, mr);
1114 	DRV_LOG(DEBUG, "MR(%p) is removed from list.", (void *)mr);
1115 	mlx5_mr_free(mr, dev->mr_scache.dereg_mr_cb);
1116 	mlx5_mr_rebuild_cache(&dev->mr_scache);
1117 	/*
1118 	 * No explicit wmb is needed after updating dev_gen due to
1119 	 * store-release ordering in unlock that provides the
1120 	 * implicit barrier at the software visible level.
1121 	 */
1122 	++dev->mr_scache.dev_gen;
1123 	DRV_LOG(DEBUG, "Broadcasting local cache flush, gen=%d.",
1124 		dev->mr_scache.dev_gen);
1125 	rte_rwlock_read_unlock(&dev->mr_scache.rwlock);
1126 	return 0;
1127 }
1128 
1129 void
1130 mlx5_class_driver_register(struct mlx5_class_driver *driver)
1131 {
1132 	mlx5_common_driver_on_register_pci(driver);
1133 	TAILQ_INSERT_TAIL(&drivers_list, driver, next);
1134 }
1135 
1136 static void mlx5_common_driver_init(void)
1137 {
1138 	mlx5_common_pci_init();
1139 #ifdef RTE_EXEC_ENV_LINUX
1140 	mlx5_common_auxiliary_init();
1141 #endif
1142 }
1143 
1144 static bool mlx5_common_initialized;
1145 
1146 /**
1147  * One time initialization routine for run-time dependency on glue library
1148  * for multiple PMDs. Each mlx5 PMD that depends on mlx5_common module,
1149  * must invoke in its constructor.
1150  */
1151 void
1152 mlx5_common_init(void)
1153 {
1154 	if (mlx5_common_initialized)
1155 		return;
1156 
1157 	pthread_mutex_init(&devices_list_lock, NULL);
1158 	mlx5_glue_constructor();
1159 	mlx5_common_driver_init();
1160 	mlx5_common_initialized = true;
1161 }
1162 
1163 /**
1164  * This function is responsible of initializing the variable
1165  *  haswell_broadwell_cpu by checking if the cpu is intel
1166  *  and reading the data returned from mlx5_cpu_id().
1167  *  since haswell and broadwell cpus don't have improved performance
1168  *  when using relaxed ordering we want to check the cpu type before
1169  *  before deciding whether to enable RO or not.
1170  *  if the cpu is haswell or broadwell the variable will be set to 1
1171  *  otherwise it will be 0.
1172  */
1173 RTE_INIT_PRIO(mlx5_is_haswell_broadwell_cpu, LOG)
1174 {
1175 #ifdef RTE_ARCH_X86_64
1176 	unsigned int broadwell_models[4] = {0x3d, 0x47, 0x4F, 0x56};
1177 	unsigned int haswell_models[4] = {0x3c, 0x3f, 0x45, 0x46};
1178 	unsigned int i, model, family, brand_id, vendor;
1179 	unsigned int signature_intel_ebx = 0x756e6547;
1180 	unsigned int extended_model;
1181 	unsigned int eax = 0;
1182 	unsigned int ebx = 0;
1183 	unsigned int ecx = 0;
1184 	unsigned int edx = 0;
1185 	int max_level;
1186 
1187 	mlx5_cpu_id(0, &eax, &ebx, &ecx, &edx);
1188 	vendor = ebx;
1189 	max_level = eax;
1190 	if (max_level < 1) {
1191 		haswell_broadwell_cpu = 0;
1192 		return;
1193 	}
1194 	mlx5_cpu_id(1, &eax, &ebx, &ecx, &edx);
1195 	model = (eax >> 4) & 0x0f;
1196 	family = (eax >> 8) & 0x0f;
1197 	brand_id = ebx & 0xff;
1198 	extended_model = (eax >> 12) & 0xf0;
1199 	/* Check if the processor is Haswell or Broadwell */
1200 	if (vendor == signature_intel_ebx) {
1201 		if (family == 0x06)
1202 			model += extended_model;
1203 		if (brand_id == 0 && family == 0x6) {
1204 			for (i = 0; i < RTE_DIM(broadwell_models); i++)
1205 				if (model == broadwell_models[i]) {
1206 					haswell_broadwell_cpu = 1;
1207 					return;
1208 				}
1209 			for (i = 0; i < RTE_DIM(haswell_models); i++)
1210 				if (model == haswell_models[i]) {
1211 					haswell_broadwell_cpu = 1;
1212 					return;
1213 				}
1214 		}
1215 	}
1216 #endif
1217 	haswell_broadwell_cpu = 0;
1218 }
1219 
1220 /**
1221  * Allocate the User Access Region with DevX on specified device.
1222  * This routine handles the following UAR allocation issues:
1223  *
1224  *  - Try to allocate the UAR with the most appropriate memory mapping
1225  *    type from the ones supported by the host.
1226  *
1227  *  - Try to allocate the UAR with non-NULL base address OFED 5.0.x and
1228  *    Upstream rdma_core before v29 returned the NULL as UAR base address
1229  *    if UAR was not the first object in the UAR page.
1230  *    It caused the PMD failure and we should try to get another UAR till
1231  *    we get the first one with non-NULL base address returned.
1232  *
1233  * @param [in] cdev
1234  *   Pointer to mlx5 device structure to perform allocation on its context.
1235  *
1236  * @return
1237  *   UAR object pointer on success, NULL otherwise and rte_errno is set.
1238  */
1239 static void *
1240 mlx5_devx_alloc_uar(struct mlx5_common_device *cdev)
1241 {
1242 	void *uar;
1243 	uint32_t retry, uar_mapping;
1244 	void *base_addr;
1245 
1246 	for (retry = 0; retry < MLX5_ALLOC_UAR_RETRY; ++retry) {
1247 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC
1248 		/* Control the mapping type according to the settings. */
1249 		uar_mapping = (cdev->config.dbnc == MLX5_SQ_DB_NCACHED) ?
1250 			    MLX5DV_UAR_ALLOC_TYPE_NC : MLX5DV_UAR_ALLOC_TYPE_BF;
1251 #else
1252 		/*
1253 		 * It seems we have no way to control the memory mapping type
1254 		 * for the UAR, the default "Write-Combining" type is supposed.
1255 		 */
1256 		uar_mapping = 0;
1257 #endif
1258 		uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping);
1259 #ifdef MLX5DV_UAR_ALLOC_TYPE_NC
1260 		if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_BF) {
1261 			/*
1262 			 * In some environments like virtual machine the
1263 			 * Write Combining mapped might be not supported and
1264 			 * UAR allocation fails. We tried "Non-Cached" mapping
1265 			 * for the case.
1266 			 */
1267 			DRV_LOG(DEBUG, "Failed to allocate DevX UAR (BF)");
1268 			uar_mapping = MLX5DV_UAR_ALLOC_TYPE_NC;
1269 			uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping);
1270 		} else if (!uar && uar_mapping == MLX5DV_UAR_ALLOC_TYPE_NC) {
1271 			/*
1272 			 * If Verbs/kernel does not support "Non-Cached"
1273 			 * try the "Write-Combining".
1274 			 */
1275 			DRV_LOG(DEBUG, "Failed to allocate DevX UAR (NC)");
1276 			uar_mapping = MLX5DV_UAR_ALLOC_TYPE_BF;
1277 			uar = mlx5_glue->devx_alloc_uar(cdev->ctx, uar_mapping);
1278 		}
1279 #endif
1280 		if (!uar) {
1281 			DRV_LOG(ERR, "Failed to allocate DevX UAR (BF/NC)");
1282 			rte_errno = ENOMEM;
1283 			goto exit;
1284 		}
1285 		base_addr = mlx5_os_get_devx_uar_base_addr(uar);
1286 		if (base_addr)
1287 			break;
1288 		/*
1289 		 * The UARs are allocated by rdma_core within the
1290 		 * IB device context, on context closure all UARs
1291 		 * will be freed, should be no memory/object leakage.
1292 		 */
1293 		DRV_LOG(DEBUG, "Retrying to allocate DevX UAR");
1294 		uar = NULL;
1295 	}
1296 	/* Check whether we finally succeeded with valid UAR allocation. */
1297 	if (!uar) {
1298 		DRV_LOG(ERR, "Failed to allocate DevX UAR (NULL base)");
1299 		rte_errno = ENOMEM;
1300 	}
1301 	/*
1302 	 * Return void * instead of struct mlx5dv_devx_uar *
1303 	 * is for compatibility with older rdma-core library headers.
1304 	 */
1305 exit:
1306 	return uar;
1307 }
1308 
1309 void
1310 mlx5_devx_uar_release(struct mlx5_uar *uar)
1311 {
1312 	if (uar->obj != NULL)
1313 		mlx5_glue->devx_free_uar(uar->obj);
1314 	memset(uar, 0, sizeof(*uar));
1315 }
1316 
1317 int
1318 mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar)
1319 {
1320 	off_t uar_mmap_offset;
1321 	const size_t page_size = rte_mem_page_size();
1322 	void *base_addr;
1323 	void *uar_obj;
1324 
1325 	if (page_size == (size_t)-1) {
1326 		DRV_LOG(ERR, "Failed to get mem page size");
1327 		rte_errno = ENOMEM;
1328 		return -1;
1329 	}
1330 	uar_obj = mlx5_devx_alloc_uar(cdev);
1331 	if (uar_obj == NULL || mlx5_os_get_devx_uar_reg_addr(uar_obj) == NULL) {
1332 		rte_errno = errno;
1333 		DRV_LOG(ERR, "Failed to allocate UAR.");
1334 		return -1;
1335 	}
1336 	uar->obj = uar_obj;
1337 	uar_mmap_offset = mlx5_os_get_devx_uar_mmap_offset(uar_obj);
1338 	base_addr = mlx5_os_get_devx_uar_base_addr(uar_obj);
1339 	uar->dbnc = mlx5_db_map_type_get(uar_mmap_offset, page_size);
1340 	uar->bf_db.db = mlx5_os_get_devx_uar_reg_addr(uar_obj);
1341 	uar->cq_db.db = RTE_PTR_ADD(base_addr, MLX5_CQ_DOORBELL);
1342 #ifndef RTE_ARCH_64
1343 	rte_spinlock_init(&uar->bf_sl);
1344 	rte_spinlock_init(&uar->cq_sl);
1345 	uar->bf_db.sl_p = &uar->bf_sl;
1346 	uar->cq_db.sl_p = &uar->cq_sl;
1347 #endif /* RTE_ARCH_64 */
1348 	return 0;
1349 }
1350 
1351 RTE_PMD_EXPORT_NAME(mlx5_common_driver, __COUNTER__);
1352