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; +}