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