Module Name: src Committed By: jmcneill Date: Tue Jun 25 22:23:39 UTC 2019
Modified Files: src/sys/arch/arm/acpi: acpipchb.c Log Message: Honour _CRS mem ranges and translation offsets instead of assuming 1:1 mappings. Tested on Overdrive 1000. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/acpi/acpipchb.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/acpi/acpipchb.c diff -u src/sys/arch/arm/acpi/acpipchb.c:1.8 src/sys/arch/arm/acpi/acpipchb.c:1.9 --- src/sys/arch/arm/acpi/acpipchb.c:1.8 Wed Jun 19 13:39:18 2019 +++ src/sys/arch/arm/acpi/acpipchb.c Tue Jun 25 22:23:39 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: acpipchb.c,v 1.8 2019/06/19 13:39:18 jmcneill Exp $ */ +/* $NetBSD: acpipchb.c,v 1.9 2019/06/25 22:23:39 jmcneill Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.8 2019/06/19 13:39:18 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.9 2019/06/25 22:23:39 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -59,12 +59,19 @@ __KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v #define PCIHOST_CACHELINE_SIZE arm_dcache_align -struct acpipchb_bus_space { - struct bus_space bs; +#define ACPIPCHB_MAX_RANGES 64 /* XXX arbitrary limit */ +struct acpipchb_bus_range { bus_addr_t min; bus_addr_t max; bus_addr_t offset; +}; + +struct acpipchb_bus_space { + struct bus_space bs; + + struct acpipchb_bus_range range[ACPIPCHB_MAX_RANGES]; + int nrange; int (*map)(void *, bus_addr_t, bus_size_t, int, bus_space_handle_t *); @@ -73,19 +80,22 @@ struct acpipchb_bus_space { struct acpipchb_softc { device_t sc_dev; + bus_space_tag_t sc_memt; + struct arm32_bus_dma_tag sc_dmat; struct acpi_pci_context sc_ap; ACPI_HANDLE sc_handle; ACPI_INTEGER sc_bus; + struct acpipchb_bus_space sc_pcimem_bst; struct acpipchb_bus_space sc_pciio_bst; }; static int acpipchb_match(device_t, cfdata_t, void *); static void acpipchb_attach(device_t, device_t, void *); -static void acpipchb_setup_pciio(struct acpipchb_softc *, struct pcibus_attach_args *); +static void acpipchb_setup_ranges(struct acpipchb_softc *, struct pcibus_attach_args *); CFATTACH_DECL_NEW(acpipchb, sizeof(struct acpipchb_softc), acpipchb_match, acpipchb_attach, NULL, NULL); @@ -115,6 +125,7 @@ acpipchb_attach(device_t parent, device_ ACPI_INTEGER cca, seg; sc->sc_dev = self; + sc->sc_memt = aa->aa_memt; sc->sc_handle = aa->aa_node->ad_handle; if (ACPI_FAILURE(acpi_eval_integer(sc->sc_handle, "_BBN", &sc->sc_bus))) @@ -143,9 +154,9 @@ acpipchb_attach(device_t parent, device_ } memset(&pba, 0, sizeof(pba)); - pba.pba_flags = aa->aa_pciflags; + pba.pba_flags = aa->aa_pciflags & ~(PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY); + pba.pba_memt = 0; pba.pba_iot = 0; - pba.pba_memt = aa->aa_memt; pba.pba_dmat = &sc->sc_dmat; #ifdef _PCI_HAVE_DMA64 pba.pba_dmat64 = &sc->sc_dmat; @@ -153,12 +164,12 @@ acpipchb_attach(device_t parent, device_ pba.pba_pc = &sc->sc_ap.ap_pc; pba.pba_bus = sc->sc_bus; - acpipchb_setup_pciio(sc, &pba); + acpipchb_setup_ranges(sc, &pba); config_found_ia(self, "pcibus", &pba, pcibusprint); } -struct acpipchb_setup_pciio_args { +struct acpipchb_setup_ranges_args { struct acpipchb_softc *sc; struct pcibus_attach_args *pba; }; @@ -168,61 +179,97 @@ acpipchb_bus_space_map(void *t, bus_addr bus_space_handle_t *bshp) { struct acpipchb_bus_space * const abs = t; + int i; - if (bpa < abs->min || bpa + size >= abs->max) + if (size == 0) return ERANGE; - return abs->map(t, bpa + abs->offset, size, flag, bshp); + for (i = 0; i < abs->nrange; i++) { + struct acpipchb_bus_range * const range = &abs->range[i]; + if (bpa >= range->min && bpa + size - 1 <= range->max) + return abs->map(t, bpa + range->offset, size, flag, bshp); + } + + return ERANGE; } static ACPI_STATUS -acpipchb_setup_pciio_cb(ACPI_RESOURCE *res, void *ctx) +acpipchb_setup_ranges_cb(ACPI_RESOURCE *res, void *ctx) { - struct acpipchb_setup_pciio_args * const args = ctx; + struct acpipchb_setup_ranges_args * const args = ctx; struct acpipchb_softc * const sc = args->sc; - struct acpipchb_bus_space * const abs = &sc->sc_pciio_bst; struct pcibus_attach_args *pba = args->pba; + struct acpipchb_bus_space *abs; + struct acpipchb_bus_range *range; + const char *range_type; + u_int pci_flags; if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) return AE_OK; - if (res->Data.Address.ResourceType != ACPI_IO_RANGE) + switch (res->Data.Address.ResourceType) { + case ACPI_IO_RANGE: + abs = &sc->sc_pciio_bst; + range_type = "I/O"; + pci_flags = PCI_FLAGS_IO_OKAY; + break; + case ACPI_MEMORY_RANGE: + abs = &sc->sc_pcimem_bst; + range_type = "MEM"; + pci_flags = PCI_FLAGS_MEM_OKAY; + break; + default: return AE_OK; + } - abs->bs = *pba->pba_memt; - abs->bs.bs_cookie = abs; - abs->map = abs->bs.bs_map; - abs->bs.bs_map = acpipchb_bus_space_map; + if (abs->nrange == ACPIPCHB_MAX_RANGES) { + aprint_error_dev(sc->sc_dev, + "maximum number of ranges reached, increase ACPIPCHB_MAX_RANGES\n"); + return AE_LIMIT; + } + range = &abs->range[abs->nrange]; switch (res->Type) { case ACPI_RESOURCE_TYPE_ADDRESS32: - abs->min = res->Data.Address32.Address.Minimum; - abs->max = res->Data.Address32.Address.Maximum; - abs->offset = res->Data.Address32.Address.TranslationOffset; + range->min = res->Data.Address32.Address.Minimum; + range->max = res->Data.Address32.Address.Maximum; + range->offset = res->Data.Address32.Address.TranslationOffset; break; case ACPI_RESOURCE_TYPE_ADDRESS64: - abs->min = res->Data.Address64.Address.Minimum; - abs->max = res->Data.Address64.Address.Maximum; - abs->offset = res->Data.Address64.Address.TranslationOffset; + range->min = res->Data.Address64.Address.Minimum; + range->max = res->Data.Address64.Address.Maximum; + range->offset = res->Data.Address64.Address.TranslationOffset; break; + default: + return AE_OK; } + abs->nrange++; - aprint_debug_dev(sc->sc_dev, "PCI I/O [%#lx-%#lx] -> %#lx\n", abs->min, abs->max, abs->offset); + aprint_debug_dev(sc->sc_dev, "PCI %s [%#lx-%#lx] -> %#lx\n", range_type, range->min, range->max, range->offset); - pba->pba_iot = &sc->sc_pciio_bst.bs; - pba->pba_flags |= PCI_FLAGS_IO_OKAY; + if ((pba->pba_flags & pci_flags) == 0) { + abs->bs = *sc->sc_memt; + abs->bs.bs_cookie = abs; + abs->map = abs->bs.bs_map; + abs->bs.bs_map = acpipchb_bus_space_map; + if ((pci_flags & PCI_FLAGS_IO_OKAY) != 0) + pba->pba_iot = &abs->bs; + else if ((pci_flags & PCI_FLAGS_MEM_OKAY) != 0) + pba->pba_memt = &abs->bs; + pba->pba_flags |= pci_flags; + } - return AE_LIMIT; + return AE_OK; } static void -acpipchb_setup_pciio(struct acpipchb_softc *sc, struct pcibus_attach_args *pba) +acpipchb_setup_ranges(struct acpipchb_softc *sc, struct pcibus_attach_args *pba) { - struct acpipchb_setup_pciio_args args; + struct acpipchb_setup_ranges_args args; args.sc = sc; args.pba = pba; - AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_pciio_cb, &args); + AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_ranges_cb, &args); }