1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020 Mellanox Technologies Ltd
7 #include <rte_malloc.h>
8 #include <rte_devargs.h>
10 #include <rte_class.h>
12 #include "mlx5_common_log.h"
13 #include "mlx5_common_pci.h"
14 #include "mlx5_common_private.h"
16 static struct rte_pci_driver mlx5_common_pci_driver;
18 /********** Legacy PCI bus driver, to be removed ********/
20 struct mlx5_pci_device {
21 struct rte_pci_device *pci_dev;
22 TAILQ_ENTRY(mlx5_pci_device) next;
23 uint32_t classes_loaded;
26 /* Head of list of drivers. */
27 static TAILQ_HEAD(mlx5_pci_bus_drv_head, mlx5_pci_driver) drv_list =
28 TAILQ_HEAD_INITIALIZER(drv_list);
30 /* Head of mlx5 pci devices. */
31 static TAILQ_HEAD(mlx5_pci_devices_head, mlx5_pci_device) devices_list =
32 TAILQ_HEAD_INITIALIZER(devices_list);
36 unsigned int driver_class;
38 { .name = "vdpa", .driver_class = MLX5_CLASS_VDPA },
39 { .name = "eth", .driver_class = MLX5_CLASS_ETH },
40 /* Keep name "net" for backward compatibility. */
41 { .name = "net", .driver_class = MLX5_CLASS_ETH },
42 { .name = "regex", .driver_class = MLX5_CLASS_REGEX },
43 { .name = "compress", .driver_class = MLX5_CLASS_COMPRESS },
44 { .name = "crypto", .driver_class = MLX5_CLASS_CRYPTO },
47 static const unsigned int mlx5_class_combinations[] = {
53 MLX5_CLASS_ETH | MLX5_CLASS_REGEX,
54 MLX5_CLASS_VDPA | MLX5_CLASS_REGEX,
55 MLX5_CLASS_ETH | MLX5_CLASS_COMPRESS,
56 MLX5_CLASS_VDPA | MLX5_CLASS_COMPRESS,
57 MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS,
58 MLX5_CLASS_ETH | MLX5_CLASS_CRYPTO,
59 MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS,
60 MLX5_CLASS_VDPA | MLX5_CLASS_CRYPTO,
61 MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO,
62 MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO,
63 MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS,
64 MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO,
65 MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO,
66 MLX5_CLASS_ETH | MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO,
67 MLX5_CLASS_VDPA | MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO,
68 MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS |
70 MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS |
72 /* New class combination should be added here. */
76 class_name_to_value(const char *class_name)
80 for (i = 0; i < RTE_DIM(mlx5_classes); i++) {
81 if (strcmp(class_name, mlx5_classes[i].name) == 0)
82 return mlx5_classes[i].driver_class;
87 static struct mlx5_pci_driver *
88 driver_get(uint32_t class)
90 struct mlx5_pci_driver *driver;
92 TAILQ_FOREACH(driver, &drv_list, next) {
93 if (driver->driver_class == class)
100 bus_cmdline_options_handler(__rte_unused const char *key,
101 const char *class_names, void *opaque)
111 nstr = strdup(class_names);
117 found = strtok_r(nstr, ":", &refstr);
121 /* Extract each individual class name. Multiple
122 * class key,value is supplied as class=net:vdpa:foo:bar.
124 class_val = class_name_to_value(found);
125 /* Check if its a valid class. */
131 found = strtok_r(NULL, ":", &refstr);
136 DRV_LOG(ERR, "Invalid mlx5 class options %s."
137 " Maybe typo in device class argument setting?",
143 parse_class_options(const struct rte_devargs *devargs)
145 const char *key = RTE_DEVARGS_KEY_CLASS;
146 struct rte_kvargs *kvlist;
151 kvlist = rte_kvargs_parse(devargs->args, NULL);
154 if (rte_kvargs_count(kvlist, key))
155 rte_kvargs_process(kvlist, key, bus_cmdline_options_handler,
157 rte_kvargs_free(kvlist);
162 mlx5_bus_match(const struct mlx5_pci_driver *drv,
163 const struct rte_pci_device *pci_dev)
165 const struct rte_pci_id *id_table;
167 for (id_table = drv->pci_driver.id_table; id_table->vendor_id != 0;
169 /* Check if device's ids match the class driver's ids. */
170 if (id_table->vendor_id != pci_dev->id.vendor_id &&
171 id_table->vendor_id != RTE_PCI_ANY_ID)
173 if (id_table->device_id != pci_dev->id.device_id &&
174 id_table->device_id != RTE_PCI_ANY_ID)
176 if (id_table->subsystem_vendor_id !=
177 pci_dev->id.subsystem_vendor_id &&
178 id_table->subsystem_vendor_id != RTE_PCI_ANY_ID)
180 if (id_table->subsystem_device_id !=
181 pci_dev->id.subsystem_device_id &&
182 id_table->subsystem_device_id != RTE_PCI_ANY_ID)
184 if (id_table->class_id != pci_dev->id.class_id &&
185 id_table->class_id != RTE_CLASS_ANY_ID)
193 is_valid_class_combination(uint32_t user_classes)
197 /* Verify if user specified valid supported combination. */
198 for (i = 0; i < RTE_DIM(mlx5_class_combinations); i++) {
199 if (mlx5_class_combinations[i] == user_classes)
202 /* Not found any valid class combination. */
206 static struct mlx5_pci_device *
207 pci_to_mlx5_device(const struct rte_pci_device *pci_dev)
209 struct mlx5_pci_device *dev;
211 TAILQ_FOREACH(dev, &devices_list, next) {
212 if (dev->pci_dev == pci_dev)
219 device_class_enabled(const struct mlx5_pci_device *device, uint32_t class)
221 return (device->classes_loaded & class) ? true : false;
225 dev_release(struct mlx5_pci_device *dev)
227 TAILQ_REMOVE(&devices_list, dev, next);
232 drivers_remove(struct mlx5_pci_device *dev, uint32_t enabled_classes)
234 struct mlx5_pci_driver *driver;
235 int local_ret = -ENODEV;
239 enabled_classes &= dev->classes_loaded;
240 while (enabled_classes) {
241 driver = driver_get(RTE_BIT64(i));
243 local_ret = driver->pci_driver.remove(dev->pci_dev);
245 dev->classes_loaded &= ~RTE_BIT64(i);
249 enabled_classes &= ~RTE_BIT64(i);
258 drivers_probe(struct mlx5_pci_device *dev, struct rte_pci_driver *pci_drv,
259 struct rte_pci_device *pci_dev, uint32_t user_classes)
261 struct mlx5_pci_driver *driver;
262 uint32_t enabled_classes = 0;
266 TAILQ_FOREACH(driver, &drv_list, next) {
267 if ((driver->driver_class & user_classes) == 0)
269 if (!mlx5_bus_match(driver, pci_dev))
271 already_loaded = dev->classes_loaded & driver->driver_class;
272 if (already_loaded &&
273 !(driver->pci_driver.drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) {
274 DRV_LOG(ERR, "Device %s is already probed",
275 pci_dev->device.name);
279 ret = driver->pci_driver.probe(pci_drv, pci_dev);
281 DRV_LOG(ERR, "Failed to load driver %s",
282 driver->pci_driver.driver.name);
285 enabled_classes |= driver->driver_class;
287 dev->classes_loaded |= enabled_classes;
290 /* Only unload drivers which are enabled which were enabled
291 * in this probe instance.
293 drivers_remove(dev, enabled_classes);
298 * DPDK callback to register to probe multiple drivers for a PCI device.
301 * PCI driver structure.
303 * PCI device information.
306 * 0 on success, a negative errno value otherwise and rte_errno is set.
309 mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
310 struct rte_pci_device *pci_dev)
312 struct mlx5_pci_device *dev;
313 uint32_t user_classes = 0;
314 bool new_device = false;
317 ret = parse_class_options(pci_dev->device.devargs);
322 /* Validate combination here. */
323 ret = is_valid_class_combination(user_classes);
325 DRV_LOG(ERR, "Unsupported mlx5 classes supplied.");
329 /* Default to net class. */
330 user_classes = MLX5_CLASS_ETH;
332 dev = pci_to_mlx5_device(pci_dev);
334 dev = rte_zmalloc("mlx5_pci_device", sizeof(*dev), 0);
337 dev->pci_dev = pci_dev;
338 TAILQ_INSERT_HEAD(&devices_list, dev, next);
341 ret = drivers_probe(dev, pci_drv, pci_dev, user_classes);
352 * DPDK callback to remove one or more drivers for a PCI device.
354 * This function removes all drivers probed for a given PCI device.
357 * Pointer to the PCI device.
360 * 0 on success, the function cannot fail.
363 mlx5_pci_remove(struct rte_pci_device *pci_dev)
365 struct mlx5_pci_device *dev;
368 dev = pci_to_mlx5_device(pci_dev);
371 /* Matching device found, cleanup and unload drivers. */
372 ret = drivers_remove(dev, dev->classes_loaded);
379 mlx5_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
380 uint64_t iova, size_t len)
382 struct mlx5_pci_driver *driver = NULL;
383 struct mlx5_pci_driver *temp;
384 struct mlx5_pci_device *dev;
387 dev = pci_to_mlx5_device(pci_dev);
390 TAILQ_FOREACH(driver, &drv_list, next) {
391 if (device_class_enabled(dev, driver->driver_class) &&
392 driver->pci_driver.dma_map) {
393 ret = driver->pci_driver.dma_map(pci_dev, addr,
401 TAILQ_FOREACH(temp, &drv_list, next) {
404 if (device_class_enabled(dev, temp->driver_class) &&
405 temp->pci_driver.dma_map && temp->pci_driver.dma_unmap)
406 temp->pci_driver.dma_unmap(pci_dev, addr, iova, len);
412 mlx5_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
413 uint64_t iova, size_t len)
415 struct mlx5_pci_driver *driver;
416 struct mlx5_pci_device *dev;
417 int local_ret = -EINVAL;
420 dev = pci_to_mlx5_device(pci_dev);
424 /* There is no unmap error recovery in current implementation. */
425 TAILQ_FOREACH_REVERSE(driver, &drv_list, mlx5_pci_bus_drv_head, next) {
426 if (device_class_enabled(dev, driver->driver_class) &&
427 driver->pci_driver.dma_unmap) {
428 local_ret = driver->pci_driver.dma_unmap(pci_dev, addr,
430 if (local_ret && (ret == 0))
439 /* PCI ID table is build dynamically based on registered mlx5 drivers. */
440 static struct rte_pci_id *mlx5_pci_id_table;
442 static struct rte_pci_driver mlx5_pci_driver = {
444 .name = MLX5_PCI_DRIVER_NAME,
446 .probe = mlx5_pci_probe,
447 .remove = mlx5_pci_remove,
448 .dma_map = mlx5_pci_dma_map,
449 .dma_unmap = mlx5_pci_dma_unmap,
453 pci_id_table_size_get(const struct rte_pci_id *id_table)
457 for (; id_table->vendor_id != 0; id_table++)
463 pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table,
466 int current_size = next_idx - 1;
469 for (i = 0; i < current_size; i++) {
470 if (id->device_id == table[i].device_id &&
471 id->vendor_id == table[i].vendor_id &&
472 id->subsystem_vendor_id == table[i].subsystem_vendor_id &&
473 id->subsystem_device_id == table[i].subsystem_device_id)
480 pci_id_insert(struct rte_pci_id *new_table, int *next_idx,
481 const struct rte_pci_id *id_table)
483 /* Traverse the id_table, check if entry exists in new_table;
484 * Add non duplicate entries to new table.
486 for (; id_table->vendor_id != 0; id_table++) {
487 if (!pci_id_exists(id_table, new_table, *next_idx)) {
488 /* New entry; add to the table. */
489 new_table[*next_idx] = *id_table;
496 pci_ids_table_update(const struct rte_pci_id *driver_id_table)
498 const struct rte_pci_id *id_iter;
499 struct rte_pci_id *updated_table;
500 struct rte_pci_id *old_table;
504 old_table = mlx5_pci_id_table;
506 num_ids = pci_id_table_size_get(old_table);
507 num_ids += pci_id_table_size_get(driver_id_table);
508 /* Increase size by one for the termination entry of vendor_id = 0. */
510 updated_table = calloc(num_ids, sizeof(*updated_table));
513 if (old_table == NULL) {
514 /* Copy the first driver's ID table. */
515 for (id_iter = driver_id_table; id_iter->vendor_id != 0;
517 updated_table[i] = *id_iter;
519 /* First copy existing table entries. */
520 for (id_iter = old_table; id_iter->vendor_id != 0;
522 updated_table[i] = *id_iter;
523 /* New id to be added at the end of current ID table. */
524 pci_id_insert(updated_table, &i, driver_id_table);
526 /* Terminate table with empty entry. */
527 updated_table[i].vendor_id = 0;
528 mlx5_pci_driver.id_table = updated_table;
529 mlx5_common_pci_driver.id_table = updated_table;
530 mlx5_pci_id_table = updated_table;
537 mlx5_pci_driver_register(struct mlx5_pci_driver *driver)
541 ret = pci_ids_table_update(driver->pci_driver.id_table);
544 mlx5_pci_driver.drv_flags |= driver->pci_driver.drv_flags;
545 TAILQ_INSERT_TAIL(&drv_list, driver, next);
548 /********** New common PCI bus driver ********/
551 mlx5_dev_is_pci(const struct rte_device *dev)
553 return strcmp(dev->bus->name, "pci") == 0;
557 mlx5_dev_pci_match(const struct mlx5_class_driver *drv,
558 const struct rte_device *dev)
560 const struct rte_pci_device *pci_dev;
561 const struct rte_pci_id *id_table;
563 if (!mlx5_dev_is_pci(dev))
565 pci_dev = RTE_DEV_TO_PCI_CONST(dev);
566 for (id_table = drv->id_table; id_table->vendor_id != 0;
568 /* Check if device's ids match the class driver's ids. */
569 if (id_table->vendor_id != pci_dev->id.vendor_id &&
570 id_table->vendor_id != RTE_PCI_ANY_ID)
572 if (id_table->device_id != pci_dev->id.device_id &&
573 id_table->device_id != RTE_PCI_ANY_ID)
575 if (id_table->subsystem_vendor_id !=
576 pci_dev->id.subsystem_vendor_id &&
577 id_table->subsystem_vendor_id != RTE_PCI_ANY_ID)
579 if (id_table->subsystem_device_id !=
580 pci_dev->id.subsystem_device_id &&
581 id_table->subsystem_device_id != RTE_PCI_ANY_ID)
583 if (id_table->class_id != pci_dev->id.class_id &&
584 id_table->class_id != RTE_CLASS_ANY_ID)
592 mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
593 struct rte_pci_device *pci_dev)
595 return mlx5_common_dev_probe(&pci_dev->device);
599 mlx5_common_pci_remove(struct rte_pci_device *pci_dev)
601 return mlx5_common_dev_remove(&pci_dev->device);
605 mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,
606 uint64_t iova, size_t len)
608 return mlx5_common_dev_dma_map(&pci_dev->device, addr, iova, len);
612 mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,
613 uint64_t iova, size_t len)
615 return mlx5_common_dev_dma_unmap(&pci_dev->device, addr, iova, len);
619 mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver)
621 if (driver->id_table != NULL) {
622 if (pci_ids_table_update(driver->id_table) != 0)
625 if (driver->probe_again)
626 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_PROBE_AGAIN;
627 if (driver->intr_lsc)
628 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC;
629 if (driver->intr_rmv)
630 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV;
633 static struct rte_pci_driver mlx5_common_pci_driver = {
635 .name = MLX5_PCI_DRIVER_NAME,
637 .probe = mlx5_common_pci_probe,
638 .remove = mlx5_common_pci_remove,
639 .dma_map = mlx5_common_pci_dma_map,
640 .dma_unmap = mlx5_common_pci_dma_unmap,
643 void mlx5_common_pci_init(void)
645 const struct rte_pci_id empty_table[] = {
651 /* All mlx5 PMDs constructor runs at same priority. So any of the PMD
652 * including this one can register the PCI table first. If any other
653 * PMD(s) have registered the PCI ID table, No need to register an empty
656 if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table))
658 rte_pci_register(&mlx5_common_pci_driver);
661 RTE_FINI(mlx5_common_pci_finish)
663 if (mlx5_pci_id_table != NULL) {
664 /* Constructor doesn't register with PCI bus if it failed
665 * to build the table.
667 rte_pci_unregister(&mlx5_common_pci_driver);
668 free(mlx5_pci_id_table);
672 RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__);