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