bus: skip useless iterations in find function
[dpdk.git] / lib / librte_eal / common / eal_common_bus.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2016 NXP.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of NXP nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/queue.h>
36
37 #include <rte_bus.h>
38
39 #include "eal_private.h"
40
41 struct rte_bus_list rte_bus_list =
42         TAILQ_HEAD_INITIALIZER(rte_bus_list);
43
44 void
45 rte_bus_register(struct rte_bus *bus)
46 {
47         RTE_VERIFY(bus);
48         RTE_VERIFY(bus->name && strlen(bus->name));
49         /* A bus should mandatorily have the scan implemented */
50         RTE_VERIFY(bus->scan);
51         RTE_VERIFY(bus->probe);
52         RTE_VERIFY(bus->find_device);
53         /* Buses supporting driver plug also require unplug. */
54         RTE_VERIFY(!bus->plug || bus->unplug);
55
56         TAILQ_INSERT_TAIL(&rte_bus_list, bus, next);
57         RTE_LOG(DEBUG, EAL, "Registered [%s] bus.\n", bus->name);
58 }
59
60 void
61 rte_bus_unregister(struct rte_bus *bus)
62 {
63         TAILQ_REMOVE(&rte_bus_list, bus, next);
64         RTE_LOG(DEBUG, EAL, "Unregistered [%s] bus.\n", bus->name);
65 }
66
67 /* Scan all the buses for registered devices */
68 int
69 rte_bus_scan(void)
70 {
71         int ret;
72         struct rte_bus *bus = NULL;
73
74         TAILQ_FOREACH(bus, &rte_bus_list, next) {
75                 ret = bus->scan();
76                 if (ret)
77                         RTE_LOG(ERR, EAL, "Scan for (%s) bus failed.\n",
78                                 bus->name);
79         }
80
81         return 0;
82 }
83
84 /* Probe all devices of all buses */
85 int
86 rte_bus_probe(void)
87 {
88         int ret;
89         struct rte_bus *bus, *vbus = NULL;
90
91         TAILQ_FOREACH(bus, &rte_bus_list, next) {
92                 if (!strcmp(bus->name, "vdev")) {
93                         vbus = bus;
94                         continue;
95                 }
96
97                 ret = bus->probe();
98                 if (ret)
99                         RTE_LOG(ERR, EAL, "Bus (%s) probe failed.\n",
100                                 bus->name);
101         }
102
103         if (vbus) {
104                 ret = vbus->probe();
105                 if (ret)
106                         RTE_LOG(ERR, EAL, "Bus (%s) probe failed.\n",
107                                 vbus->name);
108         }
109
110         return 0;
111 }
112
113 /* Dump information of a single bus */
114 static int
115 bus_dump_one(FILE *f, struct rte_bus *bus)
116 {
117         int ret;
118
119         /* For now, dump only the bus name */
120         ret = fprintf(f, " %s\n", bus->name);
121
122         /* Error in case of inability in writing to stream */
123         if (ret < 0)
124                 return ret;
125
126         return 0;
127 }
128
129 void
130 rte_bus_dump(FILE *f)
131 {
132         int ret;
133         struct rte_bus *bus;
134
135         TAILQ_FOREACH(bus, &rte_bus_list, next) {
136                 ret = bus_dump_one(f, bus);
137                 if (ret) {
138                         RTE_LOG(ERR, EAL, "Unable to write to stream (%d)\n",
139                                 ret);
140                         break;
141                 }
142         }
143 }
144
145 struct rte_bus *
146 rte_bus_find(const struct rte_bus *start, rte_bus_cmp_t cmp,
147              const void *data)
148 {
149         struct rte_bus *bus;
150
151         if (start != NULL)
152                 bus = TAILQ_NEXT(start, next);
153         else
154                 bus = TAILQ_FIRST(&rte_bus_list);
155         while (bus != NULL) {
156                 if (cmp(bus, data) == 0)
157                         break;
158                 bus = TAILQ_NEXT(bus, next);
159         }
160         return bus;
161 }
162
163 static int
164 cmp_rte_device(const struct rte_device *dev1, const void *_dev2)
165 {
166         const struct rte_device *dev2 = _dev2;
167
168         return dev1 != dev2;
169 }
170
171 static int
172 bus_find_device(const struct rte_bus *bus, const void *_dev)
173 {
174         struct rte_device *dev;
175
176         dev = bus->find_device(NULL, cmp_rte_device, _dev);
177         return dev == NULL;
178 }
179
180 struct rte_bus *
181 rte_bus_find_by_device(const struct rte_device *dev)
182 {
183         return rte_bus_find(NULL, bus_find_device, (const void *)dev);
184 }
185
186 static int
187 cmp_bus_name(const struct rte_bus *bus, const void *_name)
188 {
189         const char *name = _name;
190
191         return strcmp(bus->name, name);
192 }
193
194 struct rte_bus *
195 rte_bus_find_by_name(const char *busname)
196 {
197         return rte_bus_find(NULL, cmp_bus_name, (const void *)busname);
198 }
199
200 static int
201 bus_can_parse(const struct rte_bus *bus, const void *_name)
202 {
203         const char *name = _name;
204
205         return !(bus->parse && bus->parse(name, NULL) == 0);
206 }
207
208 struct rte_bus *
209 rte_bus_find_by_device_name(const char *str)
210 {
211         char name[RTE_DEV_NAME_MAX_LEN];
212         char *c;
213
214         snprintf(name, sizeof(name), "%s", str);
215         c = strchr(name, ',');
216         if (c != NULL)
217                 c[0] = '\0';
218         return rte_bus_find(NULL, bus_can_parse, name);
219 }
220
221
222 /*
223  * Get iommu class of devices on the bus.
224  */
225 enum rte_iova_mode
226 rte_bus_get_iommu_class(void)
227 {
228         int mode = RTE_IOVA_DC;
229         struct rte_bus *bus;
230
231         TAILQ_FOREACH(bus, &rte_bus_list, next) {
232
233                 if (bus->get_iommu_class)
234                         mode |= bus->get_iommu_class();
235         }
236
237         if (mode != RTE_IOVA_VA) {
238                 /* Use default IOVA mode */
239                 mode = RTE_IOVA_PA;
240         }
241         return mode;
242 }