xref: /dpdk/drivers/common/nfp/nfp_common_pci.c (revision da7e701151ea8b742d4c38ace3e4fefd1b4507fc)
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 	if (rte_kvargs_count(kvargs, RTE_DEVARGS_KEY_CLASS) != 0) {
174 		rte_kvargs_process(kvargs, RTE_DEVARGS_KEY_CLASS,
175 				nfp_kvarg_dev_class_handler, &dev_class);
176 	}
177 
178 	rte_kvargs_free(kvargs);
179 
180 	return dev_class;
181 }
182 
183 static int
184 nfp_drivers_probe(struct rte_pci_device *pci_dev,
185 		enum nfp_class class)
186 {
187 	int32_t ret = 0;
188 	struct nfp_class_driver *driver;
189 
190 	TAILQ_FOREACH(driver, &nfp_drivers_list, next) {
191 		if (driver->drv_class != class)
192 			continue;
193 
194 		ret = driver->probe(pci_dev);
195 		if (ret < 0) {
196 			PMD_DRV_LOG(ERR, "Failed to load driver %s", driver->name);
197 			return ret;
198 		}
199 	}
200 
201 	return 0;
202 }
203 
204 static int
205 nfp_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
206 		struct rte_pci_device *pci_dev)
207 {
208 	enum nfp_class class;
209 	struct rte_device *eal_dev = &pci_dev->device;
210 
211 	PMD_DRV_LOG(INFO, "probe device %s.", eal_dev->name);
212 
213 	class = nfp_parse_class_options(eal_dev->devargs);
214 	if (class == NFP_CLASS_INVALID) {
215 		PMD_DRV_LOG(ERR, "Unsupported nfp class type: %s",
216 				eal_dev->devargs->args);
217 		return -ENOTSUP;
218 	}
219 
220 	return nfp_drivers_probe(pci_dev, class);
221 }
222 
223 static int
224 nfp_common_pci_remove(__rte_unused struct rte_pci_device *pci_dev)
225 {
226 	return 0;
227 }
228 
229 static struct rte_pci_driver nfp_common_pci_driver = {
230 	.driver = {
231 		.name = NFP_PCI_DRIVER_NAME,
232 	},
233 	.probe = nfp_common_pci_probe,
234 	.remove = nfp_common_pci_remove,
235 };
236 
237 static void
238 nfp_common_init(void)
239 {
240 	const struct rte_pci_id empty_table[] = {
241 		{
242 			.vendor_id = 0
243 		},
244 	};
245 
246 	if (nfp_common_initialized)
247 		return;
248 
249 	/*
250 	 * All the constructor of NFP PMDs run at same priority. So any of the PMD
251 	 * including this one can register the PCI table first. If any other
252 	 * PMD(s) have registered the PCI ID table, no need to register an empty
253 	 * default one.
254 	 */
255 	if (nfp_pci_id_table == NULL && nfp_pci_id_table_update(empty_table) != 0)
256 		return;
257 
258 	rte_pci_register(&nfp_common_pci_driver);
259 	nfp_common_initialized = true;
260 }
261 
262 void
263 nfp_class_driver_register(struct nfp_class_driver *driver)
264 {
265 	nfp_common_init();
266 
267 	if (driver->id_table != NULL) {
268 		if (nfp_pci_id_table_update(driver->id_table) != 0)
269 			return;
270 	}
271 
272 	nfp_common_pci_driver.drv_flags |= driver->drv_flags;
273 
274 	TAILQ_INSERT_TAIL(&nfp_drivers_list, driver, next);
275 }
276