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