[v4,8/8] bus/pci: support Windows with bifurcated drivers
diff mbox series

Message ID 20200519142020.15848-9-talshn@mellanox.com
State Superseded
Delegated to: Thomas Monjalon
Headers show
Series
  • Windows bus/pci support
Related show

Checks

Context Check Description
ci/Intel-compilation fail apply issues
ci/checkpatch success coding style OK

Commit Message

Tal Shnaiderman May 19, 2020, 2:20 p.m. UTC
From: Tal Shnaiderman <talshn@mellanox.com>

Uses SetupAPI.h functions to scan PCI tree.
Uses DEVPKEY_Device_Numa_Node to get the PCI NUMA node.
Uses SPDRP_BUSNUMBER and SPDRP_BUSNUMBER to get the BDF.
scanning currently supports types RTE_KDRV_NONE.

Signed-off-by: Tal Shnaiderman <talshn@mellanox.com>
---
 drivers/bus/pci/windows/pci.c                | 236 ++++++++++++++++++++++++++-
 lib/librte_eal/windows/include/rte_windows.h |   1 +
 2 files changed, 234 insertions(+), 3 deletions(-)

Patch
diff mbox series

diff --git a/drivers/bus/pci/windows/pci.c b/drivers/bus/pci/windows/pci.c
index b1d34ae11..b2d167bb5 100644
--- a/drivers/bus/pci/windows/pci.c
+++ b/drivers/bus/pci/windows/pci.c
@@ -1,14 +1,26 @@ 
 /* SPDX-License-Identifier: BSD-3-Clause
  * Copyright 2020 Mellanox Technologies, Ltd
  */
+#include <rte_windows.h>
 #include <rte_errno.h>
 #include <rte_log.h>
-
-#include <rte_string_fns.h>
 #include <rte_eal_memconfig.h>
 
 #include "private.h"
 
+#include <devpkey.h>
+
+#ifdef RTE_TOOLCHAIN_GCC
+#include <Devpropdef.h>
+DEFINE_DEVPROPKEY(DEVPKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc,
+	0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3);
+#endif
+
+/*
+ * This code is used to simulate a PCI probe by parsing information in
+ * the registry hive for PCI devices.
+ */
+
 /* The functions below are not implemented on Windows,
  * but need to be defined for compilation purposes
  */
@@ -146,7 +158,6 @@  rte_pci_ioport_write(struct rte_pci_ioport *p __rte_unused,
 	 */
 }
 
-
 /* remap the PCI resource of a PCI device in anonymous virtual memory */
 int
 pci_uio_remap_resource(struct rte_pci_device *dev __rte_unused)
@@ -158,6 +169,190 @@  pci_uio_remap_resource(struct rte_pci_device *dev __rte_unused)
 	 */
 	return -1;
 }
