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