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