18a41f4deSParav Pandit /* SPDX-License-Identifier: BSD-3-Clause 28a41f4deSParav Pandit * Copyright 2020 Mellanox Technologies Ltd 38a41f4deSParav Pandit */ 48a41f4deSParav Pandit 58a41f4deSParav Pandit #include <stdlib.h> 6*ad435d32SXueming Li 78a41f4deSParav Pandit #include <rte_malloc.h> 8*ad435d32SXueming Li #include <rte_devargs.h> 9*ad435d32SXueming Li #include <rte_errno.h> 1025245d5dSShiri Kuzin #include <rte_class.h> 1125245d5dSShiri Kuzin 1225245d5dSShiri Kuzin #include "mlx5_common_log.h" 138a41f4deSParav Pandit #include "mlx5_common_pci.h" 14*ad435d32SXueming Li #include "mlx5_common_private.h" 15*ad435d32SXueming Li 16*ad435d32SXueming Li static struct rte_pci_driver mlx5_common_pci_driver; 17*ad435d32SXueming Li 18*ad435d32SXueming Li /********** Legacy PCI bus driver, to be removed ********/ 198a41f4deSParav Pandit 208a41f4deSParav Pandit struct mlx5_pci_device { 218a41f4deSParav Pandit struct rte_pci_device *pci_dev; 228a41f4deSParav Pandit TAILQ_ENTRY(mlx5_pci_device) next; 238a41f4deSParav Pandit uint32_t classes_loaded; 248a41f4deSParav Pandit }; 258a41f4deSParav Pandit 268a41f4deSParav Pandit /* Head of list of drivers. */ 278a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_bus_drv_head, mlx5_pci_driver) drv_list = 288a41f4deSParav Pandit TAILQ_HEAD_INITIALIZER(drv_list); 298a41f4deSParav Pandit 308a41f4deSParav Pandit /* Head of mlx5 pci devices. */ 318a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_devices_head, mlx5_pci_device) devices_list = 328a41f4deSParav Pandit TAILQ_HEAD_INITIALIZER(devices_list); 338a41f4deSParav Pandit 348a41f4deSParav Pandit static const struct { 358a41f4deSParav Pandit const char *name; 368a41f4deSParav Pandit unsigned int driver_class; 378a41f4deSParav Pandit } mlx5_classes[] = { 388a41f4deSParav Pandit { .name = "vdpa", .driver_class = MLX5_CLASS_VDPA }, 39a99f2f90SXueming Li { .name = "eth", .driver_class = MLX5_CLASS_ETH }, 40a99f2f90SXueming Li /* Keep name "net" for backward compatibility. */ 41a99f2f90SXueming Li { .name = "net", .driver_class = MLX5_CLASS_ETH }, 428a41f4deSParav Pandit { .name = "regex", .driver_class = MLX5_CLASS_REGEX }, 43832a4cf1SMatan Azrad { .name = "compress", .driver_class = MLX5_CLASS_COMPRESS }, 44a7c86884SShiri Kuzin { .name = "crypto", .driver_class = MLX5_CLASS_CRYPTO }, 458a41f4deSParav Pandit }; 468a41f4deSParav Pandit 478a41f4deSParav Pandit static const unsigned int mlx5_class_combinations[] = { 48a99f2f90SXueming Li MLX5_CLASS_ETH, 498a41f4deSParav Pandit MLX5_CLASS_VDPA, 508a41f4deSParav Pandit MLX5_CLASS_REGEX, 51832a4cf1SMatan Azrad MLX5_CLASS_COMPRESS, 52a7c86884SShiri Kuzin MLX5_CLASS_CRYPTO, 53a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_REGEX, 548a41f4deSParav Pandit MLX5_CLASS_VDPA | MLX5_CLASS_REGEX, 55a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_COMPRESS, 56832a4cf1SMatan Azrad MLX5_CLASS_VDPA | MLX5_CLASS_COMPRESS, 57832a4cf1SMatan Azrad MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS, 58a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_CRYPTO, 59a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS, 60a7c86884SShiri Kuzin MLX5_CLASS_VDPA | MLX5_CLASS_CRYPTO, 61a7c86884SShiri Kuzin MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO, 62a7c86884SShiri Kuzin MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO, 63832a4cf1SMatan Azrad MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS, 64a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO, 65a7c86884SShiri Kuzin MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_CRYPTO, 66a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO, 67a7c86884SShiri Kuzin MLX5_CLASS_VDPA | MLX5_CLASS_COMPRESS | MLX5_CLASS_CRYPTO, 68a99f2f90SXueming Li MLX5_CLASS_ETH | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS | 69a7c86884SShiri Kuzin MLX5_CLASS_CRYPTO, 70a7c86884SShiri Kuzin MLX5_CLASS_VDPA | MLX5_CLASS_REGEX | MLX5_CLASS_COMPRESS | 71a7c86884SShiri Kuzin MLX5_CLASS_CRYPTO, 728a41f4deSParav Pandit /* New class combination should be added here. */ 738a41f4deSParav Pandit }; 748a41f4deSParav Pandit 758a41f4deSParav Pandit static int 768a41f4deSParav Pandit class_name_to_value(const char *class_name) 778a41f4deSParav Pandit { 788a41f4deSParav Pandit unsigned int i; 798a41f4deSParav Pandit 808a41f4deSParav Pandit for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 818a41f4deSParav Pandit if (strcmp(class_name, mlx5_classes[i].name) == 0) 828a41f4deSParav Pandit return mlx5_classes[i].driver_class; 838a41f4deSParav Pandit } 848a41f4deSParav Pandit return -EINVAL; 858a41f4deSParav Pandit } 868a41f4deSParav Pandit 878a41f4deSParav Pandit static struct mlx5_pci_driver * 888a41f4deSParav Pandit driver_get(uint32_t class) 898a41f4deSParav Pandit { 908a41f4deSParav Pandit struct mlx5_pci_driver *driver; 918a41f4deSParav Pandit 928a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 938a41f4deSParav Pandit if (driver->driver_class == class) 948a41f4deSParav Pandit return driver; 958a41f4deSParav Pandit } 968a41f4deSParav Pandit return NULL; 978a41f4deSParav Pandit } 988a41f4deSParav Pandit 998a41f4deSParav Pandit static int 1008a41f4deSParav Pandit bus_cmdline_options_handler(__rte_unused const char *key, 1018a41f4deSParav Pandit const char *class_names, void *opaque) 1028a41f4deSParav Pandit { 1038a41f4deSParav Pandit int *ret = opaque; 1048a41f4deSParav Pandit char *nstr_org; 1058a41f4deSParav Pandit int class_val; 1068a41f4deSParav Pandit char *found; 1078a41f4deSParav Pandit char *nstr; 1083475aeacSOphir Munk char *refstr = NULL; 1098a41f4deSParav Pandit 1108a41f4deSParav Pandit *ret = 0; 1118a41f4deSParav Pandit nstr = strdup(class_names); 1128a41f4deSParav Pandit if (!nstr) { 1138a41f4deSParav Pandit *ret = -ENOMEM; 1148a41f4deSParav Pandit return *ret; 1158a41f4deSParav Pandit } 1168a41f4deSParav Pandit nstr_org = nstr; 1173475aeacSOphir Munk found = strtok_r(nstr, ":", &refstr); 1183475aeacSOphir Munk if (!found) 1193475aeacSOphir Munk goto err; 1203475aeacSOphir Munk do { 1218a41f4deSParav Pandit /* Extract each individual class name. Multiple 1228a41f4deSParav Pandit * class key,value is supplied as class=net:vdpa:foo:bar. 1238a41f4deSParav Pandit */ 1248a41f4deSParav Pandit class_val = class_name_to_value(found); 1253475aeacSOphir Munk /* Check if its a valid class. */ 1268a41f4deSParav Pandit if (class_val < 0) { 1278a41f4deSParav Pandit *ret = -EINVAL; 1288a41f4deSParav Pandit goto err; 1298a41f4deSParav Pandit } 1308a41f4deSParav Pandit *ret |= class_val; 1313475aeacSOphir Munk found = strtok_r(NULL, ":", &refstr); 1323475aeacSOphir Munk } while (found); 1338a41f4deSParav Pandit err: 1348a41f4deSParav Pandit free(nstr_org); 1358a41f4deSParav Pandit if (*ret < 0) 1368a41f4deSParav Pandit DRV_LOG(ERR, "Invalid mlx5 class options %s." 1378a41f4deSParav Pandit " Maybe typo in device class argument setting?", 1388a41f4deSParav Pandit class_names); 1398a41f4deSParav Pandit return *ret; 1408a41f4deSParav Pandit } 1418a41f4deSParav Pandit 1428a41f4deSParav Pandit static int 1438a41f4deSParav Pandit parse_class_options(const struct rte_devargs *devargs) 1448a41f4deSParav Pandit { 14535d4f17bSXueming Li const char *key = RTE_DEVARGS_KEY_CLASS; 1468a41f4deSParav Pandit struct rte_kvargs *kvlist; 1478a41f4deSParav Pandit int ret = 0; 1488a41f4deSParav Pandit 1498a41f4deSParav Pandit if (devargs == NULL) 1508a41f4deSParav Pandit return 0; 1518a41f4deSParav Pandit kvlist = rte_kvargs_parse(devargs->args, NULL); 1528a41f4deSParav Pandit if (kvlist == NULL) 1538a41f4deSParav Pandit return 0; 1548a41f4deSParav Pandit if (rte_kvargs_count(kvlist, key)) 1558a41f4deSParav Pandit rte_kvargs_process(kvlist, key, bus_cmdline_options_handler, 1568a41f4deSParav Pandit &ret); 1578a41f4deSParav Pandit rte_kvargs_free(kvlist); 1588a41f4deSParav Pandit return ret; 1598a41f4deSParav Pandit } 1608a41f4deSParav Pandit 1618a41f4deSParav Pandit static bool 1628a41f4deSParav Pandit mlx5_bus_match(const struct mlx5_pci_driver *drv, 1638a41f4deSParav Pandit const struct rte_pci_device *pci_dev) 1648a41f4deSParav Pandit { 1658a41f4deSParav Pandit const struct rte_pci_id *id_table; 1668a41f4deSParav Pandit 1678a41f4deSParav Pandit for (id_table = drv->pci_driver.id_table; id_table->vendor_id != 0; 1688a41f4deSParav Pandit id_table++) { 1698a41f4deSParav Pandit /* Check if device's ids match the class driver's ids. */ 1708a41f4deSParav Pandit if (id_table->vendor_id != pci_dev->id.vendor_id && 1714d509afaSThomas Monjalon id_table->vendor_id != RTE_PCI_ANY_ID) 1728a41f4deSParav Pandit continue; 1738a41f4deSParav Pandit if (id_table->device_id != pci_dev->id.device_id && 1744d509afaSThomas Monjalon id_table->device_id != RTE_PCI_ANY_ID) 1758a41f4deSParav Pandit continue; 1768a41f4deSParav Pandit if (id_table->subsystem_vendor_id != 1778a41f4deSParav Pandit pci_dev->id.subsystem_vendor_id && 1784d509afaSThomas Monjalon id_table->subsystem_vendor_id != RTE_PCI_ANY_ID) 1798a41f4deSParav Pandit continue; 1808a41f4deSParav Pandit if (id_table->subsystem_device_id != 1818a41f4deSParav Pandit pci_dev->id.subsystem_device_id && 1824d509afaSThomas Monjalon id_table->subsystem_device_id != RTE_PCI_ANY_ID) 1838a41f4deSParav Pandit continue; 1848a41f4deSParav Pandit if (id_table->class_id != pci_dev->id.class_id && 1858a41f4deSParav Pandit id_table->class_id != RTE_CLASS_ANY_ID) 1868a41f4deSParav Pandit continue; 1878a41f4deSParav Pandit return true; 1888a41f4deSParav Pandit } 1898a41f4deSParav Pandit return false; 1908a41f4deSParav Pandit } 1918a41f4deSParav Pandit 1928a41f4deSParav Pandit static int 1938a41f4deSParav Pandit is_valid_class_combination(uint32_t user_classes) 1948a41f4deSParav Pandit { 1958a41f4deSParav Pandit unsigned int i; 1968a41f4deSParav Pandit 1978a41f4deSParav Pandit /* Verify if user specified valid supported combination. */ 1988a41f4deSParav Pandit for (i = 0; i < RTE_DIM(mlx5_class_combinations); i++) { 1998a41f4deSParav Pandit if (mlx5_class_combinations[i] == user_classes) 2008a41f4deSParav Pandit return 0; 2018a41f4deSParav Pandit } 2028a41f4deSParav Pandit /* Not found any valid class combination. */ 2038a41f4deSParav Pandit return -EINVAL; 2048a41f4deSParav Pandit } 2058a41f4deSParav Pandit 2068a41f4deSParav Pandit static struct mlx5_pci_device * 2078a41f4deSParav Pandit pci_to_mlx5_device(const struct rte_pci_device *pci_dev) 2088a41f4deSParav Pandit { 2098a41f4deSParav Pandit struct mlx5_pci_device *dev; 2108a41f4deSParav Pandit 2118a41f4deSParav Pandit TAILQ_FOREACH(dev, &devices_list, next) { 2128a41f4deSParav Pandit if (dev->pci_dev == pci_dev) 2138a41f4deSParav Pandit return dev; 2148a41f4deSParav Pandit } 2158a41f4deSParav Pandit return NULL; 2168a41f4deSParav Pandit } 2178a41f4deSParav Pandit 2188a41f4deSParav Pandit static bool 2198a41f4deSParav Pandit device_class_enabled(const struct mlx5_pci_device *device, uint32_t class) 2208a41f4deSParav Pandit { 2218a41f4deSParav Pandit return (device->classes_loaded & class) ? true : false; 2228a41f4deSParav Pandit } 2238a41f4deSParav Pandit 2248a41f4deSParav Pandit static void 2258a41f4deSParav Pandit dev_release(struct mlx5_pci_device *dev) 2268a41f4deSParav Pandit { 2278a41f4deSParav Pandit TAILQ_REMOVE(&devices_list, dev, next); 2288a41f4deSParav Pandit rte_free(dev); 2298a41f4deSParav Pandit } 2308a41f4deSParav Pandit 2318a41f4deSParav Pandit static int 2328a41f4deSParav Pandit drivers_remove(struct mlx5_pci_device *dev, uint32_t enabled_classes) 2338a41f4deSParav Pandit { 2348a41f4deSParav Pandit struct mlx5_pci_driver *driver; 2358a41f4deSParav Pandit int local_ret = -ENODEV; 2368a41f4deSParav Pandit unsigned int i = 0; 2378a41f4deSParav Pandit int ret = 0; 2388a41f4deSParav Pandit 2398a41f4deSParav Pandit enabled_classes &= dev->classes_loaded; 2408a41f4deSParav Pandit while (enabled_classes) { 2418a41f4deSParav Pandit driver = driver_get(RTE_BIT64(i)); 2428a41f4deSParav Pandit if (driver) { 2438a41f4deSParav Pandit local_ret = driver->pci_driver.remove(dev->pci_dev); 2448a41f4deSParav Pandit if (!local_ret) 2458a41f4deSParav Pandit dev->classes_loaded &= ~RTE_BIT64(i); 2468a41f4deSParav Pandit else if (ret == 0) 2478a41f4deSParav Pandit ret = local_ret; 2488a41f4deSParav Pandit } 2498a41f4deSParav Pandit enabled_classes &= ~RTE_BIT64(i); 2508a41f4deSParav Pandit i++; 2518a41f4deSParav Pandit } 2528a41f4deSParav Pandit if (local_ret) 2538a41f4deSParav Pandit ret = local_ret; 2548a41f4deSParav Pandit return ret; 2558a41f4deSParav Pandit } 2568a41f4deSParav Pandit 2578a41f4deSParav Pandit static int 2588a41f4deSParav Pandit drivers_probe(struct mlx5_pci_device *dev, struct rte_pci_driver *pci_drv, 2598a41f4deSParav Pandit struct rte_pci_device *pci_dev, uint32_t user_classes) 2608a41f4deSParav Pandit { 2618a41f4deSParav Pandit struct mlx5_pci_driver *driver; 2628a41f4deSParav Pandit uint32_t enabled_classes = 0; 2638a41f4deSParav Pandit bool already_loaded; 2648a41f4deSParav Pandit int ret; 2658a41f4deSParav Pandit 2668a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 2678a41f4deSParav Pandit if ((driver->driver_class & user_classes) == 0) 2688a41f4deSParav Pandit continue; 2698a41f4deSParav Pandit if (!mlx5_bus_match(driver, pci_dev)) 2708a41f4deSParav Pandit continue; 2718a41f4deSParav Pandit already_loaded = dev->classes_loaded & driver->driver_class; 2728a41f4deSParav Pandit if (already_loaded && 2738a41f4deSParav Pandit !(driver->pci_driver.drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) { 2741b9e9826SThomas Monjalon DRV_LOG(ERR, "Device %s is already probed", 2758a41f4deSParav Pandit pci_dev->device.name); 2768a41f4deSParav Pandit ret = -EEXIST; 2778a41f4deSParav Pandit goto probe_err; 2788a41f4deSParav Pandit } 2798a41f4deSParav Pandit ret = driver->pci_driver.probe(pci_drv, pci_dev); 2808a41f4deSParav Pandit if (ret < 0) { 2811b9e9826SThomas Monjalon DRV_LOG(ERR, "Failed to load driver %s", 2828a41f4deSParav Pandit driver->pci_driver.driver.name); 2838a41f4deSParav Pandit goto probe_err; 2848a41f4deSParav Pandit } 2858a41f4deSParav Pandit enabled_classes |= driver->driver_class; 2868a41f4deSParav Pandit } 2878a41f4deSParav Pandit dev->classes_loaded |= enabled_classes; 2888a41f4deSParav Pandit return 0; 2898a41f4deSParav Pandit probe_err: 2908a41f4deSParav Pandit /* Only unload drivers which are enabled which were enabled 2918a41f4deSParav Pandit * in this probe instance. 2928a41f4deSParav Pandit */ 2938a41f4deSParav Pandit drivers_remove(dev, enabled_classes); 2948a41f4deSParav Pandit return ret; 2958a41f4deSParav Pandit } 2968a41f4deSParav Pandit 2978a41f4deSParav Pandit /** 2988a41f4deSParav Pandit * DPDK callback to register to probe multiple drivers for a PCI device. 2998a41f4deSParav Pandit * 3008a41f4deSParav Pandit * @param[in] pci_drv 3018a41f4deSParav Pandit * PCI driver structure. 3028a41f4deSParav Pandit * @param[in] dev 3038a41f4deSParav Pandit * PCI device information. 3048a41f4deSParav Pandit * 3058a41f4deSParav Pandit * @return 3068a41f4deSParav Pandit * 0 on success, a negative errno value otherwise and rte_errno is set. 3078a41f4deSParav Pandit */ 3088a41f4deSParav Pandit static int 309*ad435d32SXueming Li mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 3108a41f4deSParav Pandit struct rte_pci_device *pci_dev) 3118a41f4deSParav Pandit { 3128a41f4deSParav Pandit struct mlx5_pci_device *dev; 3138a41f4deSParav Pandit uint32_t user_classes = 0; 3148a41f4deSParav Pandit bool new_device = false; 3158a41f4deSParav Pandit int ret; 3168a41f4deSParav Pandit 3178a41f4deSParav Pandit ret = parse_class_options(pci_dev->device.devargs); 3188a41f4deSParav Pandit if (ret < 0) 3198a41f4deSParav Pandit return ret; 3208a41f4deSParav Pandit user_classes = ret; 3218a41f4deSParav Pandit if (user_classes) { 3228a41f4deSParav Pandit /* Validate combination here. */ 3238a41f4deSParav Pandit ret = is_valid_class_combination(user_classes); 3248a41f4deSParav Pandit if (ret) { 3258a41f4deSParav Pandit DRV_LOG(ERR, "Unsupported mlx5 classes supplied."); 3268a41f4deSParav Pandit return ret; 3278a41f4deSParav Pandit } 3288a41f4deSParav Pandit } else { 3298a41f4deSParav Pandit /* Default to net class. */ 330a99f2f90SXueming Li user_classes = MLX5_CLASS_ETH; 3318a41f4deSParav Pandit } 3328a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 3338a41f4deSParav Pandit if (!dev) { 3348a41f4deSParav Pandit dev = rte_zmalloc("mlx5_pci_device", sizeof(*dev), 0); 3358a41f4deSParav Pandit if (!dev) 3368a41f4deSParav Pandit return -ENOMEM; 3378a41f4deSParav Pandit dev->pci_dev = pci_dev; 3388a41f4deSParav Pandit TAILQ_INSERT_HEAD(&devices_list, dev, next); 3398a41f4deSParav Pandit new_device = true; 3408a41f4deSParav Pandit } 3418a41f4deSParav Pandit ret = drivers_probe(dev, pci_drv, pci_dev, user_classes); 3428a41f4deSParav Pandit if (ret) 3438a41f4deSParav Pandit goto class_err; 3448a41f4deSParav Pandit return 0; 3458a41f4deSParav Pandit class_err: 3468a41f4deSParav Pandit if (new_device) 3478a41f4deSParav Pandit dev_release(dev); 3488a41f4deSParav Pandit return ret; 3498a41f4deSParav Pandit } 3508a41f4deSParav Pandit 3518a41f4deSParav Pandit /** 3528a41f4deSParav Pandit * DPDK callback to remove one or more drivers for a PCI device. 3538a41f4deSParav Pandit * 3548a41f4deSParav Pandit * This function removes all drivers probed for a given PCI device. 3558a41f4deSParav Pandit * 3568a41f4deSParav Pandit * @param[in] pci_dev 3578a41f4deSParav Pandit * Pointer to the PCI device. 3588a41f4deSParav Pandit * 3598a41f4deSParav Pandit * @return 3608a41f4deSParav Pandit * 0 on success, the function cannot fail. 3618a41f4deSParav Pandit */ 3628a41f4deSParav Pandit static int 363*ad435d32SXueming Li mlx5_pci_remove(struct rte_pci_device *pci_dev) 3648a41f4deSParav Pandit { 3658a41f4deSParav Pandit struct mlx5_pci_device *dev; 3668a41f4deSParav Pandit int ret; 3678a41f4deSParav Pandit 3688a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 3698a41f4deSParav Pandit if (!dev) 3708a41f4deSParav Pandit return -ENODEV; 3718a41f4deSParav Pandit /* Matching device found, cleanup and unload drivers. */ 3728a41f4deSParav Pandit ret = drivers_remove(dev, dev->classes_loaded); 3738a41f4deSParav Pandit if (!ret) 3748a41f4deSParav Pandit dev_release(dev); 3758a41f4deSParav Pandit return ret; 3768a41f4deSParav Pandit } 3778a41f4deSParav Pandit 3788a41f4deSParav Pandit static int 379*ad435d32SXueming Li mlx5_pci_dma_map(struct rte_pci_device *pci_dev, void *addr, 3808a41f4deSParav Pandit uint64_t iova, size_t len) 3818a41f4deSParav Pandit { 3828a41f4deSParav Pandit struct mlx5_pci_driver *driver = NULL; 3838a41f4deSParav Pandit struct mlx5_pci_driver *temp; 3848a41f4deSParav Pandit struct mlx5_pci_device *dev; 3858a41f4deSParav Pandit int ret = -EINVAL; 3868a41f4deSParav Pandit 3878a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 3888a41f4deSParav Pandit if (!dev) 3898a41f4deSParav Pandit return -ENODEV; 3908a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 3918a41f4deSParav Pandit if (device_class_enabled(dev, driver->driver_class) && 3928a41f4deSParav Pandit driver->pci_driver.dma_map) { 3938a41f4deSParav Pandit ret = driver->pci_driver.dma_map(pci_dev, addr, 3948a41f4deSParav Pandit iova, len); 3958a41f4deSParav Pandit if (ret) 3968a41f4deSParav Pandit goto map_err; 3978a41f4deSParav Pandit } 3988a41f4deSParav Pandit } 3998a41f4deSParav Pandit return ret; 4008a41f4deSParav Pandit map_err: 4018a41f4deSParav Pandit TAILQ_FOREACH(temp, &drv_list, next) { 4028a41f4deSParav Pandit if (temp == driver) 4038a41f4deSParav Pandit break; 4048a41f4deSParav Pandit if (device_class_enabled(dev, temp->driver_class) && 4058a41f4deSParav Pandit temp->pci_driver.dma_map && temp->pci_driver.dma_unmap) 4068a41f4deSParav Pandit temp->pci_driver.dma_unmap(pci_dev, addr, iova, len); 4078a41f4deSParav Pandit } 4088a41f4deSParav Pandit return ret; 4098a41f4deSParav Pandit } 4108a41f4deSParav Pandit 4118a41f4deSParav Pandit static int 412*ad435d32SXueming Li mlx5_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr, 4138a41f4deSParav Pandit uint64_t iova, size_t len) 4148a41f4deSParav Pandit { 4158a41f4deSParav Pandit struct mlx5_pci_driver *driver; 4168a41f4deSParav Pandit struct mlx5_pci_device *dev; 4178a41f4deSParav Pandit int local_ret = -EINVAL; 4188a41f4deSParav Pandit int ret; 4198a41f4deSParav Pandit 4208a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 4218a41f4deSParav Pandit if (!dev) 4228a41f4deSParav Pandit return -ENODEV; 4238a41f4deSParav Pandit ret = 0; 4248a41f4deSParav Pandit /* There is no unmap error recovery in current implementation. */ 4258a41f4deSParav Pandit TAILQ_FOREACH_REVERSE(driver, &drv_list, mlx5_pci_bus_drv_head, next) { 4268a41f4deSParav Pandit if (device_class_enabled(dev, driver->driver_class) && 4278a41f4deSParav Pandit driver->pci_driver.dma_unmap) { 4288a41f4deSParav Pandit local_ret = driver->pci_driver.dma_unmap(pci_dev, addr, 4298a41f4deSParav Pandit iova, len); 4308a41f4deSParav Pandit if (local_ret && (ret == 0)) 4318a41f4deSParav Pandit ret = local_ret; 4328a41f4deSParav Pandit } 4338a41f4deSParav Pandit } 4348a41f4deSParav Pandit if (local_ret) 4358a41f4deSParav Pandit ret = local_ret; 4368a41f4deSParav Pandit return ret; 4378a41f4deSParav Pandit } 4388a41f4deSParav Pandit 4398a41f4deSParav Pandit /* PCI ID table is build dynamically based on registered mlx5 drivers. */ 4408a41f4deSParav Pandit static struct rte_pci_id *mlx5_pci_id_table; 4418a41f4deSParav Pandit 4428a41f4deSParav Pandit static struct rte_pci_driver mlx5_pci_driver = { 4438a41f4deSParav Pandit .driver = { 444188773a2SAsaf Penso .name = MLX5_PCI_DRIVER_NAME, 4458a41f4deSParav Pandit }, 446*ad435d32SXueming Li .probe = mlx5_pci_probe, 447*ad435d32SXueming Li .remove = mlx5_pci_remove, 448*ad435d32SXueming Li .dma_map = mlx5_pci_dma_map, 449*ad435d32SXueming Li .dma_unmap = mlx5_pci_dma_unmap, 4508a41f4deSParav Pandit }; 4518a41f4deSParav Pandit 4528a41f4deSParav Pandit static int 4538a41f4deSParav Pandit pci_id_table_size_get(const struct rte_pci_id *id_table) 4548a41f4deSParav Pandit { 4558a41f4deSParav Pandit int table_size = 0; 4568a41f4deSParav Pandit 4578a41f4deSParav Pandit for (; id_table->vendor_id != 0; id_table++) 4588a41f4deSParav Pandit table_size++; 4598a41f4deSParav Pandit return table_size; 4608a41f4deSParav Pandit } 4618a41f4deSParav Pandit 4628a41f4deSParav Pandit static bool 4638a41f4deSParav Pandit pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table, 4648a41f4deSParav Pandit int next_idx) 4658a41f4deSParav Pandit { 4668a41f4deSParav Pandit int current_size = next_idx - 1; 4678a41f4deSParav Pandit int i; 4688a41f4deSParav Pandit 4698a41f4deSParav Pandit for (i = 0; i < current_size; i++) { 4708a41f4deSParav Pandit if (id->device_id == table[i].device_id && 4718a41f4deSParav Pandit id->vendor_id == table[i].vendor_id && 4728a41f4deSParav Pandit id->subsystem_vendor_id == table[i].subsystem_vendor_id && 4738a41f4deSParav Pandit id->subsystem_device_id == table[i].subsystem_device_id) 4748a41f4deSParav Pandit return true; 4758a41f4deSParav Pandit } 4768a41f4deSParav Pandit return false; 4778a41f4deSParav Pandit } 4788a41f4deSParav Pandit 4798a41f4deSParav Pandit static void 4808a41f4deSParav Pandit pci_id_insert(struct rte_pci_id *new_table, int *next_idx, 4818a41f4deSParav Pandit const struct rte_pci_id *id_table) 4828a41f4deSParav Pandit { 4838a41f4deSParav Pandit /* Traverse the id_table, check if entry exists in new_table; 4848a41f4deSParav Pandit * Add non duplicate entries to new table. 4858a41f4deSParav Pandit */ 4868a41f4deSParav Pandit for (; id_table->vendor_id != 0; id_table++) { 4878a41f4deSParav Pandit if (!pci_id_exists(id_table, new_table, *next_idx)) { 4888a41f4deSParav Pandit /* New entry; add to the table. */ 4898a41f4deSParav Pandit new_table[*next_idx] = *id_table; 4908a41f4deSParav Pandit (*next_idx)++; 4918a41f4deSParav Pandit } 4928a41f4deSParav Pandit } 4938a41f4deSParav Pandit } 4948a41f4deSParav Pandit 4958a41f4deSParav Pandit static int 4968a41f4deSParav Pandit pci_ids_table_update(const struct rte_pci_id *driver_id_table) 4978a41f4deSParav Pandit { 4988a41f4deSParav Pandit const struct rte_pci_id *id_iter; 4998a41f4deSParav Pandit struct rte_pci_id *updated_table; 5008a41f4deSParav Pandit struct rte_pci_id *old_table; 5018a41f4deSParav Pandit int num_ids = 0; 5028a41f4deSParav Pandit int i = 0; 5038a41f4deSParav Pandit 5048a41f4deSParav Pandit old_table = mlx5_pci_id_table; 5058a41f4deSParav Pandit if (old_table) 5068a41f4deSParav Pandit num_ids = pci_id_table_size_get(old_table); 5078a41f4deSParav Pandit num_ids += pci_id_table_size_get(driver_id_table); 5088a41f4deSParav Pandit /* Increase size by one for the termination entry of vendor_id = 0. */ 5098a41f4deSParav Pandit num_ids += 1; 5108a41f4deSParav Pandit updated_table = calloc(num_ids, sizeof(*updated_table)); 5118a41f4deSParav Pandit if (!updated_table) 5128a41f4deSParav Pandit return -ENOMEM; 513*ad435d32SXueming Li if (old_table == NULL) { 5148a41f4deSParav Pandit /* Copy the first driver's ID table. */ 5158a41f4deSParav Pandit for (id_iter = driver_id_table; id_iter->vendor_id != 0; 5168a41f4deSParav Pandit id_iter++, i++) 5178a41f4deSParav Pandit updated_table[i] = *id_iter; 5188a41f4deSParav Pandit } else { 5198a41f4deSParav Pandit /* First copy existing table entries. */ 5208a41f4deSParav Pandit for (id_iter = old_table; id_iter->vendor_id != 0; 5218a41f4deSParav Pandit id_iter++, i++) 5228a41f4deSParav Pandit updated_table[i] = *id_iter; 5238a41f4deSParav Pandit /* New id to be added at the end of current ID table. */ 5248a41f4deSParav Pandit pci_id_insert(updated_table, &i, driver_id_table); 5258a41f4deSParav Pandit } 5268a41f4deSParav Pandit /* Terminate table with empty entry. */ 5278a41f4deSParav Pandit updated_table[i].vendor_id = 0; 5288a41f4deSParav Pandit mlx5_pci_driver.id_table = updated_table; 529*ad435d32SXueming Li mlx5_common_pci_driver.id_table = updated_table; 5308a41f4deSParav Pandit mlx5_pci_id_table = updated_table; 5318a41f4deSParav Pandit if (old_table) 5328a41f4deSParav Pandit free(old_table); 5338a41f4deSParav Pandit return 0; 5348a41f4deSParav Pandit } 5358a41f4deSParav Pandit 5368a41f4deSParav Pandit void 5378a41f4deSParav Pandit mlx5_pci_driver_register(struct mlx5_pci_driver *driver) 5388a41f4deSParav Pandit { 5398a41f4deSParav Pandit int ret; 5408a41f4deSParav Pandit 5418a41f4deSParav Pandit ret = pci_ids_table_update(driver->pci_driver.id_table); 5428a41f4deSParav Pandit if (ret) 5438a41f4deSParav Pandit return; 5448a41f4deSParav Pandit mlx5_pci_driver.drv_flags |= driver->pci_driver.drv_flags; 5458a41f4deSParav Pandit TAILQ_INSERT_TAIL(&drv_list, driver, next); 5468a41f4deSParav Pandit } 5478a41f4deSParav Pandit 548*ad435d32SXueming Li /********** New common PCI bus driver ********/ 549*ad435d32SXueming Li 550*ad435d32SXueming Li bool 551*ad435d32SXueming Li mlx5_dev_is_pci(const struct rte_device *dev) 552*ad435d32SXueming Li { 553*ad435d32SXueming Li return strcmp(dev->bus->name, "pci") == 0; 554*ad435d32SXueming Li } 555*ad435d32SXueming Li 556*ad435d32SXueming Li bool 557*ad435d32SXueming Li mlx5_dev_pci_match(const struct mlx5_class_driver *drv, 558*ad435d32SXueming Li const struct rte_device *dev) 559*ad435d32SXueming Li { 560*ad435d32SXueming Li const struct rte_pci_device *pci_dev; 561*ad435d32SXueming Li const struct rte_pci_id *id_table; 562*ad435d32SXueming Li 563*ad435d32SXueming Li if (!mlx5_dev_is_pci(dev)) 564*ad435d32SXueming Li return false; 565*ad435d32SXueming Li pci_dev = RTE_DEV_TO_PCI_CONST(dev); 566*ad435d32SXueming Li for (id_table = drv->id_table; id_table->vendor_id != 0; 567*ad435d32SXueming Li id_table++) { 568*ad435d32SXueming Li /* Check if device's ids match the class driver's ids. */ 569*ad435d32SXueming Li if (id_table->vendor_id != pci_dev->id.vendor_id && 570*ad435d32SXueming Li id_table->vendor_id != RTE_PCI_ANY_ID) 571*ad435d32SXueming Li continue; 572*ad435d32SXueming Li if (id_table->device_id != pci_dev->id.device_id && 573*ad435d32SXueming Li id_table->device_id != RTE_PCI_ANY_ID) 574*ad435d32SXueming Li continue; 575*ad435d32SXueming Li if (id_table->subsystem_vendor_id != 576*ad435d32SXueming Li pci_dev->id.subsystem_vendor_id && 577*ad435d32SXueming Li id_table->subsystem_vendor_id != RTE_PCI_ANY_ID) 578*ad435d32SXueming Li continue; 579*ad435d32SXueming Li if (id_table->subsystem_device_id != 580*ad435d32SXueming Li pci_dev->id.subsystem_device_id && 581*ad435d32SXueming Li id_table->subsystem_device_id != RTE_PCI_ANY_ID) 582*ad435d32SXueming Li continue; 583*ad435d32SXueming Li if (id_table->class_id != pci_dev->id.class_id && 584*ad435d32SXueming Li id_table->class_id != RTE_CLASS_ANY_ID) 585*ad435d32SXueming Li continue; 586*ad435d32SXueming Li return true; 587*ad435d32SXueming Li } 588*ad435d32SXueming Li return false; 589*ad435d32SXueming Li } 590*ad435d32SXueming Li 591*ad435d32SXueming Li static int 592*ad435d32SXueming Li mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 593*ad435d32SXueming Li struct rte_pci_device *pci_dev) 594*ad435d32SXueming Li { 595*ad435d32SXueming Li return mlx5_common_dev_probe(&pci_dev->device); 596*ad435d32SXueming Li } 597*ad435d32SXueming Li 598*ad435d32SXueming Li static int 599*ad435d32SXueming Li mlx5_common_pci_remove(struct rte_pci_device *pci_dev) 600*ad435d32SXueming Li { 601*ad435d32SXueming Li return mlx5_common_dev_remove(&pci_dev->device); 602*ad435d32SXueming Li } 603*ad435d32SXueming Li 604*ad435d32SXueming Li static int 605*ad435d32SXueming Li mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr, 606*ad435d32SXueming Li uint64_t iova, size_t len) 607*ad435d32SXueming Li { 608*ad435d32SXueming Li return mlx5_common_dev_dma_map(&pci_dev->device, addr, iova, len); 609*ad435d32SXueming Li } 610*ad435d32SXueming Li 611*ad435d32SXueming Li static int 612*ad435d32SXueming Li mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr, 613*ad435d32SXueming Li uint64_t iova, size_t len) 614*ad435d32SXueming Li { 615*ad435d32SXueming Li return mlx5_common_dev_dma_unmap(&pci_dev->device, addr, iova, len); 616*ad435d32SXueming Li } 617*ad435d32SXueming Li 618*ad435d32SXueming Li void 619*ad435d32SXueming Li mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver) 620*ad435d32SXueming Li { 621*ad435d32SXueming Li if (driver->id_table != NULL) { 622*ad435d32SXueming Li if (pci_ids_table_update(driver->id_table) != 0) 623*ad435d32SXueming Li return; 624*ad435d32SXueming Li } 625*ad435d32SXueming Li if (driver->probe_again) 626*ad435d32SXueming Li mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_PROBE_AGAIN; 627*ad435d32SXueming Li if (driver->intr_lsc) 628*ad435d32SXueming Li mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC; 629*ad435d32SXueming Li if (driver->intr_rmv) 630*ad435d32SXueming Li mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV; 631*ad435d32SXueming Li } 632*ad435d32SXueming Li 633*ad435d32SXueming Li static struct rte_pci_driver mlx5_common_pci_driver = { 634*ad435d32SXueming Li .driver = { 635*ad435d32SXueming Li .name = MLX5_PCI_DRIVER_NAME, 636*ad435d32SXueming Li }, 637*ad435d32SXueming Li .probe = mlx5_common_pci_probe, 638*ad435d32SXueming Li .remove = mlx5_common_pci_remove, 639*ad435d32SXueming Li .dma_map = mlx5_common_pci_dma_map, 640*ad435d32SXueming Li .dma_unmap = mlx5_common_pci_dma_unmap, 641*ad435d32SXueming Li }; 642*ad435d32SXueming Li 6438a41f4deSParav Pandit void mlx5_common_pci_init(void) 6448a41f4deSParav Pandit { 6458a41f4deSParav Pandit const struct rte_pci_id empty_table[] = { 6468a41f4deSParav Pandit { 6478a41f4deSParav Pandit .vendor_id = 0 6488a41f4deSParav Pandit }, 6498a41f4deSParav Pandit }; 6508a41f4deSParav Pandit 6518a41f4deSParav Pandit /* All mlx5 PMDs constructor runs at same priority. So any of the PMD 6528a41f4deSParav Pandit * including this one can register the PCI table first. If any other 6538a41f4deSParav Pandit * PMD(s) have registered the PCI ID table, No need to register an empty 6548a41f4deSParav Pandit * default one. 6558a41f4deSParav Pandit */ 6568a41f4deSParav Pandit if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table)) 6578a41f4deSParav Pandit return; 658*ad435d32SXueming Li rte_pci_register(&mlx5_common_pci_driver); 6598a41f4deSParav Pandit } 6608a41f4deSParav Pandit 6618a41f4deSParav Pandit RTE_FINI(mlx5_common_pci_finish) 6628a41f4deSParav Pandit { 6638a41f4deSParav Pandit if (mlx5_pci_id_table != NULL) { 6648a41f4deSParav Pandit /* Constructor doesn't register with PCI bus if it failed 6658a41f4deSParav Pandit * to build the table. 6668a41f4deSParav Pandit */ 667*ad435d32SXueming Li rte_pci_unregister(&mlx5_common_pci_driver); 6688a41f4deSParav Pandit free(mlx5_pci_id_table); 6698a41f4deSParav Pandit } 6708a41f4deSParav Pandit } 671*ad435d32SXueming Li 6728a41f4deSParav Pandit RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__); 673