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