Module Name:    src
Committed By:   jmcneill
Date:           Sun Nov 11 21:24:28 UTC 2018

Modified Files:
        src/sys/arch/arm/fdt: gic_fdt.c

Log Message:
Add GICv2m support


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/arm/fdt/gic_fdt.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/fdt/gic_fdt.c
diff -u src/sys/arch/arm/fdt/gic_fdt.c:1.13 src/sys/arch/arm/fdt/gic_fdt.c:1.14
--- src/sys/arch/arm/fdt/gic_fdt.c:1.13	Mon Sep  3 16:29:23 2018
+++ src/sys/arch/arm/fdt/gic_fdt.c	Sun Nov 11 21:24:28 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: gic_fdt.c,v 1.13 2018/09/03 16:29:23 riastradh Exp $ */
+/* $NetBSD: gic_fdt.c,v 1.14 2018/11/11 21:24:28 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015-2017 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.13 2018/09/03 16:29:23 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.14 2018/11/11 21:24:28 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -39,15 +39,25 @@ __KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 
 #include <sys/kmem.h>
 #include <sys/queue.h>
 
+#include <dev/pci/pcivar.h>
+
 #include <arm/cortex/gic_intr.h>
+#include <arm/cortex/gic_reg.h>
+#include <arm/cortex/gic_v2m.h>
 #include <arm/cortex/mpcore_var.h>
 
 #include <dev/fdt/fdtvar.h>
 
 #define	GIC_MAXIRQ	1020
 
+extern struct pic_softc *pic_list[];
+
+struct gic_fdt_softc;
+struct gic_fdt_irq;
+
 static int	gic_fdt_match(device_t, cfdata_t, void *);
 static void	gic_fdt_attach(device_t, device_t, void *);
+static void	gic_fdt_attach_v2m(struct gic_fdt_softc *, bus_space_tag_t, int);
 
 static int	gic_fdt_intr(void *);
 
@@ -62,9 +72,6 @@ struct fdtbus_interrupt_controller_func 
 	.intrstr = gic_fdt_intrstr
 };
 
-struct gic_fdt_softc;
-struct gic_fdt_irq;
-
 struct gic_fdt_irqhandler {
 	struct gic_fdt_irq	*ih_irq;
 	int			(*ih_fn)(void *);
@@ -87,8 +94,11 @@ struct gic_fdt_irq {
 
 struct gic_fdt_softc {
 	device_t		sc_dev;
+	device_t		sc_gicdev;
 	int			sc_phandle;
 
+	int			sc_v2m_count;
+
 	struct gic_fdt_irq	*sc_irq[GIC_MAXIRQ];
 };
 
@@ -107,7 +117,7 @@ gic_fdt_match(device_t parent, cfdata_t 
 	};
 	struct fdt_attach_args * const faa = aux;
 
-	return of_compatible(faa->faa_phandle, compatible) >= 0;
+	return of_match_compatible(faa->faa_phandle, compatible);
 }
 
 static void
@@ -115,15 +125,16 @@ gic_fdt_attach(device_t parent, device_t
 {
 	struct gic_fdt_softc * const sc = device_private(self);
 	struct fdt_attach_args * const faa = aux;
+	const int phandle = faa->faa_phandle;
 	bus_addr_t addr_d, addr_c;
 	bus_size_t size_d, size_c;
 	bus_space_handle_t bsh;
-	int error;
+	int error, child;
 
 	sc->sc_dev = self;
-	sc->sc_phandle = faa->faa_phandle;
+	sc->sc_phandle = phandle;
 
-	error = fdtbus_register_interrupt_controller(self, faa->faa_phandle,
+	error = fdtbus_register_interrupt_controller(self, phandle,
 	    &gic_fdt_funcs);
 	if (error) {
 		aprint_error(": couldn't register with fdtbus: %d\n", error);
@@ -160,9 +171,58 @@ gic_fdt_attach(device_t parent, device_t
 		.mpcaa_off2 = addr_c - addr,
 	};
 
-	config_found(self, &mpcaa, NULL);
+	sc->sc_gicdev = config_found(self, &mpcaa, NULL);
 
 	arm_fdt_irq_set_handler(armgic_irq_handler);
+
+	for (child = OF_child(phandle); child; child = OF_peer(child)) {
+		if (!fdtbus_status_okay(child))
+			continue;
+		const char * const v2m_compat[] = { "arm,gic-v2m-frame", NULL };
+		if (of_match_compatible(child, v2m_compat))
+			gic_fdt_attach_v2m(sc, faa->faa_bst, child);
+	}
+}
+
+static void
+gic_fdt_attach_v2m(struct gic_fdt_softc *sc, bus_space_tag_t bst, int phandle)
+{
+	struct gic_v2m_frame *frame;
+	u_int base_spi, num_spis;
+	bus_space_handle_t bsh;
+	bus_addr_t addr;
+	bus_size_t size;
+
+	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+		aprint_error_dev(sc->sc_gicdev, "couldn't get V2M address\n");
+		return;
+	}
+
+	if (bus_space_map(bst, addr, size, 0, &bsh) != 0) {
+		aprint_error_dev(sc->sc_gicdev, "couldn't map V2M frame\n");
+		return;
+	}
+	const uint32_t typer = bus_space_read_4(bst, bsh, GIC_MSI_TYPER);
+	bus_space_unmap(bst, bsh, size);
+
+	if (of_getprop_uint32(phandle, "arm,msi-base-spi", &base_spi))
+		base_spi = __SHIFTOUT(typer, GIC_MSI_TYPER_BASE);
+	if (of_getprop_uint32(phandle, "arm,msi-num-spis", &num_spis))
+		num_spis = __SHIFTOUT(typer, GIC_MSI_TYPER_NUMBER);
+
+	frame = kmem_zalloc(sizeof(*frame), KM_SLEEP);
+	frame->frame_reg = addr;
+	frame->frame_pic = pic_list[0];
+	frame->frame_base = base_spi;
+	frame->frame_count = num_spis;
+
+	if (gic_v2m_init(frame, sc->sc_gicdev, sc->sc_v2m_count++) != 0) {
+		aprint_error_dev(sc->sc_gicdev, "failed to initialize GICv2m\n");
+	} else {
+		aprint_normal_dev(sc->sc_gicdev, "GICv2m @ %#" PRIx64 ", SPIs %u-%u\n",
+		    (uint64_t)frame->frame_reg, frame->frame_base,
+		    frame->frame_base + frame->frame_count);
+	}
 }
 
 static void *

Reply via email to