Index: sys/arch/arm/cortex/gic.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/cortex/gic.c,v retrieving revision 1.10 diff -u -p -r1.10 gic.c --- sys/arch/arm/cortex/gic.c 19 May 2014 22:47:53 -0000 1.10 +++ sys/arch/arm/cortex/gic.c 26 Oct 2014 20:22:00 -0000 @@ -138,24 +138,15 @@ gicd_write(struct armgic_softc *sc, bus_ /* * In the GIC prioritization scheme, lower numbers have higher priority. - * Only write priorities that could be non-secure. + * Only write priorities that are in the non-secure range. */ static inline uint32_t armgic_ipl_to_priority(int ipl) { return GICC_PMR_NONSECURE - | ((IPL_HIGH - ipl) * GICC_PMR_NS_PRIORITIES / NIPL); + | (((IPL_HIGH - ipl) * GICC_PMR_NS_PRIORITIES) / NIPL); } -#if 0 -static inline int -armgic_priority_to_ipl(uint32_t priority) -{ - return IPL_HIGH - - (priority & ~GICC_PMR_NONSECURE) * NIPL / GICC_PMR_NS_PRIORITIES; -} -#endif - static void armgic_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask) { @@ -192,6 +183,19 @@ armgic_set_priority(struct pic_softc *pi armgic_last_priority = priority; } + +static int +armgic_get_priority(struct pic_softc *pic) +{ + struct armgic_softc * const sc = PICTOSOFTC(pic); + uint32_t pmr_val; + + pmr_val = gicc_read(sc, GICC_PMR); + return IPL_HIGH + - (((pmr_val & ~GICC_PMR_NONSECURE) * NIPL) / GICC_PMR_NS_PRIORITIES); +} + + #ifdef __HAVE_PIC_FAST_SOFTINTS void softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep_p) @@ -223,15 +227,18 @@ armgic_irq_handler(void *tf) #ifdef DIAGNOSTIC const int old_mtx_count = ci->ci_mtx_count; const int old_l_biglocks = ci->ci_curlwp->l_biglocks; + const int cur_ipl = armgic_get_priority(&sc->sc_pic); #endif #ifdef DEBUG size_t n = 0; #endif + int ipl; ci->ci_data.cpu_nintr++; - KASSERTMSG(old_ipl != IPL_HIGH, "old_ipl %d pmr %#x hppir %#x", - old_ipl, gicc_read(sc, GICC_PMR), gicc_read(sc, GICC_HPPIR)); + KASSERTMSG(cur_ipl == ci->ci_cpl, "%s: ci->ci_cpl %d, cur_ipl = %d\n", + __func__, ci->ci_cpl, cur_ipl); + #if 0 printf("%s(enter): %s: pmr=%u hppir=%u\n", __func__, ci->ci_data.cpu_name, @@ -244,14 +251,16 @@ armgic_irq_handler(void *tf) for (;;) { uint32_t iar = gicc_read(sc, GICC_IAR); uint32_t irq = __SHIFTOUT(iar, GICC_IAR_IRQ); - //printf(".%u", irq); + + // printf(".%u", irq); if (irq == GICC_IAR_IRQ_SPURIOUS) { iar = gicc_read(sc, GICC_IAR); irq = __SHIFTOUT(iar, GICC_IAR_IRQ); if (irq == GICC_IAR_IRQ_SPURIOUS) break; - //printf(".%u", irq); + // printf(".%u", irq); } + KASSERT(ci->ci_cpl != IPL_HIGH); //const uint32_t cpuid = __SHIFTOUT(iar, GICC_IAR_CPUID_MASK); struct intrsource * const is = sc->sc_pic.pic_sources[irq]; @@ -267,37 +276,39 @@ armgic_irq_handler(void *tf) * so we need deal with those when lowering to the current * interrupt's ipl. * - * However, if are just raising ipl, we can just update ci_cpl. + * However, if just raising ipl, we can just update ci_cpl. */ -#if 0 - const int ipl = armgic_priority_to_ipl(gicc_read(sc, GICC_RPR)); - KASSERTMSG(panicstr != NULL || ipl == is->is_ipl, + ipl = armgic_get_priority(&sc->sc_pic); +#if 1 + KASSERTMSG(panicstr != NULL || ipl <= is->is_ipl, "%s: irq %d: running ipl %d != source ipl %u", ci->ci_data.cpu_name, irq, ipl, is->is_ipl); -#else - const int ipl = is->is_ipl; #endif + /* ipl may be lower than the triggering device level */ + if (ipl < is->is_ipl) + ipl = is->is_ipl; + if (__predict_false(ipl < ci->ci_cpl)) { - //printf("<"); + // printf("<"); pic_do_pending_ints(I32_bit, ipl, tf); KASSERT(ci->ci_cpl == ipl); } else { - KASSERTMSG(ipl > ci->ci_cpl, "ipl %d cpl %d hw-ipl %#x", + KASSERTMSG(ipl >= ci->ci_cpl, "ipl %d cpl %d hw-ipl %#x", ipl, ci->ci_cpl, gicc_read(sc, GICC_PMR)); - //printf(">"); - gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ipl)); + // printf(">"); + armgic_set_priority(&sc->sc_pic, ipl); // set PMR ci->ci_cpl = ipl; } - //printf("$"); + // printf("$"); cpsie(I32_bit); pic_dispatch(is, tf); cpsid(I32_bit); gicc_write(sc, GICC_EOIR, iar); #ifdef DEBUG n++; - KDASSERTMSG(n < 5, "%s: processed too many (%zu)", - ci->ci_data.cpu_name, n); + KDASSERTMSG(n < 5, "%s: processed too many (%zu) irq %d ipl %d", + ci->ci_data.cpu_name, n, irq, ipl); #endif } @@ -305,8 +316,8 @@ armgic_irq_handler(void *tf) /* * Now handle any pending ints. */ - //printf("!"); - KASSERT(old_ipl != IPL_HIGH); + // printf("!"); + pic_do_pending_ints(I32_bit, old_ipl, tf); KASSERTMSG(ci->ci_cpl == old_ipl, "ci_cpl %d old_ipl %d", ci->ci_cpl, old_ipl); KASSERT(old_mtx_count == ci->ci_mtx_count); @@ -466,7 +477,7 @@ armgic_cpu_init(struct pic_softc *pic, s sc->sc_enabled_local); } } - gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ci->ci_cpl)); // set PMR + armgic_set_priority(&sc->sc_pic, ci->ci_cpl); // set PMR gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable interrupt cpsie(I32_bit); // allow IRQ exceptions }