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 : 204 : rte_dev_is_probed(const struct rte_device *dev)
128 : : {
129 : : /* The field driver should be set only when the probe is successful. */
130 : 204 : 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_devargs *da;
183 : : int ret;
184 : :
185 : 0 : *new_dev = NULL;
186 : 0 : da = calloc(1, sizeof(*da));
187 [ # # ]: 0 : if (da == NULL)
188 : : return -ENOMEM;
189 : :
190 : 0 : ret = rte_devargs_parse(da, devargs);
191 [ # # ]: 0 : if (ret)
192 : 0 : goto err_devarg;
193 : :
194 [ # # ]: 0 : if (da->bus->plug == NULL) {
195 : 0 : EAL_LOG(ERR, "Function plug not supported by bus (%s)",
196 : : da->bus->name);
197 : : ret = -ENOTSUP;
198 : 0 : goto err_devarg;
199 : : }
200 : :
201 : 0 : ret = rte_devargs_insert(&da);
202 [ # # ]: 0 : if (ret)
203 : 0 : goto err_devarg;
204 : :
205 : : /* the rte_devargs will be referenced in the matching rte_device */
206 : 0 : ret = da->bus->scan();
207 [ # # ]: 0 : if (ret)
208 : 0 : goto err_devarg;
209 : :
210 : 0 : dev = da->bus->find_device(NULL, cmp_dev_name, da->name);
211 [ # # ]: 0 : if (dev == NULL) {
212 : 0 : EAL_LOG(ERR, "Cannot find device (%s)",
213 : : da->name);
214 : : ret = -ENODEV;
215 : 0 : goto err_devarg;
216 : : }
217 : : /* Since there is a matching device, it is now its responsibility
218 : : * to manage the devargs we've just inserted. From this point
219 : : * those devargs shouldn't be removed manually anymore.
220 : : */
221 : :
222 : 0 : ret = dev->bus->plug(dev);
223 [ # # ]: 0 : if (ret > 0)
224 : : ret = -ENOTSUP;
225 : :
226 [ # # # # ]: 0 : if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */
227 : 0 : EAL_LOG(ERR, "Driver cannot attach the device (%s)",
228 : : dev->name);
229 : 0 : return ret;
230 : : }
231 : :
232 : 0 : *new_dev = dev;
233 : 0 : return ret;
234 : :
235 : 0 : err_devarg:
236 [ # # ]: 0 : if (rte_devargs_remove(da) != 0) {
237 : 0 : rte_devargs_reset(da);
238 : 0 : free(da);
239 : : }
240 : : return ret;
241 : : }
242 : :
243 : : RTE_EXPORT_SYMBOL(rte_dev_probe)
244 : : int
245 : 0 : rte_dev_probe(const char *devargs)
246 : : {
247 : : struct eal_dev_mp_req req;
248 : : struct rte_device *dev;
249 : : int ret;
250 : :
251 : : memset(&req, 0, sizeof(req));
252 : : req.t = EAL_DEV_REQ_TYPE_ATTACH;
253 : : strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
254 : :
255 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
256 : : /**
257 : : * If in secondary process, just send IPC request to
258 : : * primary process.
259 : : */
260 : 0 : ret = eal_dev_hotplug_request_to_primary(&req);
261 [ # # ]: 0 : if (ret != 0) {
262 : 0 : EAL_LOG(ERR,
263 : : "Failed to send hotplug request to primary");
264 : 0 : return -ENOMSG;
265 : : }
266 [ # # ]: 0 : if (req.result != 0)
267 : 0 : EAL_LOG(ERR,
268 : : "Failed to hotplug add device");
269 : 0 : return req.result;
270 : : }
271 : :
272 : : /* attach a shared device from primary start from here: */
273 : :
274 : : /* primary attach the new device itself. */
275 : 0 : ret = local_dev_probe(devargs, &dev);
276 : :
277 [ # # ]: 0 : if (ret != 0) {
278 : 0 : EAL_LOG(ERR,
279 : : "Failed to attach device on primary process");
280 : :
281 : : /**
282 : : * it is possible that secondary process failed to attached a
283 : : * device that primary process have during initialization,
284 : : * so for -EEXIST case, we still need to sync with secondary
285 : : * process.
286 : : */
287 [ # # ]: 0 : if (ret != -EEXIST)
288 : : return ret;
289 : : }
290 : :
291 : : /* primary send attach sync request to secondary. */
292 : 0 : ret = eal_dev_hotplug_request_to_secondary(&req);
293 : :
294 : : /* if any communication error, we need to rollback. */
295 [ # # ]: 0 : if (ret != 0) {
296 : 0 : EAL_LOG(ERR,
297 : : "Failed to send hotplug add request to secondary");
298 : : ret = -ENOMSG;
299 : 0 : goto rollback;
300 : : }
301 : :
302 : : /**
303 : : * if any secondary failed to attach, we need to consider if rollback
304 : : * is necessary.
305 : : */
306 [ # # ]: 0 : if (req.result != 0) {
307 : 0 : EAL_LOG(ERR,
308 : : "Failed to attach device on secondary process");
309 : 0 : ret = req.result;
310 : :
311 : : /* for -EEXIST, we don't need to rollback. */
312 [ # # ]: 0 : if (ret == -EEXIST)
313 : : return ret;
314 : 0 : goto rollback;
315 : : }
316 : :
317 : : return 0;
318 : :
319 : 0 : rollback:
320 : 0 : req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK;
321 : :
322 : : /* primary send rollback request to secondary. */
323 [ # # ]: 0 : if (eal_dev_hotplug_request_to_secondary(&req) != 0)
324 : 0 : EAL_LOG(WARNING,
325 : : "Failed to rollback device attach on secondary."
326 : : "Devices in secondary may not sync with primary");
327 : :
328 : : /* primary rollback itself. */
329 [ # # ]: 0 : if (local_dev_remove(dev) != 0)
330 : 0 : EAL_LOG(WARNING,
331 : : "Failed to rollback device attach on primary."
332 : : "Devices in secondary may not sync with primary");
333 : :
334 : : return ret;
335 : : }
336 : :
337 : : RTE_EXPORT_SYMBOL(rte_eal_hotplug_remove)
338 : : int
339 : 0 : rte_eal_hotplug_remove(const char *busname, const char *devname)
340 : : {
341 : : struct rte_device *dev;
342 : : struct rte_bus *bus;
343 : :
344 : 0 : bus = rte_bus_find_by_name(busname);
345 [ # # ]: 0 : if (bus == NULL) {
346 : 0 : EAL_LOG(ERR, "Cannot find bus (%s)", busname);
347 : 0 : return -ENOENT;
348 : : }
349 : :
350 : 0 : dev = bus->find_device(NULL, cmp_dev_name, devname);
351 [ # # ]: 0 : if (dev == NULL) {
352 : 0 : EAL_LOG(ERR, "Cannot find plugged device (%s)", devname);
353 : 0 : return -EINVAL;
354 : : }
355 : :
356 : 0 : return rte_dev_remove(dev);
357 : : }
358 : :
359 : : /* remove device at local process. */
360 : : int
361 : 0 : local_dev_remove(struct rte_device *dev)
362 : : {
363 : : int ret;
364 : :
365 [ # # ]: 0 : if (dev->bus->unplug == NULL) {
366 : 0 : EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
367 : : dev->bus->name);
368 : 0 : return -ENOTSUP;
369 : : }
370 : :
371 : 0 : ret = dev->bus->unplug(dev);
372 [ # # ]: 0 : if (ret) {
373 : 0 : EAL_LOG(ERR, "Driver cannot detach the device (%s)",
374 : : dev->name);
375 [ # # ]: 0 : return (ret < 0) ? ret : -ENOENT;
376 : : }
377 : :
378 : : return 0;
379 : : }
380 : :
381 : : RTE_EXPORT_SYMBOL(rte_dev_remove)
382 : : int
383 : 0 : rte_dev_remove(struct rte_device *dev)
384 : : {
385 : : struct eal_dev_mp_req req;
386 : : char *devargs;
387 : : int ret;
388 : :
389 [ # # ]: 0 : if (!rte_dev_is_probed(dev)) {
390 : 0 : EAL_LOG(ERR, "Device is not probed");
391 : 0 : return -ENOENT;
392 : : }
393 : :
394 : 0 : ret = build_devargs(dev->bus->name, dev->name, "", &devargs);
395 [ # # ]: 0 : if (ret != 0)
396 : : return ret;
397 : :
398 : : memset(&req, 0, sizeof(req));
399 : 0 : req.t = EAL_DEV_REQ_TYPE_DETACH;
400 : 0 : strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN);
401 : 0 : free(devargs);
402 : :
403 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
404 : : /**
405 : : * If in secondary process, just send IPC request to
406 : : * primary process.
407 : : */
408 : 0 : ret = eal_dev_hotplug_request_to_primary(&req);
409 [ # # ]: 0 : if (ret != 0) {
410 : 0 : EAL_LOG(ERR,
411 : : "Failed to send hotplug request to primary");
412 : 0 : return -ENOMSG;
413 : : }
414 [ # # ]: 0 : if (req.result != 0)
415 : 0 : EAL_LOG(ERR,
416 : : "Failed to hotplug remove device");
417 : 0 : return req.result;
418 : : }
419 : :
420 : : /* detach a device from primary start from here: */
421 : :
422 : : /* primary send detach sync request to secondary */
423 : 0 : ret = eal_dev_hotplug_request_to_secondary(&req);
424 : :
425 : : /**
426 : : * if communication error, we need to rollback, because it is possible
427 : : * part of the secondary processes still detached it successfully.
428 : : */
429 [ # # ]: 0 : if (ret != 0) {
430 : 0 : EAL_LOG(ERR,
431 : : "Failed to send device detach request to secondary");
432 : : ret = -ENOMSG;
433 : 0 : goto rollback;
434 : : }
435 : :
436 : : /**
437 : : * if any secondary failed to detach, we need to consider if rollback
438 : : * is necessary.
439 : : */
440 [ # # ]: 0 : if (req.result != 0) {
441 : 0 : EAL_LOG(ERR,
442 : : "Failed to detach device on secondary process");
443 : 0 : ret = req.result;
444 : : /**
445 : : * if -ENOENT, we don't need to rollback, since devices is
446 : : * already detached on secondary process.
447 : : */
448 [ # # ]: 0 : if (ret != -ENOENT)
449 : 0 : goto rollback;
450 : : }
451 : :
452 : : /* primary detach the device itself. */
453 : 0 : ret = local_dev_remove(dev);
454 : :
455 : : /* if primary failed, still need to consider if rollback is necessary */
456 [ # # ]: 0 : if (ret != 0) {
457 : 0 : EAL_LOG(ERR,
458 : : "Failed to detach device on primary process");
459 : : /* if -ENOENT, we don't need to rollback */
460 [ # # ]: 0 : if (ret == -ENOENT)
461 : : return ret;
462 : 0 : goto rollback;
463 : : }
464 : :
465 : : return 0;
466 : :
467 : 0 : rollback:
468 : 0 : req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK;
469 : :
470 : : /* primary send rollback request to secondary. */
471 [ # # ]: 0 : if (eal_dev_hotplug_request_to_secondary(&req) != 0)
472 : 0 : EAL_LOG(WARNING,
473 : : "Failed to rollback device detach on secondary."
474 : : "Devices in secondary may not sync with primary");
475 : :
476 : : return ret;
477 : : }
478 : :
479 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_register)
480 : : int
481 : 0 : rte_dev_event_callback_register(const char *device_name,
482 : : rte_dev_event_cb_fn cb_fn,
483 : : void *cb_arg)
484 : : {
485 : : struct dev_event_callback *event_cb;
486 : : int ret;
487 : :
488 [ # # ]: 0 : if (!cb_fn)
489 : : return -EINVAL;
490 : :
491 : : rte_spinlock_lock(&dev_event_lock);
492 : :
493 [ # # ]: 0 : if (TAILQ_EMPTY(&dev_event_cbs))
494 : 0 : TAILQ_INIT(&dev_event_cbs);
495 : :
496 [ # # ]: 0 : TAILQ_FOREACH(event_cb, &dev_event_cbs, next) {
497 [ # # # # ]: 0 : if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) {
498 [ # # # # ]: 0 : if (device_name == NULL && event_cb->dev_name == NULL)
499 : : break;
500 [ # # # # ]: 0 : if (device_name == NULL || event_cb->dev_name == NULL)
501 : 0 : continue;
502 [ # # ]: 0 : if (!strcmp(event_cb->dev_name, device_name))
503 : : break;
504 : : }
505 : : }
506 : :
507 : : /* create a new callback. */
508 [ # # ]: 0 : if (event_cb == NULL) {
509 : 0 : event_cb = malloc(sizeof(struct dev_event_callback));
510 [ # # ]: 0 : if (event_cb != NULL) {
511 : 0 : event_cb->cb_fn = cb_fn;
512 : 0 : event_cb->cb_arg = cb_arg;
513 : 0 : event_cb->active = 0;
514 [ # # ]: 0 : if (!device_name) {
515 : 0 : event_cb->dev_name = NULL;
516 : : } else {
517 : 0 : event_cb->dev_name = strdup(device_name);
518 [ # # ]: 0 : if (event_cb->dev_name == NULL) {
519 : : ret = -ENOMEM;
520 : 0 : goto error;
521 : : }
522 : : }
523 : 0 : TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next);
524 : : } else {
525 : 0 : EAL_LOG(ERR,
526 : : "Failed to allocate memory for device "
527 : : "event callback.");
528 : : ret = -ENOMEM;
529 : 0 : goto error;
530 : : }
531 : : } else {
532 : 0 : EAL_LOG(ERR,
533 : : "The callback is already exist, no need "
534 : : "to register again.");
535 : : event_cb = NULL;
536 : : ret = -EEXIST;
537 : 0 : goto error;
538 : : }
539 : :
540 : : rte_spinlock_unlock(&dev_event_lock);
541 : 0 : return 0;
542 : 0 : error:
543 : 0 : free(event_cb);
544 : : rte_spinlock_unlock(&dev_event_lock);
545 : 0 : return ret;
546 : : }
547 : :
548 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_unregister)
549 : : int
550 : 0 : rte_dev_event_callback_unregister(const char *device_name,
551 : : rte_dev_event_cb_fn cb_fn,
552 : : void *cb_arg)
553 : : {
554 : : int ret = 0;
555 : : struct dev_event_callback *event_cb, *next;
556 : :
557 [ # # ]: 0 : if (!cb_fn)
558 : : return -EINVAL;
559 : :
560 : : rte_spinlock_lock(&dev_event_lock);
561 : : /*walk through the callbacks and remove all that match. */
562 [ # # ]: 0 : for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL;
563 : : event_cb = next) {
564 : :
565 : 0 : next = TAILQ_NEXT(event_cb, next);
566 : :
567 [ # # # # ]: 0 : if (device_name != NULL && event_cb->dev_name != NULL) {
568 [ # # ]: 0 : if (strcmp(event_cb->dev_name, device_name))
569 : 0 : continue;
570 [ # # ]: 0 : } else if (device_name != NULL) {
571 : 0 : continue;
572 : : }
573 : :
574 : : /* Remove only matching callback with arg */
575 [ # # # # ]: 0 : if (event_cb->cb_fn != cb_fn ||
576 [ # # ]: 0 : (cb_arg != (void *)-1 && event_cb->cb_arg != cb_arg))
577 : 0 : continue;
578 : :
579 : : /*
580 : : * if this callback is not executing right now,
581 : : * then remove it.
582 : : */
583 [ # # ]: 0 : if (event_cb->active == 0) {
584 [ # # ]: 0 : TAILQ_REMOVE(&dev_event_cbs, event_cb, next);
585 : 0 : free(event_cb->dev_name);
586 : 0 : free(event_cb);
587 : 0 : ret++;
588 : : } else {
589 : : ret = -EAGAIN;
590 : : break;
591 : : }
592 : : }
593 : :
594 : : /* this callback is not be registered */
595 [ # # ]: 0 : if (ret == 0)
596 : : ret = -ENOENT;
597 : :
598 : : rte_spinlock_unlock(&dev_event_lock);
599 : 0 : return ret;
600 : : }
601 : :
602 : : RTE_EXPORT_SYMBOL(rte_dev_event_callback_process)
603 : : void
604 : 0 : rte_dev_event_callback_process(const char *device_name,
605 : : enum rte_dev_event_type event)
606 : : {
607 : : struct dev_event_callback *cb_lst;
608 : :
609 [ # # ]: 0 : if (device_name == NULL)
610 : : return;
611 : :
612 : : rte_spinlock_lock(&dev_event_lock);
613 : :
614 [ # # ]: 0 : TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) {
615 [ # # ]: 0 : if (cb_lst->dev_name) {
616 [ # # ]: 0 : if (strcmp(cb_lst->dev_name, device_name))
617 : 0 : continue;
618 : : }
619 : 0 : cb_lst->active = 1;
620 : : rte_spinlock_unlock(&dev_event_lock);
621 : 0 : cb_lst->cb_fn(device_name, event,
622 : : cb_lst->cb_arg);
623 : : rte_spinlock_lock(&dev_event_lock);
624 : 0 : cb_lst->active = 0;
625 : : }
626 : : rte_spinlock_unlock(&dev_event_lock);
627 : : }
628 : :
629 : : RTE_EXPORT_SYMBOL(rte_dev_iterator_init)
630 : : int
631 : 1 : rte_dev_iterator_init(struct rte_dev_iterator *it,
632 : : const char *dev_str)
633 : : {
634 : 1 : struct rte_devargs devargs = { .bus = NULL };
635 : : struct rte_class *cls = NULL;
636 : : struct rte_bus *bus = NULL;
637 : :
638 : : /* Having both bus_str and cls_str NULL is illegal,
639 : : * marking this iterator as invalid unless
640 : : * everything goes well.
641 : : */
642 : 1 : it->bus_str = NULL;
643 : 1 : it->cls_str = NULL;
644 : :
645 : : /* Setting data field implies no malloc in parsing. */
646 : 1 : devargs.data = (void *)(intptr_t)dev_str;
647 [ - + ]: 1 : if (rte_devargs_layers_parse(&devargs, dev_str))
648 : 0 : goto get_out;
649 : :
650 : 1 : bus = devargs.bus;
651 : 1 : cls = devargs.cls;
652 : : /* The string should have at least
653 : : * one layer specified.
654 : : */
655 [ - + ]: 1 : if (bus == NULL && cls == NULL) {
656 : 0 : EAL_LOG(DEBUG, "Either bus or class must be specified.");
657 : 0 : rte_errno = EINVAL;
658 : 0 : goto get_out;
659 : : }
660 [ + - - + ]: 1 : if (bus != NULL && bus->dev_iterate == NULL) {
661 : 0 : EAL_LOG(DEBUG, "Bus %s not supported", bus->name);
662 : 0 : rte_errno = ENOTSUP;
663 : 0 : goto get_out;
664 : : }
665 [ - + - - ]: 1 : if (cls != NULL && cls->dev_iterate == NULL) {
666 : 0 : EAL_LOG(DEBUG, "Class %s not supported", cls->name);
667 : 0 : rte_errno = ENOTSUP;
668 : 0 : goto get_out;
669 : : }
670 : 1 : it->bus_str = devargs.bus_str;
671 : 1 : it->cls_str = devargs.cls_str;
672 : 1 : it->dev_str = dev_str;
673 : 1 : it->bus = bus;
674 : 1 : it->cls = cls;
675 : 1 : it->device = NULL;
676 : 1 : it->class_device = NULL;
677 : 1 : get_out:
678 : 1 : return -rte_errno;
679 : : }
680 : :
681 : : static char *
682 : 3 : dev_str_sane_copy(const char *str)
683 : : {
684 : : size_t end;
685 : : char *copy;
686 : :
687 : 3 : end = strcspn(str, ",/");
688 [ - + ]: 3 : if (str[end] == ',') {
689 : 0 : copy = strdup(&str[end + 1]);
690 : : } else {
691 : : /* '/' or '\0' */
692 : 3 : copy = strdup("");
693 : : }
694 [ - + ]: 3 : if (copy == NULL) {
695 : 0 : rte_errno = ENOMEM;
696 : : } else {
697 : : char *slash;
698 : :
699 : 3 : slash = strchr(copy, '/');
700 [ - + ]: 3 : if (slash != NULL)
701 : 0 : slash[0] = '\0';
702 : : }
703 : 3 : return copy;
704 : : }
705 : :
706 : : static int
707 : 0 : class_next_dev_cmp(const struct rte_class *cls,
708 : : const void *ctx)
709 : : {
710 : : struct rte_dev_iterator *it;
711 : : const char *cls_str = NULL;
712 : : void *dev;
713 : :
714 [ # # ]: 0 : if (cls->dev_iterate == NULL)
715 : : return 1;
716 : 0 : it = ITCTX(ctx);
717 : 0 : cls_str = CLSCTX(ctx);
718 : 0 : dev = it->class_device;
719 : : /* it->cls_str != NULL means a class
720 : : * was specified in the devstr.
721 : : */
722 [ # # # # ]: 0 : if (it->cls_str != NULL && cls != it->cls)
723 : : return 1;
724 : : /* If an error occurred previously,
725 : : * no need to test further.
726 : : */
727 [ # # ]: 0 : if (rte_errno != 0)
728 : : return -1;
729 : 0 : dev = cls->dev_iterate(dev, cls_str, it);
730 : 0 : it->class_device = dev;
731 : 0 : return dev == NULL;
732 : : }
733 : :
734 : : static int
735 : 5 : bus_next_dev_cmp(const struct rte_bus *bus,
736 : : const void *ctx)
737 : : {
738 : : struct rte_device *dev = NULL;
739 : : struct rte_class *cls = NULL;
740 : : struct rte_dev_iterator *it;
741 : : const char *bus_str = NULL;
742 : :
743 [ + + ]: 5 : if (bus->dev_iterate == NULL)
744 : : return 1;
745 : 3 : it = ITCTX(ctx);
746 : 3 : bus_str = BUSCTX(ctx);
747 : 3 : dev = it->device;
748 : : /* it->bus_str != NULL means a bus
749 : : * was specified in the devstr.
750 : : */
751 [ + - + - ]: 3 : if (it->bus_str != NULL && bus != it->bus)
752 : : return 1;
753 : : /* If an error occurred previously,
754 : : * no need to test further.
755 : : */
756 [ + - ]: 3 : if (rte_errno != 0)
757 : : return -1;
758 [ + - ]: 3 : if (it->cls_str == NULL) {
759 : 3 : dev = bus->dev_iterate(dev, bus_str, it);
760 : 3 : goto end;
761 : : }
762 : : /* cls_str != NULL */
763 [ # # ]: 0 : if (dev == NULL) {
764 : 0 : next_dev_on_bus:
765 : 0 : dev = bus->dev_iterate(dev, bus_str, it);
766 : 0 : it->device = dev;
767 : : }
768 [ # # ]: 0 : if (dev == NULL)
769 : : return 1;
770 [ # # ]: 0 : if (it->cls != NULL)
771 : 0 : cls = TAILQ_PREV(it->cls, rte_class_list, next);
772 : 0 : cls = rte_class_find(cls, class_next_dev_cmp, ctx);
773 [ # # ]: 0 : if (cls != NULL) {
774 : 0 : it->cls = cls;
775 : 0 : goto end;
776 : : }
777 : 0 : goto next_dev_on_bus;
778 : 3 : end:
779 : 3 : it->device = dev;
780 : 3 : return dev == NULL;
781 : : }
782 : : RTE_EXPORT_SYMBOL(rte_dev_iterator_next)
783 : : struct rte_device *
784 : 3 : rte_dev_iterator_next(struct rte_dev_iterator *it)
785 : : {
786 : : struct rte_bus *bus = NULL;
787 : 3 : int old_errno = rte_errno;
788 : : char *bus_str = NULL;
789 : : char *cls_str = NULL;
790 : :
791 : 3 : rte_errno = 0;
792 [ - + - - ]: 3 : if (it->bus_str == NULL && it->cls_str == NULL) {
793 : : /* Invalid iterator. */
794 : 0 : rte_errno = EINVAL;
795 : 0 : return NULL;
796 : : }
797 [ + - ]: 3 : if (it->bus != NULL)
798 : 3 : bus = TAILQ_PREV(it->bus, rte_bus_list, next);
799 [ + - ]: 3 : if (it->bus_str != NULL) {
800 : 3 : bus_str = dev_str_sane_copy(it->bus_str);
801 [ - + ]: 3 : if (bus_str == NULL)
802 : 0 : goto out;
803 : : }
804 [ - + ]: 3 : if (it->cls_str != NULL) {
805 : 0 : cls_str = dev_str_sane_copy(it->cls_str);
806 [ # # ]: 0 : if (cls_str == NULL)
807 : 0 : goto out;
808 : : }
809 [ + + ]: 3 : while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
810 : 3 : CTX(it, bus_str, cls_str)))) {
811 [ + - ]: 2 : if (it->device != NULL) {
812 : 2 : it->bus = bus;
813 : 2 : goto out;
814 : : }
815 [ # # ]: 0 : if (it->bus_str != NULL ||
816 [ # # ]: 0 : rte_errno != 0)
817 : : break;
818 : : }
819 [ - + ]: 1 : if (rte_errno == 0)
820 : 1 : rte_errno = old_errno;
821 : 0 : out:
822 : 3 : free(bus_str);
823 : 3 : free(cls_str);
824 : 3 : return it->device;
825 : : }
826 : :
827 : : RTE_EXPORT_SYMBOL(rte_dev_dma_map)
828 : : int
829 : 0 : rte_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova,
830 : : size_t len)
831 : : {
832 [ # # # # ]: 0 : if (dev->bus->dma_map == NULL || len == 0) {
833 : 0 : rte_errno = ENOTSUP;
834 : 0 : return -1;
835 : : }
836 : : /* Memory must be registered through rte_extmem_* APIs */
837 [ # # ]: 0 : if (rte_mem_virt2memseg_list(addr) == NULL) {
838 : 0 : rte_errno = EINVAL;
839 : 0 : return -1;
840 : : }
841 : :
842 : 0 : return dev->bus->dma_map(dev, addr, iova, len);
843 : : }
844 : :
845 : : RTE_EXPORT_SYMBOL(rte_dev_dma_unmap)
846 : : int
847 : 0 : rte_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
848 : : size_t len)
849 : : {
850 [ # # # # ]: 0 : if (dev->bus->dma_unmap == NULL || len == 0) {
851 : 0 : rte_errno = ENOTSUP;
852 : 0 : return -1;
853 : : }
854 : : /* Memory must be registered through rte_extmem_* APIs */
855 [ # # ]: 0 : if (rte_mem_virt2memseg_list(addr) == NULL) {
856 : 0 : rte_errno = EINVAL;
857 : 0 : return -1;
858 : : }
859 : :
860 : 0 : return dev->bus->dma_unmap(dev, addr, iova, len);
861 : : }
|