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