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 } 474