Module Name:    src
Committed By:   jakllsch
Date:           Thu Feb 28 00:17:13 UTC 2019

Modified Files:
        src/sys/arch/arm/fdt: pcihost_fdt.c

Log Message:
Implement support for IO space, and better-handle both variants of MMIO space.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/fdt/pcihost_fdt.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/fdt/pcihost_fdt.c
diff -u src/sys/arch/arm/fdt/pcihost_fdt.c:1.6 src/sys/arch/arm/fdt/pcihost_fdt.c:1.7
--- src/sys/arch/arm/fdt/pcihost_fdt.c:1.6	Mon Nov 19 11:08:16 2018
+++ src/sys/arch/arm/fdt/pcihost_fdt.c	Thu Feb 28 00:17:13 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: pcihost_fdt.c,v 1.6 2018/11/19 11:08:16 jmcneill Exp $ */
+/* $NetBSD: pcihost_fdt.c,v 1.7 2019/02/28 00:17:13 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.6 2018/11/19 11:08:16 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pcihost_fdt.c,v 1.7 2019/02/28 00:17:13 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -81,6 +81,19 @@ enum pcihost_type {
 	PCIHOST_ECAM,
 };
 
+struct pcih_bus_space {
+	struct bus_space	bst;
+
+	int		(*map)(void *, bus_addr_t, bus_size_t,
+			      int, bus_space_handle_t *);
+	struct space_range {
+		bus_addr_t	bpci;
+		bus_addr_t	bbus;
+		bus_size_t	size;
+	} 			ranges[4];
+	size_t			nranges;
+};
+
 struct pcihost_softc {
 	device_t		sc_dev;
 	bus_dma_tag_t		sc_dmat;
@@ -95,6 +108,9 @@ struct pcihost_softc {
 	u_int			sc_bus_max;
 
 	struct arm32_pci_chipset sc_pc;
+
+	struct pcih_bus_space	sc_io;
+	struct pcih_bus_space	sc_mem;
 };
 
 static int	pcihost_match(device_t, cfdata_t, void *);
@@ -126,6 +142,9 @@ static void *	pcihost_intr_establish(voi
 					 const char *);
 static void	pcihost_intr_disestablish(void *, void *);
 
+static int	pcihost_bus_space_map(void *, bus_addr_t, bus_size_t,
+		int, bus_space_handle_t *);
+
 CFATTACH_DECL_NEW(pcihost_fdt, sizeof(struct pcihost_softc),
 	pcihost_match, pcihost_attach, NULL, NULL);
 
@@ -203,6 +222,7 @@ pcihost_attach(device_t parent, device_t
 	pba.pba_flags = PCI_FLAGS_MRL_OKAY |
 			PCI_FLAGS_MRM_OKAY |
 			PCI_FLAGS_MWI_OKAY |
+			PCI_FLAGS_IO_OKAY |
 			PCI_FLAGS_MEM_OKAY;
 #ifdef __HAVE_PCI_MSI_MSIX
 	if (sc->sc_type == PCIHOST_ECAM) {
@@ -210,8 +230,8 @@ pcihost_attach(device_t parent, device_t
 				 PCI_FLAGS_MSIX_OKAY;
 	}
 #endif
-	pba.pba_iot = 0;
-	pba.pba_memt = sc->sc_bst;
+	pba.pba_iot = &sc->sc_io.bst;
+	pba.pba_memt = &sc->sc_mem.bst;
 	pba.pba_dmat = sc->sc_dmat;
 #ifdef _PCI_HAVE_DMA64
 	pba.pba_dmat64 = sc->sc_dmat;
@@ -253,6 +273,18 @@ pcihost_config(struct pcihost_softc *sc)
 	u_int probe_only;
 	int error, len;
 
+	struct pcih_bus_space * const pibs = &sc->sc_io;
+	pibs->bst = *sc->sc_bst;
+	pibs->bst.bs_cookie = pibs;
+	pibs->map = pibs->bst.bs_map;
+	pibs->bst.bs_map = pcihost_bus_space_map;
+
+	struct pcih_bus_space * const pmbs = &sc->sc_mem;
+	pmbs->bst = *sc->sc_bst;
+	pmbs->bst.bs_cookie = pmbs;
+	pmbs->map = pmbs->bst.bs_map;
+	pmbs->bst.bs_map = pcihost_bus_space_map;
+
 	/*
 	 * If this flag is set, skip configuration of the PCI bus and use existing config.
 	 */
