X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fmmio-ports.c;h=cac8a7e35ad138269d11d3e7db1d74db6959b25d;hb=42fc4263ec0e35ba6a5ac7c32956e25b4551c907;hp=50cbee7401a1bf83b9b524e4a44e878c6b69d56e;hpb=5d2ff7718d35f15636e231219d50d84fbd73ffb5;p=pciutils.git diff --git a/lib/mmio-ports.c b/lib/mmio-ports.c index 50cbee7..cac8a7e 100644 --- a/lib/mmio-ports.c +++ b/lib/mmio-ports.c @@ -3,67 +3,63 @@ * * Copyright (c) 2022 Pali Rohár * - * Can be freely distributed and used under the terms of the GNU GPL. - */ - -/* - * Tell 32-bit platforms that we are interested in 64-bit variant of off_t type - * as 32-bit variant of off_t type is signed and so it cannot represent all - * possible 32-bit offsets. It is required because off_t type is used by mmap(). + * Can be freely distributed and used under the terms of the GNU GPL v2+. + * + * SPDX-License-Identifier: GPL-2.0-or-later */ -#define _FILE_OFFSET_BITS 64 #include "internal.h" +#include "physmem.h" +#include "physmem-access.h" #include #include #include #include -#include - -#include -#include -#include -#include -#ifndef OFF_MAX -#define OFF_MAX (off_t)((1ULL << (sizeof(off_t) * CHAR_BIT - 1)) - 1) -#endif - -struct mmio_cache -{ - off_t addr_page; - off_t data_page; +struct mmio_cache { + u64 addr_page; + u64 data_page; void *addr_map; void *data_map; }; -static long pagesize; +struct mmio_access { + struct mmio_cache *cache; + struct physmem *physmem; + long pagesize; +}; static void munmap_regs(struct pci_access *a) { - struct mmio_cache *cache = a->aux; + struct mmio_access *macc = a->backend_data; + struct mmio_cache *cache = macc->cache; + struct physmem *physmem = macc->physmem; + long pagesize = macc->pagesize; if (!cache) return; - munmap(cache->addr_map, pagesize); + physmem_unmap(physmem, cache->addr_map, pagesize); if (cache->addr_page != cache->data_page) - munmap(cache->data_map, pagesize); + physmem_unmap(physmem, cache->data_map, pagesize); - pci_mfree(a->aux); - a->aux = NULL; + pci_mfree(macc->cache); + macc->cache = NULL; } static int -mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, volatile void **addr, volatile void **data) +mmap_regs(struct pci_access *a, u64 addr_reg, u64 data_reg, int data_off, volatile void **addr, volatile void **data) { - struct mmio_cache *cache = a->aux; - off_t addr_page = addr_reg & ~(pagesize-1); - off_t data_page = data_reg & ~(pagesize-1); - void *addr_map = MAP_FAILED; - void *data_map = MAP_FAILED; + struct mmio_access *macc = a->backend_data; + struct mmio_cache *cache = macc->cache; + struct physmem *physmem = macc->physmem; + long pagesize = macc->pagesize; + u64 addr_page = addr_reg & ~(pagesize-1); + u64 data_page = data_reg & ~(pagesize-1); + void *addr_map = (void *)-1; + void *data_map = (void *)-1; if (cache && cache->addr_page == addr_page) addr_map = cache->addr_map; @@ -71,35 +67,35 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo if (cache && cache->data_page == data_page) data_map = cache->data_map; - if (addr_map == MAP_FAILED) - addr_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, addr_page); + if (addr_map == (void *)-1) + addr_map = physmem_map(physmem, addr_page, pagesize, 1); - if (addr_map == MAP_FAILED) + if (addr_map == (void *)-1) return 0; - if (data_map == MAP_FAILED) + if (data_map == (void *)-1) { if (data_page == addr_page) data_map = addr_map; else - data_map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, a->fd, data_page); + data_map = physmem_map(physmem, data_page, pagesize, 1); } - if (data_map == MAP_FAILED) + if (data_map == (void *)-1) { if (!cache || cache->addr_map != addr_map) - munmap(addr_map, pagesize); + physmem_unmap(physmem, addr_map, pagesize); return 0; } if (cache && cache->addr_page != addr_page) - munmap(cache->addr_map, pagesize); + physmem_unmap(physmem, cache->addr_map, pagesize); if (cache && cache->data_page != data_page && cache->data_page != cache->addr_page) - munmap(cache->data_map, pagesize); + physmem_unmap(physmem, cache->data_map, pagesize); if (!cache) - cache = a->aux = pci_malloc(a, sizeof(*cache)); + cache = macc->cache = pci_malloc(a, sizeof(*cache)); cache->addr_page = addr_page; cache->data_page = data_page; @@ -111,47 +107,11 @@ mmap_regs(struct pci_access *a, off_t addr_reg, off_t data_reg, int data_off, vo return 1; } -static void -writeb(unsigned char value, volatile void *addr) -{ - *(volatile unsigned char *)addr = value; -} - -static void -writew(unsigned short value, volatile void *addr) -{ - *(volatile unsigned short *)addr = value; -} - -static void -writel(unsigned long value, volatile void *addr) -{ - *(volatile unsigned long *)addr = value; -} - -static unsigned char -readb(volatile void *addr) -{ - return *(volatile unsigned char *)addr; -} - -static unsigned short -readw(volatile void *addr) -{ - return *(volatile unsigned short *)addr; -} - -static unsigned long -readl(volatile void *addr) -{ - return *(volatile unsigned long *)addr; -} - static int validate_addrs(const char *addrs) { const char *sep, *next; - unsigned long long num; + u64 num; char *endptr; if (!*addrs) @@ -172,12 +132,12 @@ validate_addrs(const char *addrs) errno = 0; num = strtoull(addrs, &endptr, 16); - if (errno || endptr != sep || (num & 3) || num > OFF_MAX) + if (errno || endptr != sep || (num & 3)) return 0; errno = 0; num = strtoull(sep+1, &endptr, 16); - if (errno || endptr != next || (num & 3) || num > OFF_MAX) + if (errno || endptr != next || (num & 3)) return 0; if (!*next) @@ -200,7 +160,7 @@ get_domain_count(const char *addrs) } static int -get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg) +get_domain_addr(const char *addrs, int domain, u64 *addr_reg, u64 *data_reg) { char *endptr; @@ -221,74 +181,110 @@ get_domain_addr(const char *addrs, int domain, off_t *addr_reg, off_t *data_reg) static void conf1_config(struct pci_access *a) { - pci_define_param(a, "devmem.path", PCI_PATH_DEVMEM_DEVICE, "Path to the /dev/mem device"); + physmem_init_config(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) +{ + physmem_init_config(a); + 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 *devmem = pci_get_param(a, "devmem.path"); + char *addrs = pci_get_param(a, addrs_param_name); 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; } - if (access(devmem, R_OK)) + if (physmem_access(a, 1)) { - a->debug("cannot access %s", devmem); + a->debug("cannot access physical memory: %s", strerror(errno)); return 0; } - a->debug("using %s with %s", devmem, addrs); + a->debug("using with %s", addrs); 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 *devmem = pci_get_param(a, "devmem.path"); - - pagesize = sysconf(_SC_PAGESIZE); - if (pagesize < 0) - a->error("Cannot get page size: %s", strerror(errno)); + char *addrs_param_name = get_addrs_param_name(a); + char *addrs = pci_get_param(a, addrs_param_name); + struct mmio_access *macc; + struct physmem *physmem; + long pagesize; 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); + + physmem = physmem_open(a, 1); + if (!physmem) + a->error("Cannot open physcal memory: %s.", strerror(errno)); - a->fd = open(devmem, O_RDWR | O_DSYNC); /* O_DSYNC bypass CPU cache for mmap() on Linux */ - if (a->fd < 0) - a->error("Cannot open %s: %s.", devmem, strerror(errno)); + pagesize = physmem_get_pagesize(physmem); + if (pagesize <= 0) + a->error("Cannot get page size: %s.", strerror(errno)); + + macc = pci_malloc(a, sizeof(*macc)); + macc->cache = NULL; + macc->physmem = physmem; + macc->pagesize = pagesize; + a->backend_data = macc; } static void conf1_cleanup(struct pci_access *a) { - if (a->fd < 0) - return; + struct mmio_access *macc = a->backend_data; munmap_regs(a); - close(a->fd); - a->fd = -1; + physmem_close(macc->physmem); + pci_mfree(macc); } 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 +293,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; + u64 addr_reg, data_reg; - if (pos >= 256) + if (pos >= 4096) return 0; if (len != 1 && len != 2 && len != 4) @@ -315,19 +312,19 @@ 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); - readl(addr); /* write barrier for address */ + physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + physmem_readl(addr); /* write barrier for address */ switch (len) { case 1: - buf[0] = readb(data); + buf[0] = physmem_readb(data); break; case 2: - ((u16 *) buf)[0] = readw(data); + ((u16 *) buf)[0] = physmem_readw(data); break; case 4: - ((u32 *) buf)[0] = readl(data); + ((u32 *) buf)[0] = physmem_readl(data); break; } @@ -335,13 +332,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; + u64 addr_reg, data_reg; - if (pos >= 256) + if (pos >= 4096) return 0; if (len != 1 && len != 2 && len != 4) @@ -353,19 +360,19 @@ 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); - readl(addr); /* write barrier for address */ + physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr); + physmem_readl(addr); /* write barrier for address */ switch (len) { case 1: - writeb(buf[0], data); + physmem_writeb(buf[0], data); break; case 2: - writew(((u16 *) buf)[0], data); + physmem_writew(((u16 *) buf)[0], data); break; case 4: - writel(((u32 *) buf)[0], data); + physmem_writel(((u32 *) buf)[0], data); break; } @@ -378,11 +385,20 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len) * Correct way is to issue CPU instruction for full hw sync barrier but gcc * does not provide any (builtin) function yet. */ - readl(addr); + physmem_readl(addr); 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 +414,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 */ +};