From e2d9340ba416ef0856fb8198e16ffd255225952c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 2 Jan 2022 20:50:41 +0100 Subject: libpci: mmio-ports: Add Extended PCIe Intel Type 1 access method Extended method allows to access all PCIe registers, including extended registers starting at 0x100 offset. This method uses 4 reserved buts above bus bits for PCIe registers. On ARM platforms it is very common for PCIe controllers. Like standard method, it needs to be properly configured. --- lib/init.c | 3 ++ lib/internal.h | 2 +- lib/mmio-ports.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++--------- lib/pci.h | 1 + pcilib.man | 13 ++++++++ 5 files changed, 100 insertions(+), 17 deletions(-) diff --git a/lib/init.c b/lib/init.c index 5ce260a..e6efb8b 100644 --- a/lib/init.c +++ b/lib/init.c @@ -93,8 +93,10 @@ static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = { #endif #ifdef PCI_HAVE_PM_MMIO_CONF &pm_mmio_conf1, + &pm_mmio_conf1_ext, #else NULL, + NULL, #endif }; @@ -116,6 +118,7 @@ static int probe_sequence[] = { // Low-level methods poking the hardware directly PCI_ACCESS_I386_TYPE1, PCI_ACCESS_I386_TYPE2, + PCI_ACCESS_MMIO_TYPE1_EXT, PCI_ACCESS_MMIO_TYPE1, -1, }; diff --git a/lib/internal.h b/lib/internal.h index 81316dc..ed0e94f 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -134,5 +134,5 @@ void pci_free_caps(struct pci_dev *); extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc, pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device, pm_dump, pm_linux_sysfs, pm_darwin, pm_sylixos_device, pm_hurd, - pm_mmio_conf1, + pm_mmio_conf1, pm_mmio_conf1_ext, pm_win32_cfgmgr32, pm_win32_kldbg, pm_win32_sysdbg; diff --git a/lib/mmio-ports.c b/lib/mmio-ports.c index ae9c30d..c8e5f8c 100644 --- a/lib/mmio-ports.c +++ b/lib/mmio-ports.c @@ -225,21 +225,28 @@ conf1_config(struct pci_access *a) pci_define_param(a, "mmio-conf1.addrs", "", "Physical addresses of memory mapped Intel conf1 interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */ } +static void +conf1_ext_config(struct pci_access *a) +{ + pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); + pci_define_param(a, "mmio-conf1-ext.addrs", "", "Physical addresses of memory mapped Intel conf1 extended interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */ +} + static int -conf1_detect(struct pci_access *a) +detect(struct pci_access *a, char *addrs_param_name) { - char *addrs = pci_get_param(a, "mmio-conf1.addrs"); + char *addrs = pci_get_param(a, addrs_param_name); char *devmem = pci_get_param(a, "devmem.path"); if (!*addrs) { - a->debug("mmio-conf1.addrs was not specified"); + a->debug("%s was not specified", addrs_param_name); return 0; } if (!validate_addrs(addrs)) { - a->debug("mmio-conf1.addrs has invalid address format %s", addrs); + a->debug("%s has invalid address format %s", addrs_param_name, addrs); return 0; } @@ -253,10 +260,32 @@ conf1_detect(struct pci_access *a) return 1; } +static int +conf1_detect(struct pci_access *a) +{ + return detect(a, "mmio-conf1.addrs"); +} + +static int +conf1_ext_detect(struct pci_access *a) +{ + return detect(a, "mmio-conf1-ext.addrs"); +} + +static char* +get_addrs_param_name(struct pci_access *a) +{ + if (a->methods->config == conf1_ext_config) + return "mmio-conf1-ext.addrs"; + else + return "mmio-conf1.addrs"; +} + static void conf1_init(struct pci_access *a) { - char *addrs = pci_get_param(a, "mmio-conf1.addrs"); + char *addrs_param_name = get_addrs_param_name(a); + char *addrs = pci_get_param(a, addrs_param_name); char *devmem = pci_get_param(a, "devmem.path"); pagesize = sysconf(_SC_PAGESIZE); @@ -264,10 +293,10 @@ conf1_init(struct pci_access *a) a->error("Cannot get page size: %s", strerror(errno)); if (!*addrs) - a->error("Option mmio-conf1.addrs was not specified."); + a->error("Option %s was not specified.", addrs_param_name); if (!validate_addrs(addrs)) - a->error("Option mmio-conf1.addrs has invalid address format \"%s\".", addrs); + a->error("Option %s has invalid address format \"%s\".", addrs_param_name, addrs); a->fd = open(devmem, O_RDWR | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */ if (a->fd < 0) @@ -288,7 +317,8 @@ conf1_cleanup(struct pci_access *a) static void conf1_scan(struct pci_access *a) { - char *addrs = pci_get_param(a, "mmio-conf1.addrs"); + char *addrs_param_name = get_addrs_param_name(a); + char *addrs = pci_get_param(a, addrs_param_name); int domain_count = get_domain_count(addrs); int domain; @@ -297,13 +327,14 @@ conf1_scan(struct pci_access *a) } static int -conf1_read(struct pci_dev *d, int pos, byte *buf, int len) +conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len) { - char *addrs = pci_get_param(d->access, "mmio-conf1.addrs"); + char *addrs_param_name = get_addrs_param_name(d->access); + char *addrs = pci_get_param(d->access, addrs_param_name); volatile void *addr, *data; off_t addr_reg, data_reg; - if (pos >= 256) + if (pos >= 4096) return 0; if (len != 1 && len != 2 && len != 4) @@ -315,7 +346,7 @@ conf1_read(struct pci_dev *d, int pos, byte *buf, int len) if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data)) return 0; - writel(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); readl(addr); /* write barrier for address */ switch (len) @@ -335,13 +366,23 @@ conf1_read(struct pci_dev *d, int pos, byte *buf, int len) } static int -conf1_write(struct pci_dev *d, int pos, byte *buf, int len) +conf1_read(struct pci_dev *d, int pos, byte *buf, int len) { - char *addrs = pci_get_param(d->access, "mmio-conf1.addrs"); + if (pos >= 256) + return 0; + + return conf1_ext_read(d, pos, buf, len); +} + +static int +conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len) +{ + char *addrs_param_name = get_addrs_param_name(d->access); + char *addrs = pci_get_param(d->access, addrs_param_name); volatile void *addr, *data; off_t addr_reg, data_reg; - if (pos >= 256) + if (pos >= 4096) return 0; if (len != 1 && len != 2 && len != 4) @@ -353,7 +394,7 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len) if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data)) return 0; - writel(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); readl(addr); /* write barrier for address */ switch (len) @@ -383,6 +424,15 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len) return 1; } +static int +conf1_write(struct pci_dev *d, int pos, byte *buf, int len) +{ + if (pos >= 256) + return 0; + + return conf1_ext_write(d, pos, buf, len); +} + struct pci_methods pm_mmio_conf1 = { "mmio-conf1", "Raw memory mapped I/O port access using Intel conf1 interface", @@ -398,3 +448,19 @@ struct pci_methods pm_mmio_conf1 = { NULL, /* init_dev */ NULL /* cleanup_dev */ }; + +struct pci_methods pm_mmio_conf1_ext = { + "mmio-conf1-ext", + "Raw memory mapped I/O port access using Intel conf1 extended interface", + conf1_ext_config, + conf1_ext_detect, + conf1_init, + conf1_cleanup, + conf1_scan, + pci_generic_fill_info, + conf1_ext_read, + conf1_ext_write, + NULL, /* read_vpd */ + NULL, /* init_dev */ + NULL /* cleanup_dev */ +}; diff --git a/lib/pci.h b/lib/pci.h index f198f11..fa018f4 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -47,6 +47,7 @@ enum pci_access_type { PCI_ACCESS_WIN32_KLDBG, /* Win32 kldbgdrv.sys */ PCI_ACCESS_WIN32_SYSDBG, /* Win32 NT SysDbg */ PCI_ACCESS_MMIO_TYPE1, /* MMIO ports, type 1 */ + PCI_ACCESS_MMIO_TYPE1_EXT, /* MMIO ports, type 1 extended */ PCI_ACCESS_MAX }; diff --git a/pcilib.man b/pcilib.man index 7015294..b4c9f56 100644 --- a/pcilib.man +++ b/pcilib.man @@ -47,6 +47,13 @@ needs to be properly configured via the .B mmio-conf1.addrs parameter. .TP +.B mmio-conf1-ext +Direct hardware access via Extended PCIe Intel configuration mechanism 1 via memory-mapped I/O. +Mostly used on non-i386 platforms. Requires root privileges. Warning: This method +needs to be properly configured via the +.B mmio-conf1-ext.addrs +parameter. +.TP .B fbsd-device The .B /dev/pci @@ -152,6 +159,12 @@ Physical addresses of memory-mapped I/O ports for Intel configuration mechanism CF8 (address) and CFC (data) I/O port addresses are separated by slash and multiple addresses for different PCI domains are separated by commas. Format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... +.TP +.B mmio-conf1-ext.addrs +Physical addresses of memory-mapped I/O ports for Extended PCIe Intel configuration mechanism 1. +It has same format as +.B mmio-conf1.addrs +parameter. .SS Parameters for resolving of ID's via DNS .TP -- cgit v1.2.1