ARM: Cumulative fixes for GIC

- fix detection of interrupt root controller
 - allow (but warn) unsupported configuration bits
 - dont send EOI for spurious interrupts
 - print more informations for spurious interrupts
 - use device_printf() where appropriate

Reviewed by:	ian (earlier version)
Approved by:	kib (mentor)
This commit is contained in:
Michal Meloun 2015-11-28 12:09:36 +00:00
parent 724f4b62b0
commit 20fc8f2bb5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=291424

View File

@ -68,6 +68,8 @@ __FBSDID("$FreeBSD$");
#include "pic_if.h"
#endif
#define GIC_DEBUG_SPURIOUS
/* We are using GICv2 register naming */
/* Distributor Registers */
@ -135,6 +137,9 @@ struct arm_gic_softc {
uint8_t ver;
struct mtx mutex;
uint32_t nirqs;
#ifdef GIC_DEBUG_SPURIOUS
uint32_t last_irq[MAXCPU];
#endif
};
static struct resource_spec arm_gic_spec[] = {
@ -287,7 +292,7 @@ arm_gic_init_secondary(device_t dev)
}
#endif /* ARM_INTRNG */
#endif /* SMP */
#ifndef ARM_INTRNG
int
gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt,
@ -335,11 +340,10 @@ gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt,
*/
if (fdt32_to_cpu(intr[2]) & 0x0a) {
printf("unsupported trigger/polarity configuration "
"0x%2x\n", fdt32_to_cpu(intr[2]) & 0x0f);
return (ENOTSUP);
"0x%02x\n", fdt32_to_cpu(intr[2]) & 0x0f);
}
*pol = INTR_POLARITY_CONFORM;
if (fdt32_to_cpu(intr[2]) & 0x01)
if (fdt32_to_cpu(intr[2]) & 0x03)
*trig = INTR_TRIGGER_EDGE;
else
*trig = INTR_TRIGGER_LEVEL;
@ -367,6 +371,7 @@ arm_gic_attach(device_t dev)
int i;
uint32_t icciidr;
#ifdef ARM_INTRNG
phandle_t pxref;
intptr_t xref = gic_xref(dev);
#endif
@ -456,7 +461,9 @@ arm_gic_attach(device_t dev)
goto cleanup;
}
if (sc->gic_res[2] == NULL) {
i = OF_getencprop(ofw_bus_get_node(dev), "interrupt-parent",
&pxref, sizeof(pxref));
if (i > 0 && xref == pxref) {
if (arm_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");
@ -472,6 +479,7 @@ arm_gic_attach(device_t dev)
}
}
OF_device_register_xref(xref, dev);
return (0);
cleanup:
@ -516,8 +524,11 @@ arm_gic_intr(void *arg)
*/
if (irq >= sc->nirqs) {
device_printf(sc->gic_dev, "Spurious interrupt detected\n");
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
#ifdef GIC_DEBUG_SPURIOUS
device_printf(sc->gic_dev,
"Spurious interrupt detected: last irq: %d on CPU%d\n",
sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid));
#endif
return (FILTER_HANDLED);
}
@ -542,12 +553,16 @@ arm_gic_intr(void *arg)
arm_ipi_dispatch(isrc, tf);
goto next_irq;
#else
printf("SGI %u on UP system detected\n", irq - GIC_FIRST_SGI);
device_printf(sc->gic_dev, "SGI %u on UP system detected\n",
irq - GIC_FIRST_SGI);
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
goto next_irq;
#endif
}
#ifdef GIC_DEBUG_SPURIOUS
sc->last_irq[PCPU_GET(cpuid)] = irq;
#endif
if (isrc->isrc_trig == INTR_TRIGGER_EDGE)
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
@ -729,12 +744,12 @@ gic_map_fdt(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp)
*/
tripol = isrc->isrc_cells[2];
if (tripol & 0x0a) {
printf("unsupported trigger/polarity configuration "
"0x%2x\n", tripol & 0x0f);
return (ENOTSUP);
device_printf(sc->gic_dev,
"unsupported trigger/polarity configuration "
"0x%02x\n", tripol & 0x0f);
}
pol = INTR_POLARITY_CONFORM;
if (tripol & 0x01)
if (tripol & 0x03)
trig = INTR_TRIGGER_EDGE;
else
trig = INTR_TRIGGER_LEVEL;
@ -911,7 +926,8 @@ arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq)
if (active_irq == 0x3FF) {
if (last_irq == -1)
printf("Spurious interrupt detected\n");
device_printf(sc->gic_dev,
"Spurious interrupt detected\n");
return -1;
}