From nobody Thu Sep 17 09:56:05 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hlrjx6xPpz6sn65 for ; Thu, 17 Sep 2026 09:56:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hlrjx4yB8z3QZt for ; Thu, 17 Sep 2026 09:56:05 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789638965; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Ul/T9FgNhpPwb27YmnzCI3QgdDwWKc4Y6ScvkAacTg4=; b=Go6m1bXnCOJ3MqjvNWYMvxHIWgHiAbSrNyhbHeP+0OfeUwptKM6Erp26srWPe6Q/HfAxMW wHprBF3hh8fUL0x96z1uJUGJFN+y24FITHKjRYrz02Vj+i3UPCFHz3dnIrnK+mi42OxKod CJhDZcbkjO9cU4tISasLVeIFVAnuRedE9pAWlYm+5G/+2HfPp6mZz/drbutBP/5z04wWHw 12IGtxExKuqMy6tycaUWhGbizSl0pnb5YML3NVJLBz4Kw2fAZEgRE+UnBO/r1UhtqqBWOw 0f7b54grOagCahmWpzA7U5C6KijOHc41zl5m5K+/FuW/uc0eZ77WLt+YNDUYCA== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1789638965; b=AhqhXcORBVyw4vSBKVvHQyePvWiS0GtlQgtfg8MUoXTOr6BS7rgyAGC8CvDBf59T5Elqzf zOO8HzokQmG3OuNldZG3qICZmUIBbvRVoK5a/vq2ZfpgcYKwf0DOzyJlF7mu9NxgJZswEv osKEwilG9brQkelXSD5iEO1D3L27bIUgqxqz2tXFUBYqUrrBVBpaN+XoMYylDL703QnUII DCzLaA4e3qziuaG+qFZEGuyJ4BlS4IPWDgICDjI1Tnp6bHSYospDFpEXbkw87Tk5kogiFB qOXHWb5lUWu01TusTviWoot3S4STmRO3wlHc53gvi/3OJVypmrSfvbV8UWFN4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1789638965; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Ul/T9FgNhpPwb27YmnzCI3QgdDwWKc4Y6ScvkAacTg4=; b=i/bYqsaoYyjeHhGcqZh2svTuQnBBUdeD5ogdVFaZNVCMxUwiuZn8OiR1GhApvnXj6E9G89 iuDJm7mjroo0mMqPe/Z9xLVpkI+4nswrM+h5Dec9dhmPZab7Kh4V29h4R1PkeVKJ7AFrw1 bMTAqLZ7Qpscp4/AeowlXk+ZUICt7BwKIAdH0RJp3r2P3STXnQ89hbPmb96cWUqyK5bNhx qFr47hpbezH//Xn+LXgdUULSKbMavpoysIkhtM8knHemsQDTQi8MOhCi8OHS0EL1JpEiHk 5eex7gOxyf6EB7W4SHZ8FOC9Tlky3LFNJ9WKzOa1LpYQ9RDFGfUmwYby76+lhQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hlrjx3QNzzRjJ for ; Thu, 17 Sep 2026 09:56:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 4444e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 17 Sep 2026 09:56:05 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Sarah Walker From: Andrew Turner Subject: git: 9556306213e1 - main - arm64: Add ACPI support to GICv5 driver List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: andrew X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9556306213e1230fc3bef2598129f91e344bd49d Auto-Submitted: auto-generated Date: Thu, 17 Sep 2026 09:56:05 +0000 Message-Id: <6aabb935.4444e.2530872e@gitrepo.freebsd.org> The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=9556306213e1230fc3bef2598129f91e344bd49d commit 9556306213e1230fc3bef2598129f91e344bd49d Author: Sarah Walker AuthorDate: 2026-08-04 12:38:52 +0000 Commit: Andrew Turner CommitDate: 2026-09-17 09:20:22 +0000 arm64: Add ACPI support to GICv5 driver Add ACPI support to the GICv5 IRS, ITS and IWB drivers. Device parameters are derived from the MADT and IORT tables. Reviewed by: andrew Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D59171 --- sys/arm/arm/gic_acpi.c | 3 + sys/arm64/arm64/gicv3_its.c | 2 +- sys/arm64/arm64/gicv5.c | 50 +++++ sys/arm64/arm64/gicv5_acpi.c | 455 +++++++++++++++++++++++++++++++++++++++++++ sys/arm64/arm64/gicv5_its.c | 138 +++++++++++++ sys/arm64/arm64/gicv5_iwb.c | 93 +++++++++ sys/arm64/arm64/gicv5var.h | 2 + sys/conf/files.arm64 | 5 +- 8 files changed, 745 insertions(+), 3 deletions(-) diff --git a/sys/arm/arm/gic_acpi.c b/sys/arm/arm/gic_acpi.c index 6c8257beddfb..b64bfa3fedfd 100644 --- a/sys/arm/arm/gic_acpi.c +++ b/sys/arm/arm/gic_acpi.c @@ -139,6 +139,9 @@ gic_acpi_identify(driver_t *driver, device_t parent) 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 index 42f0fdb2697d..5d91e23830ab 100644 --- a/sys/arm64/arm64/gicv3_its.c +++ b/sys/arm64/arm64/gicv3_its.c @@ -2399,7 +2399,7 @@ gicv3_its_acpi_probe(device_t dev) 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 index a533baacf489..c2d2c31bdc00 100644 --- a/sys/arm64/arm64/gicv5.c +++ b/sys/arm64/arm64/gicv5.c @@ -55,6 +55,11 @@ #include #endif +#ifdef DEV_ACPI +#include +#include +#endif + #include "pic_if.h" #include @@ -1166,6 +1171,26 @@ gic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, bool *ppi, u_int *irqp, } #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 @@ do_gicv5_map_intr(device_t dev, struct intr_map_data *data, bool *ppip, 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 @@ do_gicv5_map_intr(device_t dev, struct intr_map_data *data, bool *ppip, &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_INT_TYPE_MASK) == GSI_INT_TYPE_IWB) + 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 @@ static int 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_INT_TYPE_MASK) == GSI_INT_TYPE_IWB) + 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 index 000000000000..95ae488e3ed2 --- /dev/null +++ b/sys/arm64/arm64/gicv5_acpi.c @@ -0,0 +1,455 @@ +/*- + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#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_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; + + 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 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 index 73395c2eb05b..f69ab215f9e7 100644 --- a/sys/arm64/arm64/gicv5_its.c +++ b/sys/arm64/arm64/gicv5_its.c @@ -56,6 +56,11 @@ #include #endif +#ifdef DEV_ACPI +#include +#include +#endif + #include #include @@ -1237,3 +1242,136 @@ gicv5_its_fdt_attach(device_t dev) 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 index fa2ad370e626..2cf4d9723961 100644 --- a/sys/arm64/arm64/gicv5_iwb.c +++ b/sys/arm64/arm64/gicv5_iwb.c @@ -47,9 +47,17 @@ #include #endif +#ifdef DEV_ACPI +#include +#include +#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 @@ gicv5_iwb_attach(device_t dev) 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 @@ do_gicv5_iwb_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, 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 @@ do_gicv5_iwb_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, &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 @@ gicv5_iwb_fdt_attach(device_t dev) 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 index 027bf2542521..faab72387668 100644 --- a/sys/arm64/arm64/gicv5var.h +++ b/sys/arm64/arm64/gicv5var.h @@ -68,4 +68,6 @@ int gicv5_intr(void *); 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 index 97268193d482..7e604693eba8 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -60,9 +60,10 @@ arm64/arm64/gic_v3.c standard 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