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 /* Read PCI MMIO space. */ 92 int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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