diff options
| author | jmcneill <jmcneill@NetBSD.org> | 2022-10-14 22:10:15 +0000 |
|---|---|---|
| committer | jmcneill <jmcneill@NetBSD.org> | 2022-10-14 22:10:15 +0000 |
| commit | a48e4a98ffaa29f9bcbc0df8a67930425e3594e8 (patch) | |
| tree | 87268ba4d77f7c820b5bc398f144520b6f5b9fac /sys/dev/acpi | |
| parent | 9320afcd94a60725da9494092a3b385d6bc32b69 (diff) | |
Add a PCI resource manager and use it on Arm ACPI platforms.
The Arm ACPI code relied on PCI_NETBSD_CONFIGURE to configure devices that
were not enabled by system firmware. This is not safe to do unless the
firmware explicitly permits it using a device specific method defined in
the PCI firmware spec.
Introduce a new PCI resource manager that discovers what has already been
configured by firmware and allocates from the remaining space. This will
ensure that devices setup by firmware are untouched and only will program
BARs of devices that are not enabled at boot time.
The current implementation assumes that the parent PCI-PCI bridge's
are already configured. A worthwhile improvement in the future would be
to support programming windows for bridges that are not fully configured.
Diffstat (limited to 'sys/dev/acpi')
| -rw-r--r-- | sys/dev/acpi/acpi_mcfg.c | 161 | ||||
| -rw-r--r-- | sys/dev/acpi/acpi_mcfg.h | 5 | ||||
| -rw-r--r-- | sys/dev/acpi/acpi_pci.c | 69 | ||||
| -rw-r--r-- | sys/dev/acpi/acpi_pci.h | 3 |
4 files changed, 95 insertions, 143 deletions
diff --git a/sys/dev/acpi/acpi_mcfg.c b/sys/dev/acpi/acpi_mcfg.c index 4e10446f2ab..91841dc3102 100644 --- a/sys/dev/acpi/acpi_mcfg.c +++ b/sys/dev/acpi/acpi_mcfg.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_mcfg.c,v 1.25 2022/02/27 14:19:07 riastradh Exp $ */ +/* $NetBSD: acpi_mcfg.c,v 1.26 2022/10/14 22:10:15 jmcneill Exp $ */ /*- * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> @@ -28,7 +28,7 @@ #include "opt_pci.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.25 2022/02/27 14:19:07 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.26 2022/10/14 22:10:15 jmcneill Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -37,7 +37,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.25 2022/02/27 14:19:07 riastradh Exp #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> -#include <dev/pci/pciconf.h> +#include <dev/pci/pci_resource.h> #include <dev/pci/pcidevs.h> #include <dev/acpi/acpireg.h> @@ -687,16 +687,14 @@ out: return error; } -#ifdef PCI_NETBSD_CONFIGURE +#ifdef PCI_RESOURCE ACPI_STATUS acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) { - struct pciconf_resources *pcires = ctx; - int type; + struct pci_resource_info *pciinfo = ctx; bus_addr_t addr; bus_size_t size; - const char *s; - int error; + int type; if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && @@ -707,21 +705,25 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) return AE_OK; if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && - res->Data.Address.ResourceType != ACPI_IO_RANGE) + res->Data.Address.ResourceType != ACPI_IO_RANGE && + res->Data.Address.ResourceType != ACPI_BUS_NUMBER_RANGE) return AE_OK; if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) { - type = PCICONF_RESOURCE_PREFETCHABLE_MEM; - s = "prefetchable"; + type = PCI_RANGE_PMEM; } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) { - type = PCICONF_RESOURCE_MEM; - s = "non-prefetchable"; + if (res->Type == ACPI_RESOURCE_TYPE_ADDRESS64) { + type = PCI_RANGE_PMEM; + } else { + type = PCI_RANGE_MEM; + } + } else if (res->Data.Address.ResourceType == ACPI_BUS_NUMBER_RANGE) { + type = PCI_RANGE_BUS; } else { KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE); - type = PCICONF_RESOURCE_IO; - s = "i/o"; + type = PCI_RANGE_IO; } switch (res->Type) { @@ -730,7 +732,7 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n", res->Data.Address16.Address.Minimum, res->Data.Address16.Address.AddressLength, - s); + pci_resource_typename(type)); addr = res->Data.Address16.Address.Minimum; size = res->Data.Address16.Address.AddressLength; break; @@ -739,7 +741,7 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n", res->Data.Address32.Address.Minimum, res->Data.Address32.Address.AddressLength, - s); + pci_resource_typename(type)); addr = res->Data.Address32.Address.Minimum; size = res->Data.Address32.Address.AddressLength; break; @@ -748,7 +750,7 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n", res->Data.Address64.Address.Minimum, res->Data.Address64.Address.AddressLength, - s); + pci_resource_typename(type)); addr = res->Data.Address64.Address.Minimum; size = res->Data.Address64.Address.AddressLength; break; @@ -757,93 +759,108 @@ acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) return AE_OK; } - error = pciconf_resource_add(pcires, type, addr, size); + pciinfo->ranges[type].start = addr; + pciinfo->ranges[type].end = addr + size - 1; - return error == 0 ? AE_OK : AE_NO_MEMORY; + return AE_OK; } int acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, - int bus, int cacheline_size) + int bus, bool mapcfgspace) { - struct pciconf_resources *pcires; + struct pci_resource_info pciinfo; struct mcfg_segment *seg; struct mcfg_bus *mb; bus_space_handle_t bsh[256]; bool bsh_mapped[256]; - int error, boff, b, d, f; + int error, boff, b, d, f, endbus; bus_addr_t baddr; ACPI_STATUS rv; - seg = acpimcfg_get_segment(pc, bus); - if (seg == NULL) - return ENOENT; - - pcires = pciconf_resource_init(); + if (mapcfgspace) { + seg = acpimcfg_get_segment(pc, bus); + if (seg == NULL) { + return ENOENT; + } + endbus = seg->ms_bus_end; - /* - * Map config space for all possible busses and mark them valid during - * configuration so pci_configure_bus can access them through our chipset - * tag with acpimcfg_conf_read/write below. - */ - memset(bsh_mapped, 0, sizeof(bsh_mapped)); - for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { - boff = b - seg->ms_bus_start; - mb = &seg->ms_bus[boff]; - baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); - - /* Map extended configuration space of all dev/func. */ - error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, - &bsh[b]); - if (error != 0) - goto cleanup; - bsh_mapped[b] = true; - for (d = 0; d < 32; d++) { - for (f = 0; f < 8; f++) { - error = bus_space_subregion(seg->ms_bst, bsh[b], - EXTCONF_OFFSET(d, f, 0), PCI_EXTCONF_SIZE, - &mb->bsh[d][f]); - if (error != 0) - break; + /* + * Map config space for all possible busses and mark them valid + * during configuration so pci_configure_bus can access them + * through our chipset tag with acpimcfg_conf_read/write below. + */ + memset(bsh_mapped, 0, sizeof(bsh_mapped)); + for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { + boff = b - seg->ms_bus_start; + mb = &seg->ms_bus[boff]; + baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); + + /* Map extended configuration space of all dev/func. */ + error = bus_space_map(seg->ms_bst, baddr, + ACPIMCFG_SIZE_PER_BUS, 0, &bsh[b]); + if (error != 0) { + goto cleanup; + } + bsh_mapped[b] = true; + for (d = 0; d < 32; d++) { + for (f = 0; f < 8; f++) { + error = bus_space_subregion(seg->ms_bst, + bsh[b], EXTCONF_OFFSET(d, f, 0), + PCI_EXTCONF_SIZE, &mb->bsh[d][f]); + if (error != 0) { + break; + } + } + } + if (error != 0) { + goto cleanup; } - } - if (error != 0) - goto cleanup; - memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); + memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); + } + } else { + endbus = 255; } + memset(&pciinfo, 0, sizeof(pciinfo)); + pciinfo.pc = pc; + pciinfo.ranges[PCI_RANGE_BUS].start = bus; + pciinfo.ranges[PCI_RANGE_BUS].end = endbus; rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, - pcires); + &pciinfo); if (ACPI_FAILURE(rv)) { error = ENXIO; goto cleanup; } + error = 0; - error = pci_configure_bus(pc, pcires, bus, cacheline_size); + pci_resource_init(&pciinfo); cleanup: - /* - * Unmap config space for the segment's busses. Valid devices will be - * re-mapped later on by acpimcfg_map_bus. - */ - for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { - boff = b - seg->ms_bus_start; - mb = &seg->ms_bus[boff]; - memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); - - if (bsh_mapped[b]) - bus_space_unmap(seg->ms_bst, bsh[b], ACPIMCFG_SIZE_PER_BUS); + if (mapcfgspace) { + /* + * Unmap config space for the segment's busses. Valid devices + * will be re-mapped later on by acpimcfg_map_bus. + */ + for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { + boff = b - seg->ms_bus_start; + mb = &seg->ms_bus[boff]; + memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); + + if (bsh_mapped[b]) { + bus_space_unmap(seg->ms_bst, bsh[b], + ACPIMCFG_SIZE_PER_BUS); + } + } } - pciconf_resource_fini(pcires); - return error; } #else int acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, - int bus, int cacheline_size) + int bus, bool mapcfgspace) { return ENXIO; } diff --git a/sys/dev/acpi/acpi_mcfg.h b/sys/dev/acpi/acpi_mcfg.h index 33c4cda303e..cb02353963c 100644 --- a/sys/dev/acpi/acpi_mcfg.h +++ b/sys/dev/acpi/acpi_mcfg.h @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_mcfg.h,v 1.4 2021/08/07 21:19:15 jmcneill Exp $ */ +/* $NetBSD: acpi_mcfg.h,v 1.5 2022/10/14 22:10:15 jmcneill Exp $ */ /*- * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> @@ -32,7 +32,8 @@ struct acpimcfg_ops; void acpimcfg_probe(struct acpi_softc *); int acpimcfg_init(bus_space_tag_t, const struct acpimcfg_ops *); int acpimcfg_map_bus(device_t, pci_chipset_tag_t, int); -int acpimcfg_configure_bus(device_t, pci_chipset_tag_t, ACPI_HANDLE, int, int); +int acpimcfg_configure_bus(device_t, pci_chipset_tag_t, ACPI_HANDLE, int, + bool); ACPI_STATUS acpimcfg_configure_bus_cb(ACPI_RESOURCE *, void *); int acpimcfg_conf_read(pci_chipset_tag_t, pcitag_t, int, pcireg_t *); diff --git a/sys/dev/acpi/acpi_pci.c b/sys/dev/acpi/acpi_pci.c index c9382549aab..c3ede190ce0 100644 --- a/sys/dev/acpi/acpi_pci.c +++ b/sys/dev/acpi/acpi_pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_pci.c,v 1.36 2022/02/27 14:19:07 riastradh Exp $ */ +/* $NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $ */ /* * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.36 2022/02/27 14:19:07 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_pci.c,v 1.37 2022/10/14 22:10:15 jmcneill Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -59,14 +59,6 @@ static ACPI_STATUS acpi_pcidev_pciroot_bus_callback(ACPI_RESOURCE *, void *); /* - * UUID for _DSM control method, from PCI Firmware Specification. - */ -static UINT8 acpi_pci_dsm_uuid[ACPI_UUID_LENGTH] = { - 0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d, - 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d -}; - -/* * Regarding PCI Segment Groups (ACPI 4.0, p. 277): * * "The optional _SEG object is located under a PCI host bridge and @@ -486,63 +478,6 @@ acpi_pcidev_find_dev(struct acpi_devnode *ad) } /* - * acpi_pci_ignore_boot_config: - * - * Returns 1 if the operating system may ignore the boot configuration - * of PCI resources. - */ -ACPI_INTEGER -acpi_pci_ignore_boot_config(ACPI_HANDLE handle) -{ - ACPI_OBJECT *pobj = NULL; - ACPI_INTEGER ret; - - /* - * This one is a little confusing, but the result of - * evaluating _DSM #5 is: - * - * 0: The operating system may not ignore the boot configuration - * of PCI resources. - * - * 1: The operating system may ignore the boot configuration of - * PCI resources, and reconfigure or rebalance these resources - * in the hierarchy as required. - */ - - if (ACPI_FAILURE(acpi_dsm(handle, acpi_pci_dsm_uuid, - 1, 5, NULL, &pobj))) { - /* - * In the absence of _DSM #5, we may assume that the - * boot config can be ignored. - */ - return 1; - } - - /* - * ...and we default to "may ignore" in the event that the - * method returns nonsense. - */ - ret = 1; - - if (pobj != NULL) { - switch (pobj->Type) { - case ACPI_TYPE_INTEGER: - ret = pobj->Integer.Value; - break; - - case ACPI_TYPE_PACKAGE: - if (pobj->Package.Count == 1 && - pobj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) - ret = pobj->Package.Elements[0].Integer.Value; - break; - } - ACPI_FREE(pobj); - } - - return ret; -} - -/* * acpi_pci_bus_get_child_devhandle: * * Implements the "pci-bus-get-child-devhandle" device call for diff --git a/sys/dev/acpi/acpi_pci.h b/sys/dev/acpi/acpi_pci.h index c5c7bc7e827..b0f4c5c552b 100644 --- a/sys/dev/acpi/acpi_pci.h +++ b/sys/dev/acpi/acpi_pci.h @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_pci.h,v 1.12 2020/05/08 14:42:38 jmcneill Exp $ */ +/* $NetBSD: acpi_pci.h,v 1.13 2022/10/14 22:10:15 jmcneill Exp $ */ /* * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -42,6 +42,5 @@ pci_chipset_tag_t acpi_pcidev_get_tag(uint16_t, uint16_t, uint16_t, uint16_t); device_t acpi_pcidev_find_dev(struct acpi_devnode *); struct acpi_devnode *acpi_pciroot_find(uint16_t, uint16_t); -ACPI_INTEGER acpi_pci_ignore_boot_config(ACPI_HANDLE); #endif /* !_SYS_DEV_ACPI_ACPI_PCI_H */ |
