X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Fmmio-ports.c;h=00a595afee38990470f8df48fcc24d5991f26a03;hb=9f3d614e4578bdec2b60d97caec400b28d4af9d3;hp=a9e23c34966365f96266ae5a2130b51c3df57525;hpb=3444b81f6b0e83eacb391e10b41f9a7b60e66f4e;p=pciutils.git diff --git a/lib/mmio-ports.c b/lib/mmio-ports.c index a9e23c3..00a595a 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(u32 value, volatile void *addr) -{ - *(volatile u32 *)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 u32 -readl(volatile void *addr) -{ - return *(volatile u32 *)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,14 +181,14 @@ 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) { - 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-ext.addrs", "", "Physical addresses of memory mapped Intel conf1 extended interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */ } @@ -236,7 +196,6 @@ static int detect(struct pci_access *a, char *addrs_param_name) { char *addrs = pci_get_param(a, addrs_param_name); - char *devmem = pci_get_param(a, "devmem.path"); if (!*addrs) { @@ -250,13 +209,13 @@ detect(struct pci_access *a, char *addrs_param_name) return 0; } - if (access(devmem, R_OK | W_OK)) + if (physmem_access(a, 1)) { - a->debug("cannot access %s: %s", devmem, strerror(errno)); + 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; } @@ -286,11 +245,9 @@ conf1_init(struct pci_access *a) { 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); - if (pagesize < 0) - a->error("Cannot get page size: %s", strerror(errno)); + struct mmio_access *macc; + struct physmem *physmem; + long pagesize; if (!*addrs) a->error("Option %s was not specified.", addrs_param_name); @@ -298,20 +255,29 @@ conf1_init(struct pci_access *a) if (!validate_addrs(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) - a->error("Cannot open %s: %s.", devmem, strerror(errno)); + physmem = physmem_open(a, 1); + if (!physmem) + a->error("Cannot open physcal memory: %s.", 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 @@ -332,7 +298,7 @@ conf1_ext_read(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 >= 4096) return 0; @@ -346,19 +312,19 @@ conf1_ext_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 | ((pos & 0xf00) << 16) | ((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; } @@ -380,7 +346,7 @@ 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 >= 4096) return 0; @@ -394,19 +360,19 @@ conf1_ext_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 | ((pos & 0xf00) << 16) | ((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; } @@ -419,7 +385,7 @@ conf1_ext_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; } @@ -434,33 +400,27 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len) } struct pci_methods pm_mmio_conf1 = { - "mmio-conf1", - "Raw memory mapped I/O port access using Intel conf1 interface", - conf1_config, - conf1_detect, - conf1_init, - conf1_cleanup, - conf1_scan, - pci_generic_fill_info, - conf1_read, - conf1_write, - NULL, /* read_vpd */ - NULL, /* init_dev */ - NULL /* cleanup_dev */ + .name = "mmio-conf1", + .help = "Raw memory mapped I/O port access using Intel conf1 interface", + .config = conf1_config, + .detect = conf1_detect, + .init = conf1_init, + .cleanup = conf1_cleanup, + .scan = conf1_scan, + .fill_info = pci_generic_fill_info, + .read = conf1_read, + .write = conf1_write, }; 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 */ + .name = "mmio-conf1-ext", + .help = "Raw memory mapped I/O port access using Intel conf1 extended interface", + .config = conf1_ext_config, + .detect = conf1_ext_detect, + .init = conf1_init, + .cleanup = conf1_cleanup, + .scan = conf1_scan, + .fill_info = pci_generic_fill_info, + .read = conf1_ext_read, + .write = conf1_ext_write, };