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