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