xref: /dpdk/drivers/bus/vmbus/linux/vmbus_bus.c (revision 831dba47bd365b8a539dfb51fffdd01f8a436f6c)
1*831dba47SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2*831dba47SStephen Hemminger  * Copyright (c) 2018, Microsoft Corporation.
3*831dba47SStephen Hemminger  * All Rights Reserved.
4*831dba47SStephen Hemminger  */
5*831dba47SStephen Hemminger 
6*831dba47SStephen Hemminger #include <string.h>
7*831dba47SStephen Hemminger #include <unistd.h>
8*831dba47SStephen Hemminger #include <dirent.h>
9*831dba47SStephen Hemminger #include <fcntl.h>
10*831dba47SStephen Hemminger #include <sys/mman.h>
11*831dba47SStephen Hemminger #include <sys/stat.h>
12*831dba47SStephen Hemminger 
13*831dba47SStephen Hemminger #include <rte_eal.h>
14*831dba47SStephen Hemminger #include <rte_uuid.h>
15*831dba47SStephen Hemminger #include <rte_tailq.h>
16*831dba47SStephen Hemminger #include <rte_log.h>
17*831dba47SStephen Hemminger #include <rte_devargs.h>
18*831dba47SStephen Hemminger #include <rte_memory.h>
19*831dba47SStephen Hemminger #include <rte_malloc.h>
20*831dba47SStephen Hemminger #include <rte_bus_vmbus.h>
21*831dba47SStephen Hemminger 
22*831dba47SStephen Hemminger #include "eal_filesystem.h"
23*831dba47SStephen Hemminger #include "private.h"
24*831dba47SStephen Hemminger 
25*831dba47SStephen Hemminger /** Pathname of VMBUS devices directory. */
26*831dba47SStephen Hemminger #define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices"
27*831dba47SStephen Hemminger 
28*831dba47SStephen Hemminger extern struct rte_vmbus_bus rte_vmbus_bus;
29*831dba47SStephen Hemminger 
30*831dba47SStephen Hemminger /* Read sysfs file to get UUID */
31*831dba47SStephen Hemminger static int
32*831dba47SStephen Hemminger parse_sysfs_uuid(const char *filename, rte_uuid_t uu)
33*831dba47SStephen Hemminger {
34*831dba47SStephen Hemminger 	char buf[BUFSIZ];
35*831dba47SStephen Hemminger 	char *cp, *in = buf;
36*831dba47SStephen Hemminger 	FILE *f;
37*831dba47SStephen Hemminger 
38*831dba47SStephen Hemminger 	f = fopen(filename, "r");
39*831dba47SStephen Hemminger 	if (f == NULL) {
40*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "cannot open sysfs value %s: %s",
41*831dba47SStephen Hemminger 			  filename, strerror(errno));
42*831dba47SStephen Hemminger 		return -1;
43*831dba47SStephen Hemminger 	}
44*831dba47SStephen Hemminger 
45*831dba47SStephen Hemminger 	if (fgets(buf, sizeof(buf), f) == NULL) {
46*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "cannot read sysfs value %s",
47*831dba47SStephen Hemminger 				filename);
48*831dba47SStephen Hemminger 		fclose(f);
49*831dba47SStephen Hemminger 		return -1;
50*831dba47SStephen Hemminger 	}
51*831dba47SStephen Hemminger 	fclose(f);
52*831dba47SStephen Hemminger 
53*831dba47SStephen Hemminger 	cp = strchr(buf, '\n');
54*831dba47SStephen Hemminger 	if (cp)
55*831dba47SStephen Hemminger 		*cp = '\0';
56*831dba47SStephen Hemminger 
57*831dba47SStephen Hemminger 	/* strip { } notation */
58*831dba47SStephen Hemminger 	if (buf[0] == '{') {
59*831dba47SStephen Hemminger 		in = buf + 1;
60*831dba47SStephen Hemminger 		cp = strchr(in, '}');
61*831dba47SStephen Hemminger 		if (cp)
62*831dba47SStephen Hemminger 			*cp = '\0';
63*831dba47SStephen Hemminger 	}
64*831dba47SStephen Hemminger 
65*831dba47SStephen Hemminger 	if (rte_uuid_parse(in, uu) < 0) {
66*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "%s %s not a valid UUID",
67*831dba47SStephen Hemminger 			filename, buf);
68*831dba47SStephen Hemminger 		return -1;
69*831dba47SStephen Hemminger 	}
70*831dba47SStephen Hemminger 
71*831dba47SStephen Hemminger 	return 0;
72*831dba47SStephen Hemminger }
73*831dba47SStephen Hemminger 
74*831dba47SStephen Hemminger static int
75*831dba47SStephen Hemminger get_sysfs_string(const char *filename, char *buf, size_t buflen)
76*831dba47SStephen Hemminger {
77*831dba47SStephen Hemminger 	char *cp;
78*831dba47SStephen Hemminger 	FILE *f;
79*831dba47SStephen Hemminger 
80*831dba47SStephen Hemminger 	f = fopen(filename, "r");
81*831dba47SStephen Hemminger 	if (f == NULL) {
82*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "cannot open sysfs value %s:%s",
83*831dba47SStephen Hemminger 			  filename, strerror(errno));
84*831dba47SStephen Hemminger 		return -1;
85*831dba47SStephen Hemminger 	}
86*831dba47SStephen Hemminger 
87*831dba47SStephen Hemminger 	if (fgets(buf, buflen, f) == NULL) {
88*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "cannot read sysfs value %s",
89*831dba47SStephen Hemminger 				filename);
90*831dba47SStephen Hemminger 		fclose(f);
91*831dba47SStephen Hemminger 		return -1;
92*831dba47SStephen Hemminger 	}
93*831dba47SStephen Hemminger 	fclose(f);
94*831dba47SStephen Hemminger 
95*831dba47SStephen Hemminger 	/* remove trailing newline */
96*831dba47SStephen Hemminger 	cp = memchr(buf, '\n', buflen);
97*831dba47SStephen Hemminger 	if (cp)
98*831dba47SStephen Hemminger 		*cp = '\0';
99*831dba47SStephen Hemminger 
100*831dba47SStephen Hemminger 	return 0;
101*831dba47SStephen Hemminger }
102*831dba47SStephen Hemminger 
103*831dba47SStephen Hemminger static int
104*831dba47SStephen Hemminger vmbus_get_uio_dev(const struct rte_vmbus_device *dev,
105*831dba47SStephen Hemminger 		  char *dstbuf, size_t buflen)
106*831dba47SStephen Hemminger {
107*831dba47SStephen Hemminger 	char dirname[PATH_MAX];
108*831dba47SStephen Hemminger 	unsigned int uio_num;
109*831dba47SStephen Hemminger 	struct dirent *e;
110*831dba47SStephen Hemminger 	DIR *dir;
111*831dba47SStephen Hemminger 
112*831dba47SStephen Hemminger 	/* Assume recent kernel where uio is in uio/uioX */
113*831dba47SStephen Hemminger 	snprintf(dirname, sizeof(dirname),
114*831dba47SStephen Hemminger 		 SYSFS_VMBUS_DEVICES "/%s/uio", dev->device.name);
115*831dba47SStephen Hemminger 
116*831dba47SStephen Hemminger 	dir = opendir(dirname);
117*831dba47SStephen Hemminger 	if (dir == NULL)
118*831dba47SStephen Hemminger 		return -1; /* Not a UIO device */
119*831dba47SStephen Hemminger 
120*831dba47SStephen Hemminger 	/* take the first file starting with "uio" */
121*831dba47SStephen Hemminger 	while ((e = readdir(dir)) != NULL) {
122*831dba47SStephen Hemminger 		const int prefix_len = 3;
123*831dba47SStephen Hemminger 		char *endptr;
124*831dba47SStephen Hemminger 
125*831dba47SStephen Hemminger 		if (strncmp(e->d_name, "uio", prefix_len) != 0)
126*831dba47SStephen Hemminger 			continue;
127*831dba47SStephen Hemminger 
128*831dba47SStephen Hemminger 		/* try uio%d */
129*831dba47SStephen Hemminger 		errno = 0;
130*831dba47SStephen Hemminger 		uio_num = strtoull(e->d_name + prefix_len, &endptr, 10);
131*831dba47SStephen Hemminger 		if (errno == 0 && endptr != (e->d_name + prefix_len)) {
132*831dba47SStephen Hemminger 			snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num);
133*831dba47SStephen Hemminger 			break;
134*831dba47SStephen Hemminger 		}
135*831dba47SStephen Hemminger 	}
136*831dba47SStephen Hemminger 	closedir(dir);
137*831dba47SStephen Hemminger 
138*831dba47SStephen Hemminger 	if (e == NULL)
139*831dba47SStephen Hemminger 		return -1;
140*831dba47SStephen Hemminger 
141*831dba47SStephen Hemminger 	return uio_num;
142*831dba47SStephen Hemminger }
143*831dba47SStephen Hemminger 
144*831dba47SStephen Hemminger /* Check map names with kernel names */
145*831dba47SStephen Hemminger static const char *map_names[VMBUS_MAX_RESOURCE] = {
146*831dba47SStephen Hemminger 	[HV_TXRX_RING_MAP] = "txrx_rings",
147*831dba47SStephen Hemminger 	[HV_INT_PAGE_MAP]  = "int_page",
148*831dba47SStephen Hemminger 	[HV_MON_PAGE_MAP]  = "monitor_page",
149*831dba47SStephen Hemminger 	[HV_RECV_BUF_MAP]  = "recv:",
150*831dba47SStephen Hemminger 	[HV_SEND_BUF_MAP]  = "send:",
151*831dba47SStephen Hemminger };
152*831dba47SStephen Hemminger 
153*831dba47SStephen Hemminger 
154*831dba47SStephen Hemminger /* map the resources of a vmbus device in virtual memory */
155*831dba47SStephen Hemminger int
156*831dba47SStephen Hemminger rte_vmbus_map_device(struct rte_vmbus_device *dev)
157*831dba47SStephen Hemminger {
158*831dba47SStephen Hemminger 	char uioname[PATH_MAX], filename[PATH_MAX];
159*831dba47SStephen Hemminger 	char dirname[PATH_MAX], mapname[64];
160*831dba47SStephen Hemminger 	int i;
161*831dba47SStephen Hemminger 
162*831dba47SStephen Hemminger 	dev->uio_num = vmbus_get_uio_dev(dev, uioname, sizeof(uioname));
163*831dba47SStephen Hemminger 	if (dev->uio_num < 0) {
164*831dba47SStephen Hemminger 		VMBUS_LOG(DEBUG, "Not managed by UIO driver, skipped");
165*831dba47SStephen Hemminger 		return 1;
166*831dba47SStephen Hemminger 	}
167*831dba47SStephen Hemminger 
168*831dba47SStephen Hemminger 	/* Extract resource value */
169*831dba47SStephen Hemminger 	for (i = 0; i < VMBUS_MAX_RESOURCE; i++) {
170*831dba47SStephen Hemminger 		struct rte_mem_resource *res = &dev->resource[i];
171*831dba47SStephen Hemminger 		unsigned long len, gpad = 0;
172*831dba47SStephen Hemminger 		char *cp;
173*831dba47SStephen Hemminger 
174*831dba47SStephen Hemminger 		snprintf(dirname, sizeof(dirname),
175*831dba47SStephen Hemminger 			 "%s/maps/map%d", uioname, i);
176*831dba47SStephen Hemminger 
177*831dba47SStephen Hemminger 		snprintf(filename, sizeof(filename),
178*831dba47SStephen Hemminger 			 "%s/name", dirname);
179*831dba47SStephen Hemminger 
180*831dba47SStephen Hemminger 		if (get_sysfs_string(filename, mapname, sizeof(mapname)) < 0) {
181*831dba47SStephen Hemminger 			VMBUS_LOG(ERR, "could not read %s", filename);
182*831dba47SStephen Hemminger 			return -1;
183*831dba47SStephen Hemminger 		}
184*831dba47SStephen Hemminger 
185*831dba47SStephen Hemminger 		if (strncmp(map_names[i], mapname, strlen(map_names[i])) != 0) {
186*831dba47SStephen Hemminger 			VMBUS_LOG(ERR,
187*831dba47SStephen Hemminger 				"unexpected resource %s (expected %s)",
188*831dba47SStephen Hemminger 				mapname, map_names[i]);
189*831dba47SStephen Hemminger 			return -1;
190*831dba47SStephen Hemminger 		}
191*831dba47SStephen Hemminger 
192*831dba47SStephen Hemminger 		snprintf(filename, sizeof(filename),
193*831dba47SStephen Hemminger 			 "%s/size", dirname);
194*831dba47SStephen Hemminger 		if (eal_parse_sysfs_value(filename, &len) < 0) {
195*831dba47SStephen Hemminger 			VMBUS_LOG(ERR,
196*831dba47SStephen Hemminger 				"could not read %s", filename);
197*831dba47SStephen Hemminger 			return -1;
198*831dba47SStephen Hemminger 		}
199*831dba47SStephen Hemminger 		res->len = len;
200*831dba47SStephen Hemminger 
201*831dba47SStephen Hemminger 		/* both send and receive buffers have gpad in name */
202*831dba47SStephen Hemminger 		cp = memchr(mapname, ':', sizeof(mapname));
203*831dba47SStephen Hemminger 		if (cp)
204*831dba47SStephen Hemminger 			gpad = strtoul(cp+1, NULL, 0);
205*831dba47SStephen Hemminger 
206*831dba47SStephen Hemminger 		/* put the GPAD value in physical address */
207*831dba47SStephen Hemminger 		res->phys_addr = gpad;
208*831dba47SStephen Hemminger 	}
209*831dba47SStephen Hemminger 
210*831dba47SStephen Hemminger 	return vmbus_uio_map_resource(dev);
211*831dba47SStephen Hemminger }
212*831dba47SStephen Hemminger 
213*831dba47SStephen Hemminger void
214*831dba47SStephen Hemminger rte_vmbus_unmap_device(struct rte_vmbus_device *dev)
215*831dba47SStephen Hemminger {
216*831dba47SStephen Hemminger 	vmbus_uio_unmap_resource(dev);
217*831dba47SStephen Hemminger }
218*831dba47SStephen Hemminger 
219*831dba47SStephen Hemminger /* Scan one vmbus sysfs entry, and fill the devices list from it. */
220*831dba47SStephen Hemminger static int
221*831dba47SStephen Hemminger vmbus_scan_one(const char *name)
222*831dba47SStephen Hemminger {
223*831dba47SStephen Hemminger 	struct rte_vmbus_device *dev, *dev2;
224*831dba47SStephen Hemminger 	char filename[PATH_MAX];
225*831dba47SStephen Hemminger 	char dirname[PATH_MAX];
226*831dba47SStephen Hemminger 	unsigned long tmp;
227*831dba47SStephen Hemminger 
228*831dba47SStephen Hemminger 	dev = calloc(1, sizeof(*dev));
229*831dba47SStephen Hemminger 	if (dev == NULL)
230*831dba47SStephen Hemminger 		return -1;
231*831dba47SStephen Hemminger 
232*831dba47SStephen Hemminger 	dev->device.name = strdup(name);
233*831dba47SStephen Hemminger 	if (!dev->device.name)
234*831dba47SStephen Hemminger 		goto error;
235*831dba47SStephen Hemminger 
236*831dba47SStephen Hemminger 	/* sysfs base directory
237*831dba47SStephen Hemminger 	 *   /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df
238*831dba47SStephen Hemminger 	 * or on older kernel
239*831dba47SStephen Hemminger 	 *   /sys/bus/vmbus/devices/vmbus_1
240*831dba47SStephen Hemminger 	 */
241*831dba47SStephen Hemminger 	snprintf(dirname, sizeof(dirname), "%s/%s",
242*831dba47SStephen Hemminger 		 SYSFS_VMBUS_DEVICES, name);
243*831dba47SStephen Hemminger 
244*831dba47SStephen Hemminger 	/* get device id */
245*831dba47SStephen Hemminger 	snprintf(filename, sizeof(filename), "%s/device_id", dirname);
246*831dba47SStephen Hemminger 	if (parse_sysfs_uuid(filename, dev->device_id) < 0)
247*831dba47SStephen Hemminger 		goto error;
248*831dba47SStephen Hemminger 
249*831dba47SStephen Hemminger 	/* get device class  */
250*831dba47SStephen Hemminger 	snprintf(filename, sizeof(filename), "%s/class_id", dirname);
251*831dba47SStephen Hemminger 	if (parse_sysfs_uuid(filename, dev->class_id) < 0)
252*831dba47SStephen Hemminger 		goto error;
253*831dba47SStephen Hemminger 
254*831dba47SStephen Hemminger 	/* get relid */
255*831dba47SStephen Hemminger 	snprintf(filename, sizeof(filename), "%s/id", dirname);
256*831dba47SStephen Hemminger 	if (eal_parse_sysfs_value(filename, &tmp) < 0)
257*831dba47SStephen Hemminger 		goto error;
258*831dba47SStephen Hemminger 	dev->relid = tmp;
259*831dba47SStephen Hemminger 
260*831dba47SStephen Hemminger 	/* get monitor id */
261*831dba47SStephen Hemminger 	snprintf(filename, sizeof(filename), "%s/monitor_id", dirname);
262*831dba47SStephen Hemminger 	if (eal_parse_sysfs_value(filename, &tmp) < 0)
263*831dba47SStephen Hemminger 		goto error;
264*831dba47SStephen Hemminger 	dev->monitor_id = tmp;
265*831dba47SStephen Hemminger 
266*831dba47SStephen Hemminger 	/* get numa node (if present) */
267*831dba47SStephen Hemminger 	snprintf(filename, sizeof(filename), "%s/numa_node",
268*831dba47SStephen Hemminger 		 dirname);
269*831dba47SStephen Hemminger 
270*831dba47SStephen Hemminger 	if (access(filename, R_OK) == 0) {
271*831dba47SStephen Hemminger 		if (eal_parse_sysfs_value(filename, &tmp) < 0)
272*831dba47SStephen Hemminger 			goto error;
273*831dba47SStephen Hemminger 		dev->device.numa_node = tmp;
274*831dba47SStephen Hemminger 	} else {
275*831dba47SStephen Hemminger 		/* if no NUMA support, set default to 0 */
276*831dba47SStephen Hemminger 		dev->device.numa_node = SOCKET_ID_ANY;
277*831dba47SStephen Hemminger 	}
278*831dba47SStephen Hemminger 
279*831dba47SStephen Hemminger 	/* device is valid, add in list (sorted) */
280*831dba47SStephen Hemminger 	VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
281*831dba47SStephen Hemminger 
282*831dba47SStephen Hemminger 	TAILQ_FOREACH(dev2, &rte_vmbus_bus.device_list, next) {
283*831dba47SStephen Hemminger 		int ret;
284*831dba47SStephen Hemminger 
285*831dba47SStephen Hemminger 		ret = rte_uuid_compare(dev->device_id, dev2->device_id);
286*831dba47SStephen Hemminger 		if (ret > 0)
287*831dba47SStephen Hemminger 			continue;
288*831dba47SStephen Hemminger 
289*831dba47SStephen Hemminger 		if (ret < 0) {
290*831dba47SStephen Hemminger 			vmbus_insert_device(dev2, dev);
291*831dba47SStephen Hemminger 		} else { /* already registered */
292*831dba47SStephen Hemminger 			VMBUS_LOG(NOTICE,
293*831dba47SStephen Hemminger 				"%s already registered", name);
294*831dba47SStephen Hemminger 			free(dev);
295*831dba47SStephen Hemminger 		}
296*831dba47SStephen Hemminger 		return 0;
297*831dba47SStephen Hemminger 	}
298*831dba47SStephen Hemminger 
299*831dba47SStephen Hemminger 	vmbus_add_device(dev);
300*831dba47SStephen Hemminger 	return 0;
301*831dba47SStephen Hemminger error:
302*831dba47SStephen Hemminger 	VMBUS_LOG(DEBUG, "failed");
303*831dba47SStephen Hemminger 
304*831dba47SStephen Hemminger 	free(dev);
305*831dba47SStephen Hemminger 	return -1;
306*831dba47SStephen Hemminger }
307*831dba47SStephen Hemminger 
308*831dba47SStephen Hemminger /*
309*831dba47SStephen Hemminger  * Scan the content of the vmbus, and the devices in the devices list
310*831dba47SStephen Hemminger  */
311*831dba47SStephen Hemminger int
312*831dba47SStephen Hemminger rte_vmbus_scan(void)
313*831dba47SStephen Hemminger {
314*831dba47SStephen Hemminger 	struct dirent *e;
315*831dba47SStephen Hemminger 	DIR *dir;
316*831dba47SStephen Hemminger 
317*831dba47SStephen Hemminger 	dir = opendir(SYSFS_VMBUS_DEVICES);
318*831dba47SStephen Hemminger 	if (dir == NULL) {
319*831dba47SStephen Hemminger 		if (errno == ENOENT)
320*831dba47SStephen Hemminger 			return 0;
321*831dba47SStephen Hemminger 
322*831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "opendir %s failed: %s",
323*831dba47SStephen Hemminger 			  SYSFS_VMBUS_DEVICES, strerror(errno));
324*831dba47SStephen Hemminger 		return -1;
325*831dba47SStephen Hemminger 	}
326*831dba47SStephen Hemminger 
327*831dba47SStephen Hemminger 	while ((e = readdir(dir)) != NULL) {
328*831dba47SStephen Hemminger 		if (e->d_name[0] == '.')
329*831dba47SStephen Hemminger 			continue;
330*831dba47SStephen Hemminger 
331*831dba47SStephen Hemminger 		if (vmbus_scan_one(e->d_name) < 0)
332*831dba47SStephen Hemminger 			goto error;
333*831dba47SStephen Hemminger 	}
334*831dba47SStephen Hemminger 	closedir(dir);
335*831dba47SStephen Hemminger 	return 0;
336*831dba47SStephen Hemminger 
337*831dba47SStephen Hemminger error:
338*831dba47SStephen Hemminger 	closedir(dir);
339*831dba47SStephen Hemminger 	return -1;
340*831dba47SStephen Hemminger }
341*831dba47SStephen Hemminger 
342*831dba47SStephen Hemminger void rte_vmbus_irq_mask(struct rte_vmbus_device *device)
343*831dba47SStephen Hemminger {
344*831dba47SStephen Hemminger 	vmbus_uio_irq_control(device, 1);
345*831dba47SStephen Hemminger }
346*831dba47SStephen Hemminger 
347*831dba47SStephen Hemminger void rte_vmbus_irq_unmask(struct rte_vmbus_device *device)
348*831dba47SStephen Hemminger {
349*831dba47SStephen Hemminger 	vmbus_uio_irq_control(device, 0);
350*831dba47SStephen Hemminger }
351*831dba47SStephen Hemminger 
352*831dba47SStephen Hemminger int rte_vmbus_irq_read(struct rte_vmbus_device *device)
353*831dba47SStephen Hemminger {
354*831dba47SStephen Hemminger 	return vmbus_uio_irq_read(device);
355*831dba47SStephen Hemminger }
356