63e329bd89503369abb4fb7c0012dd7110321dae
[dpdk.git] / lib / librte_eal / common / eal_common_dev.c
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 <string.h>
8 #include <inttypes.h>
9 #include <sys/queue.h>
10
11 #include <rte_compat.h>
12 #include <rte_bus.h>
13 #include <rte_class.h>
14 #include <rte_dev.h>
15 #include <rte_devargs.h>
16 #include <rte_debug.h>
17 #include <rte_errno.h>
18 #include <rte_kvargs.h>
19 #include <rte_log.h>
20 #include <rte_spinlock.h>
21 #include <rte_malloc.h>
22
23 #include "eal_private.h"
24
25 /**
26  * The device event callback description.
27  *
28  * It contains callback address to be registered by user application,
29  * the pointer to the parameters for callback, and the device name.
30  */
31 struct dev_event_callback {
32         TAILQ_ENTRY(dev_event_callback) next; /**< Callbacks list */
33         rte_dev_event_cb_fn cb_fn;            /**< Callback address */
34         void *cb_arg;                         /**< Callback parameter */
35         char *dev_name;  /**< Callback device name, NULL is for all device */
36         uint32_t active;                      /**< Callback is executing */
37 };
38
39 /** @internal Structure to keep track of registered callbacks */
40 TAILQ_HEAD(dev_event_cb_list, dev_event_callback);
41
42 /* The device event callback list for all registered callbacks. */
43 static struct dev_event_cb_list dev_event_cbs;
44
45 /* spinlock for device callbacks */
46 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
47
48 static int cmp_detached_dev_name(const struct rte_device *dev,
49         const void *_name)
50 {
51         const char *name = _name;
52
53         /* skip attached devices */
54         if (dev->driver != NULL)
55                 return 1;
56
57         return strcmp(dev->name, name);
58 }
59
60 static int cmp_dev_name(const struct rte_device *dev, const void *_name)
61 {
62         const char *name = _name;
63
64         return strcmp(dev->name, name);
65 }
66
67 int rte_eal_dev_attach(const char *name, const char *devargs)
68 {
69         struct rte_bus *bus;
70
71         if (name == NULL || devargs == NULL) {
72                 RTE_LOG(ERR, EAL, "Invalid device or arguments provided\n");
73                 return -EINVAL;
74         }
75
76         bus = rte_bus_find_by_device_name(name);
77         if (bus == NULL) {
78                 RTE_LOG(ERR, EAL, "Unable to find a bus for the device '%s'\n",
79                         name);
80                 return -EINVAL;
81         }
82         if (strcmp(bus->name, "pci") == 0 || strcmp(bus->name, "vdev") == 0)
83                 return rte_eal_hotplug_add(bus->name, name, devargs);
84
85         RTE_LOG(ERR, EAL,
86                 "Device attach is only supported for PCI and vdev devices.\n");
87
88         return -ENOTSUP;
89 }
90
91 int rte_eal_dev_detach(struct rte_device *dev)
92 {
93         struct rte_bus *bus;
94         int ret;
95
96         if (dev == NULL) {
97                 RTE_LOG(ERR, EAL, "Invalid device provided.\n");
98                 return -EINVAL;
99         }
100
101         bus = rte_bus_find_by_device(dev);
102         if (bus == NULL) {
103                 RTE_LOG(ERR, EAL, "Cannot find bus for device (%s)\n",
104                         dev->name);
105                 return -EINVAL;
106         }
107
108         if (bus->unplug == NULL) {
109                 RTE_LOG(ERR, EAL, "Bus function not supported\n");
110                 return -ENOTSUP;
111         }
112
113         ret = bus->unplug(dev);
114         if (ret)
115                 RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n",
116                         dev->name);
117         return ret;
118 }
119
120 int __rte_experimental rte_eal_hotplug_add(const char *busname, const char *devname,
121                         const char *devargs)
122 {
123         struct rte_bus *bus;
124         struct rte_device *dev;
125         struct rte_devargs *da;
126         int ret;
127
128         bus = rte_bus_find_by_name(busname);
129         if (bus == NULL) {
130                 RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
131                 return -ENOENT;
132         }
133
134         if (bus->plug == NULL) {
135                 RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n",
136                         bus->name);
137                 return -ENOTSUP;
138         }
139
140         da = calloc(1, sizeof(*da));
141         if (da == NULL)
142                 return -ENOMEM;
143
144         ret = rte_devargs_parsef(da, "%s:%s,%s",
145                                  busname, devname, devargs);
146         if (ret)
147                 goto err_devarg;
148
149         ret = rte_devargs_insert(da);
150         if (ret)
151                 goto err_devarg;
152
153         ret = bus->scan();
154         if (ret)
155                 goto err_devarg;
156
157         dev = bus->find_device(NULL, cmp_detached_dev_name, devname);
158         if (dev == NULL) {
159                 RTE_LOG(ERR, EAL, "Cannot find unplugged device (%s)\n",
160                         devname);
161                 ret = -ENODEV;
162                 goto err_devarg;
163         }
164
165         ret = bus->plug(dev);
166         if (ret) {
167                 RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n",
168                         dev->name);
169                 goto err_devarg;
170         }
171         return 0;
172
173 err_devarg:
174         if (rte_devargs_remove(busname, devname)) {
175                 free(da->args);
176                 free(da);
177         }
178         return ret;
179 }
180
181 int __rte_experimental
182 rte_eal_hotplug_remove(const char *busname, const char *devname)
183 {
184         struct rte_bus *bus;
185         struct rte_device *dev;
186         int ret;
187
188         bus = rte_bus_find_by_name(busname);
189         if (bus == NULL) {
190                 RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname);
191                 return -ENOENT;
192         }
193
194         if (bus->unplug == NULL) {
195                 RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n",
196                         bus->name);
197                 return -ENOTSUP;
198         }
199
200         dev = bus->find_device(NULL, cmp_dev_name, devname);
201         if (dev == NULL) {
202                 RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", devname);
203                 return -EINVAL;
204         }
205
206         ret = bus->unplug(dev);
207         if (ret)
208                 RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n",
209                         dev->name);
210         rte_devargs_remove(busname, devname);
211         return ret;
212 }
213
214 int __rte_experimental
215 rte_dev_event_callback_register(const char *device_name,
216                                 rte_dev_event_cb_fn cb_fn,
217                                 void *cb_arg)
218 {
219         struct dev_event_callback *event_cb;
220         int ret;
221
222         if (!cb_fn)
223                 return -EINVAL;
224
225         rte_spinlock_lock(&dev_event_lock);
226
227         if (TAILQ_EMPTY(&dev_event_cbs))
228                 TAILQ_INIT(&dev_event_cbs);
229
230         TAILQ_FOREACH(event_cb, &dev_event_cbs, next) {
231                 if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) {
232                         if (device_name == NULL && event_cb->dev_name == NULL)
233                                 break;
234                         if (device_name == NULL || event_cb->dev_name == NULL)
235                                 continue;
236                         if (!strcmp(event_cb->dev_name, device_name))
237                                 break;
238                 }
239         }
240
241         /* create a new callback. */
242         if (event_cb == NULL) {
243                 event_cb = malloc(sizeof(struct dev_event_callback));
244                 if (event_cb != NULL) {
245                         event_cb->cb_fn = cb_fn;
246                         event_cb->cb_arg = cb_arg;
247                         event_cb->active = 0;
248                         if (!device_name) {
249                                 event_cb->dev_name = NULL;
250                         } else {
251                                 event_cb->dev_name = strdup(device_name);
252                                 if (event_cb->dev_name == NULL) {
253                                         ret = -ENOMEM;
254                                         goto error;
255                                 }
256                         }
257                         TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next);
258                 } else {
259                         RTE_LOG(ERR, EAL,
260                                 "Failed to allocate memory for device "
261                                 "event callback.");
262                         ret = -ENOMEM;
263                         goto error;
264                 }
265         } else {
266                 RTE_LOG(ERR, EAL,
267                         "The callback is already exist, no need "
268                         "to register again.\n");
269                 ret = -EEXIST;
270         }
271
272         rte_spinlock_unlock(&dev_event_lock);
273         return 0;
274 error:
275         free(event_cb);
276         rte_spinlock_unlock(&dev_event_lock);
277         return ret;
278 }
279
280 int __rte_experimental
281 rte_dev_event_callback_unregister(const char *device_name,
282                                   rte_dev_event_cb_fn cb_fn,
283                                   void *cb_arg)
284 {
285         int ret = 0;
286         struct dev_event_callback *event_cb, *next;
287
288         if (!cb_fn)
289                 return -EINVAL;
290
291         rte_spinlock_lock(&dev_event_lock);
292         /*walk through the callbacks and remove all that match. */
293         for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL;
294              event_cb = next) {
295
296                 next = TAILQ_NEXT(event_cb, next);
297
298                 if (device_name != NULL && event_cb->dev_name != NULL) {
299                         if (!strcmp(event_cb->dev_name, device_name)) {
300                                 if (event_cb->cb_fn != cb_fn ||
301                                     (cb_arg != (void *)-1 &&
302                                     event_cb->cb_arg != cb_arg))
303                                         continue;
304                         }
305                 } else if (device_name != NULL) {
306                         continue;
307                 }
308
309                 /*
310                  * if this callback is not executing right now,
311                  * then remove it.
312                  */
313                 if (event_cb->active == 0) {
314                         TAILQ_REMOVE(&dev_event_cbs, event_cb, next);
315                         free(event_cb);
316                         ret++;
317                 } else {
318                         continue;
319                 }
320         }
321         rte_spinlock_unlock(&dev_event_lock);
322         return ret;
323 }
324
325 void
326 dev_callback_process(char *device_name, enum rte_dev_event_type event)
327 {
328         struct dev_event_callback *cb_lst;
329
330         if (device_name == NULL)
331                 return;
332
333         rte_spinlock_lock(&dev_event_lock);
334
335         TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) {
336                 if (cb_lst->dev_name) {
337                         if (strcmp(cb_lst->dev_name, device_name))
338                                 continue;
339                 }
340                 cb_lst->active = 1;
341                 rte_spinlock_unlock(&dev_event_lock);
342                 cb_lst->cb_fn(device_name, event,
343                                 cb_lst->cb_arg);
344                 rte_spinlock_lock(&dev_event_lock);
345                 cb_lst->active = 0;
346         }
347         rte_spinlock_unlock(&dev_event_lock);
348 }
349
350 __rte_experimental
351 int
352 rte_dev_iterator_init(struct rte_dev_iterator *it,
353                       const char *dev_str)
354 {
355         struct rte_devargs devargs;
356         struct rte_class *cls = NULL;
357         struct rte_bus *bus = NULL;
358
359         /* Having both bus_str and cls_str NULL is illegal,
360          * marking this iterator as invalid unless
361          * everything goes well.
362          */
363         it->bus_str = NULL;
364         it->cls_str = NULL;
365
366         devargs.data = dev_str;
367         if (rte_devargs_layers_parse(&devargs, dev_str))
368                 goto get_out;
369
370         bus = devargs.bus;
371         cls = devargs.cls;
372         /* The string should have at least
373          * one layer specified.
374          */
375         if (bus == NULL && cls == NULL) {
376                 RTE_LOG(ERR, EAL,
377                         "Either bus or class must be specified.\n");
378                 rte_errno = EINVAL;
379                 goto get_out;
380         }
381         if (bus != NULL && bus->dev_iterate == NULL) {
382                 RTE_LOG(ERR, EAL, "Bus %s not supported\n", bus->name);
383                 rte_errno = ENOTSUP;
384                 goto get_out;
385         }
386         if (cls != NULL && cls->dev_iterate == NULL) {
387                 RTE_LOG(ERR, EAL, "Class %s not supported\n", cls->name);
388                 rte_errno = ENOTSUP;
389                 goto get_out;
390         }
391         it->bus_str = devargs.bus_str;
392         it->cls_str = devargs.cls_str;
393         it->dev_str = dev_str;
394         it->bus = bus;
395         it->cls = cls;
396         it->device = NULL;
397         it->class_device = NULL;
398 get_out:
399         return -rte_errno;
400 }