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