svn commit: r340599 - in head/sys/dev: acpica pci
Jayachandran C.
jchandra at FreeBSD.org
Mon Nov 19 03:16:17 UTC 2018
Author: jchandra
Date: Mon Nov 19 03:16:16 2018
New Revision: 340599
URL: https://svnweb.freebsd.org/changeset/base/340599
Log:
acpica, pci_host_generic_acpi: redo pci_host_generic_acpi.c
This is a major update for pci_host_generic_acpi.c, the current
implementation has some gaps that are better fixed up in one go.
The changes are to:
* Follow x86 method of not adding PCI resources to PCI host bridge in
ACPI code. This has been moved to pci_host_generic_acpi.c, where we
walk thru its resources of the host bridge and add them.
* Fixup code in pci_host_generic_acpi.c to read all decoded ranges
and update the 'ranges' property. This allows us to share most of
the code with generic implementation (and the FDT one).
* Parse and setup IO ranges and bus ranges when walking the resources
above. Drop most of the changes related to this from acpica code.
* Add the ECAM memory area as mem resource 0. Implement the logic to
get the ECAM area from MCFG (using bus range which we now decode),
or from _CBA (using _BBN/bus range). Drop aarch64 ifdefs from acpica
code which did part of this.
* Switch resource activation to similar code as FDT implementation,
this can be moved into generic implementation in a later pass.
* Drop the mechanism of using the 7th bit of bus number as the domain,
this is not correct and will work only in very specific cases. Use
_SEG as PCI domain and use the bus ranges of the host bridge to
provide start bus number.
This commit should not make any functional change to dev/acpica/acpi.c
for other architectures, almost all the changes there are to revert
earlier additions in this file done for aarch64.
Reviewed by: andrew
Differential Revision: https://reviews.freebsd.org/D17791
Modified:
head/sys/dev/acpica/acpi.c
head/sys/dev/pci/pci_host_generic_acpi.c
Modified: head/sys/dev/acpica/acpi.c
==============================================================================
--- head/sys/dev/acpica/acpi.c Mon Nov 19 03:02:47 2018 (r340598)
+++ head/sys/dev/acpica/acpi.c Mon Nov 19 03:16:16 2018 (r340599)
@@ -179,9 +179,7 @@ static int acpi_child_location_str_method(device_t acd
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 @@ acpi_attach(device_t dev)
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 @@ acpi_set_resource(device_t dev, device_t child, int ty
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 @@ acpi_set_resource(device_t dev, device_t child, int ty
* 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 @@ acpi_set_resource(device_t dev, device_t child, int ty
AcpiOsFree(devinfo);
}
}
-#endif
#ifdef INTRNG
/* map with default for now */
@@ -1874,15 +1872,18 @@ acpi_isa_pnp_probe(device_t bus, device_t child, struc
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 @@ acpi_enable_pcie(void)
}
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_probe_child(ACPI_HANDLE handle, UINT32 level, voi
{
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 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, voi
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;
Modified: head/sys/dev/pci/pci_host_generic_acpi.c
==============================================================================
--- head/sys/dev/pci/pci_host_generic_acpi.c Mon Nov 19 03:02:47 2018 (r340598)
+++ head/sys/dev/pci/pci_host_generic_acpi.c Mon Nov 19 03:16:16 2018 (r340599)
@@ -63,9 +63,8 @@ __FBSDID("$FreeBSD$");
#include <machine/intr.h>
#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 int generic_pcie_acpi_probe(device_t dev);
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 @@ generic_pcie_acpi_probe(device_t dev)
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 @@ generic_pcie_acpi_read_ivar(device_t dev, device_t chi
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 @@ generic_pcie_acpi_route_interrupt(device_t bus, device
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 @@ generic_pcie_acpi_deactivate_resource(device_t dev, de
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 @@ static int
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),
More information about the svn-src-all
mailing list