Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation.
3 : : * Copyright(c) 2014 6WIND S.A.
4 : : */
5 : :
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <sys/queue.h>
10 : :
11 : : #include <bus_driver.h>
12 : : #include <rte_class.h>
13 : : #include <dev_driver.h>
14 : : #include <rte_devargs.h>
15 : : #include <rte_errno.h>
16 : : #include <rte_log.h>
17 : : #include <rte_spinlock.h>
18 : : #include <rte_string_fns.h>
19 : :
20 : : #include <eal_export.h>
21 : : #include "eal_private.h"
22 : : #include "hotplug_mp.h"
23 : :
24 : : RTE_EXPORT_SYMBOL(rte_driver_name)
25 : : const char *
26 : 0 : rte_driver_name(const struct rte_driver *driver)
27 : : {
28 : 0 : return driver->name;
29 : : }
30 : :
31 : : RTE_EXPORT_SYMBOL(rte_dev_bus)
32 : : const struct rte_bus *
33 : 0 : rte_dev_bus(const struct rte_device *dev)
34 : : {
35 : 0 : return dev->bus;
36 : : }
37 : :
38 : : RTE_EXPORT_SYMBOL(rte_dev_bus_info)
39 : : const char *
40 : 0 : rte_dev_bus_info(const struct rte_device *dev)
41 : : {
42 : 0 : return dev->bus_info;
43 : : }
44 : :
45 : : RTE_EXPORT_SYMBOL(rte_dev_devargs)
46 : : const struct rte_devargs *
47 : 0 : rte_dev_devargs(const struct rte_device *dev)
48 : : {
49 : 0 : return dev->devargs;
50 : : }
51 : :
52 : : RTE_EXPORT_SYMBOL(rte_dev_driver)
53 : : const struct rte_driver *
54 : 0 : rte_dev_driver(const struct rte_device *dev)
55 : : {
56 : 0 : return dev->driver;
57 : : }
58 : :
59 : : RTE_EXPORT_SYMBOL(rte_dev_name)
60 : : const char *
61 : 8 : rte_dev_name(const struct rte_device *dev)
62 : : {
63 : 8 : return dev->name;
64 : : }
65 : :
66 : : RTE_EXPORT_SYMBOL(rte_dev_numa_node)
67 : : int
68 : 0 : rte_dev_numa_node(const struct rte_device *dev)
69 : : {
70 : 0 : return dev->numa_node;
71 : : }
72 : :
73 : : /**
74 : : * The device event callback description.
75 : : *
76 : : * It contains callback address to be registered by user application,
77 : : * the pointer to the parameters for callback, and the device name.
78 : : */
79 : : struct dev_event_callback {
80 : : TAILQ_ENTRY(dev_event_callback) next; /**< Callbacks list */
81 : : rte_dev_event_cb_fn cb_fn; /**< Callback address */
82 : : void *cb_arg; /**< Callback parameter */
83 : : char *dev_name; /**< Callback device name, NULL is for all device */
84 : : uint32_t active; /**< Callback is executing */
85 : : };
86 : :
87 : : /** @internal Structure to keep track of registered callbacks */
88 : : TAILQ_HEAD(dev_event_cb_list, dev_event_callback);
89 : :
90 : : /* The device event callback list for all registered callbacks. */
91 : : static struct dev_event_cb_list dev_event_cbs;
92 : :
93 : : /* spinlock for device callbacks */
94 : : static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
95 : :
96 : : struct dev_next_ctx {
97 : : struct rte_dev_iterator *it;
98 : : const char *bus_str;
99 : : const char *cls_str;
100 : : };
101 : :
102 : : #define CTX(it, bus_str, cls_str) \
103 : : (&(const struct dev_next_ctx){ \
104 : : .it = it, \
105 : : .bus_str = bus_str, \
106 : : .cls_str = cls_str, \
107 : : })
108 : :
109 : : #define ITCTX(ptr) \
110 : : (((struct dev_next_ctx *)(intptr_t)ptr)->it)
111 : :
112 : : #define BUSCTX(ptr) \
113 : : (((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
114 : :
115 : : #define CLSCTX(ptr) \
116 : : (((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
117 : :
118 : 0 : static int cmp_dev_name(const struct rte_device *dev, const void *_name)
119 : : {
120 : : const char *name = _name;
121 : :
122 : 0 : return strcmp(dev->name, name);
123 : : }
124 : :
125 : : RTE_EXPORT_SYMBOL(rte_dev_is_probed)
126 : : int
127 : 14686 : rte_dev_is_probed(const struct rte_device *dev)
128 : : {
129 : : /* The field driver should be set only when the probe is successful. */
130 : 14686 : return dev->driver != NULL;
131 : : }
132 : :
133 : : /* helper function to build devargs, caller should free the memory */
134 : : static int
135 [ # # ]: 0 : build_devargs(const char *busname, const char *devname,
136 : : const char *drvargs, char **devargs)
137 : : {
138 : : int length;
139 : :
140 : : length = snprintf(NULL, 0, "%s:%s,%s", busname, devname, drvargs);
141 [ # # ]: 0 : if (length < 0)
142 : : return -EINVAL;
143 : :
144 : 0 : *devargs = malloc(length + 1);
145 [ # # ]: 0 : if (*devargs == NULL)
146 : : return -ENOMEM;
147 : :
148 : : length = snprintf(*devargs, length + 1, "%s:%s,%s",
149 : : busname, devname, drvargs);
150 [ # # ]: 0 : if (length < 0) {
151 : 0 : free(*devargs);
152 : 0 : return -EINVAL;
153 : : }
154 : :
155 : : return 0;
156 : : }
157 : :
158 : : RTE_EXPORT_SYMBOL(rte_eal_hotplug_add)
159 : : int
160 : 0 : rte_eal_hotplug_add(const char *busname, const char *devname,
161 : : const char *drvargs)
162 : : {
163 : :
164 : : char *devargs;
165 : : int ret;
166 : :
167 : 0 : ret = build_devargs(busname, devname, drvargs, &devargs);
168 [ # # ]: 0 : if (ret != 0)
169 : : return ret;
170 : :
171 : 0 : ret = rte_dev_probe(devargs);
172 : 0 : free(devargs);
173 : :
174 : 0 : return ret;
175 : : }
176 : :
177 : : /* probe device at local process. */
178 : : int
179 : 0 : local_dev_probe(const char *devargs, struct rte_device **new_dev)
180 : : {
181 : : struct rte_device *dev;
182 : : struct rte_driver *drv;
183 : : struct rte_devargs *da;
184 : : int ret;
185 : :
186 : 0 : *new_dev = NULL;
187 : 0 : da = calloc(1, sizeof(*da));
188 [ # # ]: 0 : if (da == NULL)
189 : : return -ENOMEM;
190 : :
191 : 0 : ret = rte_devargs_parse(da, devargs);
192 [ # # ]: 0 : if (ret)
193 : 0 : goto err_devarg;
194 : :
195 [ # # ]: 0 : if (da->bus->probe_device == NULL) {
196 : 0 : EAL_LOG(ERR, "Function probe_device not supported by bus (%s)",
197 : : da->bus->name);
198 : : ret = -ENOTSUP;
199 : 0 : goto err_devarg;
200 : : }
201 : :
202 : 0 : ret = rte_devargs_insert(&da);
203 [ # # ]: 0 : if (ret)
204 : 0 : goto err_devarg;
205 : :
206 : : /* the rte_devargs will be referenced in the matching rte_device */
207 : 0 : ret = da->bus->scan();
208 [ # # ]: 0 : if (ret)
209 : 0 : goto err_devarg;
210 : :
211 : 0 : dev = da->bus->find_device(da->bus, NULL, cmp_dev_name, da->name);
212 [ # # ]: 0 : if (dev == NULL) {
213 : 0 : EAL_LOG(ERR, "Cannot find device (%s)",
214 : : da->name);
215 : : ret = -ENODEV;
216 : 0 : goto err_devarg;
217 : : }
218 : : /* Since there is a matching device, it is now its responsibility
219 : : * to manage the devargs we've just inserted. From this point
220 : : * those devargs shouldn't be removed manually anymore.
221 : : */
222 : :
223 : : drv = NULL;
224 : 0 : next_driver:
225 : 0 : drv = rte_bus_find_driver(dev->bus, drv, dev);
226 [ # # ]: 0 : if (drv == NULL) {
227 : : ret = -ENOTSUP;
228 [ # # # # ]: 0 : } else if (rte_dev_is_probed(dev) && !dev->bus->allow_multi_probe) {
229 : 0 : EAL_LOG(INFO, "Device %s is already probed", dev->name);
230 : : ret = -EEXIST;
231 : : } else {
232 : 0 : bool was_probed = rte_dev_is_probed(dev);
233 : :
234 : : /*
235 : : * Reference driver structure.
236 : : * This needs to be before .probe_device as some bus (like PCI) use
237 : : * driver flags for adjusting configuration.
238 : : */
239 [ # # ]: 0 : if (!was_probed)
240 : 0 : dev->driver = drv;
241 : 0 : ret = dev->bus->probe_device(drv, dev);
242 [ # # ]: 0 : if (!was_probed && ret != 0)
243 : 0 : dev->driver = NULL;
244 : :
245 [ # # ]: 0 : if (ret > 0)
246 : 0 : goto next_driver;
247 : : }
248 : :
249 [ # # # # ]: 0 : if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */
250 : 0 : EAL_LOG(ERR, "Driver cannot attach the device (%s)",
251 : : dev->name);
252 : 0 : return ret;
253 : : }
254 : :
255 : 0 : *new_dev = dev;
256 : 0 : return ret;
257 : :
258 : 0 : err_devarg:
259 [ # # ]: 0 : if (rte_devargs_remove(da) != 0) {
260 : 0 : rte_devargs_reset(da);
261 : 0 : free(da);
262 : : }
263 : : return ret;
264 : : }
265 : :
266 : : RTE_EXPORT_SYMBOL(rte_dev_probe)
267 : : int
268 : 0 : rte_dev_probe(const char *devargs)
269 : : {
270 : : const struct internal_config *internal_conf =
271 : 0 : eal_get_internal_configuration();
272 : 0 : bool do_mp = !!internal_conf->no_shconf;
273 : : struct eal_dev_mp_req req;
274 : : struct rte_device *dev;
275 : : int ret;
276 : :
277 [ # # ]: 0 : if (!do_mp)
278 : 0 : goto skip_mp_req;
279 : :
280 [ # # ]: 0 : if (strlen(devargs) >= EAL_DEV_MP_DEV_ARGS_MAX_LEN) {
281 : 0 : EAL_LOG(ERR, "devargs truncated (len %zu, max %d)",
282 : : strlen(devargs), EAL_DEV_MP_DEV_ARGS_MAX_LEN);
283 : 0 : return -E2BIG;
284 : : }
285 : :
286 : : memset(&req, 0, sizeof(req));
287 : : req.t = EAL_DEV_REQ_TYPE_ATTACH;
288 : : strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
289 : :
290 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
291 : : /**
292 : : * If in secondary process, just send IPC request to
293 : : * primary process.
294 : : */
295 : 0 : ret = eal_dev_hotplug_request_to_primary(&req);
296 [ # # ]: 0 : if (ret != 0) {
297 : 0 : EAL_LOG(ERR,
298 : : "Failed to send hotplug request to primary");
299 : 0 : return -ENOMSG;
300 : : }
301 [ # # ]: 0 : if (req.result != 0)
302 : 0 : EAL_LOG(ERR,
303 : : "Failed to hotplug add device");
304 : 0 : return req.result;
305 : : }
306 : :
307 : : /* attach a shared device from primary start from here: */
308 : :
309 : 0 : skip_mp_req:
310 : : /* primary attach the new device itself. */
311 : 0 : ret = local_dev_probe(devargs, &dev);
312 : :
313 [ # # ]: 0 : if (ret != 0) {
314 : 0 : EAL_LOG(ERR,
315 : : "Failed to attach device on primary process");
316 : :
317 : : /**
318 : : * it is possible that secondary process failed to attached a
319 : : * device that primary process have during initialization,
320 : : * so for -EEXIST case, we still need to sync with secondary
321 : : * process.
322 : : */
323 [ # # ]: 0 : if (ret != -EEXIST)
324 : : return ret;
325 : : }
326 : :
327 [ # # ]: 0 : if (!do_mp)
328 : 0 : goto skip_mp_notify;
329 : :
330 : : /* primary send attach sync request to secondary. */
331 : 0 : ret = eal_dev_hotplug_request_to_secondary(&req);
332 : :
333 : : /* if any communication error, we need to rollback. */
334 [ # # ]: 0 : if (ret != 0) {
335 : 0 : EAL_LOG(ERR,
336 : : "Failed to send hotplug add request to secondary");
337 : : ret = -ENOMSG;
338 : 0 : goto rollback;
339 : : }
340 : :
341 : : /**
342 : : * if any secondary failed to attach, we need to consider if rollback
343 : : * is necessary.
344 : : */
345 [ # # ]: 0 : if (req.result != 0) {
346 : 0 : EAL_LOG(ERR,
347 : : "Failed to attach device on secondary process");
348 : 0 : ret = req.result;
349 : :
350 : : /* for -EEXIST, we don't need to rollback. */
351 [ # # ]: 0 : if (ret == -EEXIST)
352 : : return ret;
353 : 0 : goto rollback;
354 : : }
355 : :
356 : 0 : skip_mp_notify:
357 : : return 0;
358 : :
359 : 0 : rollback:
360 : : if (do_mp) {
361 : 0 : req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
362 : :
363 : : /* primary send rollback request to secondary. */
364 [ # # ]: 0 : if (eal_dev_hotplug_request_to_secondary(&req) != 0)
365 : 0 : EAL_LOG(WARNING,
366 : : "Failed to rollback device attach on secondary."
367 : : "Devices in secondary may not sync with primary");
368 : : }
369 : :
370 : : /* primary rollback itself. */
371 [ # # ]: 0 : if (local_dev_remove(dev) != 0)
372 : 0 : EAL_LOG(WARNING,
373 : : "Failed to rollback device attach on primary."
374 : : "Devices in secondary may not sync with primary");
375 : :
376 : : return ret;
377 : : }
378 : :
379 : : RTE_EXPORT_SYMBOL(rte_eal_hotplug_remove)
380 : : int
381 : 0 : rte_eal_hotplug_remove(const char *busname, const char *devname)
382 : : {
383 : : struct rte_device *dev;
384 : : struct rte_bus *bus;
385 : :
386 : 0 : bus = rte_bus_find_by_name(busname);
387 [ # # ]: 0 : if (bus == NULL) {
388 : 0 : EAL_LOG(ERR, "Cannot find bus (%s)", busname);
389 : 0 : return -ENOENT;
390 : : }
391 : :
392 : 0 : dev = bus->find_device(bus, NULL, cmp_dev_name, devname);
393 [ # # ]: 0 : if (dev == NULL) {
394 : 0 : EAL_LOG(ERR, "Cannot find plugged device (%s)", devname);
395 : 0 : return -EINVAL;
396 : : }
397 : :
398 : 0 : return rte_dev_remove(dev);
399 : : }
400 : :
401 : : /* remove device at local process. */
402 : : int
403 : 0 : local_dev_remove(struct rte_device *dev)
404 : : {
405 : : int ret;
406 : :
407 [ # # ]: 0 : if (dev->bus->unplug_device == NULL) {
408 : 0 : EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
409 : : dev->bus->name);
410 : 0 : return -ENOTSUP;
411 : : }
412 : :
413 : 0 : ret = dev->bus->unplug_device(dev);
414 [ # # ]: 0 : if (ret) {
415 : 0 : EAL_LOG(ERR, "Driver cannot detach the device (%s)",
416 : : dev->name);
417 [ # # ]: 0 : return (ret < 0) ? ret : -ENOENT;
418 : : }
419 : :
420 : 0 : dev->driver = NULL;
421 : :
422 : 0 : return 0;
423 : : }
424 : :
425 : : RTE_EXPORT_SYMBOL(rte_dev_remove)
426 : : int
427 : 0 : rte_dev_remove(struct rte_device *dev)
428 : : {
429 : : const struct internal_config *internal_conf =
430 : 0 : eal_get_internal_configuration();
431 : 0 : bool do_mp = !!internal_conf->no_shconf;
432 : : struct eal_dev_mp_req req;
433 : : char *devargs;
434 : : int ret;
435 : :
436 [ # # ]: 0 : if (!rte_dev_is_probed(dev)) {
437 : 0 : EAL_LOG(ERR, "Device is not probed");
438 : 0 : return -ENOENT;
439 : : }
440 : :
441 [ # # ]: 0 : if (!do_mp)
442 : 0 : goto skip_mp_req;
443 : :
444 : 0 : ret = build_devargs(dev->bus->name, dev->name, "", &devargs);
445 [ # # ]: 0 : if (ret != 0)
446 : : return ret;
447 : :
448 : : memset(&req, 0, sizeof(req));
449 : 0 : req.t = EAL_DEV_REQ_TYPE_DETACH;
450 : 0 : strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
451 : 0 : free(devargs);
452 : :
453 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
454 : : /**
455 : : * If in secondary process, just send IPC request to
456 : : * primary process.
457 : : */
458 : 0 : ret = eal_dev_hotplug_request_to_primary(&req);
459 [ # # ]: 0 : if (ret != 0) {
460 : 0 : EAL_LOG(ERR,
461 : : "Failed to send hotplug request to primary");
462 : 0 : return -ENOMSG;
463 : : }
464 [ # # ]: 0 : if (req.result != 0)
465 : 0 : EAL_LOG(ERR,
466 : : "Failed to hotplug remove device");
467 : 0 : return req.result;
468 : : }
469 : :
470 : : /* detach a device from primary start from here: */
471 : :
472 : : /* primary send detach sync request to secondary */
473 : 0 : ret = eal_dev_hotplug_request_to_secondary(&req);
474 : :
475 : : /**
476 : : * if communication error, we need to rollback, because it is possible
477 : : * part of the secondary processes still detached it successfully.
478 : : */
479 [ # # ]: 0 : if (ret != 0) {
480 : 0 : EAL_LOG(ERR,
481 : : "Failed to send device detach request to secondary");
482 : : ret = -ENOMSG;
483 : 0 : goto rollback;
484 : : }
485 : :
486 : : /**
487 : : * if any secondary failed to detach, we need to consider if rollback
488 : : * is necessary.
489 : : */
490 [ # # ]: 0 : if (req.result != 0) {
491 : 0 : EAL_LOG(ERR,
492 : : "Failed to detach device on secondary process");
493 : 0 : ret = req.result;
494 : : /**
495 : : * if -ENOENT, we don't need to rollback, since devices is
496 : : * already detached on secondary process.
497 : : */
498 [ # # ]: 0 : if (ret != -ENOENT)
499 : 0 : goto rollback;
500 : : }
501 : :
502 : 0 : skip_mp_req:
503 : : /* primary detach the device itself. */
504 : 0 : ret = local_dev_remove(dev);
505 : :
506 : : /* if primary failed, still need to consider if rollback is necessary */
507 [ # # ]: 0 : if (ret != 0) {
508 : 0 : EAL_LOG(ERR,
509 : : "Failed to detach device on primary process");
510 : : /* if -ENOENT, we don't need to rollback */
511 [ # # ]: 0 : if (ret == -ENOENT)
512 : : return ret;
513 : 0 : goto rollback;
514 : : }
515 : :
516 : : return 0;
517 : :
518 : 0 : rollback:
519 [ # # ]: 0 : if (do_mp) {
520 : 0 : req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
521 : :
522 : : /* primary send rollback request to secondary. */
523 [ # # ]: 0 : if (eal_dev_hotplug_request_to_secondary(&req) != 0)
524 : 0 : EAL_LOG(WARNING,
525 : : "Failed to rollback device detach on secondary."
526 : : "Devices in secondary may not sync with primary");
527 : : }
528 : :
529 : : return ret;
530 : : }
531 : :
532 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_register)
533 : : int
534 : 0 : rte_dev_event_callback_register(const char *device_name,
535 : : rte_dev_event_cb_fn cb_fn,
536 : : void *cb_arg)
537 : : {
538 : : struct dev_event_callback *event_cb;
539 : : int ret;
540 : :
541 [ # # ]: 0 : if (!cb_fn)
542 : : return -EINVAL;
543 : :
544 : : rte_spinlock_lock(&dev_event_lock);
545 : :
546 [ # # ]: 0 : if (TAILQ_EMPTY(&dev_event_cbs))
547 : 0 : TAILQ_INIT(&dev_event_cbs);
548 : :
549 [ # # ]: 0 : TAILQ_FOREACH(event_cb, &dev_event_cbs, next) {
550 [ # # # # ]: 0 : if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) {
551 [ # # # # ]: 0 : if (device_name == NULL && event_cb->dev_name == NULL)
552 : : break;
553 [ # # # # ]: 0 : if (device_name == NULL || event_cb->dev_name == NULL)
554 : 0 : continue;
555 [ # # ]: 0 : if (!strcmp(event_cb->dev_name, device_name))
556 : : break;
557 : : }
558 : : }
559 : :
560 : : /* create a new callback. */
561 [ # # ]: 0 : if (event_cb == NULL) {
562 : 0 : event_cb = malloc(sizeof(struct dev_event_callback));
563 [ # # ]: 0 : if (event_cb != NULL) {
564 : 0 : event_cb->cb_fn = cb_fn;
565 : 0 : event_cb->cb_arg = cb_arg;
566 : 0 : event_cb->active = 0;
567 [ # # ]: 0 : if (!device_name) {
568 : 0 : event_cb->dev_name = NULL;
569 : : } else {
570 : 0 : event_cb->dev_name = strdup(device_name);
571 [ # # ]: 0 : if (event_cb->dev_name == NULL) {
572 : : ret = -ENOMEM;
573 : 0 : goto error;
574 : : }
575 : : }
576 : 0 : TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next);
577 : : } else {
578 : 0 : EAL_LOG(ERR,
579 : : "Failed to allocate memory for device "
580 : : "event callback.");
581 : : ret = -ENOMEM;
582 : 0 : goto error;
583 : : }
584 : : } else {
585 : 0 : EAL_LOG(ERR,
586 : : "The callback is already exist, no need "
587 : : "to register again.");
588 : : event_cb = NULL;
589 : : ret = -EEXIST;
590 : 0 : goto error;
591 : : }
592 : :
593 : : rte_spinlock_unlock(&dev_event_lock);
594 : 0 : return 0;
595 : 0 : error:
596 : 0 : free(event_cb);
597 : : rte_spinlock_unlock(&dev_event_lock);
598 : 0 : return ret;
599 : : }
600 : :
601 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_unregister)
602 : : int
603 : 0 : rte_dev_event_callback_unregister(const char *device_name,
604 : : rte_dev_event_cb_fn cb_fn,
605 : : void *cb_arg)
606 : : {
607 : : int ret = 0;
608 : : struct dev_event_callback *event_cb, *next;
609 : :
610 [ # # ]: 0 : if (!cb_fn)
611 : : return -EINVAL;
612 : :
613 : : rte_spinlock_lock(&dev_event_lock);
614 : : /*walk through the callbacks and remove all that match. */
615 [ # # ]: 0 : for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL;
616 : : event_cb = next) {
617 : :
618 : 0 : next = TAILQ_NEXT(event_cb, next);
619 : :
620 [ # # # # ]: 0 : if (device_name != NULL && event_cb->dev_name != NULL) {
621 [ # # ]: 0 : if (strcmp(event_cb->dev_name, device_name))
622 : 0 : continue;
623 [ # # ]: 0 : } else if (device_name != NULL) {
624 : 0 : continue;
625 : : }
626 : :
627 : : /* Remove only matching callback with arg */
628 [ # # # # ]: 0 : if (event_cb->cb_fn != cb_fn ||
629 [ # # ]: 0 : (cb_arg != (void *)-1 && event_cb->cb_arg != cb_arg))
630 : 0 : continue;
631 : :
632 : : /*
633 : : * if this callback is not executing right now,
634 : : * then remove it.
635 : : */
636 [ # # ]: 0 : if (event_cb->active == 0) {
637 [ # # ]: 0 : TAILQ_REMOVE(&dev_event_cbs, event_cb, next);
638 : 0 : free(event_cb->dev_name);
639 : 0 : free(event_cb);
640 : 0 : ret++;
641 : : } else {
642 : : ret = -EAGAIN;
643 : : break;
644 : : }
645 : : }
646 : :
647 : : /* this callback is not be registered */
648 [ # # ]: 0 : if (ret == 0)
649 : : ret = -ENOENT;
650 : :
651 : : rte_spinlock_unlock(&dev_event_lock);
652 : 0 : return ret;
653 : : }
654 : :
655 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_process)
656 : : void
657 : 0 : rte_dev_event_callback_process(const char *device_name,
658 : : enum rte_dev_event_type event)
659 : : {
660 : : struct dev_event_callback *cb_lst;
661 : :
662 [ # # ]: 0 : if (device_name == NULL)
663 : : return;
664 : :
665 : : rte_spinlock_lock(&dev_event_lock);
666 : :
667 [ # # ]: 0 : TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) {
668 [ # # ]: 0 : if (cb_lst->dev_name) {
669 [ # # ]: 0 : if (strcmp(cb_lst->dev_name, device_name))
670 : 0 : continue;
671 : : }
672 : 0 : cb_lst->active = 1;
673 : : rte_spinlock_unlock(&dev_event_lock);
674 : 0 : cb_lst->cb_fn(device_name, event,
675 : : cb_lst->cb_arg);
676 : : rte_spinlock_lock(&dev_event_lock);
677 : 0 : cb_lst->active = 0;
678 : : }
679 : : rte_spinlock_unlock(&dev_event_lock);
680 : : }
681 : :
682 : : RTE_EXPORT_SYMBOL(rte_dev_iterator_init)
683 : : int
684 : 1 : rte_dev_iterator_init(struct rte_dev_iterator *it,
685 : : const char *dev_str)
686 : : {
687 : 1 : struct rte_devargs devargs = { .bus = NULL };
688 : : struct rte_class *cls = NULL;
689 : : struct rte_bus *bus = NULL;
690 : :
691 : : /* Having both bus_str and cls_str NULL is illegal,
692 : : * marking this iterator as invalid unless
693 : : * everything goes well.
694 : : */
695 : 1 : it->bus_str = NULL;
696 : 1 : it->cls_str = NULL;
697 : :
698 : : /* Setting data field implies no malloc in parsing. */
699 : 1 : devargs.data = (void *)(intptr_t)dev_str;
700 [ - + ]: 1 : if (rte_devargs_layers_parse(&devargs, dev_str))
701 : 0 : goto get_out;
702 : :
703 : 1 : bus = devargs.bus;
704 : 1 : cls = devargs.cls;
705 : : /* The string should have at least
706 : : * one layer specified.
707 : : */
708 [ - + ]: 1 : if (bus == NULL && cls == NULL) {
709 : 0 : EAL_LOG(DEBUG, "Either bus or class must be specified.");
710 : 0 : rte_errno = EINVAL;
711 : 0 : goto get_out;
712 : : }
713 [ + - - + ]: 1 : if (bus != NULL && bus->dev_iterate == NULL) {
714 : 0 : EAL_LOG(DEBUG, "Bus %s not supported", bus->name);
715 : 0 : rte_errno = ENOTSUP;
716 : 0 : goto get_out;
717 : : }
718 [ - + - - ]: 1 : if (cls != NULL && cls->dev_iterate == NULL) {
719 : 0 : EAL_LOG(DEBUG, "Class %s not supported", cls->name);
720 : 0 : rte_errno = ENOTSUP;
721 : 0 : goto get_out;
722 : : }
723 : 1 : it->bus_str = devargs.bus_str;
724 : 1 : it->cls_str = devargs.cls_str;
725 : 1 : it->dev_str = dev_str;
726 : 1 : it->bus = bus;
727 : 1 : it->cls = cls;
728 : 1 : it->device = NULL;
729 : 1 : it->class_device = NULL;
730 : 1 : get_out:
731 : 1 : return -rte_errno;
732 : : }
733 : :
734 : : static char *
735 : 3 : dev_str_sane_copy(const char *str)
736 : : {
737 : : size_t end;
738 : : char *copy;
739 : :
740 : 3 : end = strcspn(str, ",/");
741 [ - + ]: 3 : if (str[end] == ',') {
742 : 0 : copy = strdup(&str[end + 1]);
743 : : } else {
744 : : /* '/' or '\0' */
745 : 3 : copy = strdup("");
746 : : }
747 [ - + ]: 3 : if (copy == NULL) {
748 : 0 : rte_errno = ENOMEM;
749 : : } else {
750 : : char *slash;
751 : :
752 : 3 : slash = strchr(copy, '/');
753 [ - + ]: 3 : if (slash != NULL)
754 : 0 : slash[0] = '\0';
755 : : }
756 : 3 : return copy;
757 : : }
758 : :
759 : : static int
760 : 0 : class_next_dev_cmp(const struct rte_class *cls,
761 : : const void *ctx)
762 : : {
763 : : struct rte_dev_iterator *it;
764 : : const char *cls_str = NULL;
765 : : void *dev;
766 : :
767 [ # # ]: 0 : if (cls->dev_iterate == NULL)
768 : : return 1;
769 : 0 : it = ITCTX(ctx);
770 : 0 : cls_str = CLSCTX(ctx);
771 : 0 : dev = it->class_device;
772 : : /* it->cls_str != NULL means a class
773 : : * was specified in the devstr.
774 : : */
775 [ # # # # ]: 0 : if (it->cls_str != NULL && cls != it->cls)
776 : : return 1;
777 : : /* If an error occurred previously,
778 : : * no need to test further.
779 : : */
780 [ # # ]: 0 : if (rte_errno != 0)
781 : : return -1;
782 : 0 : dev = cls->dev_iterate(dev, cls_str, it);
783 : 0 : it->class_device = dev;
784 : 0 : return dev == NULL;
785 : : }
786 : :
787 : : static int
788 : 5 : bus_next_dev_cmp(const struct rte_bus *bus,
789 : : const void *ctx)
790 : : {
791 : : struct rte_device *dev = NULL;
792 : : struct rte_class *cls = NULL;
793 : : struct rte_dev_iterator *it;
794 : : const char *bus_str = NULL;
795 : :
796 [ + + ]: 5 : if (bus->dev_iterate == NULL)
797 : : return 1;
798 : 3 : it = ITCTX(ctx);
799 : 3 : bus_str = BUSCTX(ctx);
800 : 3 : dev = it->device;
801 : : /* it->bus_str != NULL means a bus
802 : : * was specified in the devstr.
803 : : */
804 [ + - + - ]: 3 : if (it->bus_str != NULL && bus != it->bus)
805 : : return 1;
806 : : /* If an error occurred previously,
807 : : * no need to test further.
808 : : */
809 [ + - ]: 3 : if (rte_errno != 0)
810 : : return -1;
811 [ + - ]: 3 : if (it->cls_str == NULL) {
812 : 3 : dev = bus->dev_iterate(bus, dev, bus_str, it);
813 : 3 : goto end;
814 : : }
815 : : /* cls_str != NULL */
816 [ # # ]: 0 : if (dev == NULL) {
817 : 0 : next_dev_on_bus:
818 : 0 : dev = bus->dev_iterate(bus, dev, bus_str, it);
819 : 0 : it->device = dev;
820 : : }
821 [ # # ]: 0 : if (dev == NULL)
822 : : return 1;
823 [ # # ]: 0 : if (it->cls != NULL)
824 : 0 : cls = TAILQ_PREV(it->cls, rte_class_list, next);
825 : 0 : cls = rte_class_find(cls, class_next_dev_cmp, ctx);
826 [ # # ]: 0 : if (cls != NULL) {
827 : 0 : it->cls = cls;
828 : 0 : goto end;
829 : : }
830 : 0 : goto next_dev_on_bus;
831 : 3 : end:
832 : 3 : it->device = dev;
833 : 3 : return dev == NULL;
834 : : }
835 : : RTE_EXPORT_SYMBOL(rte_dev_iterator_next)
836 : : struct rte_device *
837 : 3 : rte_dev_iterator_next(struct rte_dev_iterator *it)
838 : : {
839 : : struct rte_bus *bus = NULL;
840 : 3 : int old_errno = rte_errno;
841 : : char *bus_str = NULL;
842 : : char *cls_str = NULL;
843 : :
844 : 3 : rte_errno = 0;
845 [ - + - - ]: 3 : if (it->bus_str == NULL && it->cls_str == NULL) {
846 : : /* Invalid iterator. */
847 : 0 : rte_errno = EINVAL;
848 : 0 : return NULL;
849 : : }
850 [ + - ]: 3 : if (it->bus != NULL)
851 : 3 : bus = TAILQ_PREV(it->bus, rte_bus_list, next);
852 [ + - ]: 3 : if (it->bus_str != NULL) {
853 : 3 : bus_str = dev_str_sane_copy(it->bus_str);
854 [ - + ]: 3 : if (bus_str == NULL)
855 : 0 : goto out;
856 : : }
857 [ - + ]: 3 : if (it->cls_str != NULL) {
858 : 0 : cls_str = dev_str_sane_copy(it->cls_str);
859 [ # # ]: 0 : if (cls_str == NULL)
860 : 0 : goto out;
861 : : }
862 [ + + ]: 3 : while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
863 : 3 : CTX(it, bus_str, cls_str)))) {
864 [ + - ]: 2 : if (it->device != NULL) {
865 : 2 : it->bus = bus;
866 : 2 : goto out;
867 : : }
868 [ # # ]: 0 : if (it->bus_str != NULL ||
869 [ # # ]: 0 : rte_errno != 0)
870 : : break;
871 : : }
872 [ - + ]: 1 : if (rte_errno == 0)
873 : 1 : rte_errno = old_errno;
874 : 0 : out:
875 : 3 : free(bus_str);
876 : 3 : free(cls_str);
877 : 3 : return it->device;
878 : : }
879 : :
880 : : RTE_EXPORT_SYMBOL(rte_dev_dma_map)
881 : : int
882 : 0 : rte_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova,
883 : : size_t len)
884 : : {
885 [ # # ]: 0 : if (!rte_dev_is_probed(dev)) {
886 : 0 : rte_errno = EINVAL;
887 : 0 : return -1;
888 : : }
889 [ # # # # ]: 0 : if (dev->bus->dma_map == NULL || len == 0) {
890 : 0 : rte_errno = ENOTSUP;
891 : 0 : return -1;
892 : : }
893 : : /* Memory must be registered through rte_extmem_* APIs */
894 [ # # ]: 0 : if (rte_mem_virt2memseg_list(addr) == NULL) {
895 : 0 : rte_errno = EINVAL;
896 : 0 : return -1;
897 : : }
898 : :
899 : 0 : return dev->bus->dma_map(dev, addr, iova, len);
900 : : }
901 : :
902 : : RTE_EXPORT_SYMBOL(rte_dev_dma_unmap)
903 : : int
904 : 0 : rte_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
905 : : size_t len)
906 : : {
907 [ # # ]: 0 : if (!rte_dev_is_probed(dev)) {
908 : 0 : rte_errno = EINVAL;
909 : 0 : return -1;
910 : : }
911 [ # # # # ]: 0 : if (dev->bus->dma_unmap == NULL || len == 0) {
912 : 0 : rte_errno = ENOTSUP;
913 : 0 : return -1;
914 : : }
915 : : /* Memory must be registered through rte_extmem_* APIs */
916 [ # # ]: 0 : if (rte_mem_virt2memseg_list(addr) == NULL) {
917 : 0 : rte_errno = EINVAL;
918 : 0 : return -1;
919 : : }
920 : :
921 : 0 : return dev->bus->dma_unmap(dev, addr, iova, len);
922 : : }
|