Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2018, Microsoft Corporation.
3 : : * All Rights Reserved.
4 : : */
5 : :
6 : : #include <string.h>
7 : : #include <unistd.h>
8 : : #include <dirent.h>
9 : : #include <fcntl.h>
10 : : #include <sys/queue.h>
11 : : #include <sys/mman.h>
12 : :
13 : : #include <eal_export.h>
14 : : #include <rte_log.h>
15 : : #include <rte_eal.h>
16 : : #include <rte_tailq.h>
17 : : #include <rte_devargs.h>
18 : : #include <rte_lcore.h>
19 : : #include <rte_malloc.h>
20 : : #include <rte_errno.h>
21 : : #include <rte_memory.h>
22 : : #include <rte_bus_vmbus.h>
23 : :
24 : : #include "private.h"
25 : :
26 : : extern struct rte_vmbus_bus rte_vmbus_bus;
27 : :
28 : : /* map a particular resource from a file */
29 : : void *
30 : 0 : vmbus_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
31 : : int flags)
32 : : {
33 : : void *mapaddr;
34 : :
35 : : /* Map the memory resource of device */
36 : 0 : mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
37 : : MAP_SHARED | flags, fd, offset);
38 [ # # ]: 0 : if (mapaddr == MAP_FAILED) {
39 : 0 : VMBUS_LOG(ERR,
40 : : "mmap(%d, %p, %zu, %ld) failed: %s",
41 : : fd, requested_addr, size, (long)offset,
42 : : strerror(errno));
43 : : } else {
44 : 0 : VMBUS_LOG(DEBUG, " VMBUS memory mapped at %p",
45 : : mapaddr);
46 : : }
47 : 0 : return mapaddr;
48 : : }
49 : :
50 : : /* unmap a particular resource */
51 : : void
52 : 0 : vmbus_unmap_resource(void *requested_addr, size_t size)
53 : : {
54 [ # # ]: 0 : if (requested_addr == NULL)
55 : : return;
56 : :
57 : : /* Unmap the VMBUS memory resource of device */
58 [ # # ]: 0 : if (munmap(requested_addr, size)) {
59 : 0 : VMBUS_LOG(ERR, "munmap(%p, 0x%lx) failed: %s",
60 : : requested_addr, (unsigned long)size,
61 : : strerror(errno));
62 : : } else {
63 : 0 : VMBUS_LOG(DEBUG, " VMBUS memory unmapped at %p",
64 : : requested_addr);
65 : : }
66 : : }
67 : :
68 : : /**
69 : : * Match the VMBUS driver and device using UUID table
70 : : *
71 : : * @param drv
72 : : * VMBUS driver from which ID table would be extracted
73 : : * @param pci_dev
74 : : * VMBUS device to match against the driver
75 : : * @return
76 : : * true for successful match
77 : : * false for unsuccessful match
78 : : */
79 : : static bool
80 : 0 : vmbus_match(const struct rte_vmbus_driver *dr,
81 : : const struct rte_vmbus_device *dev)
82 : : {
83 : : const rte_uuid_t *id_table;
84 : :
85 [ # # ]: 0 : for (id_table = dr->id_table; !rte_uuid_is_null(*id_table); ++id_table) {
86 [ # # ]: 0 : if (rte_uuid_compare(*id_table, dev->class_id) == 0)
87 : : return true;
88 : : }
89 : :
90 : : return false;
91 : : }
92 : : /*
93 : : * If device ID match, call the devinit() function of the driver.
94 : : */
95 : : static int
96 : 0 : vmbus_probe_one_driver(struct rte_vmbus_driver *dr,
97 : : struct rte_vmbus_device *dev)
98 : : {
99 : : char guid[RTE_UUID_STRLEN];
100 : : int ret;
101 : :
102 [ # # ]: 0 : if (!vmbus_match(dr, dev))
103 : : return 1; /* not supported */
104 : :
105 : 0 : rte_uuid_unparse(dev->device_id, guid, sizeof(guid));
106 : 0 : VMBUS_LOG(INFO, "VMBUS device %s on NUMA socket %i",
107 : : guid, dev->device.numa_node);
108 : :
109 : : /* no initialization when marked as blocked, return without error */
110 [ # # ]: 0 : if (dev->device.devargs != NULL &&
111 [ # # ]: 0 : dev->device.devargs->policy == RTE_DEV_BLOCKED) {
112 : 0 : VMBUS_LOG(INFO, " Device is blocked, not initializing");
113 : 0 : return 1;
114 : : }
115 : :
116 : : /* map resources for device */
117 : 0 : ret = rte_vmbus_map_device(dev);
118 [ # # ]: 0 : if (ret != 0)
119 : : return ret;
120 : :
121 : : /* reference driver structure */
122 : 0 : dev->driver = dr;
123 : :
124 [ # # # # ]: 0 : if (dev->device.numa_node < 0 && rte_socket_count() > 1)
125 : 0 : VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
126 : :
127 : : /* call the driver probe() function */
128 : 0 : VMBUS_LOG(INFO, " probe driver: %s", dr->driver.name);
129 : 0 : ret = dr->probe(dr, dev);
130 [ # # ]: 0 : if (ret) {
131 : 0 : dev->driver = NULL;
132 : 0 : rte_vmbus_unmap_device(dev);
133 : : } else {
134 : 0 : dev->device.driver = &dr->driver;
135 : : }
136 : :
137 : : return ret;
138 : : }
139 : :
140 : : /*
141 : : * If device class GUID matches, call the probe function of
142 : : * register drivers for the vmbus device.
143 : : * Return -1 if initialization failed,
144 : : * and 1 if no driver found for this device.
145 : : */
146 : : static int
147 : 0 : vmbus_probe_all_drivers(struct rte_vmbus_device *dev)
148 : : {
149 : : struct rte_vmbus_driver *dr;
150 : : int rc;
151 : :
152 : : /* Check if a driver is already loaded */
153 [ # # ]: 0 : if (rte_dev_is_probed(&dev->device)) {
154 : 0 : VMBUS_LOG(DEBUG, "VMBUS driver already loaded");
155 : 0 : return 0;
156 : : }
157 : :
158 [ # # ]: 0 : FOREACH_DRIVER_ON_VMBUS(dr) {
159 : 0 : rc = vmbus_probe_one_driver(dr, dev);
160 [ # # ]: 0 : if (rc < 0) /* negative is an error */
161 : : return -1;
162 : :
163 [ # # ]: 0 : if (rc > 0) /* positive driver doesn't support it */
164 : : continue;
165 : :
166 : : return 0;
167 : : }
168 : : return 1;
169 : : }
170 : :
171 : : /*
172 : : * Scan the vmbus, and call the devinit() function for
173 : : * all registered drivers that have a matching entry in its id_table
174 : : * for discovered devices.
175 : : */
176 : : RTE_EXPORT_SYMBOL(rte_vmbus_probe)
177 : : int
178 : 211 : rte_vmbus_probe(void)
179 : : {
180 : : struct rte_vmbus_device *dev;
181 : : size_t probed = 0, failed = 0;
182 : : char ubuf[RTE_UUID_STRLEN];
183 : :
184 [ - + ]: 211 : FOREACH_DEVICE_ON_VMBUS(dev) {
185 : 0 : probed++;
186 : :
187 : 0 : rte_uuid_unparse(dev->device_id, ubuf, sizeof(ubuf));
188 : :
189 [ # # ]: 0 : if (rte_bus_device_is_ignored(&rte_vmbus_bus.bus, ubuf))
190 : 0 : continue;
191 : :
192 [ # # ]: 0 : if (vmbus_probe_all_drivers(dev) < 0) {
193 : 0 : VMBUS_LOG(NOTICE,
194 : : "Requested device %s cannot be used", ubuf);
195 : 0 : rte_errno = errno;
196 : 0 : failed++;
197 : : }
198 : : }
199 : :
200 [ + - ]: 211 : return (probed && probed == failed) ? -1 : 0;
201 : : }
202 : :
203 : : static int
204 : 277 : rte_vmbus_cleanup(void)
205 : : {
206 : : struct rte_vmbus_device *dev, *tmp_dev;
207 : : int error = 0;
208 : :
209 [ - + ]: 277 : RTE_TAILQ_FOREACH_SAFE(dev, &rte_vmbus_bus.device_list, next, tmp_dev) {
210 : 0 : const struct rte_vmbus_driver *drv = dev->driver;
211 : : int ret;
212 : :
213 [ # # # # ]: 0 : if (drv == NULL || drv->remove == NULL)
214 : 0 : continue;
215 : :
216 : 0 : ret = drv->remove(dev);
217 [ # # ]: 0 : if (ret < 0)
218 : : error = -1;
219 : :
220 : 0 : rte_vmbus_unmap_device(dev);
221 : :
222 : 0 : dev->driver = NULL;
223 : 0 : dev->device.driver = NULL;
224 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.device_list, dev, next);
225 : 0 : free(dev);
226 : : }
227 : :
228 : 277 : return error;
229 : : }
230 : :
231 : : static int
232 : 15 : vmbus_parse(const char *name, void *addr)
233 : : {
234 : : rte_uuid_t guid;
235 : : int ret;
236 : :
237 : 15 : ret = rte_uuid_parse(name, guid);
238 [ - + ]: 15 : if (ret == 0 && addr)
239 : : memcpy(addr, &guid, sizeof(guid));
240 : :
241 : 15 : return ret;
242 : : }
243 : :
244 : : static int
245 : 0 : vmbus_dev_compare(const char *name1, const char *name2)
246 : : {
247 : : rte_uuid_t guid1, guid2;
248 : :
249 [ # # # # ]: 0 : if (vmbus_parse(name1, &guid1) != 0 ||
250 : 0 : vmbus_parse(name2, &guid2) != 0)
251 : 0 : return 1;
252 : :
253 : 0 : return rte_uuid_compare(guid1, guid2);
254 : : }
255 : :
256 : : /* register vmbus driver */
257 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_register)
258 : : void
259 : 284 : rte_vmbus_register(struct rte_vmbus_driver *driver)
260 : : {
261 : 284 : VMBUS_LOG(DEBUG,
262 : : "Registered driver %s", driver->driver.name);
263 : :
264 : 284 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next);
265 : 284 : }
266 : :
267 : : /* unregister vmbus driver */
268 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_unregister)
269 : : void
270 : 0 : rte_vmbus_unregister(struct rte_vmbus_driver *driver)
271 : : {
272 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next);
273 : 0 : }
274 : :
275 : : /* Add a device to VMBUS bus */
276 : : void
277 : 0 : vmbus_add_device(struct rte_vmbus_device *vmbus_dev)
278 : : {
279 : 0 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next);
280 : 0 : }
281 : :
282 : : /* Insert a device into a predefined position in VMBUS bus */
283 : : void
284 : 0 : vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev,
285 : : struct rte_vmbus_device *new_vmbus_dev)
286 : : {
287 : 0 : TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next);
288 : 0 : }
289 : :
290 : : /* Remove a device from VMBUS bus */
291 : : void
292 : 0 : vmbus_remove_device(struct rte_vmbus_device *vmbus_dev)
293 : : {
294 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next);
295 : 0 : }
296 : :
297 : : /* VMBUS doesn't support hotplug */
298 : : static struct rte_device *
299 : 0 : vmbus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
300 : : const void *data)
301 : : {
302 : : struct rte_vmbus_device *dev;
303 : :
304 [ # # ]: 0 : FOREACH_DEVICE_ON_VMBUS(dev) {
305 [ # # # # ]: 0 : if (start && &dev->device == start) {
306 : : start = NULL;
307 : 0 : continue;
308 : : }
309 [ # # ]: 0 : if (cmp(&dev->device, data) == 0)
310 : 0 : return &dev->device;
311 : : }
312 : :
313 : : return NULL;
314 : : }
315 : :
316 : :
317 : : struct rte_vmbus_bus rte_vmbus_bus = {
318 : : .bus = {
319 : : .scan = rte_vmbus_scan,
320 : : .probe = rte_vmbus_probe,
321 : : .cleanup = rte_vmbus_cleanup,
322 : : .find_device = vmbus_find_device,
323 : : .parse = vmbus_parse,
324 : : .dev_compare = vmbus_dev_compare,
325 : : },
326 : : .device_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.device_list),
327 : : .driver_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.driver_list),
328 : : };
329 : :
330 : 284 : RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);
331 [ - + ]: 284 : RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE);
|