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);