xref: /dpdk/drivers/bus/pci/windows/pci.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  */
4 
5 #include <sys/queue.h>
6 
7 #include <rte_windows.h>
8 #include <rte_errno.h>
9 #include <rte_log.h>
10 #include <rte_eal.h>
11 #include <rte_memory.h>
12 
13 #include "private.h"
14 #include "pci_netuio.h"
15 
16 #include <devpkey.h>
17 #include <regstr.h>
18 
19 #if defined RTE_TOOLCHAIN_GCC && (__MINGW64_VERSION_MAJOR < 8)
20 #include <devpropdef.h>
21 DEFINE_DEVPROPKEY(DEVPKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc,
22 	0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3);
23 #endif
24 
25 /*
26  * This code is used to simulate a PCI probe by parsing information in
27  * the registry hive for PCI devices.
28  */
29 
30 /* Class ID consists of hexadecimal digits */
31 #define RTE_PCI_DRV_CLASSID_DIGIT "0123456789abcdefABCDEF"
32 
33 /* Some of the functions below are not implemented on Windows,
34  * but need to be defined for compilation purposes
35  */
36 
37 /* Map pci device */
38 int
39 rte_pci_map_device(struct rte_pci_device *dev)
40 {
41 	/* Only return success for devices bound to netuio.
42 	 * Devices that are bound to netuio are mapped at
43 	 * the bus probing stage.
44 	 */
45 	if (dev->kdrv == RTE_PCI_KDRV_NET_UIO)
46 		return 0;
47 	else
48 		return -1;
49 }
50 
51 /* Unmap pci device */
52 void
53 rte_pci_unmap_device(struct rte_pci_device *dev __rte_unused)
54 {
55 	/* This function is not implemented on Windows.
56 	 * We really should short-circuit the call to these functions by
57 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
58 	 * in the rte_pci_driver flags.
59 	 */
60 }
61 
62 /* Read PCI config space. */
63 int
64 rte_pci_read_config(const struct rte_pci_device *dev __rte_unused,
65 	void *buf __rte_unused, size_t len __rte_unused,
66 	off_t offset __rte_unused)
67 {
68 	/* This function is not implemented on Windows.
69 	 * We really should short-circuit the call to these functions by
70 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
71 	 * in the rte_pci_driver flags.
72 	 */
73 	return 0;
74 }
75 
76 /* Write PCI config space. */
77 int
78 rte_pci_write_config(const struct rte_pci_device *dev __rte_unused,
79 	const void *buf __rte_unused, size_t len __rte_unused,
80 	off_t offset __rte_unused)
81 {
82 	/* This function is not implemented on Windows.
83 	 * We really should short-circuit the call to these functions by
84 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
85 	 * in the rte_pci_driver flags.
86 	 */
87 	return 0;
88 }
89 
90 enum rte_iova_mode
91 pci_device_iova_mode(const struct rte_pci_driver *pdrv __rte_unused,
92 		const struct rte_pci_device *pdev __rte_unused)
93 {
94 	/* This function is not implemented on Windows.
95 	 * We really should short-circuit the call to these functions by
96 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
97 	 * in the rte_pci_driver flags.
98 	 */
99 	return RTE_IOVA_DC;
100 }
101 
102 int
103 rte_pci_ioport_map(struct rte_pci_device *dev __rte_unused,
104 	int bar __rte_unused, struct rte_pci_ioport *p __rte_unused)
105 {
106 	/* This function is not implemented on Windows.
107 	 * We really should short-circuit the call to these functions by
108 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
109 	 * in the rte_pci_driver flags.
110 	 */
111 	return -1;
112 }
113 
114 
115 void
116 rte_pci_ioport_read(struct rte_pci_ioport *p __rte_unused,
117 	void *data __rte_unused, size_t len __rte_unused,
118 	off_t offset __rte_unused)
119 {
120 	/* This function is not implemented on Windows.
121 	 * We really should short-circuit the call to these functions by
122 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
123 	 * in the rte_pci_driver flags.
124 	 */
125 }
126 
127 int
128 rte_pci_ioport_unmap(struct rte_pci_ioport *p __rte_unused)
129 {
130 	/* This function is not implemented on Windows.
131 	 * We really should short-circuit the call to these functions by
132 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
133 	 * in the rte_pci_driver flags.
134 	 */
135 	return -1;
136 }
137 
138 bool
139 pci_device_iommu_support_va(const struct rte_pci_device *dev __rte_unused)
140 {
141 	/* This function is not implemented on Windows.
142 	 * We really should short-circuit the call to these functions by
143 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
144 	 * in the rte_pci_driver flags.
145 	 */
146 	return false;
147 }
148 
149 void
150 rte_pci_ioport_write(struct rte_pci_ioport *p __rte_unused,
151 		const void *data __rte_unused, size_t len __rte_unused,
152 		off_t offset __rte_unused)
153 {
154 	/* This function is not implemented on Windows.
155 	 * We really should short-circuit the call to these functions by
156 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
157 	 * in the rte_pci_driver flags.
158 	 */
159 }
160 
161 /* remap the PCI resource of a PCI device in anonymous virtual memory */
162 int
163 pci_uio_remap_resource(struct rte_pci_device *dev __rte_unused)
164 {
165 	/* This function is not implemented on Windows.
166 	 * We really should short-circuit the call to these functions by
167 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
168 	 * in the rte_pci_driver flags.
169 	 */
170 	return -1;
171 }
172 
173 static int
174 get_device_pci_address(HDEVINFO dev_info,
175 	PSP_DEVINFO_DATA device_info_data, struct rte_pci_addr *addr)
176 {
177 	BOOL  res;
178 	ULONG bus_num, dev_and_func;
179 
180 	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
181 		SPDRP_BUSNUMBER, NULL, (PBYTE)&bus_num, sizeof(bus_num), NULL);
182 	if (!res) {
183 		RTE_LOG_WIN32_ERR(
184 			"SetupDiGetDeviceRegistryProperty(SPDRP_BUSNUMBER)");
185 		return -1;
186 	}
187 
188 	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
189 		SPDRP_ADDRESS, NULL, (PBYTE)&dev_and_func, sizeof(dev_and_func),
190 		NULL);
191 	if (!res) {
192 		RTE_LOG_WIN32_ERR(
193 			"SetupDiGetDeviceRegistryProperty(SPDRP_ADDRESS)");
194 		return -1;
195 	}
196 
197 	addr->domain = (bus_num >> 8) & 0xffff;
198 	addr->bus = bus_num & 0xff;
199 	addr->devid = dev_and_func >> 16;
200 	addr->function = dev_and_func & 0xffff;
201 	return 0;
202 }
203 
204 static int
205 get_device_resource_info(HDEVINFO dev_info,
206 	PSP_DEVINFO_DATA dev_info_data, struct rte_pci_device *dev)
207 {
208 	DEVPROPTYPE property_type;
209 	DWORD numa_node;
210 	BOOL  res;
211 	int ret;
212 
213 	switch (dev->kdrv) {
214 	case RTE_PCI_KDRV_UNKNOWN:
215 		/* bifurcated driver case - mem_resource is unneeded */
216 		dev->mem_resource[0].phys_addr = 0;
217 		dev->mem_resource[0].len = 0;
218 		dev->mem_resource[0].addr = NULL;
219 		break;
220 	case RTE_PCI_KDRV_NET_UIO:
221 		/* get device info from NetUIO kernel driver */
222 		ret = get_netuio_device_info(dev_info, dev_info_data, dev);
223 		if (ret != 0) {
224 			RTE_LOG(DEBUG, EAL,
225 				"Could not retrieve device info for PCI device "
226 				PCI_PRI_FMT,
227 				dev->addr.domain, dev->addr.bus,
228 				dev->addr.devid, dev->addr.function);
229 			return ret;
230 		}
231 		break;
232 	default:
233 		/* kernel driver type is unsupported */
234 		RTE_LOG(DEBUG, EAL,
235 			"Kernel driver type for PCI device " PCI_PRI_FMT ","
236 			" is unsupported",
237 			dev->addr.domain, dev->addr.bus,
238 			dev->addr.devid, dev->addr.function);
239 		return -1;
240 	}
241 
242 	/* Get NUMA node using DEVPKEY_Device_Numa_Node */
243 	dev->device.numa_node = SOCKET_ID_ANY;
244 	res = SetupDiGetDevicePropertyW(dev_info, dev_info_data,
245 		&DEVPKEY_Device_Numa_Node, &property_type,
246 		(BYTE *)&numa_node, sizeof(numa_node), NULL, 0);
247 	if (!res) {
248 		DWORD error = GetLastError();
249 		if (error == ERROR_NOT_FOUND) {
250 			/* On older CPUs, NUMA is not bound to PCIe locality. */
251 			dev->device.numa_node = 0;
252 			return ERROR_SUCCESS;
253 		}
254 		RTE_LOG_WIN32_ERR("SetupDiGetDevicePropertyW"
255 			"(DEVPKEY_Device_Numa_Node)");
256 		return -1;
257 	}
258 	dev->device.numa_node = numa_node;
259 
260 	return ERROR_SUCCESS;
261 }
262 
263 /*
264  * get string that contains the list of hardware IDs for a device
265  */
266 static int
267 get_pci_hardware_id(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data,
268 	char *pci_device_info, size_t pci_device_info_len)
269 {
270 	BOOL  res;
271 
272 	/* Retrieve PCI device IDs */
273 	res = SetupDiGetDeviceRegistryPropertyA(dev_info, device_info_data,
274 			SPDRP_HARDWAREID, NULL, (BYTE *)pci_device_info,
275 			pci_device_info_len, NULL);
276 	if (!res) {
277 		RTE_LOG_WIN32_ERR(
278 			"SetupDiGetDeviceRegistryPropertyA(SPDRP_HARDWAREID)");
279 		return -1;
280 	}
281 
282 	return 0;
283 }
284 
285 /*
286  * parse the SPDRP_HARDWAREID output and assign to rte_pci_id
287  *
288  * A list of the device identification string formats can be found at:
289  * https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-pci-devices
290  */
291 static int
292 parse_pci_hardware_id(const char *buf, struct rte_pci_id *pci_id)
293 {
294 	int ids = 0;
295 	uint16_t vendor_id, device_id;
296 	uint32_t subvendor_id = 0, class_id = 0;
297 	const char *cp;
298 
299 	ids = sscanf_s(buf, "PCI\\VEN_%" PRIx16 "&DEV_%" PRIx16 "&SUBSYS_%"
300 		PRIx32, &vendor_id, &device_id, &subvendor_id);
301 	if (ids != 3)
302 		return -1;
303 
304 	/* Try and find PCI class ID */
305 	for (cp = buf; !(cp[0] == 0 && cp[1] == 0); cp++)
306 		if (*cp == '&' && sscanf_s(cp,
307 				"&CC_%" PRIx32, &class_id) == 1) {
308 			/*
309 			 * If the Programming Interface code is not specified,
310 			 * assume that it is zero.
311 			 */
312 			if (strspn(cp + 4, RTE_PCI_DRV_CLASSID_DIGIT) == 4)
313 				class_id <<= 8;
314 			break;
315 		}
316 
317 	pci_id->vendor_id = vendor_id;
318 	pci_id->device_id = device_id;
319 	pci_id->subsystem_device_id = subvendor_id >> 16;
320 	pci_id->subsystem_vendor_id = subvendor_id & 0xffff;
321 	pci_id->class_id = class_id;
322 	return 0;
323 }
324 
325 static void
326 set_kernel_driver_type(PSP_DEVINFO_DATA device_info_data,
327 	struct rte_pci_device *dev)
328 {
329 	/* set kernel driver type based on device class */
330 	if (IsEqualGUID(&(device_info_data->ClassGuid), &GUID_DEVCLASS_NETUIO))
331 		dev->kdrv = RTE_PCI_KDRV_NET_UIO;
332 	else
333 		dev->kdrv = RTE_PCI_KDRV_UNKNOWN;
334 }
335 
336 static int
337 pci_scan_one(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data)
338 {
339 	struct rte_pci_device *dev = NULL;
340 	int ret = -1;
341 	char  pci_device_info[REGSTR_VAL_MAX_HCID_LEN];
342 	struct rte_pci_addr addr;
343 	struct rte_pci_id pci_id;
344 
345 	ret = get_device_pci_address(dev_info, device_info_data, &addr);
346 	if (ret != 0)
347 		goto end;
348 
349 	if (rte_pci_ignore_device(&addr)) {
350 		/*
351 		 * We won't add this device, but we want to continue
352 		 * looking for supported devices
353 		 */
354 		ret = ERROR_CONTINUE;
355 		goto end;
356 	}
357 
358 	ret = get_pci_hardware_id(dev_info, device_info_data,
359 		pci_device_info, sizeof(pci_device_info));
360 	if (ret != 0)
361 		goto end;
362 
363 	ret = parse_pci_hardware_id((const char *)&pci_device_info, &pci_id);
364 	if (ret != 0) {
365 		/*
366 		 * We won't add this device, but we want to continue
367 		 * looking for supported devices
368 		 */
369 		ret = ERROR_CONTINUE;
370 		goto end;
371 	}
372 
373 	dev = malloc(sizeof(*dev));
374 	if (dev == NULL)
375 		goto end;
376 
377 	memset(dev, 0, sizeof(*dev));
378 
379 	dev->device.bus = &rte_pci_bus.bus;
380 	dev->addr = addr;
381 	dev->id = pci_id;
382 	dev->max_vfs = 0; /* TODO: get max_vfs */
383 
384 	pci_name_set(dev);
385 
386 	set_kernel_driver_type(device_info_data, dev);
387 
388 	/* get resources */
389 	if (get_device_resource_info(dev_info, device_info_data, dev)
390 			!= ERROR_SUCCESS) {
391 		goto end;
392 	}
393 
394 	/* device is valid, add in list (sorted) */
395 	if (TAILQ_EMPTY(&rte_pci_bus.device_list)) {
396 		rte_pci_add_device(dev);
397 	} else {
398 		struct rte_pci_device *dev2 = NULL;
399 		int ret;
400 
401 		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
402 			ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr);
403 			if (ret > 0) {
404 				continue;
405 			} else if (ret < 0) {
406 				rte_pci_insert_device(dev2, dev);
407 			} else { /* already registered */
408 				dev2->kdrv = dev->kdrv;
409 				dev2->max_vfs = dev->max_vfs;
410 				memmove(dev2->mem_resource, dev->mem_resource,
411 					sizeof(dev->mem_resource));
412 				free(dev);
413 			}
414 			return 0;
415 		}
416 		rte_pci_add_device(dev);
417 	}
418 
419 	return 0;
420 end:
421 	if (dev)
422 		free(dev);
423 	return ret;
424 }
425 
426 /*
427  * Scan the contents of the PCI bus
428  * and add all network class devices into the devices list.
429  */
430 int
431 rte_pci_scan(void)
432 {
433 	int   ret = -1;
434 	DWORD device_index = 0, found_device = 0;
435 	HDEVINFO dev_info;
436 	SP_DEVINFO_DATA device_info_data;
437 
438 	/* for debug purposes, PCI can be disabled */
439 	if (!rte_eal_has_pci())
440 		return 0;
441 
442 	dev_info = SetupDiGetClassDevs(NULL, TEXT("PCI"), NULL,
443 		DIGCF_PRESENT | DIGCF_ALLCLASSES);
444 	if (dev_info == INVALID_HANDLE_VALUE) {
445 		RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)");
446 		RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n");
447 		goto end;
448 	}
449 
450 	device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
451 	device_index = 0;
452 
453 	while (SetupDiEnumDeviceInfo(dev_info, device_index,
454 	    &device_info_data)) {
455 		device_index++;
456 		/* we only want to enumerate net & netuio class devices */
457 		if (IsEqualGUID(&(device_info_data.ClassGuid),
458 			    &GUID_DEVCLASS_NET) ||
459 			IsEqualGUID(&(device_info_data.ClassGuid),
460 			    &GUID_DEVCLASS_NETUIO)) {
461 			ret = pci_scan_one(dev_info, &device_info_data);
462 			if (ret == ERROR_SUCCESS)
463 				found_device++;
464 			else if (ret != ERROR_CONTINUE)
465 				goto end;
466 		}
467 		memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA));
468 		device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
469 	}
470 
471 	RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device);
472 	ret = 0;
473 end:
474 	if (dev_info != INVALID_HANDLE_VALUE)
475 		SetupDiDestroyDeviceInfoList(dev_info);
476 
477 	return ret;
478 }
479