Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Jan 2018 17:23:24 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r327836 - in head/sys: arm/arm arm64/arm64 conf
Message-ID:  <201801111723.w0BHNO1X035839@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andrew
Date: Thu Jan 11 17:23:24 2018
New Revision: 327836
URL: https://svnweb.freebsd.org/changeset/base/327836

Log:
  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

Added:
  head/sys/arm/arm/gic_acpi.c   (contents, props changed)
  head/sys/arm64/arm64/gic_v3_acpi.c   (contents, props changed)
Modified:
  head/sys/arm/arm/gic.c
  head/sys/arm64/arm64/gic_v3.c
  head/sys/arm64/arm64/gic_v3_var.h
  head/sys/arm64/arm64/gicv3_its.c
  head/sys/conf/files.arm64

Modified: head/sys/arm/arm/gic.c
==============================================================================
--- head/sys/arm/arm/gic.c	Thu Jan 11 17:09:12 2018	(r327835)
+++ head/sys/arm/arm/gic.c	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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,
 #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 @@ gic_map_intr(device_t dev, struct intr_map_data *data,
 		    (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:

Added: head/sys/arm/arm/gic_acpi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/arm/gic_acpi.c	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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);

Modified: head/sys/arm64/arm64/gic_v3.c
==============================================================================
--- head/sys/arm64/arm64/gic_v3.c	Thu Jan 11 17:09:12 2018	(r327835)
+++ head/sys/arm64/arm64/gic_v3.c	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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>
@@ -570,6 +576,9 @@ do_gic_v3_map_intr(device_t dev, struct intr_map_data 
 #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 @@ do_gic_v3_map_intr(device_t dev, struct intr_map_data 
 		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:

Added: head/sys/arm64/arm64/gic_v3_acpi.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/arm64/gic_v3_acpi.c	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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));
+}

Modified: head/sys/arm64/arm64/gic_v3_var.h
==============================================================================
--- head/sys/arm64/arm64/gic_v3_var.h	Thu Jan 11 17:09:12 2018	(r327835)
+++ head/sys/arm64/arm64/gic_v3_var.h	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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 *);

Modified: head/sys/arm64/arm64/gicv3_its.c
==============================================================================
--- head/sys/arm64/arm64/gicv3_its.c	Thu Jan 11 17:09:12 2018	(r327835)
+++ head/sys/arm64/arm64/gicv3_its.c	Thu Jan 11 17:23:24 2018	(r327836)
@@ -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_fd
 #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 @@ gicv3_its_fdt_attach(device_t dev)
 
 	/* 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);
 }

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Thu Jan 11 17:09:12 2018	(r327835)
+++ head/sys/conf/files.arm64	Thu Jan 11 17:23:24 2018	(r327836)
@@ -63,6 +63,7 @@ arm/annapurna/alpine/alpine_serdes.c		optional al_serd
 	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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201801111723.w0BHNO1X035839>