[igt-dev] [PATCH i-g-t] lib: add pci helper functions to intel_chipset

Daniel Mrzyglod daniel.t.mrzyglod at intel.com
Mon Mar 11 13:23:09 UTC 2019


From: "Mrzyglod, Daniel T" <daniel.t.mrzyglod at intel.com>

This patch add two helper functions:
 * reading register from PCI based on open fd
 * getting PCI domain/bus/dev/func based on fd

The reason why we need this function is up to scenario when we have
multiple PCI devices.

Signed-off-by: Mrzyglod, Daniel T <daniel.t.mrzyglod at intel.com>
---
 lib/intel_chipset.c | 176 ++++++++++++++++++++++++++++++++++++++++++++
 lib/intel_chipset.h |  13 ++++
 2 files changed, 189 insertions(+)

diff --git a/lib/intel_chipset.c b/lib/intel_chipset.c
index 4748a3fb..3dd722d6 100644
--- a/lib/intel_chipset.c
+++ b/lib/intel_chipset.c
@@ -36,6 +36,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
+#include <linux/limits.h>
 #include "i915_drm.h"
 
 #include "drmtest.h"
@@ -178,3 +179,178 @@ intel_check_pch(void)
 		return;
 	}
 }
+
+/**
+ * parse_pci_address_string:
+ * @pci_address: PCI string in form 0000:00:00.0
+ * @dev_addr: structure to be filled by this parsing function
+ *
+ * This function fill fd_pci_address structure with data about pci: domain, bus
+ * device, function
+ * Return:
+ * O or -EINVAL
+ */
+static int parse_pci_address_string(char *pci_address,
+				    struct fd_pci_address *dev_addr)
+{
+	unsigned long val;
+	char *pch;
+	int i = 0;
+
+	if (strlen(pci_address) != 12)
+		return -EINVAL;
+
+	/* parse PCI address  string for domain */
+	pch = strtok(pci_address, ":.");
+	errno = 0;
+	val = strtoul(pch, NULL, 16);
+	if (errno != 0 || val > UINT16_MAX)
+		return -EINVAL;
+	dev_addr->domain = val;
+
+	/* parse  PCI address for: BUS DEVICE FUNCTION */
+	for (i = 0; i < 3; i++) {
+		pch = strtok(NULL, ":.");
+		errno = 0;
+		val = strtoul(pch, NULL, 16);
+		if (errno != 0 || val > UINT8_MAX)
+			return -EINVAL;
+
+		switch (i) {
+		case 0:
+			dev_addr->bus = val;
+			break;
+		case 1:
+			dev_addr->dev = val;
+			break;
+		case 2:
+			dev_addr->func = val;
+			break;
+		default:
+			return -EINVAL;
+		break;
+		}
+	}
+
+	pch = strtok(NULL, ":.");
+	if (pch)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * parse_pci_filepath_string:
+ * @filepath: string in form ../../devices/pci0000:00/0000:00:00.0/drm/card0
+ * @dev_addr: structure to be filled by this parsing function
+ *
+ * This function parse filepath string to PCI address string 0000:00:00.0 form.
+ * and fill dev_addr.
+ * Return:
+ * O or -EINVAL
+ */
+static int
+parse_pci_filepath_string(char *filepath, struct fd_pci_address *dev_addr)
+{
+	char *pch = strstr(filepath, "pci");
+	char *begin = NULL;
+	char *end = NULL;
+
+	if (pch) {
+		pch = strstr(pch, "/");
+		pch++;
+		begin = pch;
+		end = strstr(pch, "/");
+		*end = '\0';
+		} else {
+			return -EINVAL;
+		}
+	if (strlen(begin) != 12)
+		return -EINVAL;
+	if (parse_pci_address_string(begin, dev_addr) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+/**
+ * get_pci_address_space:
+ * @fd: file descriptor of opened device
+ * @dev_addr: structure with pci_address to be filled by this parsing function
+ *
+ * This function fill dev_addr from reading fstats from opened device.
+ * from it.
+ * Return:
+ * O or -EINVAL
+ */
+int intel_get_pci_address_space(int fd, struct fd_pci_address *dev_addr)
+{
+	struct stat sb;
+	char filepath[PATH_MAX];
+	char fdp[PATH_MAX];
+	int ret = -1;
+
+	if (fstat(fd, &sb) == -1) {
+		perror("stat");
+		return -EINVAL;
+	}
+
+	sprintf(fdp, "/sys/dev/char/%d:%d",  major(sb.st_rdev),
+		minor(sb.st_rdev));
+	readlink(fdp, filepath, PATH_MAX);
+
+	ret = parse_pci_filepath_string(filepath, dev_addr);
+	if (ret < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * pci_read_register_u32:
+ * @fd: file descriptor of opened device
+ * @reg_name: offset in mmio space
+ *
+ * This function read UINT32 from pci.
+ * Return:
+ * Register value or igt_fail
+ */
+uint32_t intel_pci_read_register_u32(int fd, uint32_t reg_name)
+{
+	uint32_t reg_val = 0;
+	int error = -1;
+	int mmio_bar, mmio_size;
+	struct pci_device *dev;
+	struct fd_pci_address dev_addr;
+	void *igt_mmio;
+
+	intel_get_pci_address_space(fd, &dev_addr);
+	pci_system_init();
+	dev = pci_device_find_by_slot((uint32_t)dev_addr.domain,
+				      (uint32_t)dev_addr.bus,
+				      (uint32_t)dev_addr.dev,
+				      (uint32_t)dev_addr.func);
+
+	error = pci_device_probe(dev);
+	igt_fail_on_f(error != 0,
+		      "Couldn't probe graphics card\n");
+
+	mmio_bar = 0;
+	mmio_size = 2 * 1024 * 1024;
+
+	error = pci_device_map_range(dev,
+				     dev->regions[mmio_bar].base_addr,
+				     mmio_size,
+				     PCI_DEV_MAP_FLAG_WRITABLE,
+				     &igt_mmio);
+	igt_fail_on_f(error != 0,
+		      "Couldn't map MMIO region\n");
+
+	reg_val = *(volatile uint32_t *)((volatile char *)igt_mmio + reg_name);
+
+	error = pci_device_unmap_range(dev, igt_mmio,
+				       mmio_size);
+	igt_fail_on_f(error != 0,
+		      "Couldn't unmap MMIO region\n");
+
+	return reg_val;
+}
diff --git a/lib/intel_chipset.h b/lib/intel_chipset.h
index 40170b7b..96a618eb 100644
--- a/lib/intel_chipset.h
+++ b/lib/intel_chipset.h
@@ -73,6 +73,19 @@ struct intel_device_info {
 
 const struct intel_device_info *intel_get_device_info(uint16_t devid) __attribute__((pure));
 
+struct fd_pci_address {
+	/**
+	 * PCI Address
+	 */
+	uint16_t	domain;
+	uint8_t		bus;
+	uint8_t		dev;
+	uint8_t		func;
+};
+
+uint32_t intel_pci_read_register_u32(int fd, uint32_t reg_name);
+int intel_get_pci_address_space(int fd, struct fd_pci_address *dev_addr);
+
 unsigned intel_gen(uint16_t devid) __attribute__((pure));
 unsigned intel_gt(uint16_t devid) __attribute__((pure));
 
-- 
2.20.1



More information about the igt-dev mailing list