Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2021 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <inttypes.h>
7 : : #include <stdint.h>
8 : : #include <stdbool.h>
9 : : #include <stdlib.h>
10 : : #include <stdio.h>
11 : : #include <sys/queue.h>
12 : : #include <eal_export.h>
13 : : #include <rte_errno.h>
14 : : #include <rte_interrupts.h>
15 : : #include <rte_log.h>
16 : : #include <bus_driver.h>
17 : : #include <rte_per_lcore.h>
18 : : #include <rte_memory.h>
19 : : #include <rte_eal.h>
20 : : #include <rte_eal_paging.h>
21 : : #include <rte_lcore.h>
22 : : #include <rte_string_fns.h>
23 : : #include <rte_common.h>
24 : : #include <rte_devargs.h>
25 : :
26 : : #include "private.h"
27 : :
28 : : static struct rte_devargs *
29 : 0 : auxiliary_devargs_lookup(const char *name)
30 : : {
31 : : struct rte_devargs *devargs;
32 : :
33 [ # # ]: 0 : RTE_EAL_DEVARGS_FOREACH(RTE_BUS_AUXILIARY_NAME, devargs) {
34 [ # # ]: 0 : if (strcmp(devargs->name, name) == 0)
35 : 0 : return devargs;
36 : : }
37 : : return NULL;
38 : : }
39 : :
40 : : #ifndef AUXILIARY_OS_SUPPORTED
41 : : /*
42 : : * Test whether the auxiliary device exist.
43 : : *
44 : : * Stub for OS not supporting auxiliary bus.
45 : : */
46 : : bool
47 : : auxiliary_dev_exists(const char *name)
48 : : {
49 : : RTE_SET_USED(name);
50 : : return false;
51 : : }
52 : :
53 : : /*
54 : : * Scan the devices in the auxiliary bus.
55 : : *
56 : : * Stub for OS not supporting auxiliary bus.
57 : : */
58 : : int
59 : : auxiliary_scan(void)
60 : : {
61 : : return 0;
62 : : }
63 : : #endif /* AUXILIARY_OS_SUPPORTED */
64 : :
65 : : /*
66 : : * Update a device's devargs being scanned.
67 : : */
68 : : void
69 : 0 : auxiliary_on_scan(struct rte_auxiliary_device *aux_dev)
70 : : {
71 : 0 : aux_dev->device.devargs = auxiliary_devargs_lookup(aux_dev->name);
72 : 0 : }
73 : :
74 : : /*
75 : : * Match the auxiliary driver and device using driver function.
76 : : */
77 : : bool
78 : 0 : auxiliary_match(const struct rte_auxiliary_driver *aux_drv,
79 : : const struct rte_auxiliary_device *aux_dev)
80 : : {
81 [ # # ]: 0 : if (aux_drv->match == NULL)
82 : : return false;
83 : 0 : return aux_drv->match(aux_dev->name);
84 : : }
85 : :
86 : : /*
87 : : * Call the probe() function of the driver.
88 : : */
89 : : static int
90 : 0 : rte_auxiliary_probe_one_driver(struct rte_auxiliary_driver *drv,
91 : : struct rte_auxiliary_device *dev)
92 : : {
93 : : enum rte_iova_mode iova_mode;
94 : : int ret;
95 : :
96 [ # # ]: 0 : if (drv == NULL || dev == NULL)
97 : : return -EINVAL;
98 : :
99 : : /* Check if driver supports it. */
100 [ # # ]: 0 : if (!auxiliary_match(drv, dev))
101 : : /* Match of device and driver failed */
102 : : return 1;
103 : :
104 : : /* No initialization when marked as blocked, return without error. */
105 [ # # ]: 0 : if (dev->device.devargs != NULL &&
106 [ # # ]: 0 : dev->device.devargs->policy == RTE_DEV_BLOCKED) {
107 : 0 : AUXILIARY_LOG(INFO, "Device is blocked, not initializing");
108 : 0 : return -1;
109 : : }
110 : :
111 [ # # # # ]: 0 : if (dev->device.numa_node < 0 && rte_socket_count() > 1)
112 : 0 : AUXILIARY_LOG(INFO, "Device %s is not NUMA-aware", dev->name);
113 : :
114 [ # # ]: 0 : if (rte_dev_is_probed(&dev->device)) {
115 : 0 : AUXILIARY_LOG(DEBUG, "Device %s is already probed on auxiliary bus",
116 : : dev->device.name);
117 : 0 : return -EEXIST;
118 : : }
119 : :
120 : 0 : iova_mode = rte_eal_iova_mode();
121 [ # # # # ]: 0 : if ((drv->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) > 0 &&
122 : : iova_mode != RTE_IOVA_VA) {
123 : 0 : AUXILIARY_LOG(ERR, "Driver %s expecting VA IOVA mode but current mode is PA, not initializing",
124 : : drv->driver.name);
125 : 0 : return -EINVAL;
126 : : }
127 : :
128 : : /* Allocate interrupt instance */
129 : 0 : dev->intr_handle =
130 : 0 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
131 [ # # ]: 0 : if (dev->intr_handle == NULL) {
132 : 0 : AUXILIARY_LOG(ERR, "Could not allocate interrupt instance for device %s",
133 : : dev->name);
134 : 0 : return -ENOMEM;
135 : : }
136 : :
137 : 0 : dev->driver = drv;
138 : :
139 : 0 : AUXILIARY_LOG(INFO, "Probe auxiliary driver: %s device: %s (NUMA node %i)",
140 : : drv->driver.name, dev->name, dev->device.numa_node);
141 : 0 : ret = drv->probe(drv, dev);
142 [ # # ]: 0 : if (ret != 0) {
143 : 0 : dev->driver = NULL;
144 : 0 : rte_intr_instance_free(dev->intr_handle);
145 : 0 : dev->intr_handle = NULL;
146 : : } else {
147 : 0 : dev->device.driver = &drv->driver;
148 : : }
149 : :
150 : : return ret;
151 : : }
152 : :
153 : : /*
154 : : * Call the remove() function of the driver.
155 : : */
156 : : static int
157 : 0 : rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
158 : : {
159 : : struct rte_auxiliary_driver *drv;
160 : : int ret = 0;
161 : :
162 [ # # ]: 0 : if (dev == NULL)
163 : : return -EINVAL;
164 : :
165 : 0 : drv = dev->driver;
166 [ # # ]: 0 : if (drv == NULL)
167 : : return 0;
168 : :
169 : 0 : AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
170 : : drv->driver.name, dev->name, dev->device.numa_node);
171 : :
172 [ # # ]: 0 : if (drv->remove != NULL) {
173 : 0 : ret = drv->remove(dev);
174 [ # # ]: 0 : if (ret < 0)
175 : : return ret;
176 : : }
177 : :
178 : : /* clear driver structure */
179 : 0 : dev->driver = NULL;
180 : 0 : dev->device.driver = NULL;
181 : :
182 : 0 : return 0;
183 : : }
184 : :
185 : : /*
186 : : * Call the probe() function of all registered drivers for the given device.
187 : : * Return < 0 if initialization failed.
188 : : * Return 1 if no driver is found for this device.
189 : : */
190 : : static int
191 : 0 : auxiliary_probe_all_drivers(struct rte_auxiliary_device *dev)
192 : : {
193 : : struct rte_auxiliary_driver *drv;
194 : : int rc;
195 : :
196 [ # # ]: 0 : if (dev == NULL)
197 : : return -EINVAL;
198 : :
199 [ # # ]: 0 : FOREACH_DRIVER_ON_AUXILIARY_BUS(drv) {
200 [ # # ]: 0 : if (!drv->match(dev->name))
201 : 0 : continue;
202 : :
203 : 0 : rc = rte_auxiliary_probe_one_driver(drv, dev);
204 [ # # ]: 0 : if (rc < 0)
205 : : /* negative value is an error */
206 : 0 : return rc;
207 [ # # ]: 0 : if (rc > 0)
208 : : /* positive value means driver doesn't support it */
209 : 0 : continue;
210 : : return 0;
211 : : }
212 : : return 1;
213 : : }
214 : :
215 : : /*
216 : : * Scan the content of the auxiliary bus, and call the probe function for
217 : : * all registered drivers to try to probe discovered devices.
218 : : */
219 : : static int
220 : 181 : auxiliary_probe(void)
221 : : {
222 : : struct rte_auxiliary_device *dev = NULL;
223 : : size_t probed = 0, failed = 0;
224 : : int ret = 0;
225 : :
226 [ - + ]: 181 : FOREACH_DEVICE_ON_AUXILIARY_BUS(dev) {
227 : 0 : probed++;
228 : :
229 : 0 : ret = auxiliary_probe_all_drivers(dev);
230 [ # # ]: 0 : if (ret < 0) {
231 [ # # ]: 0 : if (ret != -EEXIST) {
232 : 0 : AUXILIARY_LOG(ERR, "Requested device %s cannot be used",
233 : : dev->name);
234 : 0 : rte_errno = errno;
235 : 0 : failed++;
236 : : }
237 : : ret = 0;
238 : : }
239 : : }
240 : :
241 [ + - ]: 181 : return (probed && probed == failed) ? -1 : 0;
242 : : }
243 : :
244 : : static int
245 : 37 : auxiliary_parse(const char *name, void *addr)
246 : : {
247 : : struct rte_auxiliary_driver *drv = NULL;
248 : : const char **out = addr;
249 : :
250 : : /* Allow empty device name "auxiliary:" to bypass entire bus scan. */
251 [ + - ]: 37 : if (strlen(name) == 0)
252 : : return 0;
253 : :
254 [ + + ]: 74 : FOREACH_DRIVER_ON_AUXILIARY_BUS(drv) {
255 [ + - ]: 37 : if (drv->match(name))
256 : : break;
257 : : }
258 [ - + ]: 37 : if (drv != NULL && addr != NULL)
259 : 0 : *out = name;
260 [ + - ]: 37 : return drv != NULL ? 0 : -1;
261 : : }
262 : :
263 : : /* Register a driver */
264 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_auxiliary_register)
265 : : void
266 : 253 : rte_auxiliary_register(struct rte_auxiliary_driver *driver)
267 : : {
268 : 253 : TAILQ_INSERT_TAIL(&auxiliary_bus.driver_list, driver, next);
269 : 253 : }
270 : :
271 : : /* Unregister a driver */
272 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_auxiliary_unregister)
273 : : void
274 : 253 : rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
275 : : {
276 [ - + ]: 253 : TAILQ_REMOVE(&auxiliary_bus.driver_list, driver, next);
277 : 253 : }
278 : :
279 : : /* Add a device to auxiliary bus */
280 : : void
281 : 0 : auxiliary_add_device(struct rte_auxiliary_device *aux_dev)
282 : : {
283 : 0 : TAILQ_INSERT_TAIL(&auxiliary_bus.device_list, aux_dev, next);
284 : 0 : }
285 : :
286 : : /* Insert a device into a predefined position in auxiliary bus */
287 : : void
288 : 0 : auxiliary_insert_device(struct rte_auxiliary_device *exist_aux_dev,
289 : : struct rte_auxiliary_device *new_aux_dev)
290 : : {
291 : 0 : TAILQ_INSERT_BEFORE(exist_aux_dev, new_aux_dev, next);
292 : 0 : }
293 : :
294 : : /* Remove a device from auxiliary bus */
295 : : static void
296 : : rte_auxiliary_remove_device(struct rte_auxiliary_device *auxiliary_dev)
297 : : {
298 [ # # ]: 0 : TAILQ_REMOVE(&auxiliary_bus.device_list, auxiliary_dev, next);
299 : : }
300 : :
301 : : static struct rte_device *
302 : 0 : auxiliary_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
303 : : const void *data)
304 : : {
305 : : const struct rte_auxiliary_device *pstart;
306 : : struct rte_auxiliary_device *adev;
307 : :
308 [ # # ]: 0 : if (start != NULL) {
309 : 0 : pstart = RTE_DEV_TO_AUXILIARY_CONST(start);
310 : 0 : adev = TAILQ_NEXT(pstart, next);
311 : : } else {
312 : 0 : adev = TAILQ_FIRST(&auxiliary_bus.device_list);
313 : : }
314 [ # # ]: 0 : while (adev != NULL) {
315 [ # # ]: 0 : if (cmp(&adev->device, data) == 0)
316 : 0 : return &adev->device;
317 : 0 : adev = TAILQ_NEXT(adev, next);
318 : : }
319 : : return NULL;
320 : : }
321 : :
322 : : static int
323 : 0 : auxiliary_plug(struct rte_device *dev)
324 : : {
325 [ # # ]: 0 : if (!auxiliary_dev_exists(dev->name))
326 : : return -ENOENT;
327 : 0 : return auxiliary_probe_all_drivers(RTE_DEV_TO_AUXILIARY(dev));
328 : : }
329 : :
330 : : static int
331 : 0 : auxiliary_unplug(struct rte_device *dev)
332 : : {
333 : : struct rte_auxiliary_device *adev;
334 : : int ret;
335 : :
336 : 0 : adev = RTE_DEV_TO_AUXILIARY(dev);
337 : 0 : ret = rte_auxiliary_driver_remove_dev(adev);
338 [ # # ]: 0 : if (ret == 0) {
339 : : rte_auxiliary_remove_device(adev);
340 : 0 : rte_devargs_remove(dev->devargs);
341 : 0 : rte_intr_instance_free(adev->intr_handle);
342 : 0 : free(adev);
343 : : }
344 : 0 : return ret;
345 : : }
346 : :
347 : : static int
348 : 253 : auxiliary_cleanup(void)
349 : : {
350 : : struct rte_auxiliary_device *dev, *tmp_dev;
351 : : int error = 0;
352 : :
353 [ - + ]: 253 : RTE_TAILQ_FOREACH_SAFE(dev, &auxiliary_bus.device_list, next, tmp_dev) {
354 : : int ret;
355 : :
356 : 0 : ret = auxiliary_unplug(&dev->device);
357 [ # # ]: 0 : if (ret < 0) {
358 : 0 : rte_errno = errno;
359 : : error = -1;
360 : : }
361 : : }
362 : :
363 : 253 : return error;
364 : : }
365 : :
366 : : static int
367 : 0 : auxiliary_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
368 : : {
369 : 0 : struct rte_auxiliary_device *aux_dev = RTE_DEV_TO_AUXILIARY(dev);
370 : :
371 [ # # # # ]: 0 : if (dev == NULL || aux_dev->driver == NULL) {
372 : 0 : rte_errno = EINVAL;
373 : 0 : return -1;
374 : : }
375 [ # # ]: 0 : if (aux_dev->driver->dma_map == NULL) {
376 : 0 : rte_errno = ENOTSUP;
377 : 0 : return -1;
378 : : }
379 : 0 : return aux_dev->driver->dma_map(aux_dev, addr, iova, len);
380 : : }
381 : :
382 : : static int
383 : 0 : auxiliary_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
384 : : size_t len)
385 : : {
386 : 0 : struct rte_auxiliary_device *aux_dev = RTE_DEV_TO_AUXILIARY(dev);
387 : :
388 [ # # # # ]: 0 : if (dev == NULL || aux_dev->driver == NULL) {
389 : 0 : rte_errno = EINVAL;
390 : 0 : return -1;
391 : : }
392 [ # # ]: 0 : if (aux_dev->driver->dma_unmap == NULL) {
393 : 0 : rte_errno = ENOTSUP;
394 : 0 : return -1;
395 : : }
396 : 0 : return aux_dev->driver->dma_unmap(aux_dev, addr, iova, len);
397 : : }
398 : :
399 : : bool
400 : 0 : auxiliary_is_ignored_device(const char *name)
401 : : {
402 : 0 : struct rte_devargs *devargs = auxiliary_devargs_lookup(name);
403 : :
404 [ # # # ]: 0 : switch (auxiliary_bus.bus.conf.scan_mode) {
405 : 0 : case RTE_BUS_SCAN_ALLOWLIST:
406 [ # # # # ]: 0 : if (devargs && devargs->policy == RTE_DEV_ALLOWED)
407 : 0 : return false;
408 : : break;
409 : 0 : case RTE_BUS_SCAN_UNDEFINED:
410 : : case RTE_BUS_SCAN_BLOCKLIST:
411 [ # # # # ]: 0 : if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED)
412 : 0 : return false;
413 : : break;
414 : : }
415 : : return true;
416 : : }
417 : :
418 : : static enum rte_iova_mode
419 : 186 : auxiliary_get_iommu_class(void)
420 : : {
421 : : const struct rte_auxiliary_driver *drv;
422 : :
423 [ + + ]: 372 : FOREACH_DRIVER_ON_AUXILIARY_BUS(drv) {
424 [ + - ]: 186 : if ((drv->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) > 0)
425 : : return RTE_IOVA_VA;
426 : : }
427 : :
428 : : return RTE_IOVA_DC;
429 : : }
430 : :
431 : : struct rte_auxiliary_bus auxiliary_bus = {
432 : : .bus = {
433 : : .scan = auxiliary_scan,
434 : : .probe = auxiliary_probe,
435 : : .cleanup = auxiliary_cleanup,
436 : : .find_device = auxiliary_find_device,
437 : : .plug = auxiliary_plug,
438 : : .unplug = auxiliary_unplug,
439 : : .parse = auxiliary_parse,
440 : : .dma_map = auxiliary_dma_map,
441 : : .dma_unmap = auxiliary_dma_unmap,
442 : : .get_iommu_class = auxiliary_get_iommu_class,
443 : : .dev_iterate = auxiliary_dev_iterate,
444 : : },
445 : : .device_list = TAILQ_HEAD_INITIALIZER(auxiliary_bus.device_list),
446 : : .driver_list = TAILQ_HEAD_INITIALIZER(auxiliary_bus.driver_list),
447 : : };
448 : :
449 : 253 : RTE_REGISTER_BUS(auxiliary, auxiliary_bus.bus);
450 [ - + ]: 253 : RTE_LOG_REGISTER_DEFAULT(auxiliary_bus_logtype, NOTICE);
|