iAdd ACPI attachments the the GIC and GICv3 interrupt controller drivers.

For each we need to walk the MADT to find which we have, then add the
driver as needed. As each may have a child they will each walk the same
table to find these details.

Reviewed by:	mmel
Obtained from:	ABT Systems Ltd
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D8720
This commit is contained in:
Andrew Turner 2018-01-11 17:23:24 +00:00
parent 224c3776f6
commit ee42eb7e5c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327836
7 changed files with 782 additions and 5 deletions

View File

@ -36,6 +36,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_acpi.h"
#include "opt_platform.h"
#include <sys/param.h>
@ -68,6 +69,11 @@ __FBSDID("$FreeBSD$");
#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 <arm/arm/gic.h>
#include <arm/arm/gic_common.h>
@ -888,6 +894,9 @@ gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
#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) {
@ -902,6 +911,14 @@ gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
("%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:
/* Non-GICv2m MSI */

346
sys/arm/arm/gic_acpi.c Normal file
View File

@ -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 <damjan.marion@gmail.com>
*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/intr.h>
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
#include <arm/arm/gic.h>
#include <arm/arm/gic_common.h>
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);

View File

@ -30,6 +30,7 @@
* SUCH DAMAGE.
*/
#include "opt_acpi.h"
#include "opt_platform.h"
#include <sys/cdefs.h>
@ -63,6 +64,11 @@ __FBSDID("$FreeBSD$");
#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>
@ -569,6 +575,9 @@ do_gic_v3_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
struct intr_map_data_msi *dam;
#ifdef FDT
struct intr_map_data_fdt *daf;
#endif
#ifdef DEV_ACPI
struct intr_map_data_acpi *daa;
#endif
u_int irq;
@ -582,6 +591,14 @@ do_gic_v3_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;
pol = daa->pol;
trig = daa->trig;
break;
#endif
case INTR_MAP_DATA_MSI:
/* SPI-mapped MSI */

View File

@ -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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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 <machine/intr.h>
#include <machine/resource.h>
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
#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));
}

View File

@ -32,6 +32,8 @@
#ifndef _GIC_V3_VAR_H_
#define _GIC_V3_VAR_H_
#include <arm/arm/gic_common.h>
#define GIC_V3_DEVSTR "ARM Generic Interrupt Controller v3.0"
DECLARE_CLASS(gic_v3_driver);
@ -92,10 +94,8 @@ struct gic_v3_devinfo {
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 *);

View File

@ -30,6 +30,7 @@
* SUCH DAMAGE.
*/
#include "opt_acpi.h"
#include "opt_platform.h"
#include <sys/cdefs.h>
@ -1640,7 +1641,7 @@ DEFINE_CLASS_1(its, gicv3_its_fdt_driver, gicv3_its_fdt_methods,
#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
@ -1686,3 +1687,62 @@ gicv3_its_fdt_attach(device_t dev)
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);
}
#endif

View File

@ -63,6 +63,7 @@ arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \
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/exception.S standard
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