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 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 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 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 = (bus_num >> 8) & 0xffff; 199 addr->bus = bus_num & 0xff; 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 int ret; 213 214 switch (dev->kdrv) { 215 case RTE_PCI_KDRV_UNKNOWN: 216 /* bifurcated driver case - mem_resource is unneeded */ 217 dev->mem_resource[0].phys_addr = 0; 218 dev->mem_resource[0].len = 0; 219 dev->mem_resource[0].addr = NULL; 220 break; 221 case RTE_PCI_KDRV_NET_UIO: 222 /* get device info from NetUIO kernel driver */ 223 ret = get_netuio_device_info(dev_info, dev_info_data, dev); 224 if (ret != 0) { 225 RTE_LOG(DEBUG, EAL, 226 "Could not retrieve device info for PCI device " 227 PCI_PRI_FMT, 228 dev->addr.domain, dev->addr.bus, 229 dev->addr.devid, dev->addr.function); 230 return ret; 231 } 232 break; 233 default: 234 /* kernel driver type is unsupported */ 235 RTE_LOG(DEBUG, EAL, 236 "Kernel driver type for PCI device " PCI_PRI_FMT "," 237 " is unsupported", 238 dev->addr.domain, dev->addr.bus, 239 dev->addr.devid, dev->addr.function); 240 return -1; 241 } 242 243 /* Get NUMA node using DEVPKEY_Device_Numa_Node */ 244 dev->device.numa_node = SOCKET_ID_ANY; 245 res = SetupDiGetDevicePropertyW(dev_info, dev_info_data, 246 &DEVPKEY_Device_Numa_Node, &property_type, 247 (BYTE *)&numa_node, sizeof(numa_node), NULL, 0); 248 if (!res) { 249 DWORD error = GetLastError(); 250 if (error == ERROR_NOT_FOUND) { 251 /* On older CPUs, NUMA is not bound to PCIe locality. */ 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_common_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 pci_free(dev); 413 } 414 return 0; 415 } 416 rte_pci_add_device(dev); 417 } 418 419 return 0; 420 end: 421 pci_free(dev); 422 return ret; 423 } 424 425 /* 426 * Scan the contents of the PCI bus 427 * and add all network class devices into the devices list. 428 */ 429 int 430 rte_pci_scan(void) 431 { 432 int ret = -1; 433 DWORD device_index = 0, found_device = 0; 434 HDEVINFO dev_info; 435 SP_DEVINFO_DATA device_info_data; 436 437 /* for debug purposes, PCI can be disabled */ 438 if (!rte_eal_has_pci()) 439 return 0; 440 441 dev_info = SetupDiGetClassDevs(NULL, TEXT("PCI"), NULL, 442 DIGCF_PRESENT | DIGCF_ALLCLASSES); 443 if (dev_info == INVALID_HANDLE_VALUE) { 444 RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)"); 445 RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n"); 446 goto end; 447 } 448 449 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 450 device_index = 0; 451 452 while (SetupDiEnumDeviceInfo(dev_info, device_index, 453 &device_info_data)) { 454 device_index++; 455 /* we only want to enumerate net & netuio class devices */ 456 if (IsEqualGUID(&(device_info_data.ClassGuid), 457 &GUID_DEVCLASS_NET) || 458 IsEqualGUID(&(device_info_data.ClassGuid), 459 &GUID_DEVCLASS_NETUIO)) { 460 ret = pci_scan_one(dev_info, &device_info_data); 461 if (ret == ERROR_SUCCESS) 462 found_device++; 463 else if (ret != ERROR_CONTINUE) 464 goto end; 465 } 466 memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA)); 467 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 468 } 469 470 RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device); 471 ret = 0; 472 end: 473 if (dev_info != INVALID_HANDLE_VALUE) 474 SetupDiDestroyDeviceInfoList(dev_info); 475 476 return ret; 477 } 478