eal: use SPDX tags in 6WIND copyrighted files
[dpdk.git] / lib / librte_eal / common / eal_common_devargs.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2014 6WIND S.A.
3  */
4
5 /* This file manages the list of devices and their arguments, as given
6  * by the user at startup
7  *
8  * Code here should not call rte_log since the EAL environment
9  * may not be initialized.
10  */
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #include <rte_compat.h>
16 #include <rte_dev.h>
17 #include <rte_devargs.h>
18 #include <rte_tailq.h>
19 #include "eal_private.h"
20
21 /** Global list of user devices */
22 struct rte_devargs_list devargs_list =
23         TAILQ_HEAD_INITIALIZER(devargs_list);
24
25 int
26 rte_eal_parse_devargs_str(const char *devargs_str,
27                         char **drvname, char **drvargs)
28 {
29         char *sep;
30
31         if ((devargs_str) == NULL || (drvname) == NULL || (drvargs == NULL))
32                 return -1;
33
34         *drvname = strdup(devargs_str);
35         if (*drvname == NULL)
36                 return -1;
37
38         /* set the first ',' to '\0' to split name and arguments */
39         sep = strchr(*drvname, ',');
40         if (sep != NULL) {
41                 sep[0] = '\0';
42                 *drvargs = strdup(sep + 1);
43         } else {
44                 *drvargs = strdup("");
45         }
46
47         if (*drvargs == NULL) {
48                 free(*drvname);
49                 *drvname = NULL;
50                 return -1;
51         }
52         return 0;
53 }
54
55 static int
56 bus_name_cmp(const struct rte_bus *bus, const void *name)
57 {
58         return strncmp(bus->name, name, strlen(bus->name));
59 }
60
61 int __rte_experimental
62 rte_eal_devargs_parse(const char *dev, struct rte_devargs *da)
63 {
64         struct rte_bus *bus = NULL;
65         const char *devname;
66         const size_t maxlen = sizeof(da->name);
67         size_t i;
68
69         if (dev == NULL || da == NULL)
70                 return -EINVAL;
71         /* Retrieve eventual bus info */
72         do {
73                 devname = dev;
74                 bus = rte_bus_find(bus, bus_name_cmp, dev);
75                 if (bus == NULL)
76                         break;
77                 devname = dev + strlen(bus->name) + 1;
78                 if (rte_bus_find_by_device_name(devname) == bus)
79                         break;
80         } while (1);
81         /* Store device name */
82         i = 0;
83         while (devname[i] != '\0' && devname[i] != ',') {
84                 da->name[i] = devname[i];
85                 i++;
86                 if (i == maxlen) {
87                         fprintf(stderr, "WARNING: Parsing \"%s\": device name should be shorter than %zu\n",
88                                 dev, maxlen);
89                         da->name[i - 1] = '\0';
90                         return -EINVAL;
91                 }
92         }
93         da->name[i] = '\0';
94         if (bus == NULL) {
95                 bus = rte_bus_find_by_device_name(da->name);
96                 if (bus == NULL) {
97                         fprintf(stderr, "ERROR: failed to parse device \"%s\"\n",
98                                 da->name);
99                         return -EFAULT;
100                 }
101         }
102         da->bus = bus;
103         /* Parse eventual device arguments */
104         if (devname[i] == ',')
105                 da->args = strdup(&devname[i + 1]);
106         else
107                 da->args = strdup("");
108         if (da->args == NULL) {
109                 fprintf(stderr, "ERROR: not enough memory to parse arguments\n");
110                 return -ENOMEM;
111         }
112         return 0;
113 }
114
115 int __rte_experimental
116 rte_eal_devargs_insert(struct rte_devargs *da)
117 {
118         int ret;
119
120         ret = rte_eal_devargs_remove(da->bus->name, da->name);
121         if (ret < 0)
122                 return ret;
123         TAILQ_INSERT_TAIL(&devargs_list, da, next);
124         return 0;
125 }
126
127 /* store a whitelist parameter for later parsing */
128 int
129 rte_eal_devargs_add(enum rte_devtype devtype, const char *devargs_str)
130 {
131         struct rte_devargs *devargs = NULL;
132         struct rte_bus *bus = NULL;
133         const char *dev = devargs_str;
134
135         /* use calloc instead of rte_zmalloc as it's called early at init */
136         devargs = calloc(1, sizeof(*devargs));
137         if (devargs == NULL)
138                 goto fail;
139
140         if (rte_eal_devargs_parse(dev, devargs))
141                 goto fail;
142         devargs->type = devtype;
143         bus = devargs->bus;
144         if (devargs->type == RTE_DEVTYPE_BLACKLISTED_PCI)
145                 devargs->policy = RTE_DEV_BLACKLISTED;
146         if (bus->conf.scan_mode == RTE_BUS_SCAN_UNDEFINED) {
147                 if (devargs->policy == RTE_DEV_WHITELISTED)
148                         bus->conf.scan_mode = RTE_BUS_SCAN_WHITELIST;
149                 else if (devargs->policy == RTE_DEV_BLACKLISTED)
150                         bus->conf.scan_mode = RTE_BUS_SCAN_BLACKLIST;
151         }
152         TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
153         return 0;
154
155 fail:
156         if (devargs) {
157                 free(devargs->args);
158                 free(devargs);
159         }
160
161         return -1;
162 }
163
164 int __rte_experimental
165 rte_eal_devargs_remove(const char *busname, const char *devname)
166 {
167         struct rte_devargs *d;
168         void *tmp;
169
170         TAILQ_FOREACH_SAFE(d, &devargs_list, next, tmp) {
171                 if (strcmp(d->bus->name, busname) == 0 &&
172                     strcmp(d->name, devname) == 0) {
173                         TAILQ_REMOVE(&devargs_list, d, next);
174                         free(d->args);
175                         free(d);
176                         return 0;
177                 }
178         }
179         return 1;
180 }
181
182 /* count the number of devices of a specified type */
183 unsigned int
184 rte_eal_devargs_type_count(enum rte_devtype devtype)
185 {
186         struct rte_devargs *devargs;
187         unsigned int count = 0;
188
189         TAILQ_FOREACH(devargs, &devargs_list, next) {
190                 if (devargs->type != devtype)
191                         continue;
192                 count++;
193         }
194         return count;
195 }
196
197 /* dump the user devices on the console */
198 void
199 rte_eal_devargs_dump(FILE *f)
200 {
201         struct rte_devargs *devargs;
202
203         fprintf(f, "User device list:\n");
204         TAILQ_FOREACH(devargs, &devargs_list, next) {
205                 fprintf(f, "  [%s]: %s %s\n",
206                         (devargs->bus ? devargs->bus->name : "??"),
207                         devargs->name, devargs->args);
208         }
209 }