]> mj.ucw.cz Git - pciutils.git/commitdiff
libpci: mmio-ports: Bypass CPU cache and add barriers for read/write
authorPali Rohár <pali@kernel.org>
Sat, 5 Nov 2022 16:32:38 +0000 (17:32 +0100)
committerPali Rohár <pali@kernel.org>
Fri, 18 Nov 2022 13:10:06 +0000 (14:10 +0100)
Between accessing address address and data I/O ports it is needed to issue
barriers. Use explicit readl() for barrier and O_DSYNC to bypass CPU cache.

lib/mmio-ports.c

index b9e3926bf262bd652b0e9e388bbaa1b3e8f83b65..50cbee7401a1bf83b9b524e4a44e878c6b69d56e 100644 (file)
@@ -269,7 +269,7 @@ conf1_init(struct pci_access *a)
   if (!validate_addrs(addrs))
     a->error("Option mmio-conf1.addrs has invalid address format \"%s\".", addrs);
 
-  a->fd = open(devmem, O_RDWR);
+  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));
 }
@@ -316,6 +316,7 @@ conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
     return 0;
 
   writel(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
+  readl(addr); /* write barrier for address */
 
   switch (len)
     {
@@ -353,6 +354,7 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
     return 0;
 
   writel(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
+  readl(addr); /* write barrier for address */
 
   switch (len)
     {
@@ -367,6 +369,17 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
       break;
     }
 
+  /*
+   * write barrier for data
+   * Note that we cannot read from data port because it may have side effect.
+   * Instead we read from address port (which should not have side effect) to
+   * create a barrier between two conf1_write() calls. But this does not have
+   * to be 100% correct as it does not ensure barrier on data port itself.
+   * Correct way is to issue CPU instruction for full hw sync barrier but gcc
+   * does not provide any (builtin) function yet.
+   */
+  readl(addr);
+
   return 1;
 }