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