Index: head/sys/dev/acpica/acpi.c =================================================================== --- head/sys/dev/acpica/acpi.c +++ head/sys/dev/acpica/acpi.c @@ -179,9 +179,7 @@ char *buf, size_t buflen); static int acpi_child_pnpinfo_str_method(device_t acdev, device_t child, char *buf, size_t buflen); -#if defined(__i386__) || defined(__amd64__) static void acpi_enable_pcie(void); -#endif static void acpi_hint_device_unit(device_t acdev, device_t child, const char *name, int *unitp); static void acpi_reset_interfaces(device_t dev); @@ -502,10 +500,8 @@ goto out; } -#if defined(__i386__) || defined(__amd64__) /* Handle MCFG table if present. */ acpi_enable_pcie(); -#endif /* * Note that some systems (specifically, those with namespace evaluation @@ -1286,11 +1282,10 @@ struct acpi_softc *sc = device_get_softc(dev); struct acpi_device *ad = device_get_ivars(child); struct resource_list *rl = &ad->ad_rl; -#if defined(__i386__) || defined(__amd64__) ACPI_DEVICE_INFO *devinfo; -#endif rman_res_t end; - + int allow; + /* Ignore IRQ resources for PCI link devices. */ if (type == SYS_RES_IRQ && ACPI_ID_PROBE(dev, child, pcilink_ids, NULL) <= 0) @@ -1305,11 +1300,15 @@ * x86 of a PCI bridge claiming the I/O ports used for PCI config * access. */ -#if defined(__i386__) || defined(__amd64__) if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) { if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) { - if (!(type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT)) { +#if defined(__i386__) || defined(__amd64__) + allow = (type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT); +#else + allow = 0; +#endif + if (!allow) { AcpiOsFree(devinfo); return (0); } @@ -1317,7 +1316,6 @@ AcpiOsFree(devinfo); } } -#endif #ifdef INTRNG /* map with default for now */ @@ -1874,15 +1872,18 @@ return_VALUE (result); } -#if defined(__i386__) || defined(__amd64__) /* * Look for a MCFG table. If it is present, use the settings for * domain (segment) 0 to setup PCI config space access via the memory * map. + * + * On non-x86 architectures (arm64 for now), this will be done from the + * PCI host bridge driver. */ static void acpi_enable_pcie(void) { +#if defined(__i386__) || defined(__amd64__) ACPI_TABLE_HEADER *hdr; ACPI_MCFG_ALLOCATION *alloc, *end; ACPI_STATUS status; @@ -1901,32 +1902,9 @@ } alloc++; } +#endif } -#elif defined(__aarch64__) -static void -acpi_enable_pcie(device_t child, int segment) -{ - ACPI_TABLE_HEADER *hdr; - ACPI_MCFG_ALLOCATION *alloc, *end; - ACPI_STATUS status; - status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr); - if (ACPI_FAILURE(status)) - return; - - end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length); - alloc = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1); - while (alloc < end) { - if (alloc->PciSegment == segment) { - bus_set_resource(child, SYS_RES_MEMORY, 0, - alloc->Address, 0x10000000); - return; - } - alloc++; - } -} -#endif - /* * Scan all of the ACPI namespace and attach child devices. * @@ -2016,9 +1994,6 @@ { ACPI_DEVICE_INFO *devinfo; struct acpi_device *ad; -#ifdef __aarch64__ - int segment; -#endif struct acpi_prw_data prw; ACPI_OBJECT_TYPE type; ACPI_HANDLE h; @@ -2121,13 +2096,6 @@ ad->ad_cls_class = strtoul(devinfo->ClassCode.String, NULL, 16); } -#ifdef __aarch64__ - if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) { - if (ACPI_SUCCESS(acpi_GetInteger(handle, "_SEG", &segment))) { - acpi_enable_pcie(child, segment); - } - } -#endif AcpiOsFree(devinfo); } break; Index: head/sys/dev/pci/pci_host_generic_acpi.c =================================================================== --- head/sys/dev/pci/pci_host_generic_acpi.c +++ head/sys/dev/pci/pci_host_generic_acpi.c @@ -63,9 +63,8 @@ #include #include "pcib_if.h" +#include "acpi_bus_if.h" -int pci_host_generic_acpi_attach(device_t); - /* Assembling ECAM Configuration Address */ #define PCIE_BUS_SHIFT 20 #define PCIE_SLOT_SHIFT 15 @@ -100,6 +99,9 @@ static ACPI_STATUS pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *, void *); static int generic_pcie_acpi_read_ivar(device_t, device_t, int, uintptr_t *); +/* + * generic_pcie_acpi_probe - look for root bridge flag + */ static int generic_pcie_acpi_probe(device_t dev) { @@ -119,81 +121,201 @@ return (BUS_PROBE_GENERIC); } -int -pci_host_generic_acpi_attach(device_t dev) +/* + * pci_host_generic_acpi_parse_resource - parse PCI memory, IO and bus spaces + * 'produced' by this bridge + */ +static ACPI_STATUS +pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *res, void *arg) { + device_t dev = (device_t)arg; struct generic_pcie_acpi_softc *sc; + struct rman *rm; + rman_res_t min, max, off; + int r; + + rm = NULL; + sc = device_get_softc(dev); + r = sc->base.nranges; + switch (res->Type) { + case ACPI_RESOURCE_TYPE_ADDRESS16: + min = res->Data.Address16.Address.Minimum; + max = res->Data.Address16.Address.Maximum; + break; + case ACPI_RESOURCE_TYPE_ADDRESS32: + min = res->Data.Address32.Address.Minimum; + max = res->Data.Address32.Address.Maximum; + off = res->Data.Address32.Address.TranslationOffset; + break; + case ACPI_RESOURCE_TYPE_ADDRESS64: + if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE) + break; + min = res->Data.Address64.Address.Minimum; + max = res->Data.Address64.Address.Maximum; + off = res->Data.Address64.Address.TranslationOffset; + break; + default: + return (AE_OK); + } + + /* Save detected ranges */ + if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE || + res->Data.Address.ResourceType == ACPI_IO_RANGE) { + sc->base.ranges[r].pci_base = min; + sc->base.ranges[r].phys_base = min + off; + sc->base.ranges[r].size = max - min + 1; + if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) + sc->base.ranges[r].flags |= FLAG_MEM; + else if (res->Data.Address.ResourceType == ACPI_IO_RANGE) + sc->base.ranges[r].flags |= FLAG_IO; + sc->base.nranges++; + } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) { + sc->base.bus_start = min; + sc->base.bus_end = max; + } + return (AE_OK); +} + +static int +pci_host_acpi_get_ecam_resource(device_t dev) +{ + struct generic_pcie_acpi_softc *sc; + struct acpi_device *ad; + struct resource_list *rl; + ACPI_TABLE_HEADER *hdr; + ACPI_MCFG_ALLOCATION *mcfg_entry, *mcfg_end; ACPI_HANDLE handle; ACPI_STATUS status; - int error, bus_start; + rman_res_t base, start, end; + int found, val; sc = device_get_softc(dev); + handle = acpi_get_handle(dev); + /* Try MCFG first */ + status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr); + if (ACPI_SUCCESS(status)) { + found = FALSE; + mcfg_end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length); + mcfg_entry = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1); + while (mcfg_entry < mcfg_end && !found) { + if (mcfg_entry->PciSegment == sc->base.ecam && + mcfg_entry->StartBusNumber <= sc->base.bus_start && + mcfg_entry->EndBusNumber >= sc->base.bus_start) + found = TRUE; + else + mcfg_entry++; + } + if (found) { + if (mcfg_entry->EndBusNumber < sc->base.bus_end) { + device_printf(dev, "bus end mismatch! expected %d found %d.\n", + sc->base.bus_end, (int)mcfg_entry->EndBusNumber); + sc->base.bus_end = mcfg_entry->EndBusNumber; + } + base = mcfg_entry->Address; + } else { + device_printf(dev, "MCFG exists, but does not have bus %d-%d\n", + sc->base.bus_start, sc->base.bus_end); + return (ENXIO); + } + } else { + status = acpi_GetInteger(handle, "_CBA", &val); + if (ACPI_SUCCESS(status)) + base = val; + else + return (ENXIO); + } + + /* add as MEM rid 0 */ + ad = device_get_ivars(dev); + rl = &ad->ad_rl; + start = base + (sc->base.bus_start << PCIE_BUS_SHIFT); + end = base + ((sc->base.bus_end + 1) << PCIE_BUS_SHIFT) - 1; + resource_list_add(rl, SYS_RES_MEMORY, 0, start, end, end - start + 1); + if (bootverbose) + device_printf(dev, "ECAM for bus %d-%d at mem %jx-%jx\n", + sc->base.bus_start, sc->base.bus_end, start, end); + return (0); +} + +static int +pci_host_generic_acpi_attach(device_t dev) +{ + struct generic_pcie_acpi_softc *sc; + ACPI_HANDLE handle; + uint64_t phys_base; + uint64_t pci_base; + uint64_t size; + ACPI_STATUS status; + int error; + int tuple; + + sc = device_get_softc(dev); handle = acpi_get_handle(dev); + + /* Get Start bus number for the PCI host bus is from _BBN method */ + status = acpi_GetInteger(handle, "_BBN", &sc->base.bus_start); + if (ACPI_FAILURE(status)) { + device_printf(dev, "No _BBN, using start bus 0\n"); + sc->base.bus_start = 0; + } + sc->base.bus_end = 255; + + /* Get PCI Segment (domain) needed for MCFG lookup */ + status = acpi_GetInteger(handle, "_SEG", &sc->base.ecam); + if (ACPI_FAILURE(status)) { + device_printf(dev, "No _SEG for PCI Bus, using segment 0\n"); + sc->base.ecam = 0; + } + + /* Bus decode ranges */ + status = AcpiWalkResources(handle, "_CRS", + pci_host_generic_acpi_parse_resource, (void *)dev); + if (ACPI_FAILURE(status)) + return (ENXIO); + + /* Coherency attribute */ if (ACPI_FAILURE(acpi_GetInteger(handle, "_CCA", &sc->base.coherent))) sc->base.coherent = 0; if (bootverbose) device_printf(dev, "Bus is%s cache-coherent\n", sc->base.coherent ? "" : " not"); - if (!ACPI_FAILURE(acpi_GetInteger(handle, "_BBN", &bus_start))) { - sc->base.ecam = bus_start >> 7; - sc->base.bus_start = bus_start & 0x7F; - } else { - sc->base.ecam = 0; - sc->base.bus_start = 0; - } - sc->base.bus_end = 0xFF; - + /* add config space resource */ + pci_host_acpi_get_ecam_resource(dev); acpi_pcib_fetch_prt(dev, &sc->ap_prt); error = pci_host_generic_core_attach(dev); if (error != 0) return (error); - status = AcpiWalkResources(handle, "_CRS", - pci_host_generic_acpi_parse_resource, (void *)dev); + for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) { + phys_base = sc->base.ranges[tuple].phys_base; + pci_base = sc->base.ranges[tuple].pci_base; + size = sc->base.ranges[tuple].size; + if (phys_base == 0 || size == 0) + continue; /* empty range element */ + if (sc->base.ranges[tuple].flags & FLAG_MEM) { + error = rman_manage_region(&sc->base.mem_rman, + phys_base, phys_base + size - 1); + } else if (sc->base.ranges[tuple].flags & FLAG_IO) { + error = rman_manage_region(&sc->base.io_rman, + pci_base + PCI_IO_WINDOW_OFFSET, + pci_base + PCI_IO_WINDOW_OFFSET + size - 1); + } else + continue; + if (error) { + device_printf(dev, "rman_manage_region() failed." + "error = %d\n", error); + rman_fini(&sc->base.mem_rman); + return (error); + } + } - if (ACPI_FAILURE(status)) - return (ENXIO); - device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } -static ACPI_STATUS -pci_host_generic_acpi_parse_resource(ACPI_RESOURCE *res, void *arg) -{ - device_t dev = (device_t)arg; - struct generic_pcie_acpi_softc *sc; - rman_res_t min, max; - int error; - - switch (res->Type) { - case ACPI_RESOURCE_TYPE_ADDRESS32: - min = (rman_res_t)res->Data.Address32.Address.Minimum; - max = (rman_res_t)res->Data.Address32.Address.Maximum; - break; - case ACPI_RESOURCE_TYPE_ADDRESS64: - min = (rman_res_t)res->Data.Address64.Address.Minimum; - max = (rman_res_t)res->Data.Address64.Address.Maximum; - break; - default: - return (AE_OK); - } - - sc = device_get_softc(dev); - - error = rman_manage_region(&sc->base.mem_rman, min, max); - if (error) { - device_printf(dev, "unable to allocate %lx-%lx range\n", min, max); - return (AE_NOT_FOUND); - } - device_printf(dev, "allocating %lx-%lx range\n", min, max); - - return (AE_OK); -} - static int generic_pcie_acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) @@ -203,7 +325,7 @@ sc = device_get_softc(dev); if (index == PCIB_IVAR_BUS) { - *result = sc->base.ecam * 0x80 + sc->base.bus_start; + *result = sc->base.bus_start; return (0); } @@ -223,50 +345,62 @@ struct generic_pcie_acpi_softc *sc; sc = device_get_softc(bus); - return (acpi_pcib_route_interrupt(bus, dev, pin, &sc->ap_prt)); } -static struct resource * -pci_host_generic_acpi_alloc_resource(device_t dev, device_t child, int type, - int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) -{ - struct resource *res = NULL; - -#if defined(NEW_PCIB) && defined(PCI_RES_BUS) - struct generic_pcie_acpi_softc *sc; - - if (type == PCI_RES_BUS) { - sc = device_get_softc(dev); - return (pci_domain_alloc_bus(sc->base.ecam, child, rid, start, - end, count, flags)); - } -#endif - - if (type == SYS_RES_MEMORY) - res = pci_host_generic_core_alloc_resource(dev, child, type, - rid, start, end, count, flags); - - if (res == NULL) - res = bus_generic_alloc_resource(dev, child, type, rid, start, end, - count, flags); - - return (res); -} - +/* + * Follow logic of FDT activate + */ static int generic_pcie_acpi_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct generic_pcie_acpi_softc *sc; + uint64_t phys_base; + uint64_t pci_base; + uint64_t size; + int found; int res; + int i; sc = device_get_softc(dev); if ((res = rman_activate_resource(r)) != 0) return (res); - res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid,r); + switch (type) { + case SYS_RES_IOPORT: + found = 0; + for (i = 0; i < MAX_RANGES_TUPLES; i++) { + pci_base = sc->base.ranges[i].pci_base; + phys_base = sc->base.ranges[i].phys_base; + size = sc->base.ranges[i].size; + + if ((rid > pci_base) && (rid < (pci_base + size))) { + found = 1; + break; + } + } + if (found) { + rman_set_start(r, rman_get_start(r) + phys_base); + rman_set_end(r, rman_get_end(r) + phys_base); + res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r); + } else { + device_printf(dev, + "Failed to activate IOPORT resource\n"); + res = 0; + } + break; + case SYS_RES_MEMORY: + case SYS_RES_IRQ: + res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, + type, rid, r); + break; + default: + break; + } + return (res); } @@ -279,8 +413,17 @@ if ((res = rman_deactivate_resource(r)) != 0) return (res); - res = BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), child, type, - rid, r); + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + case SYS_RES_IRQ: + res = BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), child, + type, rid, r); + break; + default: + break; + } + return (res); } @@ -347,30 +490,25 @@ generic_pcie_acpi_get_id(device_t pci, device_t child, enum pci_id_type type, uintptr_t *id) { - struct generic_pcie_acpi_softc *sc; - int err; - /* Use the PCI RID to find the MSI ID */ - if (type == PCI_ID_MSI) { - sc = device_get_softc(pci); - type = PCI_ID_RID; - err = pcib_get_id(pci, child, type, id); - if (err != 0) - return (err); - *id |= sc->base.ecam << 16; - return (0); - } - - return (pcib_get_id(pci, child, type, id)); + /* + * Use the PCI RID to find the MSI ID for now, we support only 1:1 + * mapping + * + * On aarch64, more complex mapping would come from IORT table + */ + if (type == PCI_ID_MSI) + return (pcib_get_id(pci, child, PCI_ID_RID, id)); + else + return (pcib_get_id(pci, child, type, id)); } static device_method_t generic_pcie_acpi_methods[] = { DEVMETHOD(device_probe, generic_pcie_acpi_probe), DEVMETHOD(device_attach, pci_host_generic_acpi_attach), - DEVMETHOD(bus_alloc_resource, pci_host_generic_acpi_alloc_resource), - DEVMETHOD(bus_activate_resource, generic_pcie_acpi_activate_resource), - DEVMETHOD(bus_deactivate_resource, generic_pcie_acpi_deactivate_resource), DEVMETHOD(bus_read_ivar, generic_pcie_acpi_read_ivar), + DEVMETHOD(bus_activate_resource, generic_pcie_acpi_activate_resource), + DEVMETHOD(bus_deactivate_resource,generic_pcie_acpi_deactivate_resource), /* pcib interface */ DEVMETHOD(pcib_route_interrupt, generic_pcie_acpi_route_interrupt),