xref: /dpdk/drivers/bus/pci/windows/pci.c (revision db4e81351fb85ff623bd0438d1b5a8fb55fe9fee)
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_memconfig.h>
8 #include <rte_eal.h>
9 
10 #include "private.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 int
53 pci_update_device(const struct rte_pci_addr *addr __rte_unused)
54 {
55 	/* This function is not implemented on Windows.
56 	 * We really should short-circuit the call to these functions by
57 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
58 	 * in the rte_pci_driver flags.
59 	 */
60 	return 0;
61 }
62 
63 /* Read PCI config space. */
64 int
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
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 enum rte_iova_mode
92 pci_device_iova_mode(const struct rte_pci_driver *pdrv __rte_unused,
93 		const struct rte_pci_device *pdev __rte_unused)
94 {
95 	/* This function is not implemented on Windows.
96 	 * We really should short-circuit the call to these functions by
97 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
98 	 * in the rte_pci_driver flags.
99 	 */
100 	return RTE_IOVA_DC;
101 }
102 
103 int
104 rte_pci_ioport_map(struct rte_pci_device *dev __rte_unused,
105 	int bar __rte_unused, struct rte_pci_ioport *p __rte_unused)
106 {
107 	/* This function is not implemented on Windows.
108 	 * We really should short-circuit the call to these functions by
109 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
110 	 * in the rte_pci_driver flags.
111 	 */
112 	return -1;
113 }
114 
115 
116 void
117 rte_pci_ioport_read(struct rte_pci_ioport *p __rte_unused,
118 	void *data __rte_unused, size_t len __rte_unused,
119 	off_t offset __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 }
127 
128 int
129 rte_pci_ioport_unmap(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 bool
140 pci_device_iommu_support_va(const struct rte_pci_device *dev __rte_unused)
141 {
142 	/* This function is not implemented on Windows.
143 	 * We really should short-circuit the call to these functions by
144 	 * clearing the RTE_PCI_DRV_NEED_MAPPING flag
145 	 * in the rte_pci_driver flags.
146 	 */
147 	return false;
148 }
149 
150 void
151 rte_pci_ioport_write(struct rte_pci_ioport *p __rte_unused,
152 		const void *data __rte_unused, size_t len __rte_unused,
153 		off_t offset __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 }
161 
162 /* remap the PCI resource of a PCI device in anonymous virtual memory */
163 int
164 pci_uio_remap_resource(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 -1;
172 }
173 
174 static int
175 get_device_pci_address(HDEVINFO dev_info,
176 	PSP_DEVINFO_DATA device_info_data, struct rte_pci_addr *addr)
177 {
178 	BOOL  res;
179 	ULONG bus_num, dev_and_func;
180 
181 	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
182 		SPDRP_BUSNUMBER, NULL, (PBYTE)&bus_num, sizeof(bus_num), NULL);
183 	if (!res) {
184 		RTE_LOG_WIN32_ERR(
185 			"SetupDiGetDeviceRegistryProperty(SPDRP_BUSNUMBER)");
186 		return -1;
187 	}
188 
189 	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
190 		SPDRP_ADDRESS, NULL, (PBYTE)&dev_and_func, sizeof(dev_and_func),
191 		NULL);
192 	if (!res) {
193 		RTE_LOG_WIN32_ERR(
194 			"SetupDiGetDeviceRegistryProperty(SPDRP_ADDRESS)");
195 		return -1;
196 	}
197 
198 	addr->domain = 0;
199 	addr->bus = bus_num;
200 	addr->devid = dev_and_func >> 16;
201 	addr->function = dev_and_func & 0xffff;
202 	return 0;
203 }
204 
205 static int
206 get_device_resource_info(HDEVINFO dev_info,
207 	PSP_DEVINFO_DATA dev_info_data, struct rte_pci_device *dev)
208 {
209 	DEVPROPTYPE property_type;
210 	DWORD numa_node;
211 	BOOL  res;
212 
213 	switch (dev->kdrv) {
214 	case RTE_PCI_KDRV_NONE:
215 		/* Get NUMA node using DEVPKEY_Device_Numa_Node */
216 		res = SetupDiGetDevicePropertyW(dev_info, dev_info_data,
217 			&DEVPKEY_Device_Numa_Node, &property_type,
218 			(BYTE *)&numa_node, sizeof(numa_node), NULL, 0);
219 		if (!res) {
220 			RTE_LOG_WIN32_ERR(
221 				"SetupDiGetDevicePropertyW"
222 				"(DEVPKEY_Device_Numa_Node)");
223 			return -1;
224 		}
225 		dev->device.numa_node = numa_node;
226 		/* mem_resource - Unneeded for RTE_PCI_KDRV_NONE */
227 		dev->mem_resource[0].phys_addr = 0;
228 		dev->mem_resource[0].len = 0;
229 		dev->mem_resource[0].addr = NULL;
230 		break;
231 	default:
232 		/* kernel driver type is unsupported */
233 		RTE_LOG(DEBUG, EAL,
234 			"Kernel driver type for PCI device " PCI_PRI_FMT ","
235 			" is unsupported",
236 			dev->addr.domain, dev->addr.bus,
237 			dev->addr.devid, dev->addr.function);
238 		return -1;
239 	}
240 
241 	return ERROR_SUCCESS;
242 }
243 
244 /*
245  * get string that contains the list of hardware IDs for a device
246  */
247 static int
248 get_pci_hardware_id(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data,
249 	char *pci_device_info, size_t pci_device_info_len)
250 {
251 	BOOL  res;
252 
253 	/* Retrieve PCI device IDs */
254 	res = SetupDiGetDeviceRegistryPropertyA(dev_info, device_info_data,
255 			SPDRP_HARDWAREID, NULL, (BYTE *)pci_device_info,
256 			pci_device_info_len, NULL);
257 	if (!res) {
258 		RTE_LOG_WIN32_ERR(
259 			"SetupDiGetDeviceRegistryPropertyA(SPDRP_HARDWAREID)");
260 		return -1;
261 	}
262 
263 	return 0;
264 }
265 
266 /*
267  * parse the SPDRP_HARDWAREID output and assign to rte_pci_id
268  */
269 static int
270 parse_pci_hardware_id(const char *buf, struct rte_pci_id *pci_id)
271 {
272 	int ids = 0;
273 	uint16_t vendor_id, device_id;
274 	uint32_t subvendor_id = 0;
275 
276 	ids = sscanf_s(buf, "PCI\\VEN_%" PRIx16 "&DEV_%" PRIx16 "&SUBSYS_%"
277 		PRIx32, &vendor_id, &device_id, &subvendor_id);
278 	if (ids != 3)
279 		return -1;
280 
281 	pci_id->vendor_id = vendor_id;
282 	pci_id->device_id = device_id;
283 	pci_id->subsystem_device_id = subvendor_id >> 16;
284 	pci_id->subsystem_vendor_id = subvendor_id & 0xffff;
285 	return 0;
286 }
287 
288 static void
289 get_kernel_driver_type(struct rte_pci_device *dev)
290 {
291 	/*
292 	 * If another kernel driver is supported the relevant checking
293 	 * functions should be here
294 	 */
295 	dev->kdrv = RTE_PCI_KDRV_NONE;
296 }
297 
298 static int
299 pci_scan_one(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data)
300 {
301 	struct rte_pci_device *dev;
302 	int ret = -1;
303 	char  pci_device_info[PATH_MAX];
304 	struct rte_pci_addr addr;
305 	struct rte_pci_id pci_id;
306 
307 	dev = malloc(sizeof(*dev));
308 	if (dev == NULL)
309 		goto end;
310 
311 	memset(dev, 0, sizeof(*dev));
312 
313 	ret = get_pci_hardware_id(dev_info, device_info_data,
314 		pci_device_info, PATH_MAX);
315 	if (ret != 0)
316 		goto end;
317 
318 	ret = parse_pci_hardware_id((const char *)&pci_device_info, &pci_id);
319 	if (ret != 0) {
320 		/*
321 		 * We won't add this device, but we want to continue
322 		 * looking for supported devices
323 		 */
324 		ret = ERROR_CONTINUE;
325 		goto end;
326 	}
327 
328 	ret = get_device_pci_address(dev_info, device_info_data, &addr);
329 	if (ret != 0)
330 		goto end;
331 
332 	dev->addr = addr;
333 	dev->id = pci_id;
334 	dev->max_vfs = 0; /* TODO: get max_vfs */
335 
336 	pci_name_set(dev);
337 
338 	get_kernel_driver_type(dev);
339 
340 	/* get resources */
341 	if (get_device_resource_info(dev_info, device_info_data, dev)
342 			!= ERROR_SUCCESS) {
343 		goto end;
344 	}
345 
346 	/* device is valid, add in list (sorted) */
347 	if (TAILQ_EMPTY(&rte_pci_bus.device_list)) {
348 		rte_pci_add_device(dev);
349 	} else {
350 		struct rte_pci_device *dev2 = NULL;
351 		int ret;
352 
353 		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
354 			ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr);
355 			if (ret > 0) {
356 				continue;
357 			} else if (ret < 0) {
358 				rte_pci_insert_device(dev2, dev);
359 			} else { /* already registered */
360 				dev2->kdrv = dev->kdrv;
361 				dev2->max_vfs = dev->max_vfs;
362 				memmove(dev2->mem_resource, dev->mem_resource,
363 					sizeof(dev->mem_resource));
364 				free(dev);
365 			}
366 			return 0;
367 		}
368 		rte_pci_add_device(dev);
369 	}
370 
371 	return 0;
372 end:
373 	if (dev)
374 		free(dev);
375 	return ret;
376 }
377 
378 /*
379  * Scan the contents of the PCI bus
380  * and add all network class devices into the devices list.
381  */
382 int
383 rte_pci_scan(void)
384 {
385 	int   ret = -1;
386 	DWORD device_index = 0, found_device = 0;
387 	HDEVINFO dev_info;
388 	SP_DEVINFO_DATA device_info_data;
389 
390 	/* for debug purposes, PCI can be disabled */
391 	if (!rte_eal_has_pci())
392 		return 0;
393 
394 	dev_info = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, TEXT("PCI"), NULL,
395 				DIGCF_PRESENT);
396 	if (dev_info == INVALID_HANDLE_VALUE) {
397 		RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)");
398 		RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n");
399 		goto end;
400 	}
401 
402 	device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
403 	device_index = 0;
404 
405 	while (SetupDiEnumDeviceInfo(dev_info, device_index,
406 	    &device_info_data)) {
407 		device_index++;
408 		ret = pci_scan_one(dev_info, &device_info_data);
409 		if (ret == ERROR_SUCCESS)
410 			found_device++;
411 		else if (ret != ERROR_CONTINUE)
412 			goto end;
413 
414 		memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA));
415 		device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
416 	}
417 
418 	RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device);
419 	ret = 0;
420 end:
421 	if (dev_info != INVALID_HANDLE_VALUE)
422 		SetupDiDestroyDeviceInfoList(dev_info);
423 
424 	return ret;
425 }
426