Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add support for Arm N1 SDP PCIe host controller.
details: https://anonhg.NetBSD.org/src/rev/50c1318caa36
branches: trunk
changeset: 968460:50c1318caa36
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Fri Jan 17 17:06:32 2020 +0000
description:
Add support for Arm N1 SDP PCIe host controller.
The N1 SDP has a few bugs that we need to work around:
- PCIe root port config space lives in a non-standard location.
- Access to PCIe config space of devices that do not exist results in
an sync SError. Firmware creates a "known devices" table at a fixed
physical address that we use to filter PCI conf access to only known
devices.
This change splits the Arm ACPI PCI quirks into separate files for each
host controller, and allows per-segment quirks to be applied.
These changes exposed some bugs in the MI ACPI layer related to
multi-segment support. The MI ACPI PCI code was using a shared PCI
chipset tag to access devices, and these accesses can happen before our
PCI host bridge drivers are attached! The global chipset tag is now gone,
and an MD callback can provide a custom tag on a per-segment basis.
diffstat:
sys/arch/arm/acpi/acpi_pci_graviton.c | 144 +++++++++++++++++++++++++
sys/arch/arm/acpi/acpi_pci_machdep.c | 85 +++++++++++++-
sys/arch/arm/acpi/acpi_pci_machdep.h | 17 ++-
sys/arch/arm/acpi/acpi_pci_n1sdp.c | 193 ++++++++++++++++++++++++++++++++++
sys/arch/arm/acpi/acpipchb.c | 150 ++-----------------------
sys/arch/arm/acpi/files.acpi | 4 +-
sys/arch/arm/fdt/acpi_fdt.c | 12 +-
sys/arch/x86/x86/mpacpi.c | 10 +-
sys/dev/acpi/acpi.c | 25 +++-
sys/dev/acpi/acpi_pci.c | 39 +++++-
sys/dev/acpi/acpi_pci.h | 7 +-
sys/dev/acpi/acpi_pci_link.c | 48 ++++----
sys/dev/acpi/acpica/OsdHardware.c | 15 +-
sys/dev/acpi/acpivar.h | 11 +-
14 files changed, 547 insertions(+), 213 deletions(-)
diffs (truncated from 1274 to 300 lines):
diff -r 4824de0505d0 -r 50c1318caa36 sys/arch/arm/acpi/acpi_pci_graviton.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/acpi/acpi_pci_graviton.c Fri Jan 17 17:06:32 2020 +0000
@@ -0,0 +1,144 @@
+/* $NetBSD: acpi_pci_graviton.c,v 1.1 2020/01/17 17:06:33 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jared McNeill <jmcneill%invisible.ca@localhost>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: acpi_pci_graviton.c,v 1.1 2020/01/17 17:06:33 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/extent.h>
+#include <sys/kmem.h>
+
+#include <machine/cpu.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pciconf.h>
+
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpi_pci.h>
+#include <dev/acpi/acpi_mcfg.h>
+
+#include <arm/acpi/acpi_pci_machdep.h>
+
+static int
+acpi_pci_graviton_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data)
+{
+ struct acpi_pci_context *ap = pc->pc_conf_v;
+ int b, d, f;
+
+ pci_decompose_tag(pc, tag, &b, &d, &f);
+
+ if (ap->ap_bus == b) {
+ if (d > 0 || f > 0) {
+ *data = -1;
+ return EINVAL;
+ }
+ *data = bus_space_read_4(ap->ap_bst, ap->ap_conf_bsh, reg);
+ return 0;
+ }
+
+ return acpimcfg_conf_read(pc, tag, reg, data);
+}
+
+static int
+acpi_pci_graviton_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
+{
+ struct acpi_pci_context *ap = pc->pc_conf_v;
+ int b, d, f;
+
+ pci_decompose_tag(pc, tag, &b, &d, &f);
+
+ if (ap->ap_bus == b) {
+ if (d > 0 || f > 0) {
+ return EINVAL;
+ }
+ bus_space_write_4(ap->ap_bst, ap->ap_conf_bsh, reg, data);
+ return 0;
+ }
+
+ return acpimcfg_conf_write(pc, tag, reg, data);
+}
+
+static ACPI_STATUS
+acpi_pci_graviton_map(ACPI_HANDLE handle, UINT32 level, void *ctx, void **retval)
+{
+ struct acpi_pci_context *ap = ctx;
+ struct acpi_resources res;
+ struct acpi_mem *mem;
+ ACPI_HANDLE parent;
+ ACPI_INTEGER seg;
+ ACPI_STATUS rv;
+ int error;
+
+ rv = AcpiGetParent(handle, &parent);
+ if (ACPI_FAILURE(rv))
+ return rv;
+ rv = acpi_eval_integer(parent, "_SEG", &seg);
+ if (ACPI_FAILURE(rv))
+ seg = 0;
+ if (ap->ap_seg != seg)
+ return AE_OK;
+
+ rv = acpi_resource_parse(ap->ap_dev, handle, "_CRS", &res, &acpi_resource_parse_ops_quiet);
+ if (ACPI_FAILURE(rv))
+ return rv;
+
+ mem = acpi_res_mem(&res, 0);
+ if (mem == NULL) {
+ acpi_resource_cleanup(&res);
+ return AE_NOT_FOUND;
+ }
+
+ error = bus_space_map(ap->ap_bst, mem->ar_base, mem->ar_length,
+ _ARM_BUS_SPACE_MAP_STRONGLY_ORDERED, &ap->ap_conf_bsh);
+ if (error != 0)
+ return AE_NO_MEMORY;
+
+ ap->ap_conf_read = acpi_pci_graviton_conf_read;
+ ap->ap_conf_write = acpi_pci_graviton_conf_write;
+
+ return AE_CTRL_TERMINATE;
+}
+
+void
+acpi_pci_graviton_init(struct acpi_pci_context *ap)
+{
+ ACPI_STATUS rv;
+
+ rv = AcpiGetDevices(__UNCONST("AMZN0001"), acpi_pci_graviton_map, ap, NULL);
+ if (ACPI_FAILURE(rv))
+ return;
+}
diff -r 4824de0505d0 -r 50c1318caa36 sys/arch/arm/acpi/acpi_pci_machdep.c
--- a/sys/arch/arm/acpi/acpi_pci_machdep.c Fri Jan 17 16:59:07 2020 +0000
+++ b/sys/arch/arm/acpi/acpi_pci_machdep.c Fri Jan 17 17:06:32 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_pci_machdep.c,v 1.12 2019/10/15 13:27:50 jmcneill Exp $ */
+/* $NetBSD: acpi_pci_machdep.c,v 1.13 2020/01/17 17:06:33 jmcneill Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_pci_machdep.c,v 1.12 2019/10/15 13:27:50 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_pci_machdep.c,v 1.13 2020/01/17 17:06:33 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -70,6 +70,23 @@
static TAILQ_HEAD(, acpi_pci_prt) acpi_pci_irq_routes =
TAILQ_HEAD_INITIALIZER(acpi_pci_irq_routes);
+struct acpi_pci_pct {
+ struct acpi_pci_context pct_ap;
+ TAILQ_ENTRY(acpi_pci_pct) pct_list;
+};
+
+static TAILQ_HEAD(, acpi_pci_pct) acpi_pci_chipset_tags =
+ TAILQ_HEAD_INITIALIZER(acpi_pci_chipset_tags);
+
+static const struct acpi_pci_quirk acpi_pci_quirks[] = {
+ /* OEM ID OEM Table ID Revision Seg Func */
+ { "AMAZON", "GRAVITON", 0, -1, acpi_pci_graviton_init },
+ { "ARMLTD", "ARMN1SDP", 0x20181101, 0, acpi_pci_n1sdp_init },
+ { "ARMLTD", "ARMN1SDP", 0x20181101, 1, acpi_pci_n1sdp_init },
+};
+
+pci_chipset_tag_t acpi_pci_md_get_chipset_tag(struct acpi_softc *, int, int);
+
static void acpi_pci_md_attach_hook(device_t, device_t,
struct pcibus_attach_args *);
static int acpi_pci_md_bus_maxdevs(void *, int);
@@ -115,7 +132,7 @@
};
static ACPI_STATUS
-acpi_pci_md_pci_link(ACPI_HANDLE handle, int bus)
+acpi_pci_md_pci_link(ACPI_HANDLE handle, pci_chipset_tag_t pc, int bus)
{
ACPI_PCI_ROUTING_TABLE *prt;
ACPI_HANDLE linksrc;
@@ -144,7 +161,7 @@
}
linkdev = acpi_pci_link_devbyhandle(linksrc);
- acpi_pci_link_add_reference(linkdev, 0, bus, dev, prt->Pin & 3);
+ acpi_pci_link_add_reference(linkdev, pc, 0, bus, dev, prt->Pin & 3);
} else {
aprint_debug("ACPI: %s dev %u INT%c on globint %d\n",
acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->SourceIndex);
@@ -208,7 +225,7 @@
/*
* This is a new ACPI managed bus. Add PCI link references.
*/
- acpi_pci_md_pci_link(ad->ad_handle, pba->pba_bus);
+ acpi_pci_md_pci_link(ad->ad_handle, pba->pba_pc, pba->pba_bus);
}
}
@@ -343,7 +360,8 @@
if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, tab->Source, &linksrc)))
goto done;
linkdev = acpi_pci_link_devbyhandle(linksrc);
- *ih = acpi_pci_link_route_interrupt(linkdev, tab->SourceIndex,
+ *ih = acpi_pci_link_route_interrupt(linkdev,
+ pa->pa_pc, tab->SourceIndex,
&line, &pol, &trig);
error = 0;
goto done;
@@ -417,3 +435,58 @@
{
intr_disestablish(vih);
}
+
+const struct acpi_pci_quirk *
+acpi_pci_md_find_quirk(int seg)
+{
+ ACPI_STATUS rv;
+ ACPI_TABLE_MCFG *mcfg;
+ u_int n;
+
+ rv = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg);
+ if (ACPI_FAILURE(rv))
+ return NULL;
+
+ for (n = 0; n < __arraycount(acpi_pci_quirks); n++) {
+ const struct acpi_pci_quirk *q = &acpi_pci_quirks[n];
+ if (memcmp(q->q_oemid, mcfg->Header.OemId, ACPI_OEM_ID_SIZE) == 0 &&
+ memcmp(q->q_oemtableid, mcfg->Header.OemTableId, ACPI_OEM_TABLE_ID_SIZE) == 0 &&
+ q->q_oemrevision == mcfg->Header.OemRevision &&
+ (q->q_segment == -1 || q->q_segment == seg))
+ return q;
+ }
+
+ return NULL;
+}
+
+pci_chipset_tag_t
+acpi_pci_md_get_chipset_tag(struct acpi_softc *sc, int seg, int bbn)
+{
+ struct acpi_pci_pct *pct = NULL, *pctp;
+ const struct acpi_pci_quirk *q;
+
+ TAILQ_FOREACH(pctp, &acpi_pci_chipset_tags, pct_list)
+ if (pctp->pct_ap.ap_seg == seg) {
+ pct = pctp;
+ break;
+ }
+
+ if (pct == NULL) {
+ pct = kmem_zalloc(sizeof(*pct), KM_SLEEP);
+ pct->pct_ap.ap_dev = sc->sc_dev;
+ pct->pct_ap.ap_pc = arm_acpi_pci_chipset;
+ pct->pct_ap.ap_pc.pc_conf_v = &pct->pct_ap;
+ pct->pct_ap.ap_seg = seg;
+ pct->pct_ap.ap_bus = bbn;
+ pct->pct_ap.ap_bst = acpi_softc->sc_memt;
+
+ q = acpi_pci_md_find_quirk(seg);
+ if (q != NULL)
+ q->q_init(&pct->pct_ap);
+
+ TAILQ_INSERT_TAIL(&acpi_pci_chipset_tags, pct, pct_list);
+ }
+
+ return &pct->pct_ap.ap_pc;
+}
+__strong_alias(acpi_get_pci_chipset_tag,acpi_pci_md_get_chipset_tag);
diff -r 4824de0505d0 -r 50c1318caa36 sys/arch/arm/acpi/acpi_pci_machdep.h
--- a/sys/arch/arm/acpi/acpi_pci_machdep.h Fri Jan 17 16:59:07 2020 +0000
+++ b/sys/arch/arm/acpi/acpi_pci_machdep.h Fri Jan 17 17:06:32 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_pci_machdep.h,v 1.5 2019/10/15 13:27:50 jmcneill Exp $ */
+/* $NetBSD: acpi_pci_machdep.h,v 1.6 2020/01/17 17:06:33 jmcneill Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -39,11 +39,24 @@
device_t ap_dev;
u_int ap_seg;
int ap_bus;
- ACPI_HANDLE ap_handle;
Home |
Main Index |
Thread Index |
Old Index