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 : 180 : 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 [ - + ]: 180 : 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 [ + - ]: 180 : return (probed && probed == failed) ? -1 : 0;
220 : : }
221 : :
222 : : static int
223 : 252 : rte_vmbus_cleanup(void)
224 : : {
225 : : struct rte_vmbus_device *dev, *tmp_dev;
226 : : int error = 0;
227 : :
228 [ - + ]: 252 : 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 : : dev->driver = NULL;
242 : : dev->device.driver = NULL;
243 : 0 : free(dev);
244 : : }
245 : :
246 : 252 : return error;
247 : : }
248 : :
249 : : static int
250 : 15 : vmbus_parse(const char *name, void *addr)
251 : : {
252 : : rte_uuid_t guid;
253 : : int ret;
254 : :
255 : 15 : ret = rte_uuid_parse(name, guid);
256 [ - + ]: 15 : if (ret == 0 && addr)
257 : : memcpy(addr, &guid, sizeof(guid));
258 : :
259 : 15 : return ret;
260 : : }
261 : :
262 : : /*
263 : : * scan for matching device args on command line
264 : : * example:
265 : : * -a 'vmbus:635a7ae3-091e-4410-ad59-667c4f8c04c3,latency=20'
266 : : */
267 : : struct rte_devargs *
268 : 0 : vmbus_devargs_lookup(struct rte_vmbus_device *dev)
269 : : {
270 : : struct rte_devargs *devargs;
271 : : rte_uuid_t addr;
272 : :
273 [ # # ]: 0 : RTE_EAL_DEVARGS_FOREACH("vmbus", devargs) {
274 : 0 : vmbus_parse(devargs->name, &addr);
275 : :
276 [ # # ]: 0 : if (rte_uuid_compare(dev->device_id, addr) == 0)
277 : 0 : return devargs;
278 : : }
279 : : return NULL;
280 : :
281 : : }
282 : :
283 : : /* register vmbus driver */
284 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_register)
285 : : void
286 : 252 : rte_vmbus_register(struct rte_vmbus_driver *driver)
287 : : {
288 : 252 : VMBUS_LOG(DEBUG,
289 : : "Registered driver %s", driver->driver.name);
290 : :
291 : 252 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next);
292 : 252 : }
293 : :
294 : : /* unregister vmbus driver */
295 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vmbus_unregister)
296 : : void
297 : 0 : rte_vmbus_unregister(struct rte_vmbus_driver *driver)
298 : : {
299 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next);
300 : 0 : }
301 : :
302 : : /* Add a device to VMBUS bus */
303 : : void
304 : 0 : vmbus_add_device(struct rte_vmbus_device *vmbus_dev)
305 : : {
306 : 0 : TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next);
307 : 0 : }
308 : :
309 : : /* Insert a device into a predefined position in VMBUS bus */
310 : : void
311 : 0 : vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev,
312 : : struct rte_vmbus_device *new_vmbus_dev)
313 : : {
314 : 0 : TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next);
315 : 0 : }
316 : :
317 : : /* Remove a device from VMBUS bus */
318 : : void
319 : 0 : vmbus_remove_device(struct rte_vmbus_device *vmbus_dev)
320 : : {
321 [ # # ]: 0 : TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next);
322 : 0 : }
323 : :
324 : : /* VMBUS doesn't support hotplug */
325 : : static struct rte_device *
326 : 0 : vmbus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
327 : : const void *data)
328 : : {
329 : : struct rte_vmbus_device *dev;
330 : :
331 [ # # ]: 0 : FOREACH_DEVICE_ON_VMBUS(dev) {
332 [ # # # # ]: 0 : if (start && &dev->device == start) {
333 : : start = NULL;
334 : 0 : continue;
335 : : }
336 [ # # ]: 0 : if (cmp(&dev->device, data) == 0)
337 : 0 : return &dev->device;
338 : : }
339 : :
340 : : return NULL;
341 : : }
342 : :
343 : :
344 : : struct rte_vmbus_bus rte_vmbus_bus = {
345 : : .bus = {
346 : : .scan = rte_vmbus_scan,
347 : : .probe = rte_vmbus_probe,
348 : : .cleanup = rte_vmbus_cleanup,
349 : : .find_device = vmbus_find_device,
350 : : .parse = vmbus_parse,
351 : : },
352 : : .device_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.device_list),
353 : : .driver_list = TAILQ_HEAD_INITIALIZER(rte_vmbus_bus.driver_list),
354 : : };
355 : :
356 : 252 : RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);
357 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE);
|