summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2022-01-02 20:50:41 +0100
committerPali Rohár <pali@kernel.org>2022-11-18 14:43:13 +0100
commite2d9340ba416ef0856fb8198e16ffd255225952c (patch)
treeb3d93d189401a76e9d7496b1ad66018c253a2d7e
parent0a4fae20efcafa60ec2f2efd2e7de81b863471b7 (diff)
downloadpciutils-e2d9340ba416ef0856fb8198e16ffd255225952c.tar.gz
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.
-rw-r--r--lib/init.c3
-rw-r--r--lib/internal.h2
-rw-r--r--lib/mmio-ports.c98
-rw-r--r--lib/pci.h1
-rw-r--r--pcilib.man13
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