1*8a41f4deSParav Pandit /* SPDX-License-Identifier: BSD-3-Clause 2*8a41f4deSParav Pandit * Copyright 2020 Mellanox Technologies Ltd 3*8a41f4deSParav Pandit */ 4*8a41f4deSParav Pandit 5*8a41f4deSParav Pandit #include <stdlib.h> 6*8a41f4deSParav Pandit #include <rte_malloc.h> 7*8a41f4deSParav Pandit #include "mlx5_common_utils.h" 8*8a41f4deSParav Pandit #include "mlx5_common_pci.h" 9*8a41f4deSParav Pandit 10*8a41f4deSParav Pandit struct mlx5_pci_device { 11*8a41f4deSParav Pandit struct rte_pci_device *pci_dev; 12*8a41f4deSParav Pandit TAILQ_ENTRY(mlx5_pci_device) next; 13*8a41f4deSParav Pandit uint32_t classes_loaded; 14*8a41f4deSParav Pandit }; 15*8a41f4deSParav Pandit 16*8a41f4deSParav Pandit /* Head of list of drivers. */ 17*8a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_bus_drv_head, mlx5_pci_driver) drv_list = 18*8a41f4deSParav Pandit TAILQ_HEAD_INITIALIZER(drv_list); 19*8a41f4deSParav Pandit 20*8a41f4deSParav Pandit /* Head of mlx5 pci devices. */ 21*8a41f4deSParav Pandit static TAILQ_HEAD(mlx5_pci_devices_head, mlx5_pci_device) devices_list = 22*8a41f4deSParav Pandit TAILQ_HEAD_INITIALIZER(devices_list); 23*8a41f4deSParav Pandit 24*8a41f4deSParav Pandit static const struct { 25*8a41f4deSParav Pandit const char *name; 26*8a41f4deSParav Pandit unsigned int driver_class; 27*8a41f4deSParav Pandit } mlx5_classes[] = { 28*8a41f4deSParav Pandit { .name = "vdpa", .driver_class = MLX5_CLASS_VDPA }, 29*8a41f4deSParav Pandit { .name = "net", .driver_class = MLX5_CLASS_NET }, 30*8a41f4deSParav Pandit { .name = "regex", .driver_class = MLX5_CLASS_REGEX }, 31*8a41f4deSParav Pandit }; 32*8a41f4deSParav Pandit 33*8a41f4deSParav Pandit static const unsigned int mlx5_class_combinations[] = { 34*8a41f4deSParav Pandit MLX5_CLASS_NET, 35*8a41f4deSParav Pandit MLX5_CLASS_VDPA, 36*8a41f4deSParav Pandit MLX5_CLASS_REGEX, 37*8a41f4deSParav Pandit MLX5_CLASS_NET | MLX5_CLASS_REGEX, 38*8a41f4deSParav Pandit MLX5_CLASS_VDPA | MLX5_CLASS_REGEX, 39*8a41f4deSParav Pandit /* New class combination should be added here. */ 40*8a41f4deSParav Pandit }; 41*8a41f4deSParav Pandit 42*8a41f4deSParav Pandit static int 43*8a41f4deSParav Pandit class_name_to_value(const char *class_name) 44*8a41f4deSParav Pandit { 45*8a41f4deSParav Pandit unsigned int i; 46*8a41f4deSParav Pandit 47*8a41f4deSParav Pandit for (i = 0; i < RTE_DIM(mlx5_classes); i++) { 48*8a41f4deSParav Pandit if (strcmp(class_name, mlx5_classes[i].name) == 0) 49*8a41f4deSParav Pandit return mlx5_classes[i].driver_class; 50*8a41f4deSParav Pandit } 51*8a41f4deSParav Pandit return -EINVAL; 52*8a41f4deSParav Pandit } 53*8a41f4deSParav Pandit 54*8a41f4deSParav Pandit static struct mlx5_pci_driver * 55*8a41f4deSParav Pandit driver_get(uint32_t class) 56*8a41f4deSParav Pandit { 57*8a41f4deSParav Pandit struct mlx5_pci_driver *driver; 58*8a41f4deSParav Pandit 59*8a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 60*8a41f4deSParav Pandit if (driver->driver_class == class) 61*8a41f4deSParav Pandit return driver; 62*8a41f4deSParav Pandit } 63*8a41f4deSParav Pandit return NULL; 64*8a41f4deSParav Pandit } 65*8a41f4deSParav Pandit 66*8a41f4deSParav Pandit static int 67*8a41f4deSParav Pandit bus_cmdline_options_handler(__rte_unused const char *key, 68*8a41f4deSParav Pandit const char *class_names, void *opaque) 69*8a41f4deSParav Pandit { 70*8a41f4deSParav Pandit int *ret = opaque; 71*8a41f4deSParav Pandit char *nstr_org; 72*8a41f4deSParav Pandit int class_val; 73*8a41f4deSParav Pandit char *found; 74*8a41f4deSParav Pandit char *nstr; 75*8a41f4deSParav Pandit 76*8a41f4deSParav Pandit *ret = 0; 77*8a41f4deSParav Pandit nstr = strdup(class_names); 78*8a41f4deSParav Pandit if (!nstr) { 79*8a41f4deSParav Pandit *ret = -ENOMEM; 80*8a41f4deSParav Pandit return *ret; 81*8a41f4deSParav Pandit } 82*8a41f4deSParav Pandit nstr_org = nstr; 83*8a41f4deSParav Pandit while (nstr) { 84*8a41f4deSParav Pandit /* Extract each individual class name. Multiple 85*8a41f4deSParav Pandit * class key,value is supplied as class=net:vdpa:foo:bar. 86*8a41f4deSParav Pandit */ 87*8a41f4deSParav Pandit found = strsep(&nstr, ":"); 88*8a41f4deSParav Pandit if (!found) 89*8a41f4deSParav Pandit continue; 90*8a41f4deSParav Pandit /* Check if its a valid class. */ 91*8a41f4deSParav Pandit class_val = class_name_to_value(found); 92*8a41f4deSParav Pandit if (class_val < 0) { 93*8a41f4deSParav Pandit *ret = -EINVAL; 94*8a41f4deSParav Pandit goto err; 95*8a41f4deSParav Pandit } 96*8a41f4deSParav Pandit *ret |= class_val; 97*8a41f4deSParav Pandit } 98*8a41f4deSParav Pandit err: 99*8a41f4deSParav Pandit free(nstr_org); 100*8a41f4deSParav Pandit if (*ret < 0) 101*8a41f4deSParav Pandit DRV_LOG(ERR, "Invalid mlx5 class options %s." 102*8a41f4deSParav Pandit " Maybe typo in device class argument setting?", 103*8a41f4deSParav Pandit class_names); 104*8a41f4deSParav Pandit return *ret; 105*8a41f4deSParav Pandit } 106*8a41f4deSParav Pandit 107*8a41f4deSParav Pandit static int 108*8a41f4deSParav Pandit parse_class_options(const struct rte_devargs *devargs) 109*8a41f4deSParav Pandit { 110*8a41f4deSParav Pandit const char *key = MLX5_CLASS_ARG_NAME; 111*8a41f4deSParav Pandit struct rte_kvargs *kvlist; 112*8a41f4deSParav Pandit int ret = 0; 113*8a41f4deSParav Pandit 114*8a41f4deSParav Pandit if (devargs == NULL) 115*8a41f4deSParav Pandit return 0; 116*8a41f4deSParav Pandit kvlist = rte_kvargs_parse(devargs->args, NULL); 117*8a41f4deSParav Pandit if (kvlist == NULL) 118*8a41f4deSParav Pandit return 0; 119*8a41f4deSParav Pandit if (rte_kvargs_count(kvlist, key)) 120*8a41f4deSParav Pandit rte_kvargs_process(kvlist, key, bus_cmdline_options_handler, 121*8a41f4deSParav Pandit &ret); 122*8a41f4deSParav Pandit rte_kvargs_free(kvlist); 123*8a41f4deSParav Pandit return ret; 124*8a41f4deSParav Pandit } 125*8a41f4deSParav Pandit 126*8a41f4deSParav Pandit static bool 127*8a41f4deSParav Pandit mlx5_bus_match(const struct mlx5_pci_driver *drv, 128*8a41f4deSParav Pandit const struct rte_pci_device *pci_dev) 129*8a41f4deSParav Pandit { 130*8a41f4deSParav Pandit const struct rte_pci_id *id_table; 131*8a41f4deSParav Pandit 132*8a41f4deSParav Pandit for (id_table = drv->pci_driver.id_table; id_table->vendor_id != 0; 133*8a41f4deSParav Pandit id_table++) { 134*8a41f4deSParav Pandit /* Check if device's ids match the class driver's ids. */ 135*8a41f4deSParav Pandit if (id_table->vendor_id != pci_dev->id.vendor_id && 136*8a41f4deSParav Pandit id_table->vendor_id != PCI_ANY_ID) 137*8a41f4deSParav Pandit continue; 138*8a41f4deSParav Pandit if (id_table->device_id != pci_dev->id.device_id && 139*8a41f4deSParav Pandit id_table->device_id != PCI_ANY_ID) 140*8a41f4deSParav Pandit continue; 141*8a41f4deSParav Pandit if (id_table->subsystem_vendor_id != 142*8a41f4deSParav Pandit pci_dev->id.subsystem_vendor_id && 143*8a41f4deSParav Pandit id_table->subsystem_vendor_id != PCI_ANY_ID) 144*8a41f4deSParav Pandit continue; 145*8a41f4deSParav Pandit if (id_table->subsystem_device_id != 146*8a41f4deSParav Pandit pci_dev->id.subsystem_device_id && 147*8a41f4deSParav Pandit id_table->subsystem_device_id != PCI_ANY_ID) 148*8a41f4deSParav Pandit continue; 149*8a41f4deSParav Pandit if (id_table->class_id != pci_dev->id.class_id && 150*8a41f4deSParav Pandit id_table->class_id != RTE_CLASS_ANY_ID) 151*8a41f4deSParav Pandit continue; 152*8a41f4deSParav Pandit return true; 153*8a41f4deSParav Pandit } 154*8a41f4deSParav Pandit return false; 155*8a41f4deSParav Pandit } 156*8a41f4deSParav Pandit 157*8a41f4deSParav Pandit static int 158*8a41f4deSParav Pandit is_valid_class_combination(uint32_t user_classes) 159*8a41f4deSParav Pandit { 160*8a41f4deSParav Pandit unsigned int i; 161*8a41f4deSParav Pandit 162*8a41f4deSParav Pandit /* Verify if user specified valid supported combination. */ 163*8a41f4deSParav Pandit for (i = 0; i < RTE_DIM(mlx5_class_combinations); i++) { 164*8a41f4deSParav Pandit if (mlx5_class_combinations[i] == user_classes) 165*8a41f4deSParav Pandit return 0; 166*8a41f4deSParav Pandit } 167*8a41f4deSParav Pandit /* Not found any valid class combination. */ 168*8a41f4deSParav Pandit return -EINVAL; 169*8a41f4deSParav Pandit } 170*8a41f4deSParav Pandit 171*8a41f4deSParav Pandit static struct mlx5_pci_device * 172*8a41f4deSParav Pandit pci_to_mlx5_device(const struct rte_pci_device *pci_dev) 173*8a41f4deSParav Pandit { 174*8a41f4deSParav Pandit struct mlx5_pci_device *dev; 175*8a41f4deSParav Pandit 176*8a41f4deSParav Pandit TAILQ_FOREACH(dev, &devices_list, next) { 177*8a41f4deSParav Pandit if (dev->pci_dev == pci_dev) 178*8a41f4deSParav Pandit return dev; 179*8a41f4deSParav Pandit } 180*8a41f4deSParav Pandit return NULL; 181*8a41f4deSParav Pandit } 182*8a41f4deSParav Pandit 183*8a41f4deSParav Pandit static bool 184*8a41f4deSParav Pandit device_class_enabled(const struct mlx5_pci_device *device, uint32_t class) 185*8a41f4deSParav Pandit { 186*8a41f4deSParav Pandit return (device->classes_loaded & class) ? true : false; 187*8a41f4deSParav Pandit } 188*8a41f4deSParav Pandit 189*8a41f4deSParav Pandit static void 190*8a41f4deSParav Pandit dev_release(struct mlx5_pci_device *dev) 191*8a41f4deSParav Pandit { 192*8a41f4deSParav Pandit TAILQ_REMOVE(&devices_list, dev, next); 193*8a41f4deSParav Pandit rte_free(dev); 194*8a41f4deSParav Pandit } 195*8a41f4deSParav Pandit 196*8a41f4deSParav Pandit static int 197*8a41f4deSParav Pandit drivers_remove(struct mlx5_pci_device *dev, uint32_t enabled_classes) 198*8a41f4deSParav Pandit { 199*8a41f4deSParav Pandit struct mlx5_pci_driver *driver; 200*8a41f4deSParav Pandit int local_ret = -ENODEV; 201*8a41f4deSParav Pandit unsigned int i = 0; 202*8a41f4deSParav Pandit int ret = 0; 203*8a41f4deSParav Pandit 204*8a41f4deSParav Pandit enabled_classes &= dev->classes_loaded; 205*8a41f4deSParav Pandit while (enabled_classes) { 206*8a41f4deSParav Pandit driver = driver_get(RTE_BIT64(i)); 207*8a41f4deSParav Pandit if (driver) { 208*8a41f4deSParav Pandit local_ret = driver->pci_driver.remove(dev->pci_dev); 209*8a41f4deSParav Pandit if (!local_ret) 210*8a41f4deSParav Pandit dev->classes_loaded &= ~RTE_BIT64(i); 211*8a41f4deSParav Pandit else if (ret == 0) 212*8a41f4deSParav Pandit ret = local_ret; 213*8a41f4deSParav Pandit } 214*8a41f4deSParav Pandit enabled_classes &= ~RTE_BIT64(i); 215*8a41f4deSParav Pandit i++; 216*8a41f4deSParav Pandit } 217*8a41f4deSParav Pandit if (local_ret) 218*8a41f4deSParav Pandit ret = local_ret; 219*8a41f4deSParav Pandit return ret; 220*8a41f4deSParav Pandit } 221*8a41f4deSParav Pandit 222*8a41f4deSParav Pandit static int 223*8a41f4deSParav Pandit drivers_probe(struct mlx5_pci_device *dev, struct rte_pci_driver *pci_drv, 224*8a41f4deSParav Pandit struct rte_pci_device *pci_dev, uint32_t user_classes) 225*8a41f4deSParav Pandit { 226*8a41f4deSParav Pandit struct mlx5_pci_driver *driver; 227*8a41f4deSParav Pandit uint32_t enabled_classes = 0; 228*8a41f4deSParav Pandit bool already_loaded; 229*8a41f4deSParav Pandit int ret; 230*8a41f4deSParav Pandit 231*8a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 232*8a41f4deSParav Pandit if ((driver->driver_class & user_classes) == 0) 233*8a41f4deSParav Pandit continue; 234*8a41f4deSParav Pandit if (!mlx5_bus_match(driver, pci_dev)) 235*8a41f4deSParav Pandit continue; 236*8a41f4deSParav Pandit already_loaded = dev->classes_loaded & driver->driver_class; 237*8a41f4deSParav Pandit if (already_loaded && 238*8a41f4deSParav Pandit !(driver->pci_driver.drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) { 239*8a41f4deSParav Pandit DRV_LOG(ERR, "Device %s is already probed\n", 240*8a41f4deSParav Pandit pci_dev->device.name); 241*8a41f4deSParav Pandit ret = -EEXIST; 242*8a41f4deSParav Pandit goto probe_err; 243*8a41f4deSParav Pandit } 244*8a41f4deSParav Pandit ret = driver->pci_driver.probe(pci_drv, pci_dev); 245*8a41f4deSParav Pandit if (ret < 0) { 246*8a41f4deSParav Pandit DRV_LOG(ERR, "Failed to load driver = %s.\n", 247*8a41f4deSParav Pandit driver->pci_driver.driver.name); 248*8a41f4deSParav Pandit goto probe_err; 249*8a41f4deSParav Pandit } 250*8a41f4deSParav Pandit enabled_classes |= driver->driver_class; 251*8a41f4deSParav Pandit } 252*8a41f4deSParav Pandit dev->classes_loaded |= enabled_classes; 253*8a41f4deSParav Pandit return 0; 254*8a41f4deSParav Pandit probe_err: 255*8a41f4deSParav Pandit /* Only unload drivers which are enabled which were enabled 256*8a41f4deSParav Pandit * in this probe instance. 257*8a41f4deSParav Pandit */ 258*8a41f4deSParav Pandit drivers_remove(dev, enabled_classes); 259*8a41f4deSParav Pandit return ret; 260*8a41f4deSParav Pandit } 261*8a41f4deSParav Pandit 262*8a41f4deSParav Pandit /** 263*8a41f4deSParav Pandit * DPDK callback to register to probe multiple drivers for a PCI device. 264*8a41f4deSParav Pandit * 265*8a41f4deSParav Pandit * @param[in] pci_drv 266*8a41f4deSParav Pandit * PCI driver structure. 267*8a41f4deSParav Pandit * @param[in] dev 268*8a41f4deSParav Pandit * PCI device information. 269*8a41f4deSParav Pandit * 270*8a41f4deSParav Pandit * @return 271*8a41f4deSParav Pandit * 0 on success, a negative errno value otherwise and rte_errno is set. 272*8a41f4deSParav Pandit */ 273*8a41f4deSParav Pandit static int 274*8a41f4deSParav Pandit mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 275*8a41f4deSParav Pandit struct rte_pci_device *pci_dev) 276*8a41f4deSParav Pandit { 277*8a41f4deSParav Pandit struct mlx5_pci_device *dev; 278*8a41f4deSParav Pandit uint32_t user_classes = 0; 279*8a41f4deSParav Pandit bool new_device = false; 280*8a41f4deSParav Pandit int ret; 281*8a41f4deSParav Pandit 282*8a41f4deSParav Pandit ret = parse_class_options(pci_dev->device.devargs); 283*8a41f4deSParav Pandit if (ret < 0) 284*8a41f4deSParav Pandit return ret; 285*8a41f4deSParav Pandit user_classes = ret; 286*8a41f4deSParav Pandit if (user_classes) { 287*8a41f4deSParav Pandit /* Validate combination here. */ 288*8a41f4deSParav Pandit ret = is_valid_class_combination(user_classes); 289*8a41f4deSParav Pandit if (ret) { 290*8a41f4deSParav Pandit DRV_LOG(ERR, "Unsupported mlx5 classes supplied."); 291*8a41f4deSParav Pandit return ret; 292*8a41f4deSParav Pandit } 293*8a41f4deSParav Pandit } else { 294*8a41f4deSParav Pandit /* Default to net class. */ 295*8a41f4deSParav Pandit user_classes = MLX5_CLASS_NET; 296*8a41f4deSParav Pandit } 297*8a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 298*8a41f4deSParav Pandit if (!dev) { 299*8a41f4deSParav Pandit dev = rte_zmalloc("mlx5_pci_device", sizeof(*dev), 0); 300*8a41f4deSParav Pandit if (!dev) 301*8a41f4deSParav Pandit return -ENOMEM; 302*8a41f4deSParav Pandit dev->pci_dev = pci_dev; 303*8a41f4deSParav Pandit TAILQ_INSERT_HEAD(&devices_list, dev, next); 304*8a41f4deSParav Pandit new_device = true; 305*8a41f4deSParav Pandit } 306*8a41f4deSParav Pandit ret = drivers_probe(dev, pci_drv, pci_dev, user_classes); 307*8a41f4deSParav Pandit if (ret) 308*8a41f4deSParav Pandit goto class_err; 309*8a41f4deSParav Pandit return 0; 310*8a41f4deSParav Pandit class_err: 311*8a41f4deSParav Pandit if (new_device) 312*8a41f4deSParav Pandit dev_release(dev); 313*8a41f4deSParav Pandit return ret; 314*8a41f4deSParav Pandit } 315*8a41f4deSParav Pandit 316*8a41f4deSParav Pandit /** 317*8a41f4deSParav Pandit * DPDK callback to remove one or more drivers for a PCI device. 318*8a41f4deSParav Pandit * 319*8a41f4deSParav Pandit * This function removes all drivers probed for a given PCI device. 320*8a41f4deSParav Pandit * 321*8a41f4deSParav Pandit * @param[in] pci_dev 322*8a41f4deSParav Pandit * Pointer to the PCI device. 323*8a41f4deSParav Pandit * 324*8a41f4deSParav Pandit * @return 325*8a41f4deSParav Pandit * 0 on success, the function cannot fail. 326*8a41f4deSParav Pandit */ 327*8a41f4deSParav Pandit static int 328*8a41f4deSParav Pandit mlx5_common_pci_remove(struct rte_pci_device *pci_dev) 329*8a41f4deSParav Pandit { 330*8a41f4deSParav Pandit struct mlx5_pci_device *dev; 331*8a41f4deSParav Pandit int ret; 332*8a41f4deSParav Pandit 333*8a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 334*8a41f4deSParav Pandit if (!dev) 335*8a41f4deSParav Pandit return -ENODEV; 336*8a41f4deSParav Pandit /* Matching device found, cleanup and unload drivers. */ 337*8a41f4deSParav Pandit ret = drivers_remove(dev, dev->classes_loaded); 338*8a41f4deSParav Pandit if (!ret) 339*8a41f4deSParav Pandit dev_release(dev); 340*8a41f4deSParav Pandit return ret; 341*8a41f4deSParav Pandit } 342*8a41f4deSParav Pandit 343*8a41f4deSParav Pandit static int 344*8a41f4deSParav Pandit mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr, 345*8a41f4deSParav Pandit uint64_t iova, size_t len) 346*8a41f4deSParav Pandit { 347*8a41f4deSParav Pandit struct mlx5_pci_driver *driver = NULL; 348*8a41f4deSParav Pandit struct mlx5_pci_driver *temp; 349*8a41f4deSParav Pandit struct mlx5_pci_device *dev; 350*8a41f4deSParav Pandit int ret = -EINVAL; 351*8a41f4deSParav Pandit 352*8a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 353*8a41f4deSParav Pandit if (!dev) 354*8a41f4deSParav Pandit return -ENODEV; 355*8a41f4deSParav Pandit TAILQ_FOREACH(driver, &drv_list, next) { 356*8a41f4deSParav Pandit if (device_class_enabled(dev, driver->driver_class) && 357*8a41f4deSParav Pandit driver->pci_driver.dma_map) { 358*8a41f4deSParav Pandit ret = driver->pci_driver.dma_map(pci_dev, addr, 359*8a41f4deSParav Pandit iova, len); 360*8a41f4deSParav Pandit if (ret) 361*8a41f4deSParav Pandit goto map_err; 362*8a41f4deSParav Pandit } 363*8a41f4deSParav Pandit } 364*8a41f4deSParav Pandit return ret; 365*8a41f4deSParav Pandit map_err: 366*8a41f4deSParav Pandit TAILQ_FOREACH(temp, &drv_list, next) { 367*8a41f4deSParav Pandit if (temp == driver) 368*8a41f4deSParav Pandit break; 369*8a41f4deSParav Pandit if (device_class_enabled(dev, temp->driver_class) && 370*8a41f4deSParav Pandit temp->pci_driver.dma_map && temp->pci_driver.dma_unmap) 371*8a41f4deSParav Pandit temp->pci_driver.dma_unmap(pci_dev, addr, iova, len); 372*8a41f4deSParav Pandit } 373*8a41f4deSParav Pandit return ret; 374*8a41f4deSParav Pandit } 375*8a41f4deSParav Pandit 376*8a41f4deSParav Pandit static int 377*8a41f4deSParav Pandit mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr, 378*8a41f4deSParav Pandit uint64_t iova, size_t len) 379*8a41f4deSParav Pandit { 380*8a41f4deSParav Pandit struct mlx5_pci_driver *driver; 381*8a41f4deSParav Pandit struct mlx5_pci_device *dev; 382*8a41f4deSParav Pandit int local_ret = -EINVAL; 383*8a41f4deSParav Pandit int ret; 384*8a41f4deSParav Pandit 385*8a41f4deSParav Pandit dev = pci_to_mlx5_device(pci_dev); 386*8a41f4deSParav Pandit if (!dev) 387*8a41f4deSParav Pandit return -ENODEV; 388*8a41f4deSParav Pandit ret = 0; 389*8a41f4deSParav Pandit /* There is no unmap error recovery in current implementation. */ 390*8a41f4deSParav Pandit TAILQ_FOREACH_REVERSE(driver, &drv_list, mlx5_pci_bus_drv_head, next) { 391*8a41f4deSParav Pandit if (device_class_enabled(dev, driver->driver_class) && 392*8a41f4deSParav Pandit driver->pci_driver.dma_unmap) { 393*8a41f4deSParav Pandit local_ret = driver->pci_driver.dma_unmap(pci_dev, addr, 394*8a41f4deSParav Pandit iova, len); 395*8a41f4deSParav Pandit if (local_ret && (ret == 0)) 396*8a41f4deSParav Pandit ret = local_ret; 397*8a41f4deSParav Pandit } 398*8a41f4deSParav Pandit } 399*8a41f4deSParav Pandit if (local_ret) 400*8a41f4deSParav Pandit ret = local_ret; 401*8a41f4deSParav Pandit return ret; 402*8a41f4deSParav Pandit } 403*8a41f4deSParav Pandit 404*8a41f4deSParav Pandit /* PCI ID table is build dynamically based on registered mlx5 drivers. */ 405*8a41f4deSParav Pandit static struct rte_pci_id *mlx5_pci_id_table; 406*8a41f4deSParav Pandit 407*8a41f4deSParav Pandit static struct rte_pci_driver mlx5_pci_driver = { 408*8a41f4deSParav Pandit .driver = { 409*8a41f4deSParav Pandit .name = "mlx5_pci", 410*8a41f4deSParav Pandit }, 411*8a41f4deSParav Pandit .probe = mlx5_common_pci_probe, 412*8a41f4deSParav Pandit .remove = mlx5_common_pci_remove, 413*8a41f4deSParav Pandit .dma_map = mlx5_common_pci_dma_map, 414*8a41f4deSParav Pandit .dma_unmap = mlx5_common_pci_dma_unmap, 415*8a41f4deSParav Pandit }; 416*8a41f4deSParav Pandit 417*8a41f4deSParav Pandit static int 418*8a41f4deSParav Pandit pci_id_table_size_get(const struct rte_pci_id *id_table) 419*8a41f4deSParav Pandit { 420*8a41f4deSParav Pandit int table_size = 0; 421*8a41f4deSParav Pandit 422*8a41f4deSParav Pandit for (; id_table->vendor_id != 0; id_table++) 423*8a41f4deSParav Pandit table_size++; 424*8a41f4deSParav Pandit return table_size; 425*8a41f4deSParav Pandit } 426*8a41f4deSParav Pandit 427*8a41f4deSParav Pandit static bool 428*8a41f4deSParav Pandit pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table, 429*8a41f4deSParav Pandit int next_idx) 430*8a41f4deSParav Pandit { 431*8a41f4deSParav Pandit int current_size = next_idx - 1; 432*8a41f4deSParav Pandit int i; 433*8a41f4deSParav Pandit 434*8a41f4deSParav Pandit for (i = 0; i < current_size; i++) { 435*8a41f4deSParav Pandit if (id->device_id == table[i].device_id && 436*8a41f4deSParav Pandit id->vendor_id == table[i].vendor_id && 437*8a41f4deSParav Pandit id->subsystem_vendor_id == table[i].subsystem_vendor_id && 438*8a41f4deSParav Pandit id->subsystem_device_id == table[i].subsystem_device_id) 439*8a41f4deSParav Pandit return true; 440*8a41f4deSParav Pandit } 441*8a41f4deSParav Pandit return false; 442*8a41f4deSParav Pandit } 443*8a41f4deSParav Pandit 444*8a41f4deSParav Pandit static void 445*8a41f4deSParav Pandit pci_id_insert(struct rte_pci_id *new_table, int *next_idx, 446*8a41f4deSParav Pandit const struct rte_pci_id *id_table) 447*8a41f4deSParav Pandit { 448*8a41f4deSParav Pandit /* Traverse the id_table, check if entry exists in new_table; 449*8a41f4deSParav Pandit * Add non duplicate entries to new table. 450*8a41f4deSParav Pandit */ 451*8a41f4deSParav Pandit for (; id_table->vendor_id != 0; id_table++) { 452*8a41f4deSParav Pandit if (!pci_id_exists(id_table, new_table, *next_idx)) { 453*8a41f4deSParav Pandit /* New entry; add to the table. */ 454*8a41f4deSParav Pandit new_table[*next_idx] = *id_table; 455*8a41f4deSParav Pandit (*next_idx)++; 456*8a41f4deSParav Pandit } 457*8a41f4deSParav Pandit } 458*8a41f4deSParav Pandit } 459*8a41f4deSParav Pandit 460*8a41f4deSParav Pandit static int 461*8a41f4deSParav Pandit pci_ids_table_update(const struct rte_pci_id *driver_id_table) 462*8a41f4deSParav Pandit { 463*8a41f4deSParav Pandit const struct rte_pci_id *id_iter; 464*8a41f4deSParav Pandit struct rte_pci_id *updated_table; 465*8a41f4deSParav Pandit struct rte_pci_id *old_table; 466*8a41f4deSParav Pandit int num_ids = 0; 467*8a41f4deSParav Pandit int i = 0; 468*8a41f4deSParav Pandit 469*8a41f4deSParav Pandit old_table = mlx5_pci_id_table; 470*8a41f4deSParav Pandit if (old_table) 471*8a41f4deSParav Pandit num_ids = pci_id_table_size_get(old_table); 472*8a41f4deSParav Pandit num_ids += pci_id_table_size_get(driver_id_table); 473*8a41f4deSParav Pandit /* Increase size by one for the termination entry of vendor_id = 0. */ 474*8a41f4deSParav Pandit num_ids += 1; 475*8a41f4deSParav Pandit updated_table = calloc(num_ids, sizeof(*updated_table)); 476*8a41f4deSParav Pandit if (!updated_table) 477*8a41f4deSParav Pandit return -ENOMEM; 478*8a41f4deSParav Pandit if (TAILQ_EMPTY(&drv_list)) { 479*8a41f4deSParav Pandit /* Copy the first driver's ID table. */ 480*8a41f4deSParav Pandit for (id_iter = driver_id_table; id_iter->vendor_id != 0; 481*8a41f4deSParav Pandit id_iter++, i++) 482*8a41f4deSParav Pandit updated_table[i] = *id_iter; 483*8a41f4deSParav Pandit } else { 484*8a41f4deSParav Pandit /* First copy existing table entries. */ 485*8a41f4deSParav Pandit for (id_iter = old_table; id_iter->vendor_id != 0; 486*8a41f4deSParav Pandit id_iter++, i++) 487*8a41f4deSParav Pandit updated_table[i] = *id_iter; 488*8a41f4deSParav Pandit /* New id to be added at the end of current ID table. */ 489*8a41f4deSParav Pandit pci_id_insert(updated_table, &i, driver_id_table); 490*8a41f4deSParav Pandit } 491*8a41f4deSParav Pandit /* Terminate table with empty entry. */ 492*8a41f4deSParav Pandit updated_table[i].vendor_id = 0; 493*8a41f4deSParav Pandit mlx5_pci_driver.id_table = updated_table; 494*8a41f4deSParav Pandit mlx5_pci_id_table = updated_table; 495*8a41f4deSParav Pandit if (old_table) 496*8a41f4deSParav Pandit free(old_table); 497*8a41f4deSParav Pandit return 0; 498*8a41f4deSParav Pandit } 499*8a41f4deSParav Pandit 500*8a41f4deSParav Pandit void 501*8a41f4deSParav Pandit mlx5_pci_driver_register(struct mlx5_pci_driver *driver) 502*8a41f4deSParav Pandit { 503*8a41f4deSParav Pandit int ret; 504*8a41f4deSParav Pandit 505*8a41f4deSParav Pandit ret = pci_ids_table_update(driver->pci_driver.id_table); 506*8a41f4deSParav Pandit if (ret) 507*8a41f4deSParav Pandit return; 508*8a41f4deSParav Pandit mlx5_pci_driver.drv_flags |= driver->pci_driver.drv_flags; 509*8a41f4deSParav Pandit TAILQ_INSERT_TAIL(&drv_list, driver, next); 510*8a41f4deSParav Pandit } 511*8a41f4deSParav Pandit 512*8a41f4deSParav Pandit void mlx5_common_pci_init(void) 513*8a41f4deSParav Pandit { 514*8a41f4deSParav Pandit const struct rte_pci_id empty_table[] = { 515*8a41f4deSParav Pandit { 516*8a41f4deSParav Pandit .vendor_id = 0 517*8a41f4deSParav Pandit }, 518*8a41f4deSParav Pandit }; 519*8a41f4deSParav Pandit 520*8a41f4deSParav Pandit /* All mlx5 PMDs constructor runs at same priority. So any of the PMD 521*8a41f4deSParav Pandit * including this one can register the PCI table first. If any other 522*8a41f4deSParav Pandit * PMD(s) have registered the PCI ID table, No need to register an empty 523*8a41f4deSParav Pandit * default one. 524*8a41f4deSParav Pandit */ 525*8a41f4deSParav Pandit if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table)) 526*8a41f4deSParav Pandit return; 527*8a41f4deSParav Pandit rte_pci_register(&mlx5_pci_driver); 528*8a41f4deSParav Pandit } 529*8a41f4deSParav Pandit 530*8a41f4deSParav Pandit RTE_FINI(mlx5_common_pci_finish) 531*8a41f4deSParav Pandit { 532*8a41f4deSParav Pandit if (mlx5_pci_id_table != NULL) { 533*8a41f4deSParav Pandit /* Constructor doesn't register with PCI bus if it failed 534*8a41f4deSParav Pandit * to build the table. 535*8a41f4deSParav Pandit */ 536*8a41f4deSParav Pandit rte_pci_unregister(&mlx5_pci_driver); 537*8a41f4deSParav Pandit free(mlx5_pci_id_table); 538*8a41f4deSParav Pandit } 539*8a41f4deSParav Pandit } 540*8a41f4deSParav Pandit RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__); 541