pci: Add cacheline and MWI helpers from Linux
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 1 Nov 2017 18:09:09 +0000 (14:09 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Nov 2017 15:46:55 +0000 (10:46 -0500)
These were copied and ported from commit 569dbb88e80d ("Linux 4.13").

They are simple enough that we can use them too.  We weren't doing anything
with memory-write-invalidate, but it's a performance helper.  Eventually,
we might end up porting all of Linux's PCI infrastructure.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/pci.c
kern/arch/x86/pci.h
kern/drivers/net/bnx2x/bnx2x_dev.c
kern/drivers/net/etherigbe.c

index 9b153a5..771b9ba 100644 (file)
@@ -620,3 +620,55 @@ uintptr_t pci_map_membar(struct pci_device *dev, int bir)
                return 0;
        return vmap_pmem_nocache(paddr, sz);
 }
+
+/* The following were ported from Linux:
+ *
+ * pci_set_cacheline_size
+ * pci_set_mwi
+ * pci_clear_mwi
+ */
+int pci_set_cacheline_size(struct pci_device *dev)
+{
+       uint8_t cl_sz;
+       uint8_t pci_cache_line_size = ARCH_CL_SIZE >> 2;
+
+       cl_sz = pcidev_read8(dev, PCI_CACHE_LINE_SIZE);
+       /* Validate current setting: the PCI_CACHE_LINE_SIZE must be equal to or
+        * multiple of the right value. */
+       if (cl_sz >= pci_cache_line_size && (cl_sz % pci_cache_line_size) == 0)
+               return 0;
+       pcidev_write8(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
+       cl_sz = pcidev_read8(dev, PCI_CACHE_LINE_SIZE);
+       if (cl_sz == pci_cache_line_size)
+               return 0;
+       printk("PCI device %s does not support cache line size of %d\n",
+              dev->name, pci_cache_line_size << 2);
+       return -EINVAL;
+}
+
+int pci_set_mwi(struct pci_device *dev)
+{
+       int rc;
+       uint16_t cmd;
+
+       rc = pci_set_cacheline_size(dev);
+       if (rc)
+               return rc;
+       cmd = pcidev_read16(dev, PCI_COMMAND);
+       if (!(cmd & PCI_COMMAND_INVALIDATE)) {
+               cmd |= PCI_COMMAND_INVALIDATE;
+               pcidev_write16(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+void pci_clear_mwi(struct pci_device *dev)
+{
+       uint16_t cmd;
+
+       cmd = pcidev_read16(dev, PCI_COMMAND);
+       if (cmd & PCI_COMMAND_INVALIDATE) {
+               cmd &= ~PCI_COMMAND_INVALIDATE;
+               pcidev_write16(dev, PCI_COMMAND, cmd);
+       }
+}
index a1f40b9..c772bbe 100644 (file)
@@ -264,6 +264,9 @@ void pci_dump_config(struct pci_device *pcidev, size_t len);
 int pci_find_cap(struct pci_device *pcidev, uint8_t cap_id, uint32_t *cap_reg);
 unsigned int pci_to_tbdf(struct pci_device *pcidev);
 uintptr_t pci_map_membar(struct pci_device *dev, int bir);
+int pci_set_cacheline_size(struct pci_device *dev);
+int pci_set_mwi(struct pci_device *dev);
+void pci_clear_mwi(struct pci_device *dev);
 static inline void pci_set_drvdata(struct pci_device *pcidev, void *data);
 static inline void *pci_get_drvdata(struct pci_device *pcidev);
 
index 3364d0b..1ae8abc 100644 (file)
@@ -354,7 +354,7 @@ static int bnx2x_reset(struct bnx2x *ctlr)
 
 static void bnx2x_pci(void)
 {
-       int cls, id;
+       int id;
        struct pci_device *pcidev;
        struct bnx2x *ctlr;
        const struct pci_device_id *pci_id;
@@ -378,22 +378,7 @@ static void bnx2x_pci(void)
 
                /* MMIO, pci_bus_master, etc, are all done in bnx2x_attach */
 
-               cls = pcidev_read8(pcidev, PCI_CLSZ_REG);
-               switch (cls) {
-                       default:
-                               printd("bnx2x: unexpected CLS - %d\n", cls * 4);
-                               break;
-                       case 0x00:
-                       case 0xFF:
-                               /* bogus value; use a sane default.  cls is set in DWORD (u32)
-                                * units. */
-                               cls = ARCH_CL_SIZE / sizeof(long);
-                               pcidev_write8(pcidev, PCI_CLSZ_REG, cls);
-                               break;
-                       case 0x08:
-                       case 0x10:
-                               break;
-               }
+               pci_set_cacheline_size(pcidev);
 
                ctlr = kzmalloc(sizeof(struct bnx2x), 0);
                if (ctlr == NULL)
index 9e37b7e..ad973e1 100644 (file)
@@ -1935,7 +1935,7 @@ igbereset(struct ctlr* ctlr)
 static void
 igbepci(void)
 {
-       int cls, id;
+       int id;
        struct pci_device *pcidev;
        struct ctlr *ctlr;
        void *mem;
@@ -1978,22 +1978,7 @@ igbepci(void)
                        printd("igbe: can't map %p\n", pcidev->bar[0].mmio_base32);
                        continue;
                }
-               cls = pcidev_read8(pcidev, PCI_CLSZ_REG);
-               switch(cls){
-                       default:
-                               printd("igbe: unexpected CLS - %d\n", cls*4);
-                               break;
-                       case 0x00:
-                       case 0xFF:
-                               /* bogus value; use a sane default.  cls is set in DWORD (u32)
-                                * units. */
-                               cls = ARCH_CL_SIZE / sizeof(long);
-                               pcidev_write8(pcidev, PCI_CLSZ_REG, cls);
-                               break;
-                       case 0x08:
-                       case 0x10:
-                               break;
-               }
+               pci_set_cacheline_size(pcidev);
                ctlr = kzmalloc(sizeof(struct ctlr), 0);
                if(ctlr == NULL) {
                        vunmap_vmem((uintptr_t)mem, pcidev->bar[0].mmio_sz);
@@ -2010,7 +1995,7 @@ igbepci(void)
                ctlr->port = pcidev->bar[0].raw_bar & ~0x0f;
                ctlr->pci = pcidev;
                ctlr->id = id;
-               ctlr->cls = cls * sizeof(long);
+               ctlr->cls = pcidev_read8(pcidev, PCI_CLSZ_REG);
                ctlr->nic = mem;
 
                if(igbereset(ctlr)){