+
+static int
+get_device_pci_address(HDEVINFO dev_info,
+	PSP_DEVINFO_DATA device_info_data, struct rte_pci_addr *addr)
+{
+	BOOL  res;
+	ULONG bus_num, dev_and_func;
+
+	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
+		SPDRP_BUSNUMBER, NULL, (PBYTE)&bus_num, sizeof(bus_num), NULL);
+	if (!res) {
+		RTE_LOG_WIN32_ERR(
+			"SetupDiGetDeviceRegistryProperty(SPDRP_BUSNUMBER)");
+		return -1;
+	}
+
+	res = SetupDiGetDeviceRegistryProperty(dev_info, device_info_data,
+		SPDRP_ADDRESS, NULL, (PBYTE)&dev_and_func, sizeof(dev_and_func),
+		NULL);
+	if (!res) {
+		RTE_LOG_WIN32_ERR(
+			"SetupDiGetDeviceRegistryProperty(SPDRP_ADDRESS)");
+		return -1;
+	}
+
+	addr->domain = 0;
+	addr->bus = bus_num;
+	addr->devid = dev_and_func >> 16;
+	addr->function = dev_and_func & 0xffff;
+	return 0;
+}
+
+static int
+get_device_resource_info(HDEVINFO dev_info,
+	PSP_DEVINFO_DATA dev_info_data, struct rte_pci_device *dev)
+{
+	DEVPROPTYPE property_type;
+	DWORD numa_node;
+	BOOL  res;
+
+	switch (dev->kdrv) {
+	case RTE_KDRV_NONE:
+		/* Get NUMA node using DEVPKEY_Device_Numa_Node */
+		res = SetupDiGetDevicePropertyW(dev_info, dev_info_data,
+			&DEVPKEY_Device_Numa_Node, &property_type,
+			(BYTE *)&numa_node, sizeof(numa_node), NULL, 0);
+		if (!res) {
+			RTE_LOG_WIN32_ERR(
+				"SetupDiGetDevicePropertyW"
+				"(DEVPKEY_Device_Numa_Node)");
+			return -1;
+		}
+		dev->device.numa_node = numa_node;
+		/* mem_resource - Unneeded for RTE_KDRV_NONE */
+		dev->mem_resource[0].phys_addr = 0;
+		dev->mem_resource[0].len = 0;
+		dev->mem_resource[0].addr = NULL;
+		break;
+	default:
+		return ERROR_NOT_SUPPORTED;
+	}
+
+	return 0;
+}
+/*
+ * get_pci_hardware_info from the SPDRP_HARDWAREID output
+ */
+static int
+get_pci_hardware_info(const char *buf, struct rte_pci_id *pci_id)
+{
+	int ids = 0;
+	uint16_t vendor_id, device_id, subvendor_id = 0;
+
+	ids = sscanf_s(buf, "PCI\\VEN_%x&DEV_%x&SUBSYS_%x", &vendor_id,
+		&device_id, &subvendor_id);
+	if (ids != 3)
+		return -1;
+
+	pci_id->vendor_id = vendor_id;
+	pci_id->device_id = device_id;
+	pci_id->subsystem_vendor_id = subvendor_id >> 16;
+	pci_id->subsystem_device_id = subvendor_id & 0xffff;
+	return 0;
+}
+
+static void
+get_kernel_driver_type(struct rte_pci_device *dev __rte_unused)
+{
+	/*
+	 * If another kernel driver is supported the relevant checking
+	 * functions should be here
+	 */
+	dev->kdrv = RTE_KDRV_NONE;
+}
+
+static int
+pci_scan_one(HDEVINFO dev_info, PSP_DEVINFO_DATA device_info_data)
+{
+	struct	rte_pci_device *dev;
+	int		ret = -1;
+
+	dev = malloc(sizeof(*dev));
+	if (dev == NULL) {
+		ret = -1;
+		goto end;
+	}
+
+	memset(dev, 0, sizeof(*dev));
+
+	char  pci_device_info[PATH_MAX];
+	BOOL  res;
+	struct rte_pci_addr addr;
+	struct rte_pci_id pci_id;
+
+	/* Retrieve PCI device IDs */
+	res = SetupDiGetDeviceRegistryPropertyA(dev_info, device_info_data,
+			SPDRP_HARDWAREID, NULL, (BYTE *)&pci_device_info,
+			sizeof(pci_device_info), NULL);
+	if (!res) {
+		RTE_LOG_WIN32_ERR(
+			"SetupDiGetDeviceRegistryPropertyA(SPDRP_HARDWAREID)");
+		return -1;
+	}
+
+	ret = get_pci_hardware_info((const char *)&pci_device_info, &pci_id);
+	if (ret != 0) {
+		/*
+		 * We won't add this device, but we want to continue
+		 * looking for supported devices
+		 */
+		ret = ERROR_CONTINUE;
+		goto end;
+	}
+
+	ret = get_device_pci_address(dev_info, device_info_data, &addr);
+	if (ret != 0)
+		goto end;
+
+	dev->addr = addr;
+	dev->id = pci_id;
+	dev->max_vfs = 0; /* TODO: get max_vfs */
+
+	pci_name_set(dev);
+
+	get_kernel_driver_type(dev);
+
+	/* get resources */
+	if (get_device_resource_info(dev_info, device_info_data, dev)
+			!= ERROR_SUCCESS) {
+		goto end;
+	}
+
+	/* device is valid, add in list (sorted) */
+	if (TAILQ_EMPTY(&rte_pci_bus.device_list)) {
+		rte_pci_add_device(dev);
+	} else {
+		struct rte_pci_device *dev2 = NULL;
+		int ret;
+
+		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
+			ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr);
+			if (ret > 0) {
+				continue;
+			} else if (ret < 0) {
+				rte_pci_insert_device(dev2, dev);
+			} else { /* already registered */
+				dev2->kdrv = dev->kdrv;
+				dev2->max_vfs = dev->max_vfs;
+				memmove(dev2->mem_resource, dev->mem_resource,
+					sizeof(dev->mem_resource));
+				free(dev);
+			}
+			return 0;
+		}
+		rte_pci_add_device(dev);
+	}
+
+	return 0;
+end:
+	if (dev)
+		free(dev);
+	return ret;
+}
+
 /*
  * Scan the contents of the PCI bus
  * and add all network class devices into the devices list.
@@ -165,5 +360,40 @@  pci_uio_remap_resource(struct rte_pci_device *dev __rte_unused)
 int
 rte_pci_scan(void)
 {
+	DWORD			device_index = 0, found_device = 0;
+	HDEVINFO		dev_info;
+	SP_DEVINFO_DATA	device_info_data;
+	int				ret = -1;
+
+	dev_info = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, TEXT("PCI"), NULL,
+				DIGCF_PRESENT);
+	if (dev_info == INVALID_HANDLE_VALUE) {
+		RTE_LOG(ERR, EAL, "Unable to enumerate PCI devices.\n");
+		RTE_LOG_WIN32_ERR("SetupDiGetClassDevs(pci_scan)");
+		goto end;
+	}
+
+	device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+	device_index = 0;
+
+	while (SetupDiEnumDeviceInfo(dev_info, device_index,
+	    &device_info_data)) {
+		device_index++;
+		ret = pci_scan_one(dev_info, &device_info_data);
+		if (ret == ERROR_SUCCESS)
+			found_device++;
+		else if (ret != ERROR_CONTINUE)
+			goto end;
+
+		memset(&device_info_data, 0, sizeof(SP_DEVINFO_DATA));
+		device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+	}
+
+	RTE_LOG(DEBUG, EAL, "PCI scan found %lu devices\n", found_device);
 	return 0;
+end:
+	if (dev_info != INVALID_HANDLE_VALUE)
+		SetupDiDestroyDeviceInfoList(dev_info);
+
+	return ret;
 }
diff --git a/lib/librte_eal/windows/include/rte_windows.h b/lib/librte_eal/windows/include/rte_windows.h
index 899ed7d87..725ac4f9b 100644
--- a/lib/librte_eal/windows/include/rte_windows.h
+++ b/lib/librte_eal/windows/include/rte_windows.h
@@ -25,6 +25,7 @@ 
 #include <psapi.h>
 #include <setupapi.h>
 #include <winioctl.h>
+#include <devguid.h>
 
 /* Have GUIDs defined. */
 #ifndef INITGUID