Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/acpi Add GICv3 ACPI attachment glue.



details:   https://anonhg.NetBSD.org/src/rev/6f1e9b36e15b
branches:  trunk
changeset: 445304:6f1e9b36e15b
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Oct 21 21:18:41 2018 +0000

description:
Add GICv3 ACPI attachment glue.

diffstat:

 sys/arch/arm/acpi/files.acpi   |    5 +-
 sys/arch/arm/acpi/gicv3_acpi.c |  266 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 270 insertions(+), 1 deletions(-)

diffs (289 lines):

diff -r d9ac86ff6d8e -r 6f1e9b36e15b sys/arch/arm/acpi/files.acpi
--- a/sys/arch/arm/acpi/files.acpi      Sun Oct 21 18:32:23 2018 +0000
+++ b/sys/arch/arm/acpi/files.acpi      Sun Oct 21 21:18:41 2018 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.acpi,v 1.2 2018/10/15 11:35:03 jmcneill Exp $
+#      $NetBSD: files.acpi,v 1.3 2018/10/21 21:18:41 jmcneill Exp $
 #
 # Configuration info for ACPI compliant ARM boards.
 #
@@ -21,6 +21,9 @@
 attach gic at acpimadtbus with gic_acpi
 file   arch/arm/acpi/gic_acpi.c                gic_acpi
 
+attach gicvthree at acpimadtbus with gicv3_acpi
+file   arch/arm/acpi/gicv3_acpi.c              gicv3_acpi
+
 attach gtmr at acpisdtbus with gtmr_acpi
 file   arch/arm/acpi/gtmr_acpi.c               gtmr_acpi
 
