From: kettenis Date: Tue, 21 Aug 2018 22:16:42 +0000 (+0000) Subject: Implement address translation. Makes I/O space access work. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=71fe361b81dce7ad056b3ae6a44b91153a3e1939;p=openbsd Implement address translation. Makes I/O space access work. --- diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c index fdd5f299363..a27f4fbd4b8 100644 --- a/sys/dev/fdt/dwpcie.c +++ b/sys/dev/fdt/dwpcie.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwpcie.c,v 1.9 2018/08/06 10:52:30 patrick Exp $ */ +/* $OpenBSD: dwpcie.c,v 1.10 2018/08/21 22:16:42 kettenis Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -39,6 +39,7 @@ #define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0) #define IATU_VIEWPORT 0x900 #define IATU_REGION_CTRL_1 0x904 +#define IATU_REGION_CTRL_1_TYPE_IO 2 #define IATU_REGION_CTRL_1_TYPE_CFG0 4 #define IATU_REGION_CTRL_1_TYPE_CFG1 5 #define IATU_REGION_CTRL_2 0x908 @@ -105,6 +106,9 @@ struct dwpcie_softc { struct dwpcie_range *sc_ranges; int sc_rangeslen; + struct bus_space sc_bus_iot; + struct bus_space sc_bus_memt; + struct arm64_pci_chipset sc_pc; struct extent *sc_busex; struct extent *sc_memex; @@ -161,6 +165,11 @@ void dwpcie_intr_disestablish(void *, void *); void *dwpcie_armada8k_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), void *, char *); +int dwpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int dwpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); + void dwpcie_attach(struct device *parent, struct device *self, void *aux) { @@ -289,13 +298,23 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux) extent_free(sc->sc_busex, bus_range[0], bus_range[1] - bus_range[0] + 1, EX_WAITOK); - /* Set up memory mapped I/O range. */ + /* Set up I/O and memory mapped I/O ranges. */ for (i = 0; i < nranges; i++) { + if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000) + extent_free(sc->sc_ioex, sc->sc_ranges[i].pci_base, + sc->sc_ranges[i].size, EX_WAITOK); if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) extent_free(sc->sc_memex, sc->sc_ranges[i].pci_base, - sc->sc_ranges[i].size, EX_NOWAIT); + sc->sc_ranges[i].size, EX_WAITOK); } + memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); + sc->sc_bus_iot.bus_private = sc; + sc->sc_bus_iot._space_map = dwpcie_bs_iomap; + memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); + sc->sc_bus_memt.bus_private = sc; + sc->sc_bus_memt._space_map = dwpcie_bs_memmap; + sc->sc_pc.pc_conf_v = sc; sc->sc_pc.pc_attach_hook = dwpcie_attach_hook; sc->sc_pc.pc_bus_maxdevs = dwpcie_bus_maxdevs; @@ -315,8 +334,8 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux) memset(&pba, 0, sizeof(pba)); pba.pba_busname = "pci"; - pba.pba_iot = faa->fa_iot; - pba.pba_memt = faa->fa_iot; + pba.pba_iot = &sc->sc_bus_iot; + pba.pba_memt = &sc->sc_bus_memt; pba.pba_dmat = faa->fa_dmat; pba.pba_pc = &sc->sc_pc; pba.pba_busex = sc->sc_busex; @@ -332,8 +351,8 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux) void dwpcie_armada8k_init(struct dwpcie_softc *sc) { + int i, timo, viewport = 0; uint32_t reg; - int timo; if (!dwpcie_armada8k_link_up(sc)) { reg = HREAD4(sc, PCIE_GLOBAL_CTRL); @@ -359,7 +378,7 @@ dwpcie_armada8k_init(struct dwpcie_softc *sc) HWRITE4(sc, PCIE_AWUSER, reg); /* Set up addres translation for PCI confg space. */ - HWRITE4(sc, IATU_VIEWPORT, 0); + HWRITE4(sc, IATU_VIEWPORT, viewport++); HWRITE4(sc, IATU_LWR_BASE_ADDR, sc->sc_cfg_addr); HWRITE4(sc, IATU_UPPER_BASE_ADDR, sc->sc_cfg_addr >> 32); HWRITE4(sc, IATU_LIMIT_ADDR, sc->sc_cfg_addr + sc->sc_cfg_size - 1); @@ -367,6 +386,25 @@ dwpcie_armada8k_init(struct dwpcie_softc *sc) HWRITE4(sc, IATU_UPPER_TARGET_ADDR, 0); HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN); + /* Set up address translation for I/O space. */ + for (i = 0; i < sc->sc_rangeslen; i++) { + if ((sc->sc_ranges[i].flags & 0x03000000) != 0x01000000) + continue; + HWRITE4(sc, IATU_VIEWPORT, viewport++); + HWRITE4(sc, IATU_LWR_BASE_ADDR, + sc->sc_ranges[i].phys_base); + HWRITE4(sc, IATU_UPPER_BASE_ADDR, + sc->sc_ranges[i].phys_base >> 32); + HWRITE4(sc, IATU_LIMIT_ADDR, + sc->sc_ranges[i].phys_base + sc->sc_ranges[i].size - 1); + HWRITE4(sc, IATU_LWR_TARGET_ADDR, + sc->sc_ranges[i].pci_base); + HWRITE4(sc, IATU_UPPER_TARGET_ADDR, + sc->sc_ranges[i].pci_base >> 32); + HWRITE4(sc, IATU_REGION_CTRL_1, IATU_REGION_CTRL_1_TYPE_IO); + HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN); + } + if (!dwpcie_armada8k_link_up(sc)) { reg = HREAD4(sc, PCIE_GLOBAL_CTRL); reg |= PCIE_GLOBAL_CTRL_APP_LTSSM_EN; @@ -631,3 +669,47 @@ dwpcie_intr_disestablish(void *v, void *cookie) { panic("%s", __func__); } + +int +dwpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + struct dwpcie_softc *sc = t->bus_private; + int i; + + for (i = 0; i < sc->sc_rangeslen; i++) { + uint64_t pci_start = sc->sc_ranges[i].pci_base; + uint64_t pci_end = pci_start + sc->sc_ranges[i].size; + uint64_t phys_start = sc->sc_ranges[i].phys_base; + + if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && + addr >= pci_start && addr + size <= pci_end) { + return bus_space_map(sc->sc_iot, + addr - pci_start + phys_start, size, flags, bshp); + } + } + + return ENXIO; +} + +int +dwpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + struct dwpcie_softc *sc = t->bus_private; + int i; + + for (i = 0; i < sc->sc_rangeslen; i++) { + uint64_t pci_start = sc->sc_ranges[i].pci_base; + uint64_t pci_end = pci_start + sc->sc_ranges[i].size; + uint64_t phys_start = sc->sc_ranges[i].phys_base; + + if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 && + addr >= pci_start && addr + size <= pci_end) { + return bus_space_map(sc->sc_iot, + addr - pci_start + phys_start, size, flags, bshp); + } + } + + return ENXIO; +}