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_private.h"
15 : :
16 : : static struct rte_bus_list rte_bus_list =
17 : : TAILQ_HEAD_INITIALIZER(rte_bus_list);
18 : :
19 : : const char *
20 : 11885 : rte_bus_name(const struct rte_bus *bus)
21 : : {
22 : 11885 : return bus->name;
23 : : }
24 : :
25 : : void
26 : 2761 : rte_bus_register(struct rte_bus *bus)
27 : : {
28 [ - + ]: 2761 : RTE_VERIFY(bus);
29 [ + - - + ]: 2761 : RTE_VERIFY(rte_bus_name(bus) && strlen(rte_bus_name(bus)));
30 : : /* A bus should mandatorily have the scan implemented */
31 [ - + ]: 2761 : RTE_VERIFY(bus->scan);
32 [ - + ]: 2761 : RTE_VERIFY(bus->probe);
33 [ - + ]: 2761 : RTE_VERIFY(bus->find_device);
34 : : /* Buses supporting driver plug also require unplug. */
35 [ + + - + ]: 2761 : RTE_VERIFY(!bus->plug || bus->unplug);
36 : :
37 : 2761 : TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
38 : 2761 : EAL_LOG(DEBUG, "Registered [%s] bus.", rte_bus_name(bus));
39 : 2761 : }
40 : :
41 : : void
42 : 0 : rte_bus_unregister(struct rte_bus *bus)
43 : : {
44 [ # # ]: 0 : TAILQ_REMOVE(&rte_bus_list, bus, next);
45 : 0 : EAL_LOG(DEBUG, "Unregistered [%s] bus.", rte_bus_name(bus));
46 : 0 : }
47 : :
48 : : /* Scan all the buses for registered devices */
49 : : int
50 : 184 : rte_bus_scan(void)
51 : : {
52 : : int ret;
53 : : struct rte_bus *bus = NULL;
54 : :
55 [ + + ]: 2208 : TAILQ_FOREACH(bus, &rte_bus_list, next) {
56 : 2024 : ret = bus->scan();
57 [ - + ]: 2024 : if (ret)
58 : 0 : EAL_LOG(ERR, "Scan for (%s) bus failed.",
59 : : rte_bus_name(bus));
60 : : }
61 : :
62 : 184 : return 0;
63 : : }
64 : :
65 : : /* Probe all devices of all buses */
66 : : int
67 : 179 : rte_bus_probe(void)
68 : : {
69 : : int ret;
70 : : struct rte_bus *bus, *vbus = NULL;
71 : :
72 [ + + ]: 2148 : TAILQ_FOREACH(bus, &rte_bus_list, next) {
73 [ + + ]: 1969 : if (!strcmp(rte_bus_name(bus), "vdev")) {
74 : : vbus = bus;
75 : 179 : continue;
76 : : }
77 : :
78 : 1790 : ret = bus->probe();
79 [ - + ]: 1790 : if (ret)
80 : 0 : EAL_LOG(ERR, "Bus (%s) probe failed.",
81 : : rte_bus_name(bus));
82 : : }
83 : :
84 [ + - ]: 179 : if (vbus) {
85 : 179 : ret = vbus->probe();
86 [ - + ]: 179 : if (ret)
87 : 0 : EAL_LOG(ERR, "Bus (%s) probe failed.",
88 : : rte_bus_name(vbus));
89 : : }
90 : :
91 : 179 : return 0;
92 : : }
93 : :
94 : : /* Clean up all devices of all buses */
95 : : int
96 : 251 : eal_bus_cleanup(void)
97 : : {
98 : : int ret = 0;
99 : : struct rte_bus *bus;
100 : :
101 [ + + ]: 3012 : TAILQ_FOREACH(bus, &rte_bus_list, next) {
102 [ + + ]: 2761 : if (bus->cleanup == NULL)
103 : 753 : continue;
104 [ - + ]: 2008 : if (bus->cleanup() != 0)
105 : : ret = -1;
106 : : }
107 : :
108 : 251 : return ret;
109 : : }
110 : :
111 : : /* Dump information of a single bus */
112 : : static int
113 : 0 : bus_dump_one(FILE *f, struct rte_bus *bus)
114 : : {
115 : : int ret;
116 : :
117 : : /* For now, dump only the bus name */
118 : 0 : 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
128 : 0 : rte_bus_dump(FILE *f)
129 : : {
130 : : int ret;
131 : : struct rte_bus *bus;
132 : :
133 [ # # ]: 0 : TAILQ_FOREACH(bus, &rte_bus_list, next) {
134 : 0 : ret = bus_dump_one(f, bus);
135 [ # # ]: 0 : if (ret) {
136 : 0 : EAL_LOG(ERR, "Unable to write to stream (%d)",
137 : : ret);
138 : 0 : break;
139 : : }
140 : : }
141 : 0 : }
142 : :
143 : : struct rte_bus *
144 : 95 : 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 [ + + ]: 95 : if (start != NULL)
150 : 3 : bus = TAILQ_NEXT(start, next);
151 : : else
152 : 92 : bus = TAILQ_FIRST(&rte_bus_list);
153 [ + + ]: 948 : while (bus != NULL) {
154 [ + + ]: 895 : if (cmp(bus, data) == 0)
155 : : break;
156 : 853 : bus = TAILQ_NEXT(bus, next);
157 : : }
158 : 95 : return bus;
159 : : }
160 : :
161 : : static int
162 : 0 : cmp_rte_device(const struct rte_device *dev1, const void *_dev2)
163 : : {
164 : : const struct rte_device *dev2 = _dev2;
165 : :
166 : 0 : return dev1 != dev2;
167 : : }
168 : :
169 : : static int
170 : 0 : bus_find_device(const struct rte_bus *bus, const void *_dev)
171 : : {
172 : : struct rte_device *dev;
173 : :
174 : 0 : dev = bus->find_device(NULL, cmp_rte_device, _dev);
175 : 0 : return dev == NULL;
176 : : }
177 : :
178 : : struct rte_bus *
179 : 0 : rte_bus_find_by_device(const struct rte_device *dev)
180 : : {
181 : 0 : return rte_bus_find(NULL, bus_find_device, (const void *)dev);
182 : : }
183 : :
184 : : static int
185 : 152 : cmp_bus_name(const struct rte_bus *bus, const void *_name)
186 : : {
187 : : const char *name = _name;
188 : :
189 : 152 : return strcmp(rte_bus_name(bus), name);
190 : : }
191 : :
192 : : struct rte_bus *
193 : 18 : rte_bus_find_by_name(const char *busname)
194 : : {
195 : 18 : return rte_bus_find(NULL, cmp_bus_name, (const void *)busname);
196 : : }
197 : :
198 : : static int
199 : 336 : bus_can_parse(const struct rte_bus *bus, const void *_name)
200 : : {
201 : : const char *name = _name;
202 : :
203 [ + - + + ]: 336 : return !(bus->parse && bus->parse(name, NULL) == 0);
204 : : }
205 : :
206 : : struct rte_bus *
207 [ + + ]: 37 : 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 : 37 : c = strchr(name, ',');
214 [ + + ]: 37 : if (c != NULL)
215 : 1 : c[0] = '\0';
216 : 37 : 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
224 : 184 : 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 [ + + ]: 2208 : TAILQ_FOREACH(bus, &rte_bus_list, next) {
232 : : enum rte_iova_mode bus_iova_mode;
233 : :
234 [ + + ]: 2024 : if (bus->get_iommu_class == NULL)
235 : 552 : continue;
236 : :
237 : 1472 : bus_iova_mode = bus->get_iommu_class();
238 [ + + + - ]: 1473 : 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 [ + - ]: 1472 : 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 [ + + ]: 1472 : } else if (bus_iova_mode == RTE_IOVA_VA)
249 : : buses_want_va = true;
250 : : }
251 [ + + ]: 184 : if (buses_want_va && !buses_want_pa) {
252 : : mode = RTE_IOVA_VA;
253 [ + - ]: 183 : } else if (buses_want_pa && !buses_want_va) {
254 : : mode = RTE_IOVA_PA;
255 : : } else {
256 : : mode = RTE_IOVA_DC;
257 [ - + ]: 183 : if (buses_want_va) {
258 : 0 : EAL_LOG(WARNING, "Some buses want 'VA' but forcing 'DC' because other buses want 'PA'.");
259 : 0 : EAL_LOG(WARNING, "Depending on the final decision by the EAL, not all buses may be able to initialize.");
260 : : }
261 : : }
262 : :
263 : 184 : return mode;
264 : : }
265 : :
266 : : static int
267 : 0 : bus_handle_sigbus(const struct rte_bus *bus,
268 : : const void *failure_addr)
269 : : {
270 : : int ret;
271 : :
272 [ # # ]: 0 : if (!bus->sigbus_handler)
273 : : return -1;
274 : :
275 : 0 : ret = bus->sigbus_handler(failure_addr);
276 : :
277 : : /* find bus but handle failed, keep the errno be set. */
278 [ # # # # ]: 0 : if (ret < 0 && rte_errno == 0)
279 : 0 : rte_errno = ENOTSUP;
280 : :
281 : 0 : return ret > 0;
282 : : }
283 : :
284 : : int
285 : 0 : rte_bus_sigbus_handler(const void *failure_addr)
286 : : {
287 : : struct rte_bus *bus;
288 : :
289 : : int ret = 0;
290 : 0 : int old_errno = rte_errno;
291 : :
292 : 0 : rte_errno = 0;
293 : :
294 : 0 : bus = rte_bus_find(NULL, bus_handle_sigbus, failure_addr);
295 : : /* can not find bus. */
296 [ # # ]: 0 : if (!bus)
297 : : return 1;
298 : : /* find bus but handle failed, pass on the new errno. */
299 [ # # ]: 0 : else if (rte_errno != 0)
300 : : return -1;
301 : :
302 : : /* restore the old errno. */
303 : 0 : rte_errno = old_errno;
304 : :
305 : 0 : return ret;
306 : : }
|