@@ -276,47 +308,73 @@ pcihost_config(struct pcihost_softc *sc)
 	 */
 	while (len >= 28) {
 		const uint32_t phys_hi = be32dec(&ranges[0]);
+		const uint64_t bus_phys = be64dec(&ranges[1]);
 		const uint64_t cpu_phys = be64dec(&ranges[3]);
 		const uint64_t size = be64dec(&ranges[5]);
 
+		len -= 28;
+		ranges += 7;
+
+		const bool is64 = (__SHIFTOUT(phys_hi, PHYS_HI_SPACE) ==
+		    PHYS_HI_SPACE_MEM64) ? true : false;
 		switch (__SHIFTOUT(phys_hi, PHYS_HI_SPACE)) {
 		case PHYS_HI_SPACE_IO:
+			if (pibs->nranges + 1 >= __arraycount(pibs->ranges)) {
+				aprint_error_dev(sc->sc_dev, "too many IO ranges\n");
+				continue;
+			}
+			pibs->ranges[pibs->nranges].bpci = bus_phys;
+			pibs->ranges[pibs->nranges].bbus = cpu_phys;
+			pibs->ranges[pibs->nranges].size = size;
+			++pibs->nranges;
 			if (ioext != NULL) {
 				aprint_error_dev(sc->sc_dev, "ignoring duplicate IO space range\n");
 				continue;
 			}
-			ioext = extent_create("pciio", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
+			ioext = extent_create("pciio", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
 			aprint_verbose_dev(sc->sc_dev,
-			    "I/O memory @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
-			    cpu_phys, size);
+			    "IO: 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
+			    bus_phys, size, cpu_phys);
+			/* reserve a PC-like legacy IO ports range, perhaps for access to VGA registers */
+			if (bus_phys == 0 && size >= 0x10000)
+				extent_alloc_region(ioext, 0, 0x1000, EX_WAITOK);
 			break;
+		case PHYS_HI_SPACE_MEM64:
+			/* FALLTHROUGH */
 		case PHYS_HI_SPACE_MEM32:
-			if ((phys_hi & PHYS_HI_PREFETCH) != 0) {
+			if (pmbs->nranges + 1 >= __arraycount(pmbs->ranges)) {
+				aprint_error_dev(sc->sc_dev, "too many mem ranges\n");
+				continue;
+			}
+			/* both pmem and mem spaces are in the same tag */
+			pmbs->ranges[pmbs->nranges].bpci = bus_phys;
+			pmbs->ranges[pmbs->nranges].bbus = cpu_phys;
+			pmbs->ranges[pmbs->nranges].size = size;
+			++pmbs->nranges;
+			if ((phys_hi & PHYS_HI_PREFETCH) != 0 ||
+			    __SHIFTOUT(phys_hi, PHYS_HI_SPACE) == PHYS_HI_SPACE_MEM64) {
 				if (pmemext != NULL) {
 					aprint_error_dev(sc->sc_dev, "ignoring duplicate mem (prefetchable) range\n");
 					continue;
 				}
-				pmemext = extent_create("pcipmem", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
+				pmemext = extent_create("pcipmem", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
 				aprint_verbose_dev(sc->sc_dev,
-				    "32-bit MMIO (prefetchable) @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
-				    cpu_phys, size);
+				    "MMIO (%d-bit prefetchable): 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
+				    is64 ? 64 : 32, bus_phys, size, cpu_phys);
 			} else {
 				if (memext != NULL) {
 					aprint_error_dev(sc->sc_dev, "ignoring duplicate mem (non-prefetchable) range\n");
 					continue;
 				}
-				memext = extent_create("pcimem", cpu_phys, cpu_phys + size - 1, NULL, 0, EX_NOWAIT);
+				memext = extent_create("pcimem", bus_phys, bus_phys + size - 1, NULL, 0, EX_NOWAIT);
 				aprint_verbose_dev(sc->sc_dev,
-				    "32-bit MMIO (non-prefetchable) @ 0x%" PRIx64 " size 0x%" PRIx64 "\n",
-				    cpu_phys, size);
+				    "MMIO (%d-bit non-prefetchable): 0x%" PRIx64 "+0x%" PRIx64 "@0x%" PRIx64 "\n",
+				    is64 ? 64 : 32, bus_phys, size, cpu_phys);
 			}
 			break;
 		default:
 			break;
 		}
-
-		len -= 28;
-		ranges += 7;
 	}
 
 	error = pci_configure_bus(&sc->sc_pc, ioext, memext, pmemext, sc->sc_bus_min, PCIHOST_CACHELINE_SIZE);
@@ -597,3 +655,20 @@ pcihost_intr_disestablish(void *v, void 
 
 	fdtbus_intr_disestablish(sc->sc_phandle, vih);
 }
+
+static int
+pcihost_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
+    bus_space_handle_t *bshp)
+{
+	struct pcih_bus_space * const pbs = t;
+
+	for (size_t i = 0; i < pbs->nranges; i++) {
+		const bus_addr_t rmin = pbs->ranges[i].bpci;
+		const bus_addr_t rmax = pbs->ranges[i].bpci - 1 + pbs->ranges[i].size;
+		if ((bpa >= rmin) && ((bpa - 1 + size) <= rmax)) {
+			return pbs->map(t, bpa - pbs->ranges[i].bpci + pbs->ranges[i].bbus, size, flag, bshp);
+		}
+	}
+
+	return ERANGE;
+}

Reply via email to