Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168247521
D59171.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D59171.diff
View Options
diff --git a/sys/arm/arm/gic_acpi.c b/sys/arm/arm/gic_acpi.c
--- a/sys/arm/arm/gic_acpi.c
+++ b/sys/arm/arm/gic_acpi.c
@@ -139,6 +139,9 @@
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
madt_handler, &madt_data);
+ if (!madt_data.dist)
+ return;
+
/* Check the version of the GIC we have */
switch (madt_data.dist->Version) {
case ACPI_MADT_GIC_VERSION_NONE:
diff --git a/sys/arm64/arm64/gicv3_its.c b/sys/arm64/arm64/gicv3_its.c
--- a/sys/arm64/arm64/gicv3_its.c
+++ b/sys/arm64/arm64/gicv3_its.c
@@ -2399,7 +2399,7 @@
if (gic_get_bus(dev) != GIC_BUS_ACPI)
return (EINVAL);
- if (gic_get_hw_rev(dev) < 3)
+ if (gic_get_hw_rev(dev) < 3 || gic_get_hw_rev(dev) > 4)
return (EINVAL);
if (!gic_get_support_lpis(dev))
diff --git a/sys/arm64/arm64/gicv5.c b/sys/arm64/arm64/gicv5.c
--- a/sys/arm64/arm64/gicv5.c
+++ b/sys/arm64/arm64/gicv5.c
@@ -55,6 +55,11 @@
#include <dev/ofw/ofw_bus_subr.h>
#endif
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#endif
+
#include "pic_if.h"
#include <arm/arm/gic_common.h>
@@ -1166,6 +1171,26 @@
}
#endif
+#ifdef DEV_ACPI
+static int
+do_gicv5_map_iwb_intr(struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct intr_map_data_acpi *daa;
+ device_t iwb;
+ int iwb_id;
+
+ daa = (struct intr_map_data_acpi *)data;
+ iwb_id = (daa->irq & GSI_IWB_ID_MASK) >> GSI_IWB_ID_SHIFT;
+ iwb = acpi_iort_get_iwb_dev(iwb_id);
+
+ if (iwb == NULL)
+ return (ENODEV);
+
+ return (PIC_MAP_INTR(iwb, data, isrcp));
+}
+#endif
+
static int
do_gicv5_map_intr(device_t dev, struct intr_map_data *data, bool *ppip,
u_int *irqp, enum intr_polarity *polp, enum intr_trigger *trigp)
@@ -1175,6 +1200,9 @@
enum intr_trigger trig;
#ifdef FDT
struct intr_map_data_fdt *daf;
+#endif
+#ifdef DEV_ACPI
+ struct intr_map_data_acpi *daa;
#endif
u_int irq;
bool ppi;
@@ -1189,6 +1217,17 @@
&trig) != 0)
return (EINVAL);
break;
+#endif
+#ifdef DEV_ACPI
+ case INTR_MAP_DATA_ACPI:
+ daa = (struct intr_map_data_acpi *)data;
+ if (daa->irq & GSI_IS_IWB_MASK)
+ return (EINVAL);
+ irq = daa->irq & GSI_INT_ID_MASK;
+ pol = daa->pol;
+ trig = daa->trig;
+ ppi = ((daa->irq & GSI_INT_TYPE_MASK) == GSI_INT_TYPE_PPI);
+ break;
#endif
default:
return (EINVAL);
@@ -1231,11 +1270,22 @@
gicv5_map_intr(device_t dev, struct intr_map_data *data,
struct intr_irqsrc **isrcp)
{
+#ifdef DEV_ACPI
+ struct intr_map_data_acpi *daa;
+#endif
struct gicv5_softc *sc;
u_int irq;
int error;
bool ppi;
+#ifdef DEV_ACPI
+ if (data->type == INTR_MAP_DATA_ACPI) {
+ daa = (struct intr_map_data_acpi *)data;
+ if (daa->irq & GSI_IS_IWB_MASK)
+ return (do_gicv5_map_iwb_intr(data, isrcp));
+ }
+#endif
+
error = do_gicv5_map_intr(dev, data, &ppi, &irq, NULL, NULL);
if (error == 0) {
sc = device_get_softc(dev);
diff --git a/sys/arm64/arm64/gicv5_acpi.c b/sys/arm64/arm64/gicv5_acpi.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/arm64/gicv5_acpi.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2026 Arm Ltd
+ *
+ * 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 AUTHOR 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 AUTHOR 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 "opt_acpi.h"
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/cpuset.h>
+
+#include <machine/intr.h>
+#include <machine/resource.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+
+#include <arm/arm/gic_common.h>
+#include "gicv5var.h"
+
+struct gic_v5_acpi_devinfo {
+ struct gicv5_devinfo di_base;
+};
+
+static device_identify_t gic_v5_acpi_identify;
+static device_probe_t gic_v5_acpi_probe;
+static device_attach_t gic_v5_acpi_attach;
+static bus_get_resource_list_t gic_v5_acpi_get_resource_list;
+
+static void gic_v5_acpi_bus_attach(device_t);
+
+static device_method_t gic_v5_acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, gic_v5_acpi_identify),
+ DEVMETHOD(device_probe, gic_v5_acpi_probe),
+ DEVMETHOD(device_attach, gic_v5_acpi_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_get_resource_list, gic_v5_acpi_get_resource_list),
+
+ /* End */
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(gic, gic_v5_acpi_driver, gic_v5_acpi_methods,
+ sizeof(struct gicv5_softc), gicv5_driver);
+
+EARLY_DRIVER_MODULE(gic_v5, acpi, gic_v5_acpi_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+
+struct madt_table_data {
+ device_t parent;
+ device_t dev;
+ ACPI_MADT_GICV5_IRS *irs;
+ int count;
+};
+
+#define IRS_REGISTER_SIZE 0x10000
+#define ITS_REGISTER_SIZE 0x10000
+#define ITS_TRANSLATE_REGISTER_SIZE 0x10000
+#define IWB_REGISTER_SIZE 0x10000
+
+static void
+madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ struct madt_table_data *madt_data;
+ ACPI_MADT_GICV5_IRS *irs;
+
+ madt_data = (struct madt_table_data *)arg;
+
+ switch (entry->Type) {
+ case ACPI_MADT_TYPE_GICV5_IRS:
+ if (madt_data->irs) {
+ if (bootverbose)
+ device_printf(madt_data->parent,
+ "gic: Already have an IRS");
+ break;
+ }
+
+ irs = (ACPI_MADT_GICV5_IRS *)entry;
+
+ if (irs->Version != 5)
+ break;
+
+ madt_data->irs = irs;
+ madt_data->count++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ ACPI_MADT_GICv5_ITS *its;
+ ACPI_MADT_GICv5_ITS_TRANSLATE *its_translate;
+ ACPI_MADT_GICV5_IRS *irs;
+
+ struct madt_table_data *madt_data;
+
+ madt_data = (struct madt_table_data *)arg;
+
+ switch (entry->Type) {
+ case ACPI_MADT_TYPE_GICV5_IRS:
+ if (madt_data->irs) {
+ if (bootverbose)
+ device_printf(madt_data->parent,
+ "gic: Already have an IRS");
+ break;
+ }
+
+ irs = (ACPI_MADT_GICV5_IRS *)entry;
+
+ if (irs->Version != 5)
+ break;
+
+ madt_data->irs = irs;
+
+ BUS_SET_RESOURCE(madt_data->parent, madt_data->dev,
+ SYS_RES_MEMORY, madt_data->count, irs->ConfigBaseAddress,
+ IRS_REGISTER_SIZE);
+ madt_data->count++;
+ break;
+
+ case ACPI_MADT_TYPE_GICV5_ITS:
+ its = (ACPI_MADT_GICv5_ITS *)entry;
+
+ BUS_SET_RESOURCE(madt_data->parent, madt_data->dev,
+ SYS_RES_MEMORY, madt_data->count, its->BaseAddress,
+ ITS_REGISTER_SIZE);
+ madt_data->count++;
+ break;
+
+ case ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE:
+ its_translate = (ACPI_MADT_GICv5_ITS_TRANSLATE *)entry;
+
+ BUS_SET_RESOURCE(madt_data->parent, madt_data->dev,
+ SYS_RES_MEMORY, madt_data->count,
+ its_translate->BaseAddress, ITS_TRANSLATE_REGISTER_SIZE);
+ madt_data->count++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+gic_v5_acpi_identify(driver_t *driver, device_t parent)
+{
+ struct madt_table_data madt_data;
+ ACPI_TABLE_MADT *madt;
+ vm_paddr_t physaddr;
+ uintptr_t private;
+ device_t dev;
+
+ physaddr = acpi_find_table(ACPI_SIG_MADT);
+ if (physaddr == 0)
+ return;
+
+ madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+ if (madt == NULL) {
+ device_printf(parent, "gic: Unable to map the MADT\n");
+ return;
+ }
+
+ madt_data.parent = parent;
+ madt_data.count = 0;
+ madt_data.irs = NULL;
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ madt_handler, &madt_data);
+ if (madt_data.count == 0) {
+ device_printf(parent, "No GICv5 IRS\n");
+ goto out;
+ }
+
+ dev = BUS_ADD_CHILD(parent, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE,
+ "gic", -1);
+ if (dev == NULL) {
+ device_printf(parent, "add gic child failed\n");
+ goto out;
+ }
+
+ /* Add the MADT data */
+ private = madt_data.irs->Version;
+ acpi_set_private(dev, (void *)private);
+
+ madt_data.dev = dev;
+ madt_data.count = 0;
+ madt_data.irs = NULL;
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ rdist_map, &madt_data);
+
+out:
+ acpi_unmap_table(madt);
+}
+
+static int
+gic_v5_acpi_probe(device_t dev)
+{
+ switch ((uintptr_t)acpi_get_private(dev)) {
+ case 5:
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ device_set_desc(dev, "ARM Generic Interrupt Controller v5");
+ return (BUS_PROBE_NOWILDCARD);
+}
+
+static void
+madt_count_irs(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ struct gicv5_softc *sc = arg;
+
+ if (entry->Type == ACPI_MADT_TYPE_GICV5_IRS)
+ sc->gic_nirs++;
+}
+
+static int
+gic_v5_acpi_count_nirs(struct gicv5_softc *sc, ACPI_TABLE_MADT *madt)
+{
+ sc->gic_nirs = 0;
+
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ madt_count_irs, sc);
+
+ return (sc->gic_nirs > 0 ? 0 : ENXIO);
+}
+
+struct process_gicc_args {
+ struct gicv5_softc *sc;
+ ACPI_TABLE_MADT *madt;
+ uint32_t irs_id;
+ cpuset_t cpuset;
+};
+
+struct process_irs_args {
+ device_t dev;
+ struct gicv5_softc *sc;
+ ACPI_TABLE_MADT *madt;
+};
+
+static void
+madt_process_gicc(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ struct process_gicc_args *gicc_args;
+ ACPI_MADT_GENERIC_INTERRUPT *gicc;
+
+ gicc_args = (struct process_gicc_args *)arg;
+
+ if (entry->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+ gicc = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
+
+ if (gicc->IrsId == gicc_args->irs_id)
+ CPU_SET(gicc->CpuInterfaceNumber, &gicc_args->cpuset);
+ }
+}
+
+static void
+madt_process_irs(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ struct process_gicc_args gicc_args;
+ struct process_irs_args *irs_args;
+ ACPI_MADT_GICV5_IRS *irs;
+ struct gicv5_softc *sc;
+ ACPI_TABLE_MADT *madt;
+ int error;
+
+ irs_args = (struct process_irs_args *)arg;
+ sc = irs_args->sc;
+ madt = irs_args->madt;
+
+ if (entry->Type == ACPI_MADT_TYPE_GICV5_IRS) {
+ irs = (ACPI_MADT_GICV5_IRS *)entry;
+
+ gicc_args.sc = sc;
+ gicc_args.madt = madt;
+ gicc_args.irs_id = irs->IrsId;
+ CPU_ZERO(&gicc_args.cpuset);
+
+ /* Build gicc_args.cpuset from GICC tables */
+ acpi_walk_subtables(madt + 1,
+ (char *)madt + madt->Header.Length,
+ madt_process_gicc, &gicc_args);
+
+ sc->gic_nirs++;
+
+ gicv5_irs_init(irs_args->dev, sc->gic_nirs - 1,
+ &gicc_args.cpuset);
+
+ error = bus_set_resource(irs_args->dev, SYS_RES_MEMORY,
+ sc->gic_nirs - 1, irs->ConfigBaseAddress,
+ IRS_REGISTER_SIZE);
+ if (error != 0)
+ panic("%s: Unable to set memory resourec",
+ device_get_nameunit(irs_args->dev));
+ }
+}
+
+static int
+gic_v5_acpi_process_irs(device_t dev, struct gicv5_softc *sc,
+ ACPI_TABLE_MADT *madt)
+{
+ struct process_irs_args args;
+
+ args.dev = dev;
+ args.sc = sc;
+ args.madt = madt;
+
+ sc->gic_nirs = 0;
+
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ madt_process_irs, &args);
+
+ return (0);
+}
+
+static int
+gic_v5_acpi_attach(device_t dev)
+{
+ struct gicv5_softc *sc;
+ ACPI_TABLE_MADT *madt;
+ vm_paddr_t physaddr;
+ int err;
+
+ sc = device_get_softc(dev);
+ sc->gic_dev = dev;
+ sc->gic_bus = GIC_BUS_ACPI;
+
+ physaddr = acpi_find_table(ACPI_SIG_MADT);
+ if (physaddr == 0)
+ return (ENXIO);
+
+ madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+ if (madt == NULL) {
+ device_printf(dev, "Unable to map the MADT\n");
+ return (ENXIO);
+ }
+
+ err = gic_v5_acpi_count_nirs(sc, madt);
+ if (err != 0)
+ goto count_error;
+
+ sc->gic_irs = mallocarray(sc->gic_nirs, sizeof(sc->gic_irs[0]),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ // for each IRS
+ // walk GICC entries to find matching IRS IDs
+ err = gic_v5_acpi_process_irs(dev, sc, madt);
+
+ gicv5_attach(dev);
+
+ sc->gic_pic = intr_pic_register(dev, ACPI_INTR_XREF);
+ if (sc->gic_pic == NULL)
+ panic("%s: could not register PIC", device_get_nameunit(dev));
+
+ intr_ipi_pic_register(dev, 0);
+
+ err = intr_pic_claim_root(dev, ACPI_INTR_XREF, gicv5_intr, sc,
+ INTR_ROOT_IRQ);
+ if (err != 0)
+ panic("%s: Unable to claim PIC root", device_get_nameunit(dev));
+
+ gic_v5_acpi_bus_attach(dev);
+
+ bus_attach_children(dev);
+
+ acpi_unmap_table(madt);
+
+ return (0);
+
+count_error:
+ if (bootverbose) {
+ device_printf(dev,
+ "Failed to attach. Error %d\n", err);
+ }
+
+ acpi_unmap_table(madt);
+
+ return (err);
+}
+
+static void
+gic_v5_add_children(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ ACPI_MADT_GICv5_ITS *its;
+ struct gic_v5_acpi_devinfo *di;
+ struct gicv5_softc *sc;
+ device_t dev;
+
+ if (entry->Type == ACPI_MADT_TYPE_GICV5_ITS) {
+ /* We have an ITS, add it as a child */
+ its = (ACPI_MADT_GICv5_ITS *)entry;
+ dev = arg;
+ sc = device_get_softc(dev);
+
+ di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ resource_list_init(&di->di_base.di_rl);
+ resource_list_add(&di->di_base.di_rl, SYS_RES_MEMORY, 0,
+ its->BaseAddress, its->BaseAddress + ITS_REGISTER_SIZE - 1,
+ ITS_REGISTER_SIZE);
+
+ di->di_base.di_irs = sc->gic_irs[0];
+
+ gicv5_add_child(dev, &di->di_base);
+
+ }
+}
+
+static bool
+gicv5_add_child_iwb(device_t dev, struct gicv5_devinfo *di)
+{
+ device_t cdev;
+ struct gicv5_softc *sc;
+
+ cdev = device_add_child(dev, "iwb", DEVICE_UNIT_ANY);
+ if (cdev == NULL)
+ return (false);
+
+ sc = device_get_softc(dev);
+ sc->gic_nchildren++;
+ device_set_ivars(cdev, di);
+
+ return (true);
+}
+
+static void
+gic_v5_acpi_bus_attach(device_t dev)
+{
+ ACPI_TABLE_MADT *madt;
+ vm_paddr_t physaddr;
+
+ physaddr = acpi_find_table(ACPI_SIG_MADT);
+ if (physaddr == 0) {
+ device_printf(dev, "gic_v5_acpi_bus_attach: no madt\n");
+ return;
+ }
+
+ madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+ if (madt == NULL) {
+ device_printf(dev, "Unable to map the MADT to add children\n");
+ return;
+ }
+
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ gic_v5_add_children, dev);
+
+ acpi_unmap_table(madt);
+
+ bus_attach_children(dev);
+}
+
+static struct resource_list *
+gic_v5_acpi_get_resource_list(device_t bus, device_t child)
+{
+ struct gic_v5_acpi_devinfo *di;
+
+ di = device_get_ivars(child);
+ KASSERT(di != NULL, ("%s: No devinfo", __func__));
+
+ return (&di->di_base.di_rl);
+}
diff --git a/sys/arm64/arm64/gicv5_its.c b/sys/arm64/arm64/gicv5_its.c
--- a/sys/arm64/arm64/gicv5_its.c
+++ b/sys/arm64/arm64/gicv5_its.c
@@ -56,6 +56,11 @@
#include <dev/ofw/ofw_subr.h>
#endif
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#endif
+
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
@@ -1237,3 +1242,136 @@
return (gicv5_its_attach(dev));
}
#endif /* FDT */
+
+#ifdef DEV_ACPI
+static int
+gicv5_its_acpi_probe(device_t dev);
+static int
+gicv5_its_acpi_attach(device_t dev);
+
+static device_method_t gicv5_its_acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, gicv5_its_acpi_probe),
+ DEVMETHOD(device_attach, gicv5_its_acpi_attach),
+
+ /* End */
+ DEVMETHOD_END
+};
+
+#define its_baseclasses itsv5_acpi_baseclasses
+DEFINE_CLASS_1(its, gicv5_its_acpi_driver, gicv5_its_acpi_methods,
+ sizeof(struct gicv5_its_softc), gicv5_its_driver);
+#undef its_baseclasses
+
+EARLY_DRIVER_MODULE(itsv5_acpi, gic, gicv5_its_acpi_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+
+static int
+gicv5_its_acpi_probe(device_t dev)
+{
+ device_t parent = device_get_parent(dev);
+
+ if (!parent)
+ return (ENXIO);
+
+ if (strcmp(device_get_name(parent), "gic"))
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM GICv5 Interrupt Translation Service");
+ return (BUS_PROBE_DEFAULT);
+}
+
+struct find_its_translate_data {
+ bus_addr_t its_frame_paddr;
+ uint8_t flags;
+ int its_found;
+ int its_translate_found;
+ u_int its_translate_xref;
+ int its_translate_pxm;
+};
+
+static void
+find_its_translate(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+ ACPI_MADT_GICv5_ITS_TRANSLATE *its_translate;
+ ACPI_MADT_GICv5_ITS *its;
+ struct find_its_translate_data *find_data;
+ int err;
+
+ find_data = (struct find_its_translate_data *)arg;
+
+ switch (entry->Type) {
+ case ACPI_MADT_TYPE_GICV5_ITS:
+ its = (ACPI_MADT_GICv5_ITS *)entry;
+
+ find_data->its_found++;
+ find_data->flags = its->Flags;
+ break;
+
+ case ACPI_MADT_TYPE_GICV5_ITS_TRANSLATE:
+ its_translate = (ACPI_MADT_GICv5_ITS_TRANSLATE *)entry;
+
+ err = acpi_iort_its_lookup(its_translate->TranslateFrameId,
+ &find_data->its_translate_xref,
+ &find_data->its_translate_pxm);
+ if (err != 0)
+ break;
+
+ find_data->its_translate_found++;
+ find_data->its_frame_paddr = its_translate->BaseAddress;
+ break;
+ }
+}
+
+static int
+gicv5_its_acpi_attach(device_t dev)
+{
+ struct find_its_translate_data find_data;
+ struct gicv5_its_softc *sc;
+ ACPI_TABLE_MADT *madt;
+ vm_paddr_t physaddr;
+
+ sc = device_get_softc(dev);
+
+ physaddr = acpi_find_table(ACPI_SIG_MADT);
+ if (physaddr == 0)
+ return (ENODEV);
+
+ madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+ if (madt == NULL) {
+ device_printf(dev, "gicv5_its: Unable to map the MADT\n");
+ return (ENODEV);
+ }
+
+ find_data.its_found = 0;
+ find_data.its_translate_found = 0;
+
+ acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+ find_its_translate, &find_data);
+
+ if (!find_data.its_found) {
+ device_printf(dev, "No valid ITS found\n");
+ return (EINVAL);
+ }
+ if (find_data.its_found > 1) {
+ device_printf(dev, "Multiple ITS found\n");
+ return (EINVAL);
+ }
+ if (!find_data.its_translate_found) {
+ device_printf(dev, "No valid ITS frame found\n");
+ return (EINVAL);
+ }
+ if (find_data.its_translate_found > 1) {
+ device_printf(dev, "Multiple ITS frames found\n");
+ return (EINVAL);
+ }
+
+ sc->its_frame.its_frame_paddr = find_data.its_frame_paddr;
+ sc->its_frame.its_pic = NULL;
+ sc->its_frame.its_xref = find_data.its_translate_xref;
+ sc->its_coherent = !(find_data.flags &
+ ACPI_MADT_GICV5_ITS_NON_COHERENT);
+
+ return (gicv5_its_attach(dev));
+}
+#endif /* DEV_ACPI */
diff --git a/sys/arm64/arm64/gicv5_iwb.c b/sys/arm64/arm64/gicv5_iwb.c
--- a/sys/arm64/arm64/gicv5_iwb.c
+++ b/sys/arm64/arm64/gicv5_iwb.c
@@ -47,9 +47,17 @@
#include <dev/ofw/ofw_bus_subr.h>
#endif
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#endif
+
#include "pci_if.h"
#include "pic_if.h"
+#include "gicv5reg.h"
+#include "gicv5var.h"
+
#define IWB_IDR0 0x0000
#define IDR0_IW_RANGE_SHIFT 0
#define IDR0_IW_RANGE_MASK (0x7ffu << IDR0_IW_RANGE_SHIFT)
@@ -207,6 +215,8 @@
error = PCI_ALLOC_MSI(device_get_parent(dev), dev, &count);
if (error != 0) {
device_printf(dev, "Unable to allocate MSI interrupts\n");
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid,
+ sc->sc_mem);
return (error);
}
@@ -362,6 +372,9 @@
enum intr_trigger trig;
#ifdef FDT
struct intr_map_data_fdt *daf;
+#endif
+#ifdef DEV_ACPI
+ struct intr_map_data_acpi *daa;
#endif
u_int irq;
@@ -375,6 +388,14 @@
&trig) != 0)
return (EINVAL);
break;
+#endif
+#ifdef DEV_ACPI
+ case INTR_MAP_DATA_ACPI:
+ daa = (struct intr_map_data_acpi *)data;
+ irq = daa->irq & GSI_IWB_INT_ID_MASK;
+ pol = daa->pol;
+ trig = daa->trig;
+ break;
#endif
default:
return (EINVAL);
@@ -559,3 +580,75 @@
return (0);
}
#endif /* FDT */
+
+#ifdef DEV_ACPI
+struct gicv5_iwb_acpi_softc {
+ struct gicv5_iwb_softc sc_base;
+};
+
+static device_probe_t gicv5_iwb_acpi_probe;
+static device_attach_t gicv5_iwb_acpi_attach;
+
+static device_method_t gicv5_iwb_acpi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, gicv5_iwb_acpi_probe),
+ DEVMETHOD(device_attach, gicv5_iwb_acpi_attach),
+
+ /* End */
+ DEVMETHOD_END
+};
+
+#define iwb_baseclasses iwbv5_acpi_baseclasses
+DEFINE_CLASS_1(iwb, gicv5_iwb_acpi_driver, gicv5_iwb_acpi_methods,
+ sizeof(struct gicv5_iwb_acpi_softc), gicv5_iwb_driver);
+#undef iwb_baseclasses
+
+/* This needs to be after the ITS as it sends MSI messages there */
+EARLY_DRIVER_MODULE(gicv5_iwb_acpi, acpi, gicv5_iwb_acpi_driver, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
+
+static int
+gicv5_iwb_acpi_probe(device_t dev)
+{
+ ACPI_HANDLE h;
+
+ if ((h = acpi_get_handle(dev)) == NULL)
+ return (ENXIO);
+
+ if (!acpi_MatchHid(h, "ARMH0003"))
+ return (ENXIO);
+
+ device_set_desc(dev, "ARM GICv5 Interrupt Wire Bridge");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+gicv5_iwb_acpi_attach(device_t dev)
+{
+ struct gicv5_iwb_acpi_softc *sc;
+ u_int xref;
+ int its_id;
+ int error;
+ int pxm;
+
+ sc = device_get_softc(dev);
+
+ error = acpi_iort_lookup_its_from_iwb(dev, &its_id);
+ if (error != 0)
+ return (error);
+
+ error = acpi_iort_its_lookup(its_id, &xref, &pxm);
+ if (error != 0)
+ return (error);
+
+ error = gicv5_iwb_attach(dev);
+ if (error != 0)
+ return (error);
+
+ sc->sc_base.sc_pic = intr_pic_register(dev, xref);
+ if (sc->sc_base.sc_pic == NULL)
+ return (ENXIO);
+
+ return (0);
+}
+#endif /* ACPI */
diff --git a/sys/arm64/arm64/gicv5var.h b/sys/arm64/arm64/gicv5var.h
--- a/sys/arm64/arm64/gicv5var.h
+++ b/sys/arm64/arm64/gicv5var.h
@@ -68,4 +68,6 @@
void gicv5_irs_init(device_t, u_int, cpuset_t *);
void gicv5_irs_extend_ist(device_t, device_t, u_int);
+void gicv5_attach_iwb(device_t, device_t);
+
#endif /* _ARM64_GICV5VAR_H_ */
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -60,9 +60,10 @@
arm64/arm64/gic_v3_acpi.c optional acpi
arm64/arm64/gic_v3_fdt.c optional fdt
arm64/arm64/gicv5.c standard
+arm64/arm64/gicv5_acpi.c optional acpi
arm64/arm64/gicv5_fdt.c optional fdt
-arm64/arm64/gicv5_its.c optional fdt
-arm64/arm64/gicv5_iwb.c optional fdt
+arm64/arm64/gicv5_its.c standard
+arm64/arm64/gicv5_iwb.c standard
arm64/arm64/hyp_stub.S standard
arm64/arm64/identcpu.c standard
arm64/arm64/kexec_support.c standard
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 28, 4:06 AM (1 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37434466
Default Alt Text
D59171.diff (22 KB)
Attached To
Mode
D59171: arm64: Add ACPI support to GICv5 driver
Attached
Detach File
Event Timeline
Log In to Comment