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