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