pci: map all memory BARs into the kernel All device memory BARs get mapped, and drivers can just ask for a specific, preexisting mapping. They will stay mapped for the life of the system. This makes it easier to reset and initialize a device after the kernel boots. We don't need to map and unmap the KVA at runtime, which would have changed the kernel mapping, requiring changes to all existing address spaces / pgdirs. It's also just easier for the devices - just ask for the BAR number, and we'll provide the address. Note the 82563 wasn't using 'nocache' for its register space. Probably a bad idea. Also, I'm still up-in-the-air with respects to uinptr_t vs void*. Plan 9 and Linux drivers tend to use void* for their iomem, even though you aren't supposed to dereference it with normal operations. In Linux, you use writel(void*) (write32() here). Our older code uses e.g. write_mmreg32(uintptr_t). Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/pci.c b/kern/arch/x86/pci.c index 3c2bd2b..ecbebee 100644 --- a/kern/arch/x86/pci.c +++ b/kern/arch/x86/pci.c
@@ -137,6 +137,10 @@ bar_val & PCI_BAR_MEM_MASK; pcidev->bar[i].mmio_sz = __pci_membar_get_sz(pcidev, i); + pcidev->bar[i].mmio_kva = + (void*)vmap_pmem_nocache( + pcidev->bar[i].mmio_base32, + pcidev->bar[i].mmio_sz); } else if (pci_is_membar64(bar_val)) { /* 64 bit, the lower 32 are in this bar, the * upper are in the next bar */ @@ -152,6 +156,10 @@ (uint64_t)bar_val << 32; pcidev->bar[i].mmio_sz = __pci_membar_get_sz(pcidev, i); + pcidev->bar[i].mmio_kva = + (void*)vmap_pmem_nocache( + pcidev->bar[i].mmio_base64, + pcidev->bar[i].mmio_sz); i++; } }
diff --git a/kern/arch/x86/pci.h b/kern/arch/x86/pci.h index 6d3d85a..6df42ff 100644 --- a/kern/arch/x86/pci.h +++ b/kern/arch/x86/pci.h
@@ -164,6 +164,7 @@ uint32_t mmio_base32; uint64_t mmio_base64; uint32_t mmio_sz; + void *mmio_kva; }; struct pci_device { @@ -268,6 +269,7 @@ 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); +static inline void *pci_get_mmio_bar_kva(struct pci_device *pdev, int bar); /* MSI functions, msi.c */ int pci_msi_enable(struct pci_device *p, uint64_t vec); @@ -296,3 +298,8 @@ { return pcidev->dev_data; } + +static inline void *pci_get_mmio_bar_kva(struct pci_device *pdev, int bir) +{ + return pdev->bar[bir].mmio_kva; +}
diff --git a/kern/arch/x86/usb.c b/kern/arch/x86/usb.c index 7f8e7f0..42e679a 100644 --- a/kern/arch/x86/usb.c +++ b/kern/arch/x86/usb.c
@@ -29,11 +29,12 @@ int i, ptr, cap, sem; //ptr = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask; - uintptr_t bar0 = pci_get_membar(pcidev, 0); - assert(bar0); - uintptr_t ehci_hcc_regs = vmap_pmem_nocache(bar0, - pcidev->bar[0].mmio_sz); - uint32_t hccparams = read_mmreg32(ehci_hcc_regs + 0x08); + uintptr_t ehci_hcc_regs; + uint32_t hccparams; + + ehci_hcc_regs = (uintptr_t)pci_get_mmio_bar_kva(pcidev, 0); + assert(ehci_hcc_regs); + hccparams = read_mmreg32(ehci_hcc_regs + 0x08); ptr = (hccparams >> 8) & ((1 << 8) - 1); @@ -71,13 +72,12 @@ static void xhci_disable_leg(struct pci_device *pcidev) { - uintptr_t bar0, xhci_hcc_regs, xecp; + uintptr_t xhci_hcc_regs, xecp; uint32_t hccparams, val; int i; - bar0 = pci_get_membar(pcidev, 0); - assert(bar0); - xhci_hcc_regs = vmap_pmem_nocache(bar0, pcidev->bar[0].mmio_sz); + xhci_hcc_regs = (uintptr_t)pci_get_mmio_bar_kva(pcidev, 0); + assert(xhci_hcc_regs); hccparams = read_mmreg32(xhci_hcc_regs + 0x10); xecp = (hccparams >> 16) & 0xffff;
diff --git a/kern/drivers/dev/cbdma.c b/kern/drivers/dev/cbdma.c index e68ae45..fdd1a52 100644 --- a/kern/drivers/dev/cbdma.c +++ b/kern/drivers/dev/cbdma.c
@@ -63,8 +63,6 @@ struct dev cbdmadevtab; static struct pci_device *pci; static void *mmio; -static uint64_t mmio_phy; /* physical addr */ -static uint32_t mmio_sz; static uint8_t chancnt; /* Total number of channels per function */ static bool iommu_enabled; static bool cbdma_break_loop; /* toggle_foo functionality */ @@ -494,8 +492,6 @@ sza_printf(sza, " Driver Information:\n"); sza_printf(sza, "\tmmio: %p\n" - "\tmmio_phy: 0x%x\n" - "\tmmio_sz: %lu\n" "\ttotal_channels: %d\n" "\tdesc_kaddr: %p\n" "\tdesc_paddr: %p\n" @@ -504,7 +500,7 @@ "\tstatus_kaddr: %p\n" "\tstatus_paddr: %p\n" "\tstatus_value: 0x%x\n", - mmio, mmio_phy, mmio_sz, chancnt, + mmio, chancnt, channel0.pdesc, PADDR(channel0.pdesc), channel0.ndesc, channel0.ver, channel0.status, PADDR(channel0.status), *(uint64_t *)channel0.status); @@ -861,7 +857,6 @@ /* assigning global variables */ pci = NULL; mmio = NULL; - mmio_sz = -1; /* initialize cbdmadev */ memset(&cbdmadev, 0x0, sizeof(cbdmadev)); @@ -890,24 +885,14 @@ /* search and find the mapped mmio region */ for (i = 0; i < COUNT_OF(pci->bar); i++) { - if (pci->bar[i].mmio_sz == 0) + mmio = pci_get_mmio_bar_kva(pci, i); + if (!mmio) continue; - mmio_phy = (pci->bar[0].mmio_base32 - ? pci->bar[0].mmio_base32 - : pci->bar[0].mmio_base64); - mmio_sz = pci->bar[i].mmio_sz; - mmio = (void *) vmap_pmem_nocache(mmio_phy, mmio_sz); break; } - /* handle any errors */ - if (mmio_sz == -1) { - printk("cbdma: invalid mmio_sz\n"); - return; - } - if (mmio == NULL) { - printk("cbdma: cannot map %p\n", mmio_phy); + printk("cbdma: cannot map any bars!\n"); return; } @@ -919,9 +904,9 @@ /* initialization successful; print stats */ printk("cbdma: registered [%x:%x] at %02x:%02x.%x // " - "mmio:%p mmio_sz:%lu\n", + "mmio:%p\n", pci->ven_id, pci->dev_id, pci->bus, pci->dev, pci->func, - mmio, mmio_sz); + mmio); tbdf = MKBUS(BusPCI, pci->bus, pci->dev, pci->func); register_irq(pci->irqline, cbdma_interrupt, NULL, tbdf);
diff --git a/kern/drivers/dev/sdiahci.c b/kern/drivers/dev/sdiahci.c index 4213c4a..b8e07c3 100644 --- a/kern/drivers/dev/sdiahci.c +++ b/kern/drivers/dev/sdiahci.c
@@ -176,9 +176,6 @@ void *mmio; void *hba; - /* phyical register address */ - uintptr_t physio; - struct drive *rawdrive; struct drive *drive[NCtlrdrv]; int ndrive; @@ -2180,9 +2177,8 @@ ctlr->mport = h_cap & ((1 << 5) - 1); i = (h_cap >> 20) & ((1 << 4) - 1); /* iss */ - printk("#S/sd%c: %s: %#p %s, %d ports, irq %d\n", sdev->idno, - Tname(ctlr), ctlr->physio, descmode[i], nunit, - ctlr->pci->irqline); + printk("#S/sd%c: %s: %s, %d ports, irq %d\n", sdev->idno, + Tname(ctlr), descmode[i], nunit, ctlr->pci->irqline); /* map the drives -- they don't all need to be enabled. */ n = 0; ctlr->rawdrive = kzmalloc(NCtlrdrv * sizeof(struct drive), 0); @@ -2246,6 +2242,8 @@ continue; printd("ahci: %s: ven_id=0x%04x, dev_id=0x%04x, didtype=%d\n", __func__, p->ven_id, p->dev_id, type); + /* TODO: hokey - can this not handle a 64 bit BAR, but the + * device might provide one? Or it just hokey code? */ if (p->bar[Abar].mmio_base32 == 0) continue; if (niactlr == NCtlr) { @@ -2260,17 +2258,13 @@ kref_init(&s->r, releasedrive, 1); qlock_init(&s->ql); qlock_init(&s->unitlock); - c->physio = p->bar[Abar].mmio_base32 & ~0xf; - c->mmio = - (void *)vmap_pmem_nocache(c->physio, p->bar[Abar].mmio_sz); spinlock_init_irqsave(&c->Lock); + c->mmio = pci_get_mmio_bar_kva(p, Abar); if (c->mmio == 0) { - printk("ahci: %s: address %#lX in use did=%#x\n", - Tname(c), c->physio, p->dev_id); + printk("ahci: %s: could not map bar %d did=%#x\n", + Tname(c), Abar, p->dev_id); continue; } - printk("sdiahci %s: Mapped %p/%d to %p\n", tname[type], - c->physio, p->bar[Abar].mmio_sz, c->mmio); c->pci = p; c->type = type; @@ -2285,10 +2279,8 @@ // ahcihbareset((void *)c->mmio); if (Intel(c) && iaahcimode(p) == -1) break; - if (nunit < 1) { - vunmap_vmem((uintptr_t)c->mmio, p->bar[Abar].mmio_sz); + if (nunit < 1) continue; - } n = newctlr(c, s, nunit); if (n < 0) continue; @@ -2543,7 +2535,7 @@ ctlr = sdev->ctlr; hba = ctlr->hba; - p = seprintf(p, e, "sd%c ahci port %#p: ", sdev->idno, ctlr->physio); + p = seprintf(p, e, "sd%c ahci: ", sdev->idno); cap = ahci_hba_read32(hba, HBA_CAP); has(Hs64a, "64a"); has(Hsalp, "alp");
diff --git a/kern/drivers/dma/ioat/init.c b/kern/drivers/dma/ioat/init.c index fda838f..ef5fb28 100644 --- a/kern/drivers/dma/ioat/init.c +++ b/kern/drivers/dma/ioat/init.c
@@ -1425,14 +1425,9 @@ if (err) return err; #else - /* TODO: Make a bar-mapping helper, similar to Linux. Given BAR id, - * vmap it, and put it's info in a table. */ void *bar; - bar = (void*)vmap_pmem_nocache(pdev->bar[0].mmio_base32 - ? pdev->bar[0].mmio_base32 : - pdev->bar[0].mmio_base64, - pdev->bar[0].mmio_sz); + bar = pci_get_mmio_bar_kva(pdev, 0); iomap = &bar; #endif
diff --git a/kern/drivers/net/ether82563.c b/kern/drivers/net/ether82563.c index 5a2e1c3..c827b04 100644 --- a/kern/drivers/net/ether82563.c +++ b/kern/drivers/net/ether82563.c
@@ -574,7 +574,6 @@ }; struct ctlr { - uintptr_t mmio_paddr; struct pci_device *pcidev; struct ctlr *next; struct ether *edev; @@ -1901,13 +1900,10 @@ { uint32_t data, r, adr; uint16_t sum; - uintptr_t mmio_paddr; struct pci_device *pcidev = ctlr->pcidev; struct flash f; - mmio_paddr = pcidev->bar[1].mmio_base32 ? pcidev->bar[1].mmio_base32 - : pcidev->bar[1].mmio_base64; - f.reg = (void *)vmap_pmem(mmio_paddr, pcidev->bar[1].mmio_sz); + f.reg = pci_get_mmio_bar_kva(pcidev, 1); if (f.reg == NULL) return -1; f.reg32 = (void *)f.reg; @@ -1925,7 +1921,6 @@ ctlr->eeprom[adr] = data; sum += data; } - vunmap_vmem((uintptr_t)f.reg, pcidev->bar[1].mmio_sz); return sum; } @@ -2015,7 +2010,6 @@ static void i82563pci(void) { int type; - uintptr_t io; void *mem; struct pci_device *p; struct ctlr *ctlr; @@ -2140,19 +2134,14 @@ break; } - io = p->bar[0].mmio_base32 ? p->bar[0].mmio_base32 - : p->bar[0].mmio_base64; - mem = (void *)vmap_pmem(io, p->bar[0].mmio_sz); + mem = pci_get_mmio_bar_kva(p, 0); if (mem == NULL) { - printd("%s: can't map %.8lux\n", tname[type], io); + printd("%s: can't map bar 0!\n", tname[type]); continue; } ctlr = kzmalloc(sizeof(struct ctlr), 0); - if (ctlr == NULL) { - vunmap_vmem((uintptr_t)mem, p->bar[0].mmio_sz); + if (ctlr == NULL) error(ENOMEM, "i82563pci: alloc for ctlr failed"); - } - ctlr->mmio_paddr = io; ctlr->rbsz = ctlrtab[type].mtu; ctlr->pcidev = p; ctlr->type = type; @@ -2169,7 +2158,6 @@ pci_set_bus_master(p); if (i82563reset(ctlr)) { - vunmap_vmem((uintptr_t)mem, p->bar[0].mmio_sz); kfree(ctlr); continue; } @@ -2194,14 +2182,15 @@ /* * Any adapter matches if no edev->port is supplied, - * otherwise the ports must match. + * otherwise the ports must match. Using the 'NIC', which is BAR0's + * unique KVA, for identification. */ for (ctlr = i82563ctlrhead; ctlr != NULL; ctlr = ctlr->next) { if (ctlr->active) continue; if (type != Iany && ctlr->type != type) continue; - if (edev->port == 0 || edev->port == ctlr->mmio_paddr) { + if (edev->port == 0 || edev->port == (uintptr_t)ctlr->nic) { ctlr->active = 1; break; } @@ -2212,7 +2201,7 @@ edev->ctlr = ctlr; strlcpy(edev->drv_name, "i82563", KNAMELEN); ctlr->edev = edev; /* point back to Ether* */ - edev->port = ctlr->mmio_paddr; + edev->port = (uintptr_t)ctlr->nic; edev->irq = ctlr->pcidev->irqline; edev->tbdf = pci_to_tbdf(ctlr->pcidev); edev->mbps = 1000;
diff --git a/kern/drivers/net/etherigbe.c b/kern/drivers/net/etherigbe.c index 13d5463..ba4b05d 100644 --- a/kern/drivers/net/etherigbe.c +++ b/kern/drivers/net/etherigbe.c
@@ -1912,7 +1912,6 @@ struct pci_device *pcidev; struct ctlr *ctlr; void *mem; - uintptr_t mmio_paddr; STAILQ_FOREACH (pcidev, &pci_devices, all_dev) { /* This checks that pcidev is a Network Controller for Ethernet @@ -1945,22 +1944,15 @@ pcidev->ven_id, pcidev->dev_id, pcidev->bus, pcidev->dev, pcidev->func); - mmio_paddr = pcidev->bar[0].mmio_base32 - ? pcidev->bar[0].mmio_base32 - : pcidev->bar[0].mmio_base64; - mem = (void *)vmap_pmem_nocache(mmio_paddr, - pcidev->bar[0].mmio_sz); + mem = pci_get_mmio_bar_kva(pcidev, 0); if (mem == NULL) { - printd("igbe: can't map %p\n", - pcidev->bar[0].mmio_base32); + printd("igbe: can't map BAR 0!\n"); continue; } pci_set_cacheline_size(pcidev); ctlr = kzmalloc(sizeof(struct ctlr), 0); - if (ctlr == NULL) { - vunmap_vmem((uintptr_t)mem, pcidev->bar[0].mmio_sz); + if (ctlr == NULL) error(ENOMEM, ERROR_FIXME); - } spinlock_init_irqsave(&ctlr->imlock); spinlock_init_irqsave(&ctlr->tlock); qlock_init(&ctlr->alock); @@ -1978,7 +1970,6 @@ if (igbereset(ctlr)) { kfree(ctlr); - vunmap_vmem((uintptr_t)mem, pcidev->bar[0].mmio_sz); continue; } pci_set_bus_master(pcidev);