From f4f3784297aefecc42f1bf75789e253dd9d6eb13 Mon Sep 17 00:00:00 2001 From: mmel Date: Sun, 17 Jul 2016 13:43:00 +0000 Subject: [PATCH] OFWPCI: Improve resource handling. - add new rman for prefetchable memory. Is used only if given 'ranges' property contains prefetchable memory range. - not all ranges in 'ranges' property are subject for rman's filling. Tegra for example, have two addition records which are used for 'pci 'register' -> 'assigned-address' -> 'ranges' machinery. Add sc_ranges_mask for masking not rman related ranges. - consistently pass unknown (not managed at this level) resources allocation/release/adjust requests to parent. MFC after: 3 weeks --- sys/dev/ofw/ofwpci.c | 216 ++++++++++++++++++++++++------------------- sys/dev/ofw/ofwpci.h | 3 + 2 files changed, 124 insertions(+), 95 deletions(-) diff --git a/sys/dev/ofw/ofwpci.c b/sys/dev/ofw/ofwpci.c index eae47437c9dc..88db7ceda06b 100644 --- a/sys/dev/ofw/ofwpci.c +++ b/sys/dev/ofw/ofwpci.c @@ -94,6 +94,7 @@ static phandle_t ofw_pci_get_node(device_t, device_t); * local methods */ static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *); +static struct rman *ofw_pci_get_rman(struct ofw_pci_softc *, int, u_int); /* * Driver methods. @@ -137,7 +138,7 @@ ofw_pci_init(device_t dev) phandle_t node; u_int32_t busrange[2]; struct ofw_pci_range *rp; - int error; + int i, error; struct ofw_pci_cell_info *cell_info; node = ofw_bus_get_node(dev); @@ -201,17 +202,27 @@ ofw_pci_init(device_t dev) } sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "PCI Memory"; + sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory"; error = rman_init(&sc->sc_mem_rman); if (error != 0) { device_printf(dev, "rman_init() failed. error = %d\n", error); goto out; } - for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && - rp->pci_hi != 0; rp++) { - error = 0; + sc->sc_pmem_rman.rm_type = RMAN_ARRAY; + sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory"; + error = rman_init(&sc->sc_pmem_rman); + if (error != 0) { + device_printf(dev, "rman_init() failed. error = %d\n", error); + goto out; + } + for (i = 0; i < sc->sc_nrange; i++) { + error = 0; + rp = sc->sc_range + i; + + if (sc->sc_range_mask & ((uint64_t)1 << i)) + continue; switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { case OFW_PCI_PHYS_HI_SPACE_CONFIG: break; @@ -221,8 +232,14 @@ ofw_pci_init(device_t dev) break; case OFW_PCI_PHYS_HI_SPACE_MEM32: case OFW_PCI_PHYS_HI_SPACE_MEM64: - error = rman_manage_region(&sc->sc_mem_rman, rp->pci, - rp->pci + rp->size - 1); + if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { + sc->sc_have_pmem = 1; + error = rman_manage_region(&sc->sc_pmem_rman, + rp->pci, rp->pci + rp->size - 1); + } else { + error = rman_manage_region(&sc->sc_mem_rman, + rp->pci, rp->pci + rp->size - 1); + } break; } @@ -244,6 +261,7 @@ out: free(sc->sc_range, M_DEVBUF); rman_fini(&sc->sc_io_rman); rman_fini(&sc->sc_mem_rman); + rman_fini(&sc->sc_pmem_rman); return (error); } @@ -385,28 +403,16 @@ ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, struct rman *rm; int needactivate; + needactivate = flags & RF_ACTIVE; flags &= ~RF_ACTIVE; sc = device_get_softc(bus); - switch (type) { - case SYS_RES_MEMORY: - rm = &sc->sc_mem_rman; - break; - - case SYS_RES_IOPORT: - rm = &sc->sc_io_rman; - break; - - case SYS_RES_IRQ: - return (bus_alloc_resource(bus, type, rid, start, end, count, - flags)); - - default: - device_printf(bus, "unknown resource request from %s\n", - device_get_nameunit(child)); - return (NULL); + rm = ofw_pci_get_rman(sc, type, flags); + if (rm == NULL) { + return (bus_generic_alloc_resource(bus, child, type, rid, + start, end, count, flags)); } rv = rman_reserve_resource(rm, start, end, count, flags, child); @@ -435,15 +441,24 @@ static int ofw_pci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { + struct ofw_pci_softc *sc; + struct rman *rm; + int error; + + sc = device_get_softc(bus); + + rm = ofw_pci_get_rman(sc, type, rman_get_flags(res)); + if (rm == NULL) { + return (bus_generic_release_resource(bus, child, type, rid, + res)); + } + KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); if (rman_get_flags(res) & RF_ACTIVE) { - int error; - error = bus_deactivate_resource(child, type, rid, res); if (error != 0) return (error); } - return (rman_release_resource(res)); } @@ -454,64 +469,63 @@ ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct ofw_pci_softc *sc; bus_space_handle_t handle; bus_space_tag_t tag; + struct ofw_pci_range *rp; + vm_paddr_t start; + int space; int rv; sc = device_get_softc(bus); - if (type == SYS_RES_IRQ) { - return (bus_activate_resource(bus, type, rid, res)); + if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) { + return (bus_generic_activate_resource(bus, child, type, rid, + res)); } - if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { - struct ofw_pci_range *rp; - vm_paddr_t start; - int space; - start = (vm_paddr_t)rman_get_start(res); + start = (vm_paddr_t)rman_get_start(res); - /* - * Map this through the ranges list - */ - for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && - rp->pci_hi != 0; rp++) { - if (start < rp->pci || start >= rp->pci + rp->size) - continue; + /* + * Map this through the ranges list + */ + for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && + rp->pci_hi != 0; rp++) { + if (start < rp->pci || start >= rp->pci + rp->size) + continue; - switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { - case OFW_PCI_PHYS_HI_SPACE_IO: - space = SYS_RES_IOPORT; - break; - case OFW_PCI_PHYS_HI_SPACE_MEM32: - case OFW_PCI_PHYS_HI_SPACE_MEM64: - space = SYS_RES_MEMORY; - break; - default: - space = -1; + switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { + case OFW_PCI_PHYS_HI_SPACE_IO: + space = SYS_RES_IOPORT; + break; + case OFW_PCI_PHYS_HI_SPACE_MEM32: + case OFW_PCI_PHYS_HI_SPACE_MEM64: + space = SYS_RES_MEMORY; + break; + default: + space = -1; } - if (type == space) { - start += (rp->host - rp->pci); - break; - } + if (type == space) { + start += (rp->host - rp->pci); + break; } - - if (bootverbose) - printf("ofw_pci mapdev: start %jx, len %jd\n", - (rman_res_t)start, rman_get_size(res)); - - tag = BUS_GET_BUS_TAG(child, child); - if (tag == NULL) - return (ENOMEM); - - rman_set_bustag(res, tag); - rv = bus_space_map(tag, start, - rman_get_size(res), 0, &handle); - if (rv != 0) - return (ENOMEM); - - rman_set_bushandle(res, handle); - rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */ } + if (bootverbose) + printf("ofw_pci mapdev: start %jx, len %jd\n", + (rman_res_t)start, rman_get_size(res)); + + tag = BUS_GET_BUS_TAG(child, child); + if (tag == NULL) + return (ENOMEM); + + rman_set_bustag(res, tag); + rv = bus_space_map(tag, start, + rman_get_size(res), 0, &handle); + if (rv != 0) + return (ENOMEM); + + rman_set_bushandle(res, handle); + rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */ + return (rman_activate_resource(res)); } @@ -528,17 +542,19 @@ static int ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { + struct ofw_pci_softc *sc; + vm_size_t psize; - /* - * If this is a memory resource, unmap it. - */ - if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { - u_int32_t psize; + sc = device_get_softc(bus); - psize = rman_get_size(res); - pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize); + if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) { + return (bus_generic_deactivate_resource(bus, child, type, rid, + res)); } + psize = rman_get_size(res); + pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize); + return (rman_deactivate_resource(res)); } @@ -550,24 +566,15 @@ ofw_pci_adjust_resource(device_t bus, device_t child, int type, struct ofw_pci_softc *sc; sc = device_get_softc(bus); + + rm = ofw_pci_get_rman(sc, type, rman_get_flags(res)); + if (rm == NULL) { + return (bus_generic_adjust_resource(bus, child, type, res, + start, end)); + } + KASSERT(rman_is_region_manager(res, rm), ("rman mismatch")); KASSERT(!(rman_get_flags(res) & RF_ACTIVE), ("active resources cannot be adjusted")); - if (rman_get_flags(res) & RF_ACTIVE) - return (EINVAL); - - switch (type) { - case SYS_RES_MEMORY: - rm = &sc->sc_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_io_rman; - break; - default: - return (ENXIO); - } - - if (!rman_is_region_manager(res, rm)) - return (EINVAL); return (rman_adjust_resource(res, start, end)); } @@ -629,3 +636,22 @@ ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges) free(base_ranges, M_DEVBUF); return (nranges); } + +static struct rman * +ofw_pci_get_rman(struct ofw_pci_softc *sc, int type, u_int flags) +{ + + switch (type) { + case SYS_RES_IOPORT: + return (&sc->sc_io_rman); + case SYS_RES_MEMORY: + if (sc->sc_have_pmem && (flags & RF_PREFETCHABLE)) + return (&sc->sc_pmem_rman); + else + return (&sc->sc_mem_rman); + default: + break; + } + + return (NULL); +} diff --git a/sys/dev/ofw/ofwpci.h b/sys/dev/ofw/ofwpci.h index e9825ad4f3c0..ef4e6daca4df 100644 --- a/sys/dev/ofw/ofwpci.h +++ b/sys/dev/ofw/ofwpci.h @@ -60,13 +60,16 @@ struct ofw_pci_softc { int sc_bus; int sc_initialized; int sc_quirks; + int sc_have_pmem; struct ofw_pci_range *sc_range; int sc_nrange; + uint64_t sc_range_mask; struct ofw_pci_cell_info *sc_cell_info; struct rman sc_io_rman; struct rman sc_mem_rman; + struct rman sc_pmem_rman; bus_space_tag_t sc_memt; bus_dma_tag_t sc_dmat;