[igt-dev] [PATCH i-g-t] lib: add pci helper functions to intel_chipset
Jani Nikula
jani.nikula at linux.intel.com
Tue Mar 12 13:43:57 UTC 2019
On Mon, 11 Mar 2019, Daniel Mrzyglod <daniel.t.mrzyglod at intel.com> wrote:
> 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;
> +}
static int parse_pci_address_string(const char *pci_address,
struct fd_pci_address *dev_addr)
{
int ret;
unsigned int domain, bus, dev, func;
ret = sscanf(pci_address, "%4x:%2x:%2x.%1x", &domain, &bus, &dev, &func);
if (ret != 4)
return -EINVAL;
dev_addr->domain = domain;
dev_addr->bus = bus;
dev_addr->dev = dev;
dev_addr->func = func;
return 0;
}
BR,
Jani.
> +
> +/**
> + * 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));
--
Jani Nikula, Intel Open Source Graphics Center
More information about the igt-dev
mailing list