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 : : static bool
172 : 0 : vmbus_ignore_device(struct rte_vmbus_device *dev)
173 : : {
174 : 0 : struct rte_devargs *devargs = vmbus_devargs_lookup(dev);
175 : :
176 [ # # # ]: 0 : switch (rte_vmbus_bus.bus.conf.scan_mode) {
177 : 0 : case RTE_BUS_SCAN_ALLOWLIST:
178 [ # # # # ]: 0 : if (devargs && devargs->policy == RTE_DEV_ALLOWED)
179 : 0 : return false;
180 : : break;
181 : 0 : case RTE_BUS_SCAN_UNDEFINED:
182 : : case RTE_BUS_SCAN_BLOCKLIST:
183 [ # # # # ]: 0 : if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED)
184 : 0 : return false;
185 : : break;
186 : : }
187 : : return true;
188 : : }
189 : :
190 : : /*
191 : : * Scan the vmbus, and call the devinit() function for
192 : : * all registered drivers that have a matching entry in its id_table
193 : : * for discovered devices.
194 : : */
195 : : RTE_EXPORT_SYMBOL(rte_vmbus_probe)
196 : : int
197 : 182 : rte_vmbus_probe(void)
198 : : {
199 : : struct rte_vmbus_device *dev;
200 : : size_t probed = 0, failed = 0;
201 : : char ubuf[RTE_UUID_STRLEN];
202 : :
203 [ - + ]: 182 : FOREACH_DEVICE_ON_VMBUS(dev) {
204 : 0 : probed++;
205 : :
206 : 0 : rte_uuid_unparse(dev->device_id, ubuf, sizeof(ubuf));
207 : :
208 [ # # ]: 0 : if (vmbus_ignore_device(dev))
209 : 0 : continue;
210 : :
211 [ # # ]: 0 : if (vmbus_probe_all_drivers(dev) < 0) {
212 : 0 : VMBUS_LOG(NOTICE,
213 : : "Requested device %s cannot be used", ubuf);
214 : 0 : rte_errno = errno;
215 : 0 : failed++;
216 : : }
217 : : }
218 : :
219 [ + - ]: 182 : return (probed && probed == failed) ? -1 : 0;
220 : : }
221 : :
222 : : static int
223 : 254 : rte_vmbus_cleanup(void)
224 : : {
225 : : struct rte_vmbus_device *dev, *tmp_dev;
226 : : int error = 0;
227 : :
228 [ - + ]: 254 : RTE_TAILQ_FOREACH_SAFE(dev, &rte_vmbus_bus.device_list, next, tmp_dev) {
229 : 0 : const struct rte_vmbus_driver *drv = dev->driver;
230 : : int ret;
231 : :
232 [ # # # # ]: 0 : if (drv == NULL || drv->remove == NULL)
233 : 0 : continue;
234 : :
235 : 0 : ret = drv->remove(dev);
236 [ # # ]: 0 : if (ret < 0)
237 : : error = -1;
238 : :
239 : 0 : rte_vmbus_unmap_device(dev);
240 : :
241 : 0 : dev->driver = NULL;
242 : 0 : dev->device.driver = NULL;
243 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.device_list, dev, next);
244 : 0 : free(dev);
245 : : }
246 : :
247 : 254 : return error;
248 : : }
249 : :
250 : : static int
251 : 15 : vmbus_parse(const char *name, void *addr)
252 : : {
253 : : rte_uuid_t guid;
254 : : int ret;
255 : :
256 : 15 : ret = rte_uuid_parse(name, guid);
257 [ - + ]: 15 : if (ret == 0 && addr)
258 : : memcpy(addr, &guid, sizeof(guid));
259 : :
260 : 15 : return ret;
261 : : }
262 : :
263 : : /*
264 : : * scan for matching device args on command line
265 : : * example:
266 : : * -a 'vmbus:635a7ae3-091e-4410-ad59-667c4f8c04c3,latency=20'
267 : : */
268 : : struct rte_devargs *
269 : 0 : vmbus_devargs_lookup(struct rte_vmbus_device *dev)
270 : : {
271 : : struct rte_devargs *devargs;
272 : : rte_uuid_t addr;
273 : :
274 [ # # ]: 0 : RTE_EAL_DEVARGS_FOREACH("vmbus", devargs) {
275 : 0 : vmbus_parse(devargs->name, &addr);
276 : :
277 [ # # ]: 0 : if (rte_uuid_compare(dev->device_id, addr) == 0)
278 : 0 : return devargs;
279 : : }
280 : : return NULL;
281 : :
282 : : }
283 : :
284 : : /* register vmbus driver */
285 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_register)
286 : : void
287 : 254 : rte_vmbus_register(struct rte_vmbus_driver *driver)
288 : : {
289 : 254 : VMBUS_LOG(DEBUG,
290 : : "Registered driver %s", driver->driver.name);
291 : :
292 : 254 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next);
293 : 254 : }
294 : :
295 : : /* unregister vmbus driver */
296 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_unregister)
297 : : void
298 : 0 : rte_vmbus_unregister(struct rte_vmbus_driver *driver)
299 : : {
300 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next);
301 : 0 : }
302 : :
303 : : /* Add a device to VMBUS bus */
304 : : void
305 : 0 : vmbus_add_device(struct rte_vmbus_device *vmbus_dev)
306 : : {
307 : 0 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next);
308 : 0 : }
309 : :
310 : : /* Insert a device into a predefined position in VMBUS bus */
311 : : void
312 : 0 : vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev,
313 : : struct rte_vmbus_device *new_vmbus_dev)
314 : : {
315 : 0 : TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next);
316 : 0 : }
317 : :
318 : : /* Remove a device from VMBUS bus */
319 : : void
320 : 0 : vmbus_remove_device(struct rte_vmbus_device *vmbus_dev)
321 : : {
322 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next);
323 : 0 : }
324 : :
325 : : /* VMBUS doesn't support hotplug */
326 : : static struct rte_device *
327 : 0 : vmbus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
328 : : const void *data)
329 : : {
330 : : struct rte_vmbus_device *dev;
331 : :
332 [ # # ]: 0 : FOREACH_DEVICE_ON_VMBUS(dev) {
333 [ # # # # ]: 0 : if (start && &dev->device == start) {
334 : : start = NULL;
335 : 0 : continue;
336 : : }
337 [ # # ]: 0 : if (cmp(&dev->device, data) == 0)
338 : 0 : return &dev->device;
339 : : }
340 : :
341 : : return NULL;
342 : : }
343 : :
344 : :
345 : : struct rte_vmbus_bus rte_vmbus_bus = {
346 : : .bus = {
347 : : .scan = rte_vmbus_scan,
348 : : .probe = rte_vmbus_probe,
349 : : .cleanup = rte_vmbus_cleanup,
350 : : .find_device = vmbus_find_device,
351 : : .parse = vmbus_parse,
352 : : },
353 : : .device_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.device_list),
354 : : .driver_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.driver_list),
355 : : };
356 : :
357 : 254 : RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);
358 [ - + ]: 254 : RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE);
|