xref: /dpdk/drivers/bus/vmbus/vmbus_common.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
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 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 	mapaddr = mmap(requested_addr, size, PROT_READ | PROT_WRITE,
36 		       MAP_SHARED | flags, fd, offset);
37 	if (mapaddr == MAP_FAILED) {
38 		VMBUS_LOG(ERR,
39 			  "mmap(%d, %p, %zu, %ld) failed: %s",
40 			  fd, requested_addr, size, (long)offset,
41 			  strerror(errno));
42 	} else {
43 		VMBUS_LOG(DEBUG, "  VMBUS memory mapped at %p",
44 			  mapaddr);
45 	}
46 	return mapaddr;
47 }
48 
49 /* unmap a particular resource */
50 void
51 vmbus_unmap_resource(void *requested_addr, size_t size)
52 {
53 	if (requested_addr == NULL)
54 		return;
55 
56 	/* Unmap the VMBUS memory resource of device */
57 	if (munmap(requested_addr, size)) {
58 		VMBUS_LOG(ERR, "munmap(%p, 0x%lx) failed: %s",
59 			requested_addr, (unsigned long)size,
60 			strerror(errno));
61 	} else {
62 		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 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 	for (id_table = dr->id_table; !rte_uuid_is_null(*id_table); ++id_table) {
85 		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 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 	if (!vmbus_match(dr, dev))
102 		return 1;	 /* not supported */
103 
104 	rte_uuid_unparse(dev->device_id, guid, sizeof(guid));
105 	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 	if (dev->device.devargs != NULL &&
110 		dev->device.devargs->policy == RTE_DEV_BLOCKED) {
111 		VMBUS_LOG(INFO, "  Device is blocked, not initializing");
112 		return 1;
113 	}
114 
115 	/* map resources for device */
116 	ret = rte_vmbus_map_device(dev);
117 	if (ret != 0)
118 		return ret;
119 
120 	/* reference driver structure */
121 	dev->driver = dr;
122 
123 	if (dev->device.numa_node < 0 && rte_socket_count() > 1)
124 		VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
125 
126 	/* call the driver probe() function */
127 	VMBUS_LOG(INFO, "  probe driver: %s", dr->driver.name);
128 	ret = dr->probe(dr, dev);
129 	if (ret) {
130 		dev->driver = NULL;
131 		rte_vmbus_unmap_device(dev);
132 	} else {
133 		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 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 	if (rte_dev_is_probed(&dev->device)) {
153 		VMBUS_LOG(DEBUG, "VMBUS driver already loaded");
154 		return 0;
155 	}
156 
157 	FOREACH_DRIVER_ON_VMBUS(dr) {
158 		rc = vmbus_probe_one_driver(dr, dev);
159 		if (rc < 0) /* negative is an error */
160 			return -1;
161 
162 		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 vmbus_ignore_device(struct rte_vmbus_device *dev)
172 {
173 	struct rte_devargs *devargs = vmbus_devargs_lookup(dev);
174 
175 	switch (rte_vmbus_bus.bus.conf.scan_mode) {
176 	case RTE_BUS_SCAN_ALLOWLIST:
177 		if (devargs && devargs->policy == RTE_DEV_ALLOWED)
178 			return false;
179 		break;
180 	case RTE_BUS_SCAN_UNDEFINED:
181 	case RTE_BUS_SCAN_BLOCKLIST:
182 		if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED)
183 			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 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 	FOREACH_DEVICE_ON_VMBUS(dev) {
202 		probed++;
203 
204 		rte_uuid_unparse(dev->device_id, ubuf, sizeof(ubuf));
205 
206 		if (vmbus_ignore_device(dev))
207 			continue;
208 
209 		if (vmbus_probe_all_drivers(dev) < 0) {
210 			VMBUS_LOG(NOTICE,
211 				"Requested device %s cannot be used", ubuf);
212 			rte_errno = errno;
213 			failed++;
214 		}
215 	}
216 
217 	return (probed && probed == failed) ? -1 : 0;
218 }
219 
220 static int
221 rte_vmbus_cleanup(void)
222 {
223 	struct rte_vmbus_device *dev, *tmp_dev;
224 	int error = 0;
225 
226 	RTE_TAILQ_FOREACH_SAFE(dev, &rte_vmbus_bus.device_list, next, tmp_dev) {
227 		const struct rte_vmbus_driver *drv = dev->driver;
228 		int ret;
229 
230 		if (drv == NULL || drv->remove == NULL)
231 			continue;
232 
233 		ret = drv->remove(dev);
234 		if (ret < 0)
235 			error = -1;
236 
237 		rte_vmbus_unmap_device(dev);
238 
239 		dev->driver = NULL;
240 		dev->device.driver = NULL;
241 		free(dev);
242 	}
243 
244 	return error;
245 }
246 
247 static int
248 vmbus_parse(const char *name, void *addr)
249 {
250 	rte_uuid_t guid;
251 	int ret;
252 
253 	ret = rte_uuid_parse(name, guid);
254 	if (ret == 0 && addr)
255 		memcpy(addr, &guid, sizeof(guid));
256 
257 	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 vmbus_devargs_lookup(struct rte_vmbus_device *dev)
267 {
268 	struct rte_devargs *devargs;
269 	rte_uuid_t addr;
270 
271 	RTE_EAL_DEVARGS_FOREACH("vmbus", devargs) {
272 		vmbus_parse(devargs->name, &addr);
273 
274 		if (rte_uuid_compare(dev->device_id, addr) == 0)
275 			return devargs;
276 	}
277 	return NULL;
278 
279 }
280 
281 /* register vmbus driver */
282 void
283 rte_vmbus_register(struct rte_vmbus_driver *driver)
284 {
285 	VMBUS_LOG(DEBUG,
286 		"Registered driver %s", driver->driver.name);
287 
288 	TAILQ_INSERT_TAIL(&rte_vmbus_bus.driver_list, driver, next);
289 }
290 
291 /* unregister vmbus driver */
292 void
293 rte_vmbus_unregister(struct rte_vmbus_driver *driver)
294 {
295 	TAILQ_REMOVE(&rte_vmbus_bus.driver_list, driver, next);
296 }
297 
298 /* Add a device to VMBUS bus */
299 void
300 vmbus_add_device(struct rte_vmbus_device *vmbus_dev)
301 {
302 	TAILQ_INSERT_TAIL(&rte_vmbus_bus.device_list, vmbus_dev, next);
303 }
304 
305 /* Insert a device into a predefined position in VMBUS bus */
306 void
307 vmbus_insert_device(struct rte_vmbus_device *exist_vmbus_dev,
308 		      struct rte_vmbus_device *new_vmbus_dev)
309 {
310 	TAILQ_INSERT_BEFORE(exist_vmbus_dev, new_vmbus_dev, next);
311 }
312 
313 /* Remove a device from VMBUS bus */
314 void
315 vmbus_remove_device(struct rte_vmbus_device *vmbus_dev)
316 {
317 	TAILQ_REMOVE(&rte_vmbus_bus.device_list, vmbus_dev, next);
318 }
319 
320 /* VMBUS doesn't support hotplug */
321 static struct rte_device *
322 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 	FOREACH_DEVICE_ON_VMBUS(dev) {
328 		if (start && &dev->device == start) {
329 			start = NULL;
330 			continue;
331 		}
332 		if (cmp(&dev->device, data) == 0)
333 			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 RTE_REGISTER_BUS(vmbus, rte_vmbus_bus.bus);
353 RTE_LOG_REGISTER_DEFAULT(vmbus_logtype_bus, NOTICE);
354