Index: head/sys/arm/arm/gic.c =================================================================== --- head/sys/arm/arm/gic.c +++ head/sys/arm/arm/gic.c @@ -36,6 +36,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_acpi.h" #include "opt_platform.h" #include @@ -68,6 +69,11 @@ #include #endif +#ifdef DEV_ACPI +#include +#include +#endif + #include #include @@ -888,6 +894,9 @@ #ifdef FDT struct intr_map_data_fdt *daf; #endif +#ifdef DEV_ACPI + struct intr_map_data_acpi *daa; +#endif sc = device_get_softc(dev); switch (data->type) { @@ -901,6 +910,14 @@ (sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) == 0, ("%s: Attempting to map a MSI interrupt from FDT", __func__)); + break; +#endif +#ifdef DEV_ACPI + case INTR_MAP_DATA_ACPI: + daa = (struct intr_map_data_acpi *)data; + irq = daa->irq; + pol = daa->pol; + trig = daa->trig; break; #endif case INTR_MAP_DATA_MSI: Index: head/sys/arm/arm/gic_acpi.c =================================================================== --- head/sys/arm/arm/gic_acpi.c +++ head/sys/arm/arm/gic_acpi.c @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 2011,2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * sponsorship from the FreeBSD Foundation. + * + * Developed by Damjan Marion + * + * Based on OMAP4 GIC code by Ben Gray + * + * 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. + * 3. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * 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_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +struct gic_acpi_devinfo { + struct resource_list rl; +}; + +static device_identify_t gic_acpi_identify; +static device_probe_t gic_acpi_probe; +static device_attach_t gic_acpi_attach; +static bus_get_resource_list_t gic_acpi_get_resource_list; +static bool arm_gic_add_children(device_t); + +static device_method_t gic_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, gic_acpi_identify), + DEVMETHOD(device_probe, gic_acpi_probe), + DEVMETHOD(device_attach, gic_acpi_attach), + + /* Bus interface */ + DEVMETHOD(bus_get_resource_list, gic_acpi_get_resource_list), + + DEVMETHOD_END, +}; + +DEFINE_CLASS_1(gic, gic_acpi_driver, gic_acpi_methods, + sizeof(struct arm_gic_softc), arm_gic_driver); + +static devclass_t gic_acpi_devclass; + +EARLY_DRIVER_MODULE(gic, acpi, gic_acpi_driver, gic_acpi_devclass, 0, 0, + BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); + +struct madt_table_data { + device_t parent; + ACPI_MADT_GENERIC_DISTRIBUTOR *dist; + ACPI_MADT_GENERIC_INTERRUPT *intr[MAXCPU]; +}; + +static void +madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) +{ + struct madt_table_data *madt_data; + ACPI_MADT_GENERIC_INTERRUPT *intr; + + madt_data = (struct madt_table_data *)arg; + + switch(entry->Type) { + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + if (madt_data->dist != NULL) { + if (bootverbose) + device_printf(madt_data->parent, + "gic: Already have a distributor table"); + } else + madt_data->dist = + (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry; + break; + case ACPI_MADT_TYPE_GENERIC_INTERRUPT: + intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry; + if (intr->CpuInterfaceNumber < MAXCPU) + madt_data->intr[intr->CpuInterfaceNumber] = intr; + break; + } +} + +static void +gic_acpi_identify(driver_t *driver, device_t parent) +{ + struct madt_table_data madt_data; + ACPI_MADT_GENERIC_INTERRUPT *intr; + ACPI_TABLE_MADT *madt; + vm_paddr_t physaddr; + device_t dev; + int i; + + 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; + } + + bzero(&madt_data, sizeof(madt_data)); + madt_data.parent = parent; + madt_data.dist = NULL; + + acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, + madt_handler, &madt_data); + + /* Check the version of the GIC we have */ + switch (madt_data.dist->Version) { + case ACPI_MADT_GIC_VERSION_NONE: + case ACPI_MADT_GIC_VERSION_V1: + case ACPI_MADT_GIC_VERSION_V2: + break; + default: + goto out; + } + + intr = NULL; + for (i = 0; i < MAXCPU; i++) { + if (madt_data.intr[i] != NULL) { + if (intr == NULL) { + intr = madt_data.intr[i]; + } else if (intr->BaseAddress != + madt_data.intr[i]->BaseAddress) { + device_printf(parent, +"gic: Not all CPU interfaces at the same address, this may fail\n"); + } + } + } + if (intr == NULL) { + device_printf(parent, "gic: No CPU interfaces found\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; + } + + BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0, + madt_data.dist->BaseAddress, 4 * 1024); + BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 1, + intr->BaseAddress, 4 * 1024); + + acpi_set_private(dev, (void *)(uintptr_t)madt_data.dist->Version); +out: + acpi_unmap_table(madt); +} + +static int +gic_acpi_probe(device_t dev) +{ + + switch((uintptr_t)acpi_get_private(dev)) { + case ACPI_MADT_GIC_VERSION_NONE: + case ACPI_MADT_GIC_VERSION_V1: + case ACPI_MADT_GIC_VERSION_V2: + break; + default: + return (ENXIO); + } + + device_set_desc(dev, "ARM Generic Interrupt Controller"); + return (BUS_PROBE_NOWILDCARD); +} + +static int +gic_acpi_attach(device_t dev) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + intptr_t xref; + int err; + + sc->gic_bus = GIC_BUS_ACPI; + + err = arm_gic_attach(dev); + if (err != 0) + return (err); + + xref = 0; + + /* + * Now, when everything is initialized, it's right time to + * register interrupt controller to interrupt framefork. + */ + if (intr_pic_register(dev, xref) == NULL) { + device_printf(dev, "could not register PIC\n"); + goto cleanup; + } + + /* + * Controller is root: + */ + if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, + GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { + device_printf(dev, "could not set PIC as a root\n"); + intr_pic_deregister(dev, xref); + goto cleanup; + } + /* If we have children probe and attach them */ + if (arm_gic_add_children(dev)) { + bus_generic_probe(dev); + return (bus_generic_attach(dev)); + } + + return (0); + +cleanup: + arm_gic_detach(dev); + return(ENXIO); +} + +static struct resource_list * +gic_acpi_get_resource_list(device_t bus, device_t child) +{ + struct gic_acpi_devinfo *di; + + di = device_get_ivars(child); + KASSERT(di != NULL, ("gic_acpi_get_resource_list: No devinfo")); + + return (&di->rl); +} + +static void +madt_gicv2m_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) +{ + struct arm_gic_softc *sc; + ACPI_MADT_GENERIC_MSI_FRAME *msi; + struct gic_acpi_devinfo *dinfo; + device_t dev, cdev; + + if (entry->Type == ACPI_MADT_TYPE_GENERIC_MSI_FRAME) { + sc = arg; + dev = sc->gic_dev; + msi = (ACPI_MADT_GENERIC_MSI_FRAME *)entry; + + device_printf(dev, "frame: %x %lx %x %u %u\n", msi->MsiFrameId, + msi->BaseAddress, msi->Flags, msi->SpiCount, msi->SpiBase); + + cdev = device_add_child(dev, NULL, -1); + if (cdev == NULL) + return; + + dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); + resource_list_init(&dinfo->rl); + resource_list_add(&dinfo->rl, SYS_RES_MEMORY, 0, + msi->BaseAddress, msi->BaseAddress + PAGE_SIZE - 1, + PAGE_SIZE); + device_set_ivars(cdev, dinfo); + } +} + +static bool +arm_gic_add_children(device_t dev) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + ACPI_TABLE_MADT *madt; + vm_paddr_t physaddr; + + /* This should return a valid address as it did in gic_acpi_identify */ + physaddr = acpi_find_table(ACPI_SIG_MADT); + if (physaddr == 0) + return (false); + + madt = acpi_map_table(physaddr, ACPI_SIG_MADT); + if (madt == NULL) { + device_printf(dev, "gic: Unable to map the MADT\n"); + return (false); + } + + acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, + madt_gicv2m_handler, sc); + + acpi_unmap_table(madt); + + return (true); +} + +static int +arm_gicv2m_acpi_probe(device_t dev) +{ + + if (gic_get_bus(dev) != GIC_BUS_ACPI) + return (EINVAL); + + if (gic_get_hw_rev(dev) > 2) + return (EINVAL); + + device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); + return (BUS_PROBE_DEFAULT); +} + +static device_method_t arm_gicv2m_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, arm_gicv2m_acpi_probe), + + /* End */ + DEVMETHOD_END +}; + +DEFINE_CLASS_1(gicv2m, arm_gicv2m_acpi_driver, arm_gicv2m_acpi_methods, + sizeof(struct arm_gicv2m_softc), arm_gicv2m_driver); + +static devclass_t arm_gicv2m_acpi_devclass; + +EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_acpi_driver, + arm_gicv2m_acpi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: head/sys/arm64/arm64/gic_v3.c =================================================================== --- head/sys/arm64/arm64/gic_v3.c +++ head/sys/arm64/arm64/gic_v3.c @@ -30,6 +30,7 @@ * SUCH DAMAGE. */ +#include "opt_acpi.h" #include "opt_platform.h" #include @@ -63,6 +64,11 @@ #include #endif +#ifdef DEV_ACPI +#include +#include +#endif + #include "pic_if.h" #include @@ -570,6 +576,9 @@ #ifdef FDT struct intr_map_data_fdt *daf; #endif +#ifdef DEV_ACPI + struct intr_map_data_acpi *daa; +#endif u_int irq; sc = device_get_softc(dev); @@ -581,6 +590,14 @@ if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, &trig) != 0) return (EINVAL); + break; +#endif +#ifdef DEV_ACPI + case INTR_MAP_DATA_ACPI: + daa = (struct intr_map_data_acpi *)data; + irq = daa->irq; + pol = daa->pol; + trig = daa->trig; break; #endif case INTR_MAP_DATA_MSI: Index: head/sys/arm64/arm64/gic_v3_acpi.c =================================================================== --- head/sys/arm64/arm64/gic_v3_acpi.c +++ head/sys/arm64/arm64/gic_v3_acpi.c @@ -0,0 +1,335 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * the sponsorship of the FreeBSD Foundation. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "gic_v3_reg.h" +#include "gic_v3_var.h" + +struct gic_v3_acpi_devinfo { + struct resource_list di_rl; +}; + +static device_identify_t gic_v3_acpi_identify; +static device_probe_t gic_v3_acpi_probe; +static device_attach_t gic_v3_acpi_attach; +static bus_alloc_resource_t gic_v3_acpi_bus_alloc_res; + +static void gic_v3_acpi_bus_attach(device_t); + +static device_method_t gic_v3_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, gic_v3_acpi_identify), + DEVMETHOD(device_probe, gic_v3_acpi_probe), + DEVMETHOD(device_attach, gic_v3_acpi_attach), + + /* Bus interface */ + DEVMETHOD(bus_alloc_resource, gic_v3_acpi_bus_alloc_res), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + + /* End */ + DEVMETHOD_END +}; + +DEFINE_CLASS_1(gic, gic_v3_acpi_driver, gic_v3_acpi_methods, + sizeof(struct gic_v3_softc), gic_v3_driver); + +static devclass_t gic_v3_acpi_devclass; + +EARLY_DRIVER_MODULE(gic_v3, acpi, gic_v3_acpi_driver, gic_v3_acpi_devclass, + 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); + + +struct madt_table_data { + device_t parent; + device_t dev; + ACPI_MADT_GENERIC_DISTRIBUTOR *dist; + int count; +}; + +static void +madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) +{ + struct madt_table_data *madt_data; + + madt_data = (struct madt_table_data *)arg; + + switch(entry->Type) { + case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: + if (madt_data->dist != NULL) { + if (bootverbose) + device_printf(madt_data->parent, + "gic: Already have a distributor table"); + break; + } + madt_data->dist = (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry; + break; + + case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: + break; + + default: + break; + } +} + +static void +rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg) +{ + ACPI_MADT_GENERIC_REDISTRIBUTOR *redist; + struct madt_table_data *madt_data; + + madt_data = (struct madt_table_data *)arg; + + switch(entry->Type) { + case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: + redist = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)entry; + + madt_data->count++; + BUS_SET_RESOURCE(madt_data->parent, madt_data->dev, + SYS_RES_MEMORY, madt_data->count, redist->BaseAddress, + redist->Length); + break; + + default: + break; + } +} + +static void +gic_v3_acpi_identify(driver_t *driver, device_t parent) +{ + struct madt_table_data madt_data; + ACPI_TABLE_MADT *madt; + vm_paddr_t physaddr; + 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.dist = NULL; + madt_data.count = 0; + + acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, + madt_handler, &madt_data); + if (madt_data.dist == NULL) { + device_printf(parent, + "No gic interrupt or distributor table\n"); + goto out; + } + /* This is for the wrong GIC version */ + if (madt_data.dist->Version != ACPI_MADT_GIC_VERSION_V3) + 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 */ + BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0, + madt_data.dist->BaseAddress, 128 * 1024); + + madt_data.dev = dev; + acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, + rdist_map, &madt_data); + + acpi_set_private(dev, (void *)(uintptr_t)madt_data.dist->Version); + +out: + acpi_unmap_table(madt); +} + +static int +gic_v3_acpi_probe(device_t dev) +{ + + switch((uintptr_t)acpi_get_private(dev)) { + case ACPI_MADT_GIC_VERSION_V3: + break; + default: + return (ENXIO); + } + + device_set_desc(dev, GIC_V3_DEVSTR); + return (BUS_PROBE_NOWILDCARD); +} + +static int +gic_v3_acpi_attach(device_t dev) +{ + struct gic_v3_softc *sc; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->gic_bus = GIC_BUS_ACPI; + + /* TODO: Count these correctly */ + sc->gic_redists.nregions = 1; + + err = gic_v3_attach(dev); + if (err != 0) + goto error; + + sc->gic_pic = intr_pic_register(dev, 0); + if (sc->gic_pic == NULL) { + device_printf(dev, "could not register PIC\n"); + err = ENXIO; + goto error; + } + + if (intr_pic_claim_root(dev, 0, arm_gic_v3_intr, sc, + GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { + err = ENXIO; + goto error; + } + + /* + * Try to register the ITS driver to this GIC. The GIC will act as + * a bus in that case. Failure here will not affect the main GIC + * functionality. + */ + gic_v3_acpi_bus_attach(dev); + + return (0); + +error: + if (bootverbose) { + device_printf(dev, + "Failed to attach. Error %d\n", err); + } + /* Failure so free resources */ + gic_v3_detach(dev); + + return (err); +} + +static void +gic_v3_add_children(ACPI_SUBTABLE_HEADER *entry, void *arg) +{ + ACPI_MADT_GENERIC_TRANSLATOR *gict; + struct gic_v3_acpi_devinfo *di; + device_t child, dev; + + if (entry->Type == ACPI_MADT_TYPE_GENERIC_TRANSLATOR) { + /* We have an ITS, add it as a child */ + gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry; + dev = arg; + + child = device_add_child(dev, "its", -1); + if (child == NULL) + return; + + di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO); + resource_list_init(&di->di_rl); + resource_list_add(&di->di_rl, SYS_RES_MEMORY, 0, + gict->BaseAddress, gict->BaseAddress + 128 * 1024 - 1, + 128 * 1024); + device_set_ivars(child, di); + } +} + +static void +gic_v3_acpi_bus_attach(device_t dev) +{ + ACPI_TABLE_MADT *madt; + vm_paddr_t physaddr; + + physaddr = acpi_find_table(ACPI_SIG_MADT); + if (physaddr == 0) + 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_v3_add_children, dev); + + acpi_unmap_table(madt); + + bus_generic_attach(dev); +} + +static struct resource * +gic_v3_acpi_bus_alloc_res(device_t bus, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct gic_v3_acpi_devinfo *di; + struct resource_list_entry *rle; + + /* We only allocate memory */ + if (type != SYS_RES_MEMORY) + return (NULL); + + if (RMAN_IS_DEFAULT_RANGE(start, end)) { + if ((di = device_get_ivars(child)) == NULL) + return (NULL); + + /* Find defaults for this rid */ + rle = resource_list_find(&di->di_rl, type, *rid); + if (rle == NULL) + return (NULL); + + start = rle->start; + end = rle->end; + count = rle->count; + } + + return (bus_generic_alloc_resource(bus, child, type, rid, start, end, + count, flags)); +} Index: head/sys/arm64/arm64/gic_v3_var.h =================================================================== --- head/sys/arm64/arm64/gic_v3_var.h +++ head/sys/arm64/arm64/gic_v3_var.h @@ -32,6 +32,8 @@ #ifndef _GIC_V3_VAR_H_ #define _GIC_V3_VAR_H_ +#include + #define GIC_V3_DEVSTR "ARM Generic Interrupt Controller v3.0" DECLARE_CLASS(gic_v3_driver); @@ -92,10 +94,8 @@ MALLOC_DECLARE(M_GIC_V3); /* ivars */ -enum { - GICV3_IVAR_NIRQS, - GICV3_IVAR_REDIST_VADDR, -}; +#define GICV3_IVAR_NIRQS 1000 +#define GICV3_IVAR_REDIST_VADDR 1001 __BUS_ACCESSOR(gicv3, nirqs, GICV3, NIRQS, u_int); __BUS_ACCESSOR(gicv3, redist_vaddr, GICV3, REDIST_VADDR, void *); Index: head/sys/arm64/arm64/gicv3_its.c =================================================================== --- head/sys/arm64/arm64/gicv3_its.c +++ head/sys/arm64/arm64/gicv3_its.c @@ -30,6 +30,7 @@ * SUCH DAMAGE. */ +#include "opt_acpi.h" #include "opt_platform.h" #include @@ -1640,7 +1641,7 @@ #undef its_baseclasses static devclass_t gicv3_its_fdt_devclass; -EARLY_DRIVER_MODULE(its, gic, gicv3_its_fdt_driver, +EARLY_DRIVER_MODULE(its_fdt, gic, gicv3_its_fdt_driver, gicv3_its_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); static int @@ -1682,6 +1683,65 @@ /* Register this device to handle MSI interrupts */ intr_msi_register(dev, xref); + + return (0); +} +#endif + +#ifdef DEV_ACPI +static device_probe_t gicv3_its_acpi_probe; +static device_attach_t gicv3_its_acpi_attach; + +static device_method_t gicv3_its_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gicv3_its_acpi_probe), + DEVMETHOD(device_attach, gicv3_its_acpi_attach), + + /* End */ + DEVMETHOD_END +}; + +#define its_baseclasses its_acpi_baseclasses +DEFINE_CLASS_1(its, gicv3_its_acpi_driver, gicv3_its_acpi_methods, + sizeof(struct gicv3_its_softc), gicv3_its_driver); +#undef its_baseclasses +static devclass_t gicv3_its_acpi_devclass; + +EARLY_DRIVER_MODULE(its_acpi, gic, gicv3_its_acpi_driver, + gicv3_its_acpi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); + +static int +gicv3_its_acpi_probe(device_t dev) +{ + + if (gic_get_bus(dev) != GIC_BUS_ACPI) + return (EINVAL); + + if (gic_get_hw_rev(dev) < 3) + return (EINVAL); + + device_set_desc(dev, "ARM GIC Interrupt Translation Service"); + return (BUS_PROBE_DEFAULT); +} + +static int +gicv3_its_acpi_attach(device_t dev) +{ + struct gicv3_its_softc *sc; + int err; + + err = gicv3_its_attach(dev); + if (err != 0) + return (err); + + sc = device_get_softc(dev); + + sc->sc_pic = intr_pic_register(dev, 1); + intr_pic_add_handler(device_get_parent(dev), sc->sc_pic, + gicv3_its_intr, sc, GIC_FIRST_LPI, LPI_NIRQS); + + /* Register this device to handle MSI interrupts */ + intr_msi_register(dev, 1); return (0); } Index: head/sys/conf/files.arm64 =================================================================== --- head/sys/conf/files.arm64 +++ head/sys/conf/files.arm64 @@ -63,6 +63,7 @@ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" arm/arm/generic_timer.c standard arm/arm/gic.c standard +arm/arm/gic_acpi.c optional acpi arm/arm/gic_fdt.c optional fdt arm/arm/pmu.c standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq fdt \ @@ -111,6 +112,7 @@ arm64/arm64/freebsd32_machdep.c optional compat_freebsd32 arm64/arm64/gicv3_its.c optional intrng fdt arm64/arm64/gic_v3.c standard +arm64/arm64/gic_v3_acpi.c optional acpi arm64/arm64/gic_v3_fdt.c optional fdt arm64/arm64/identcpu.c standard arm64/arm64/in_cksum.c optional inet | inet6