Module Name:    src
Committed By:   jmcneill
Date:           Sun Jun 18 22:11:50 UTC 2017

Modified Files:
        src/sys/arch/arm/cortex: gic.c

Log Message:
Don't assume that CPU index = GIC CPU interface number. We can determine
the current CPU interface number by reading from the read-only
GICD_ITARGETSR0 through GICD_ITARGETSR7 registers.

This gets interrupts working on Exynos 5422, where the boot processor has
GIC CPU interface #4.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/arch/arm/cortex/gic.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/cortex/gic.c
diff -u src/sys/arch/arm/cortex/gic.c:1.23 src/sys/arch/arm/cortex/gic.c:1.24
--- src/sys/arch/arm/cortex/gic.c:1.23	Mon Jun  5 20:02:11 2017
+++ src/sys/arch/arm/cortex/gic.c	Sun Jun 18 22:11:50 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: gic.c,v 1.23 2017/06/05 20:02:11 skrll Exp $	*/
+/*	$NetBSD: gic.c,v 1.24 2017/06/18 22:11:50 jmcneill Exp $	*/
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -34,7 +34,7 @@
 #define _INTR_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.23 2017/06/05 20:02:11 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.24 2017/06/18 22:11:50 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -100,6 +100,7 @@ static struct armgic_softc {
 #ifdef MULTIPROCESSOR
 	uint32_t sc_mptargets;
 #endif
+	uint32_t sc_bptargets;
 } armgic_softc = {
 	.sc_pic = {
 		.pic_ops = &armgic_picops,
@@ -139,6 +140,29 @@ gicd_write(struct armgic_softc *sc, bus_
 	bus_space_write_4(sc->sc_memt, sc->sc_gicdh, o, v);
 }
 
+static uint32_t
+gicd_find_targets(struct armgic_softc *sc)
+{
+	uint32_t targets = 0;
+
+	/*
+	 * GICD_ITARGETSR0 through 7 are read-only, and each field returns
+	 * a value that corresponds only to the processor reading the
+	 * register. Use this to determine the current processor's
+	 * CPU interface number.
+	 */
+	for (int i = 0; i < 8; i++) {
+		targets = gicd_read(sc, GICD_ITARGETSRn(i));
+		if (targets != 0)
+			break;
+	}
+	targets |= (targets >> 16);
+	targets |= (targets >> 8);
+	targets &= 0xff;
+
+	return targets ? targets : 1;
+}
+
 /*
  * In the GIC prioritization scheme, lower numbers have higher priority.
  * Only write priorities that could be non-secure.
@@ -326,7 +350,7 @@ armgic_establish_irq(struct pic_softc *p
 		} else
 #endif
 #endif
-		targets |= 1 << byte_shift;
+		targets |= sc->sc_bptargets << byte_shift;
 		gicd_write(sc, targets_reg, targets);
 
 		/*
@@ -417,11 +441,11 @@ void
 armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
 {
 	struct armgic_softc * const sc = PICTOSOFTC(pic);
-	sc->sc_mptargets |= 1 << cpu_index(ci);
+	sc->sc_mptargets |= gicd_find_targets(sc);
 	KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl);
 	armgic_cpu_init_priorities(sc);
 	if (!CPU_IS_PRIMARY(ci)) {
-		if (sc->sc_mptargets != 1) {
+		if (popcount(sc->sc_mptargets) != 1) {
 			armgic_cpu_init_targets(sc);
 		}
 		if (sc->sc_enabled_local) {
@@ -502,6 +526,11 @@ armgic_attach(device_t parent, device_t 
 	u_int priorities = 1 << popcount32(pmr);
 
 	/*
+	 * Find the boot processor's CPU interface number.
+	 */
+	sc->sc_bptargets = gicd_find_targets(sc);
+
+	/*
 	 * Let's find out how many real sources we have.
 	 */
 	for (size_t i = 0, group = 0;

Reply via email to