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