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