[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