diff -r d9ac86ff6d8e -r 6f1e9b36e15b sys/arch/arm/acpi/gicv3_acpi.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/acpi/gicv3_acpi.c    Sun Oct 21 21:18:41 2018 +0000
@@ -0,0 +1,266 @@
+/* $NetBSD: gicv3_acpi.c,v 1.1 2018/10/21 21:18:41 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jared McNeill <jmcneill%invisible.ca@localhost>.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define        _INTR_PRIVATE
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: gicv3_acpi.c,v 1.1 2018/10/21 21:18:41 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+#include <arm/cortex/gicv3.h>
+#include <arm/cortex/gic_reg.h>
+
+#define        GICD_SIZE       0x10000
+#define        GICR_SIZE       0x20000
+
+extern struct bus_space arm_generic_bs_tag;
+
+struct gicv3_acpi_softc {
+       struct gicv3_softc      sc_gic;
+
+       ACPI_MADT_GENERIC_DISTRIBUTOR *sc_madt_gicd;
+};
+
+static int     gicv3_acpi_match(device_t, cfdata_t, void *);
+static void    gicv3_acpi_attach(device_t, device_t, void *);
+
+static int     gicv3_acpi_map_dist(struct gicv3_acpi_softc *);
+static int     gicv3_acpi_map_redist(struct gicv3_acpi_softc *);
+
+CFATTACH_DECL_NEW(gicv3_acpi, sizeof(struct gicv3_acpi_softc), gicv3_acpi_match, gicv3_acpi_attach, NULL, NULL);
+
+static int
+gicv3_acpi_match(device_t parent, cfdata_t cf, void *aux)
+{
+       ACPI_SUBTABLE_HEADER *hdrp = aux;
+       ACPI_MADT_GENERIC_DISTRIBUTOR *gicd;
+
+       if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR)
+               return 0;
+
+       gicd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)hdrp;
+
+       switch (gicd->Version) {
+       case ACPI_MADT_GIC_VERSION_NONE:
+               return __SHIFTOUT(reg_id_aa64pfr0_el1_read(), ID_AA64PFR0_EL1_GIC) == 1;
+       case ACPI_MADT_GIC_VERSION_V3:
+       case ACPI_MADT_GIC_VERSION_V4:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static void
+gicv3_acpi_attach(device_t parent, device_t self, void *aux)
+{
+       struct gicv3_acpi_softc * const sc = device_private(self);
+       ACPI_MADT_GENERIC_DISTRIBUTOR *gicd = aux;
+       int error;
+
+       sc->sc_gic.sc_dev = self;
+       sc->sc_gic.sc_bst = &arm_generic_bs_tag;
+       sc->sc_madt_gicd = gicd;
+
+       aprint_naive("\n");
+       aprint_normal(": GICv3\n");
+
+       error = gicv3_acpi_map_dist(sc);
+       if (error) {
+               aprint_error_dev(self, "failed to map distributor: %d\n", error);
+               return;
+       }
+
+       error = gicv3_acpi_map_redist(sc);
+       if (error) {
+               aprint_error_dev(self, "failed to map redistributor: %d\n", error);
+               return;
+       }
+
+       error = gicv3_init(&sc->sc_gic);
+       if (error) {
+               aprint_error_dev(self, "failed to initialize GIC: %d\n", error);
+               return;
+       }
+
+       arm_fdt_irq_set_handler(gicv3_irq_handler);
+}
+
+static int
+gicv3_acpi_map_dist(struct gicv3_acpi_softc *sc)
+{
+       const bus_addr_t addr = sc->sc_madt_gicd->BaseAddress;
+       const bus_size_t size = GICD_SIZE;
+       int error;
+
+       error = bus_space_map(sc->sc_gic.sc_bst, addr, size, 0, &sc->sc_gic.sc_bsh_d);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static ACPI_STATUS
+gicv3_acpi_count_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
+{
+       ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
+       int *count = aux;
+
+       if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR) {
+               gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
+               *count += howmany(gicr->Length, GICR_SIZE);
+       }
+
+       return AE_OK;
+}
+
+static ACPI_STATUS
+gicv3_acpi_map_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
+{
+       struct gicv3_acpi_softc * const sc = aux;
+       ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
+       bus_space_handle_t bsh;
+       bus_size_t off;
+
+       if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR)
+               return AE_OK;
+
+       gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
+
+       if (bus_space_map(sc->sc_gic.sc_bst, gicr->BaseAddress, gicr->Length, 0, &bsh) != 0) {
+               aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
+                   gicr->BaseAddress, gicr->Length);
+               return AE_OK;
+       }
+
+       for (off = 0; off < gicr->Length; off += GICR_SIZE) {
+               const int redist = sc->sc_gic.sc_bsh_r_count;
+               if (bus_space_subregion(sc->sc_gic.sc_bst, bsh, off, GICR_SIZE, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
+                       aprint_error_dev(sc->sc_gic.sc_dev, "couldn't subregion redistributor registers\n");
+                       return AE_OK;
+               }
+
+               aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICR]\n", gicr->BaseAddress + off);
+
+               sc->sc_gic.sc_bsh_r_count++;
+
+               /* If this is the last redist in this region, skip to the next one */
+               const uint32_t typer = bus_space_read_4(sc->sc_gic.sc_bst, sc->sc_gic.sc_bsh_r[redist], GICR_TYPER);
+               if (typer & GICR_TYPER_Last)
+                       break;
+       }
+
+       return AE_OK;
+}
+
+static ACPI_STATUS
+gicv3_acpi_count_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
+{
+       ACPI_MADT_GENERIC_INTERRUPT *gicc;
+       int *count = aux;
+
+       if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+               gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
+               if ((gicc->Flags & ACPI_MADT_ENABLED) != 0)
+                       (*count)++;
+       }
+
+       return AE_OK;
+}
+
+static ACPI_STATUS
+gicv3_acpi_map_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
+{
+       struct gicv3_acpi_softc * const sc = aux;
+       ACPI_MADT_GENERIC_INTERRUPT *gicc;
+
+       if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_INTERRUPT)
+               return AE_OK;
+
+       gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
+       if ((gicc->Flags & ACPI_MADT_ENABLED) == 0)
+               return AE_OK;
+
+       const int redist = sc->sc_gic.sc_bsh_r_count;
+       if (bus_space_map(sc->sc_gic.sc_bst, gicc->GicrBaseAddress, GICR_SIZE, 0, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
+               aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
+                   gicc->GicrBaseAddress, GICR_SIZE);
+               return AE_OK;
+       }
+
+       aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICC]\n", gicc->GicrBaseAddress);
+
+       sc->sc_gic.sc_bsh_r_count++;
+
+       return AE_OK;
+}
+
+static int
+gicv3_acpi_map_redist(struct gicv3_acpi_softc *sc)
+{
+       bool use_gicr = false;
+       int max_redist = 0;
+
+       /*
+        * Try to use GICR structures to describe redistributors. If no GICR
+        * subtables are found, use the GICR address from the GICC subtables.
+        */
+       acpi_madt_walk(gicv3_acpi_count_gicr, &max_redist);
+       if (max_redist != 0)
+               use_gicr = true;
+       else
+               acpi_madt_walk(gicv3_acpi_count_gicc, &max_redist);
+
+       if (max_redist == 0)
+               return ENODEV;
+
+       sc->sc_gic.sc_bsh_r = kmem_alloc(sizeof(bus_space_handle_t) * max_redist, KM_SLEEP);
+       if (use_gicr)
+               acpi_madt_walk(gicv3_acpi_map_gicr, sc);
+       else
+               acpi_madt_walk(gicv3_acpi_map_gicc, sc);
+
+       if (sc->sc_gic.sc_bsh_r_count == 0)
+               return ENXIO;
+
+       return 0;
+}



Home | Main Index | Thread Index | Old Index