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_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_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, subvendor_id = 0; 274 275 ids = sscanf_s(buf, "PCI\\VEN_%x&DEV_%x&SUBSYS_%x", &vendor_id, 276 &device_id, &subvendor_id); 277 if (ids != 3) 278 return -1; 279 280 pci_id->vendor_id = vendor_id; 281 pci_id->device_id = device_id; 282 pci_id->subsystem_vendor_id = subvendor_id >> 16; 283 pci_id->subsystem_device_id = subvendor_id & 0xffff; 284 return 0; 285 } 286 287 static void 288 get_kernel_driver_type(struct rte_pci_device *dev) 289 { 290 /* 291 * If another kernel driver is supported the relevant checking 292 * functions should be here 293 */ 294 dev->kdrv = RTE_KDRV_NONE; 295 } 296 297 static int 298 pci_scan_one(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data) 299 { 300 struct rte_pci_device *dev; 301 int ret = -1; 302 char pci_device_info[PATH_MAX]; 303 struct rte_pci_addr addr; 304 struct rte_pci_id pci_id; 305 306 dev = malloc(sizeof(*dev)); 307 if (dev == NULL) 308 goto end; 309 310 memset(dev, 0, sizeof(*dev)); 311 312 ret = get_pci_hardware_id(dev_info, device_info_data, 313 pci_device_info, PATH_MAX); 314 if (ret != 0) 315 goto end; 316 317 ret = parse_pci_hardware_id((const char *)&pci_device_info, &pci_id); 318 if (ret != 0) { 319 /* 320 * We won't add this device, but we want to continue 321 * looking for supported devices 322 */ 323 ret = ERROR_CONTINUE; 324 goto end; 325 } 326 327 ret = get_device_pci_address(dev_info, device_info_data, &addr); 328 if (ret != 0) 329 goto end; 330 331 dev->addr = addr; 332 dev->id = pci_id; 333 dev->max_vfs = 0; /* TODO: get max_vfs */ 334 335 pci_name_set(dev); 336 337 get_kernel_driver_type(dev); 338 339 /* get resources */ 340 if (get_device_resource_info(dev_info, device_info_data, dev) 341 != ERROR_SUCCESS) { 342 goto end; 343 } 344 345 /* device is valid, add in list (sorted) */ 346 if (TAILQ_EMPTY(&rte_pci_bus.device_list)) { 347 rte_pci_add_device(dev); 348 } else { 349 struct rte_pci_device *dev2 = NULL; 350 int ret; 351 352 TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { 353 ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); 354 if (ret > 0) { 355 continue; 356 } else if (ret < 0) { 357 rte_pci_insert_device(dev2, dev); 358 } else { /* already registered */ 359 dev2->kdrv = dev->kdrv; 360 dev2->max_vfs = dev->max_vfs; 361 memmove(dev2->mem_resource, dev->mem_resource, 362 sizeof(dev->mem_resource)); 363 free(dev); 364 } 365 return 0; 366 } 367 rte_pci_add_device(dev); 368 } 369 370 return 0; 371 end: 372 if (dev) 373 free(dev); 374 return ret; 375 } 376 377 /* 378 * Scan the contents of the PCI bus 379 * and add all network class devices into the devices list. 380 */ 381 int 382 rte_pci_scan(void) 383 { 384 int ret = -1; 385 DWORD device_index = 0, found_device = 0; 386 HDEVINFO dev_info; 387 SP_DEVINFO_DATA device_info_data; 388 389 /* for debug purposes, PCI can be disabled */ 390 if (!rte_eal_has_pci()) 391 return 0; 392 393 dev_info = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, TEXT("PCI"), NULL, 394 DIGCF_PRESENT); 395 if (dev_info == INVALID_HANDLE_VALUE) { 396 RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)"); 397 RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n"); 398 goto end; 399 } 400 401 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 402 device_index = 0; 403 404 while (SetupDiEnumDeviceInfo(dev_info, device_index, 405 &device_info_data)) { 406 device_index++; 407 ret = pci_scan_one(dev_info, &device_info_data); 408 if (ret == ERROR_SUCCESS) 409 found_device++; 410 else if (ret != ERROR_CONTINUE) 411 goto end; 412 413 memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA)); 414 device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); 415 } 416 417 RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device); 418 ret = 0; 419 end: 420 if (dev_info != INVALID_HANDLE_VALUE) 421 SetupDiDestroyDeviceInfoList(dev_info); 422 423 return ret; 424 } 425