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