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