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