1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2023 Corigine, Inc. 3 * All rights reserved. 4 */ 5 6 #include "nfp_common_pci.h" 7 8 #include <string.h> 9 10 #include <rte_class.h> 11 #include <rte_devargs.h> 12 #include <rte_kvargs.h> 13 14 #include "nfp_common_log.h" 15 16 /* Reported driver name. */ 17 #define NFP_PCI_DRIVER_NAME "nfp_common_pci" 18 19 static struct rte_pci_driver nfp_common_pci_driver; 20 21 /* PCI ID table is build dynamically based on registered nfp drivers. */ 22 static struct rte_pci_id *nfp_pci_id_table; 23 24 /* Head of list of drivers. */ 25 static TAILQ_HEAD(nfp_drivers, nfp_class_driver) nfp_drivers_list = 26 TAILQ_HEAD_INITIALIZER(nfp_drivers_list); 27 28 static bool nfp_common_initialized; 29 30 static const struct { 31 const char *name; 32 enum nfp_class drv_class; 33 } nfp_classes[] = { 34 { .name = "eth", .drv_class = NFP_CLASS_ETH }, 35 }; 36 37 static enum nfp_class 38 nfp_class_name_to_value(const char *class_name) 39 { 40 uint32_t i; 41 42 for (i = 0; i < RTE_DIM(nfp_classes); i++) { 43 if (strcmp(class_name, nfp_classes[i].name) == 0) 44 return nfp_classes[i].drv_class; 45 } 46 47 return NFP_CLASS_INVALID; 48 } 49 50 static uint32_t 51 nfp_pci_id_table_size_get(const struct rte_pci_id *id_table) 52 { 53 uint32_t table_size; 54 55 if (id_table == NULL) 56 return 0; 57 58 for (table_size = 0; id_table->vendor_id != 0; id_table++) 59 table_size++; 60 61 return table_size; 62 } 63 64 static bool 65 nfp_pci_id_exists(const struct rte_pci_id *id, 66 const struct rte_pci_id *table, 67 uint32_t next_idx) 68 { 69 uint32_t i; 70 71 if (next_idx == 0) 72 return false; 73 74 for (i = 0; i < next_idx; i++) { 75 if (id->device_id == table[i].device_id && 76 id->vendor_id == table[i].vendor_id && 77 id->subsystem_vendor_id == table[i].subsystem_vendor_id && 78 id->subsystem_device_id == table[i].subsystem_device_id) 79 return true; 80 } 81 82 return false; 83 } 84 85 static void 86 nfp_pci_id_insert(struct rte_pci_id *new_table, 87 uint32_t *next_idx, 88 const struct rte_pci_id *id_table) 89 { 90 if (id_table == NULL) 91 return; 92 93 /* Add non duplicate entries to new table. */ 94 for (; id_table->vendor_id != 0; id_table++) { 95 if (!nfp_pci_id_exists(id_table, new_table, *next_idx)) { 96 new_table[*next_idx] = *id_table; 97 (*next_idx)++; 98 } 99 } 100 } 101 102 static int 103 nfp_pci_id_table_update(const struct rte_pci_id *driver_id_table) 104 { 105 uint32_t i = 0; 106 uint32_t num_ids = 0; 107 struct rte_pci_id *old_table; 108 const struct rte_pci_id *id_iter; 109 struct rte_pci_id *updated_table; 110 111 old_table = nfp_pci_id_table; 112 if (old_table != NULL) 113 num_ids = nfp_pci_id_table_size_get(old_table); 114 num_ids += nfp_pci_id_table_size_get(driver_id_table); 115 116 /* Increase size by one for the termination entry of vendor_id = 0. */ 117 num_ids += 1; 118 updated_table = calloc(num_ids, sizeof(struct rte_pci_id)); 119 if (updated_table == NULL) 120 return -ENOMEM; 121 122 if (old_table == NULL) { 123 /* Copy the first driver's ID table. */ 124 for (id_iter = driver_id_table; id_iter[i].vendor_id != 0; i++) 125 updated_table[i] = id_iter[i]; 126 } else { 127 /* First copy existing table entries. */ 128 for (id_iter = old_table; id_iter[i].vendor_id != 0; i++) 129 updated_table[i] = id_iter[i]; 130 /* New id to be added at the end of current ID table. */ 131 nfp_pci_id_insert(updated_table, &i, driver_id_table); 132 133 free(old_table); 134 } 135 136 /* Terminate table with empty entry. */ 137 updated_table[i].vendor_id = 0; 138 nfp_pci_id_table = updated_table; 139 nfp_common_pci_driver.id_table = nfp_pci_id_table; 140 141 return 0; 142 } 143 144 static int 145 nfp_kvarg_dev_class_handler(__rte_unused const char *key, 146 const char *class_str, 147 void *opaque) 148 { 149 enum nfp_class *dev_class = opaque; 150 151 if (class_str == NULL) 152 return *dev_class; 153 154 *dev_class = nfp_class_name_to_value(class_str); 155 156 return 0; 157 } 158 159 static enum nfp_class 160 nfp_parse_class_options(const struct rte_devargs *devargs) 161 { 162 struct rte_kvargs *kvargs; 163 enum nfp_class dev_class = NFP_CLASS_ETH; 164 165 if (devargs == NULL) 166 return dev_class; 167 168 kvargs = rte_kvargs_parse(devargs->args, NULL); 169 if (kvargs == NULL) 170 return dev_class; 171 172 if (rte_kvargs_count(kvargs, RTE_DEVARGS_KEY_CLASS) != 0) { 173 rte_kvargs_process(kvargs, RTE_DEVARGS_KEY_CLASS, 174 nfp_kvarg_dev_class_handler, &dev_class); 175 } 176 177 rte_kvargs_free(kvargs); 178 179 return dev_class; 180 } 181 182 static int 183 nfp_drivers_probe(struct rte_pci_device *pci_dev, 184 enum nfp_class class) 185 { 186 int32_t ret = 0; 187 struct nfp_class_driver *driver; 188 189 TAILQ_FOREACH(driver, &nfp_drivers_list, next) { 190 if (driver->drv_class != class) 191 continue; 192 193 ret = driver->probe(pci_dev); 194 if (ret < 0) { 195 PMD_DRV_LOG(ERR, "Failed to load driver %s", driver->name); 196 return ret; 197 } 198 } 199 200 return 0; 201 } 202 203 static int 204 nfp_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 205 struct rte_pci_device *pci_dev) 206 { 207 enum nfp_class class; 208 struct rte_device *eal_dev = &pci_dev->device; 209 210 PMD_DRV_LOG(INFO, "probe device %s.", eal_dev->name); 211 212 class = nfp_parse_class_options(eal_dev->devargs); 213 if (class == NFP_CLASS_INVALID) { 214 PMD_DRV_LOG(ERR, "Unsupported nfp class type: %s", 215 eal_dev->devargs->args); 216 return -ENOTSUP; 217 } 218 219 return nfp_drivers_probe(pci_dev, class); 220 } 221 222 static int 223 nfp_common_pci_remove(__rte_unused struct rte_pci_device *pci_dev) 224 { 225 return 0; 226 } 227 228 static struct rte_pci_driver nfp_common_pci_driver = { 229 .driver = { 230 .name = NFP_PCI_DRIVER_NAME, 231 }, 232 .probe = nfp_common_pci_probe, 233 .remove = nfp_common_pci_remove, 234 }; 235 236 static void 237 nfp_common_init(void) 238 { 239 const struct rte_pci_id empty_table[] = { 240 { 241 .vendor_id = 0 242 }, 243 }; 244 245 if (nfp_common_initialized) 246 return; 247 248 /* 249 * All the constructor of NFP PMDs run at same priority. So any of the PMD 250 * including this one can register the PCI table first. If any other 251 * PMD(s) have registered the PCI ID table, no need to register an empty 252 * default one. 253 */ 254 if (nfp_pci_id_table == NULL && nfp_pci_id_table_update(empty_table) != 0) 255 return; 256 257 rte_pci_register(&nfp_common_pci_driver); 258 nfp_common_initialized = true; 259 } 260 261 void 262 nfp_class_driver_register(struct nfp_class_driver *driver) 263 { 264 nfp_common_init(); 265 266 if (driver->id_table != NULL) { 267 if (nfp_pci_id_table_update(driver->id_table) != 0) 268 return; 269 } 270 271 nfp_common_pci_driver.drv_flags |= driver->drv_flags; 272 273 TAILQ_INSERT_TAIL(&nfp_drivers_list, driver, next); 274 } 275