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_memconfig.h> 8 #include <rte_eal.h> 9 10 #include "private.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 int 53 pci_update_device(const struct rte_pci_addr *addr __rte_unused) 54 { 55 /* This function is not implemented on Windows. 56 * We really should short-circuit the call to these functions by 57 * clearing the RTE_PCI_DRV_NEED_MAPPING flag 58 * in the rte_pci_driver flags. 59 */ 60 return 0; 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 = 0; 199 addr->bus = bus_num; 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 213 switch (dev->kdrv) { 214 case RTE_PCI_KDRV_NONE: 215 /* Get NUMA node using DEVPKEY_Device_Numa_Node */ 216 res = SetupDiGetDevicePropertyW(dev_info, dev_info_data, 217 &DEVPKEY_Device_Numa_Node, &property_type, 218 (BYTE *)&numa_node, sizeof(numa_node), NULL, 0); 219 if (!res) { 220 RTE_LOG_WIN32_ERR( 221 "SetupDiGetDevicePropertyW" 222 "(DEVPKEY_Device_Numa_Node)"); 223 return -1; 224 } 225 dev->device.numa_node = numa_node; 226 /* mem_resource - Unneeded for RTE_PCI_KDRV_NONE */ 227 dev->mem_resource[0].phys_addr = 0; 228 dev->mem_resource[0].len = 0; 229 dev->mem_resource[0].addr = NULL; 230 break; 231 default: 232 /* kernel driver type is unsupported */ 233 RTE_LOG(DEBUG, EAL, 234 "Kernel driver type for PCI device " PCI_PRI_FMT "," 235 " is unsupported", 236 dev->addr.domain, dev->addr.bus, 237 dev->addr.devid, dev->addr.function); 238 return -1; 239 } 240 241 return ERROR_SUCCESS; 242 } 243 244 /* 245 * get string that contains the list of hardware IDs for a device 246 */ 247 static int 248 get_pci_hardware_id(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data, 249 char *pci_device_info, size_t pci_device_info_len) 250 { 251 BOOL res; 252 253 /* Retrieve PCI device IDs */ 254 res = SetupDiGetDeviceRegistryPropertyA(dev_info, device_info_data, 255 SPDRP_HARDWAREID, NULL, (BYTE *)pci_device_info, 256 pci_device_info_len, NULL); 257 if (!res) { 258 RTE_LOG_WIN32_ERR( 259 "SetupDiGetDeviceRegistryPropertyA(SPDRP_HARDWAREID)"); 260 return -1; 261 } 262 263 return 0; 264 } 265 266 /* 267 * parse the SPDRP_HARDWAREID output and assign to rte_pci_id 268 */ 269 static int 270 parse_pci_hardware_id(const char *buf, struct rte_pci_id *pci_id) 271 { 272 int ids = 0; 273 uint16_t vendor_id, device_id; 274 uint32_t subvendor_id = 0; 275 276 ids = sscanf_s(buf, "PCI\\VEN_%" PRIx16 "&DEV_%" PRIx16 "&SUBSYS_%" 277 PRIx32, &vendor_id, &device_id, &subvendor_id); 278 if (ids != 3) 279 return -1; 280 281 pci_id->vendor_id = vendor_id; 282 pci_id->device_id = device_id; 283 pci_id->subsystem_device_id = subvendor_id >> 16; 284 pci_id->subsystem_vendor_id = subvendor_id & 0xffff; 285 return 0; 286 } 287 288 static void 289 get_kernel_driver_type(struct rte_pci_device *dev) 290 { 291 /* 292 * If another kernel driver is supported the relevant checking 293 * functions should be here 294 */ 295 dev->kdrv = RTE_PCI_KDRV_NONE; 296 } 297 298 static int 299 pci_scan_one(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data) 300 { 301 struct rte_pci_device *dev; 302 int ret = -1; 303 char pci_device_info[PATH_MAX]; 304 struct rte_pci_addr addr; 305 struct rte_pci_id pci_id; 306 307 dev = malloc(sizeof(*dev)); 308 if (dev == NULL) 309 goto end; 310 311 memset(dev, 0, sizeof(*dev)); 312 313 ret = get_pci_hardware_id(dev_info, device_info_data, 314 pci_device_info, PATH_MAX); 315 if (ret != 0) 316 goto end; 317 318 ret = parse_pci_hardware_id((const char *)&pci_device_info, &pci_id); 319 if (ret != 0) { 320 /* 321 * We won't add this device, but we want to continue 322 * looking for supported devices 323 */ 324 ret = ERROR_CONTINUE; 325 goto end; 326 } 327 328 ret = get_device_pci_address(dev_info, device_info_data, &addr); 329 if (ret != 0) 330 goto end; 331 332 dev->addr = addr; 333 dev->id = pci_id; 334 dev->max_vfs = 0; /* TODO: get max_vfs */ 335 336 pci_name_set(dev); 337 338 get_kernel_driver_type(dev); 339 340 /* get resources */ 341 if (get_device_resource_info(dev_info, device_info_data, dev) 342 != ERROR_SUCCESS) { 343 goto end; 344 } 345 346 /* device is valid, add in list (sorted) */ 347 if (TAILQ_EMPTY(&rte_pci_bus.device_list)) { 348 rte_pci_add_device(dev); 349 } else { 350 struct rte_pci_device *dev2 = NULL; 351 int ret; 352 353 TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { 354 ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); 355 if (ret > 0) { 356 continue; 357 } else if (ret < 0) { 358 rte_pci_insert_device(dev2, dev); 359 } else { /* already registered */ 360 dev2->kdrv = dev->kdrv; 361 dev2->max_vfs = dev->max_vfs; 362 memmove(dev2->mem_resource, dev->mem_resource, 363 sizeof(dev->mem_resource)); 364 free(dev); 365 } 366 return 0; 367 } 368 rte_pci_add_device(dev); 369 } 370 371 return 0; 372 end: 373 if (dev) 374 free(dev); 375 return ret; 376 } 377 378 /* 379 * Scan the contents of the PCI bus 380 * and add all network class devices into the devices list. 381 */ 382 int 383 rte_pci_scan(void) 384 { 385 int ret = -1; 386 DWORD device_index = 0, found_device = 0; 387 HDEVINFO dev_info; 388 SP_DEVINFO_DATA device_info_data; 389 390 /* for debug purposes, PCI can be disabled */ 391 if (!rte_eal_has_pci()) 392 return 0; 393 394 dev_info = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, TEXT("PCI"), NULL, 395 DIGCF_PRESENT); 396 if (dev_info == INVALID_HANDLE_VALUE) { 397 RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)"); 398 RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n"); 399 goto end; 400 } 401 402 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 403 device_index = 0; 404 405 while (SetupDiEnumDeviceInfo(dev_info, device_index, 406 &device_info_data)) { 407 device_index++; 408 ret = pci_scan_one(dev_info, &device_info_data); 409 if (ret == ERROR_SUCCESS) 410 found_device++; 411 else if (ret != ERROR_CONTINUE) 412 goto end; 413 414 memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA)); 415 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 416 } 417 418 RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device); 419 ret = 0; 420 end: 421 if (dev_info != INVALID_HANDLE_VALUE) 422 SetupDiDestroyDeviceInfoList(dev_info); 423 424 return ret; 425 } 426