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