1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 NXP
3 */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/queue.h>
8
9 #include <bus_driver.h>
10 #include <rte_debug.h>
11 #include <rte_string_fns.h>
12 #include <rte_errno.h>
13
14 #include "eal_private.h"
15
16 static struct rte_bus_list rte_bus_list =
17 TAILQ_HEAD_INITIALIZER(rte_bus_list);
18
19 const char *
rte_bus_name(const struct rte_bus * bus)20 rte_bus_name(const struct rte_bus *bus)
21 {
22 return bus->name;
23 }
24
25 void
rte_bus_register(struct rte_bus * bus)26 rte_bus_register(struct rte_bus *bus)
27 {
28 RTE_VERIFY(bus);
29 RTE_VERIFY(rte_bus_name(bus) && strlen(rte_bus_name(bus)));
30 /* A bus should mandatorily have the scan implemented */
31 RTE_VERIFY(bus->scan);
32 RTE_VERIFY(bus->probe);
33 RTE_VERIFY(bus->find_device);
34 /* Buses supporting driver plug also require unplug. */
35 RTE_VERIFY(!bus->plug || bus->unplug);
36
37 TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
38 EAL_LOG(DEBUG, "Registered [%s] bus.", rte_bus_name(bus));
39 }
40
41 void
rte_bus_unregister(struct rte_bus * bus)42 rte_bus_unregister(struct rte_bus *bus)
43 {
44 TAILQ_REMOVE(&rte_bus_list, bus, next);
45 EAL_LOG(DEBUG, "Unregistered [%s] bus.", rte_bus_name(bus));
46 }
47
48 /* Scan all the buses for registered devices */
49 int
rte_bus_scan(void)50 rte_bus_scan(void)
51 {
52 int ret;
53 struct rte_bus *bus = NULL;
54
55 TAILQ_FOREACH(bus, &rte_bus_list, next) {
56 ret = bus->scan();
57 if (ret)
58 EAL_LOG(ERR, "Scan for (%s) bus failed.",
59 rte_bus_name(bus));
60 }
61
62 return 0;
63 }
64
65 /* Probe all devices of all buses */
66 int
rte_bus_probe(void)67 rte_bus_probe(void)
68 {
69 int ret;
70 struct rte_bus *bus, *vbus = NULL;
71
72 TAILQ_FOREACH(bus, &rte_bus_list, next) {
73 if (!strcmp(rte_bus_name(bus), "vdev")) {
74 vbus = bus;
75 continue;
76 }
77
78 ret = bus->probe();
79 if (ret)
80 EAL_LOG(ERR, "Bus (%s) probe failed.",
81 rte_bus_name(bus));
82 }
83
84 if (vbus) {
85 ret = vbus->probe();
86 if (ret)
87 EAL_LOG(ERR, "Bus (%s) probe failed.",
88 rte_bus_name(vbus));
89 }
90
91 return 0;
92 }
93
94 /* Clean up all devices of all buses */
95 int
eal_bus_cleanup(void)96 eal_bus_cleanup(void)
97 {
98 int ret = 0;
99 struct rte_bus *bus;
100
101 TAILQ_FOREACH(bus, &rte_bus_list, next) {
102 if (bus->cleanup == NULL)
103 continue;
104 if (bus->cleanup() != 0)
105 ret = -1;
106 }
107
108 return ret;
109 }
110
111 /* Dump information of a single bus */
112 static int
bus_dump_one(FILE * f,struct rte_bus * bus)113 bus_dump_one(FILE *f, struct rte_bus *bus)
114 {
115 int ret;
116
117 /* For now, dump only the bus name */
118 ret = fprintf(f, " %s\n", rte_bus_name(bus));
119
120 /* Error in case of inability in writing to stream */
121 if (ret < 0)
122 return ret;
123
124 return 0;
125 }
126
127 void
rte_bus_dump(FILE * f)128 rte_bus_dump(FILE *f)
129 {
130 int ret;
131 struct rte_bus *bus;
132
133 TAILQ_FOREACH(bus, &rte_bus_list, next) {
134 ret = bus_dump_one(f, bus);
135 if (ret) {
136 EAL_LOG(ERR, "Unable to write to stream (%d)",
137 ret);
138 break;
139 }
140 }
141 }
142
143 struct rte_bus *
rte_bus_find(const struct rte_bus * start,rte_bus_cmp_t cmp,const void * data)144 rte_bus_find(const struct rte_bus *start, rte_bus_cmp_t cmp,
145 const void *data)
146 {
147 struct rte_bus *bus;
148
149 if (start != NULL)
150 bus = TAILQ_NEXT(start, next);
151 else
152 bus = TAILQ_FIRST(&rte_bus_list);
153 while (bus != NULL) {
154 if (cmp(bus, data) == 0)
155 break;
156 bus = TAILQ_NEXT(bus, next);
157 }
158 return bus;
159 }
160
161 static int
cmp_rte_device(const struct rte_device * dev1,const void * _dev2)162 cmp_rte_device(const struct rte_device *dev1, const void *_dev2)
163 {
164 const struct rte_device *dev2 = _dev2;
165
166 return dev1 != dev2;
167 }
168
169 static int
bus_find_device(const struct rte_bus * bus,const void * _dev)170 bus_find_device(const struct rte_bus *bus, const void *_dev)
171 {
172 struct rte_device *dev;
173
174 dev = bus->find_device(NULL, cmp_rte_device, _dev);
175 return dev == NULL;
176 }
177
178 struct rte_bus *
rte_bus_find_by_device(const struct rte_device * dev)179 rte_bus_find_by_device(const struct rte_device *dev)
180 {
181 return rte_bus_find(NULL, bus_find_device, (const void *)dev);
182 }
183
184 static int
cmp_bus_name(const struct rte_bus * bus,const void * _name)185 cmp_bus_name(const struct rte_bus *bus, const void *_name)
186 {
187 const char *name = _name;
188
189 return strcmp(rte_bus_name(bus), name);
190 }
191
192 struct rte_bus *
rte_bus_find_by_name(const char * busname)193 rte_bus_find_by_name(const char *busname)
194 {
195 return rte_bus_find(NULL, cmp_bus_name, (const void *)busname);
196 }
197
198 static int
bus_can_parse(const struct rte_bus * bus,const void * _name)199 bus_can_parse(const struct rte_bus *bus, const void *_name)
200 {
201 const char *name = _name;
202
203 return !(bus->parse && bus->parse(name, NULL) == 0);
204 }
205
206 struct rte_bus *
rte_bus_find_by_device_name(const char * str)207 rte_bus_find_by_device_name(const char *str)
208 {
209 char name[RTE_DEV_NAME_MAX_LEN];
210 char *c;
211
212 strlcpy(name, str, sizeof(name));
213 c = strchr(name, ',');
214 if (c != NULL)
215 c[0] = '\0';
216 return rte_bus_find(NULL, bus_can_parse, name);
217 }
218
219
220 /*
221 * Get iommu class of devices on the bus.
222 */
223 enum rte_iova_mode
rte_bus_get_iommu_class(void)224 rte_bus_get_iommu_class(void)
225 {
226 enum rte_iova_mode mode = RTE_IOVA_DC;
227 bool buses_want_va = false;
228 bool buses_want_pa = false;
229 struct rte_bus *bus;
230
231 TAILQ_FOREACH(bus, &rte_bus_list, next) {
232 enum rte_iova_mode bus_iova_mode;
233
234 if (bus->get_iommu_class == NULL)
235 continue;
236
237 bus_iova_mode = bus->get_iommu_class();
238 EAL_LOG(DEBUG, "Bus %s wants IOVA as '%s'",
239 rte_bus_name(bus),
240 bus_iova_mode == RTE_IOVA_DC ? "DC" :
241 (bus_iova_mode == RTE_IOVA_PA ? "PA" : "VA"));
242 if (bus_iova_mode == RTE_IOVA_PA) {
243 buses_want_pa = true;
244 if (!RTE_IOVA_IN_MBUF)
245 EAL_LOG(WARNING,
246 "Bus %s wants IOVA as PA not compatible with 'enable_iova_as_pa=false' build option.",
247 rte_bus_name(bus));
248 } else if (bus_iova_mode == RTE_IOVA_VA)
249 buses_want_va = true;
250 }
251 if (buses_want_va && !buses_want_pa) {
252 mode = RTE_IOVA_VA;
253 } else if (buses_want_pa && !buses_want_va) {
254 mode = RTE_IOVA_PA;
255 } else {
256 mode = RTE_IOVA_DC;
257 if (buses_want_va) {
258 EAL_LOG(WARNING, "Some buses want 'VA' but forcing 'DC' because other buses want 'PA'.");
259 EAL_LOG(WARNING, "Depending on the final decision by the EAL, not all buses may be able to initialize.");
260 }
261 }
262
263 return mode;
264 }
265
266 static int
bus_handle_sigbus(const struct rte_bus * bus,const void * failure_addr)267 bus_handle_sigbus(const struct rte_bus *bus,
268 const void *failure_addr)
269 {
270 int ret;
271
272 if (!bus->sigbus_handler)
273 return -1;
274
275 ret = bus->sigbus_handler(failure_addr);
276
277 /* find bus but handle failed, keep the errno be set. */
278 if (ret < 0 && rte_errno == 0)
279 rte_errno = ENOTSUP;
280
281 return ret > 0;
282 }
283
284 int
rte_bus_sigbus_handler(const void * failure_addr)285 rte_bus_sigbus_handler(const void *failure_addr)
286 {
287 struct rte_bus *bus;
288
289 int ret = 0;
290 int old_errno = rte_errno;
291
292 rte_errno = 0;
293
294 bus = rte_bus_find(NULL, bus_handle_sigbus, failure_addr);
295 /* can not find bus. */
296 if (!bus)
297 return 1;
298 /* find bus but handle failed, pass on the new errno. */
299 else if (rte_errno != 0)
300 return -1;
301
302 /* restore the old errno. */
303 rte_errno = old_errno;
304
305 return ret;
306 }
307