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