1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2020 Mellanox Technologies Ltd 3 */ 4 5 #include <stdlib.h> 6 7 #include <rte_malloc.h> 8 #include <rte_devargs.h> 9 #include <rte_errno.h> 10 #include <rte_class.h> 11 #include <rte_pci.h> 12 #include <rte_bus_pci.h> 13 14 #include "mlx5_common_log.h" 15 #include "mlx5_common_private.h" 16 17 static struct rte_pci_driver mlx5_common_pci_driver; 18 19 /* PCI ID table is build dynamically based on registered mlx5 drivers. */ 20 static struct rte_pci_id *mlx5_pci_id_table; 21 22 static int 23 pci_id_table_size_get(const struct rte_pci_id *id_table) 24 { 25 int table_size = 0; 26 27 for (; id_table->vendor_id != 0; id_table++) 28 table_size++; 29 return table_size; 30 } 31 32 static bool 33 pci_id_exists(const struct rte_pci_id *id, const struct rte_pci_id *table, 34 int next_idx) 35 { 36 int current_size = next_idx - 1; 37 int i; 38 39 for (i = 0; i < current_size; i++) { 40 if (id->device_id == table[i].device_id && 41 id->vendor_id == table[i].vendor_id && 42 id->subsystem_vendor_id == table[i].subsystem_vendor_id && 43 id->subsystem_device_id == table[i].subsystem_device_id) 44 return true; 45 } 46 return false; 47 } 48 49 static void 50 pci_id_insert(struct rte_pci_id *new_table, int *next_idx, 51 const struct rte_pci_id *id_table) 52 { 53 /* Traverse the id_table, check if entry exists in new_table; 54 * Add non duplicate entries to new table. 55 */ 56 for (; id_table->vendor_id != 0; id_table++) { 57 if (!pci_id_exists(id_table, new_table, *next_idx)) { 58 /* New entry; add to the table. */ 59 new_table[*next_idx] = *id_table; 60 (*next_idx)++; 61 } 62 } 63 } 64 65 static int 66 pci_ids_table_update(const struct rte_pci_id *driver_id_table) 67 { 68 const struct rte_pci_id *id_iter; 69 struct rte_pci_id *updated_table; 70 struct rte_pci_id *old_table; 71 int num_ids = 0; 72 int i = 0; 73 74 old_table = mlx5_pci_id_table; 75 if (old_table) 76 num_ids = pci_id_table_size_get(old_table); 77 num_ids += pci_id_table_size_get(driver_id_table); 78 /* Increase size by one for the termination entry of vendor_id = 0. */ 79 num_ids += 1; 80 updated_table = calloc(num_ids, sizeof(*updated_table)); 81 if (!updated_table) 82 return -ENOMEM; 83 if (old_table == NULL) { 84 /* Copy the first driver's ID table. */ 85 for (id_iter = driver_id_table; id_iter->vendor_id != 0; 86 id_iter++, i++) 87 updated_table[i] = *id_iter; 88 } else { 89 /* First copy existing table entries. */ 90 for (id_iter = old_table; id_iter->vendor_id != 0; 91 id_iter++, i++) 92 updated_table[i] = *id_iter; 93 /* New id to be added at the end of current ID table. */ 94 pci_id_insert(updated_table, &i, driver_id_table); 95 } 96 /* Terminate table with empty entry. */ 97 updated_table[i].vendor_id = 0; 98 mlx5_common_pci_driver.id_table = updated_table; 99 mlx5_pci_id_table = updated_table; 100 free(old_table); 101 return 0; 102 } 103 104 bool 105 mlx5_dev_is_pci(const struct rte_device *dev) 106 { 107 return strcmp(dev->bus->name, "pci") == 0; 108 } 109 110 bool 111 mlx5_dev_is_vf_pci(struct rte_pci_device *pci_dev) 112 { 113 switch (pci_dev->id.device_id) { 114 case PCI_DEVICE_ID_MELLANOX_CONNECTX4VF: 115 case PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF: 116 case PCI_DEVICE_ID_MELLANOX_CONNECTX5VF: 117 case PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF: 118 case PCI_DEVICE_ID_MELLANOX_CONNECTX5BFVF: 119 case PCI_DEVICE_ID_MELLANOX_CONNECTX6VF: 120 case PCI_DEVICE_ID_MELLANOX_CONNECTXVF: 121 return true; 122 default: 123 break; 124 } 125 return false; 126 } 127 128 bool 129 mlx5_dev_pci_match(const struct mlx5_class_driver *drv, 130 const struct rte_device *dev) 131 { 132 const struct rte_pci_device *pci_dev; 133 const struct rte_pci_id *id_table; 134 135 if (!mlx5_dev_is_pci(dev)) 136 return false; 137 pci_dev = RTE_DEV_TO_PCI_CONST(dev); 138 for (id_table = drv->id_table; id_table->vendor_id != 0; 139 id_table++) { 140 /* Check if device's ids match the class driver's ids. */ 141 if (id_table->vendor_id != pci_dev->id.vendor_id && 142 id_table->vendor_id != RTE_PCI_ANY_ID) 143 continue; 144 if (id_table->device_id != pci_dev->id.device_id && 145 id_table->device_id != RTE_PCI_ANY_ID) 146 continue; 147 if (id_table->subsystem_vendor_id != 148 pci_dev->id.subsystem_vendor_id && 149 id_table->subsystem_vendor_id != RTE_PCI_ANY_ID) 150 continue; 151 if (id_table->subsystem_device_id != 152 pci_dev->id.subsystem_device_id && 153 id_table->subsystem_device_id != RTE_PCI_ANY_ID) 154 continue; 155 if (id_table->class_id != pci_dev->id.class_id && 156 id_table->class_id != RTE_CLASS_ANY_ID) 157 continue; 158 return true; 159 } 160 return false; 161 } 162 163 static int 164 mlx5_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 165 struct rte_pci_device *pci_dev) 166 { 167 return mlx5_common_dev_probe(&pci_dev->device); 168 } 169 170 static int 171 mlx5_common_pci_remove(struct rte_pci_device *pci_dev) 172 { 173 return mlx5_common_dev_remove(&pci_dev->device); 174 } 175 176 static int 177 mlx5_common_pci_dma_map(struct rte_pci_device *pci_dev, void *addr, 178 uint64_t iova, size_t len) 179 { 180 return mlx5_common_dev_dma_map(&pci_dev->device, addr, iova, len); 181 } 182 183 static int 184 mlx5_common_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr, 185 uint64_t iova, size_t len) 186 { 187 return mlx5_common_dev_dma_unmap(&pci_dev->device, addr, iova, len); 188 } 189 190 void 191 mlx5_common_driver_on_register_pci(struct mlx5_class_driver *driver) 192 { 193 if (driver->id_table != NULL) { 194 if (pci_ids_table_update(driver->id_table) != 0) 195 return; 196 } 197 if (driver->probe_again) 198 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_PROBE_AGAIN; 199 if (driver->intr_lsc) 200 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC; 201 if (driver->intr_rmv) 202 mlx5_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV; 203 } 204 205 static struct rte_pci_driver mlx5_common_pci_driver = { 206 .driver = { 207 .name = MLX5_PCI_DRIVER_NAME, 208 }, 209 .probe = mlx5_common_pci_probe, 210 .remove = mlx5_common_pci_remove, 211 .dma_map = mlx5_common_pci_dma_map, 212 .dma_unmap = mlx5_common_pci_dma_unmap, 213 }; 214 215 void mlx5_common_pci_init(void) 216 { 217 const struct rte_pci_id empty_table[] = { 218 { 219 .vendor_id = 0 220 }, 221 }; 222 223 /* All mlx5 PMDs constructor runs at same priority. So any of the PMD 224 * including this one can register the PCI table first. If any other 225 * PMD(s) have registered the PCI ID table, No need to register an empty 226 * default one. 227 */ 228 if (mlx5_pci_id_table == NULL && pci_ids_table_update(empty_table)) 229 return; 230 rte_pci_register(&mlx5_common_pci_driver); 231 } 232 233 RTE_FINI(mlx5_common_pci_finish) 234 { 235 if (mlx5_pci_id_table != NULL) { 236 /* Constructor doesn't register with PCI bus if it failed 237 * to build the table. 238 */ 239 rte_pci_unregister(&mlx5_common_pci_driver); 240 free(mlx5_pci_id_table); 241 } 242 } 243 244 RTE_PMD_EXPORT_NAME(mlx5_common_pci, __COUNTER__); 245