Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/sparc/sparc In DIAGNOSTIC kernels detect situation ...



details:   https://anonhg.NetBSD.org/src/rev/50cfe9a7940b
branches:  trunk
changeset: 534852:50cfe9a7940b
user:      uwe <uwe%NetBSD.org@localhost>
date:      Sun Aug 04 14:57:34 2002 +0000

description:
In DIAGNOSTIC kernels detect situation that on sun4m neither hardware
nor software interrupt pending bit is set for the current ipl.  Report
this as a "bogus" interrupt (better name anyone?).  This is a symptom
of a bug in interrupt handling in one of device drivers interrupting
at this ipl.  Reviewed by pk.

diffstat:

 sys/arch/sparc/sparc/intr.c   |  26 ++++++++++-
 sys/arch/sparc/sparc/locore.s |  95 +++++++++++++++++++++++++++++++++++++-----
 2 files changed, 107 insertions(+), 14 deletions(-)

diffs (178 lines):

diff -r e6f8c8867d6e -r 50cfe9a7940b sys/arch/sparc/sparc/intr.c
--- a/sys/arch/sparc/sparc/intr.c       Sun Aug 04 14:43:47 2002 +0000
+++ b/sys/arch/sparc/sparc/intr.c       Sun Aug 04 14:57:34 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: intr.c,v 1.58 2001/12/04 00:05:06 darrenr Exp $ */
+/*     $NetBSD: intr.c,v 1.59 2002/08/04 14:57:34 uwe Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -75,6 +75,9 @@
 void *softnet_cookie;
 
 void   strayintr __P((struct clockframe *));
+#ifdef DIAGNOSTIC
+void   bogusintr __P((struct clockframe *));
+#endif
 void   softnet __P((void *));
 
 /*
@@ -96,7 +99,7 @@
 
        timesince = time.tv_sec - straytime;
        if (timesince <= 10) {
-               if (++nstray > 9)
+               if (++nstray > 10)
                        panic("crazy interrupts");
        } else {
                straytime = time.tv_sec;
@@ -104,6 +107,25 @@
        }
 }
 
+
+#ifdef DIAGNOSTIC
+/*
+ * Bogus interrupt for which neither hard nor soft interrupt bit in
+ * the IPR was set.
+ */
+void
+bogusintr(fp)
+       struct clockframe *fp;
+{
+       char bits[64];
+
+       printf("bogus interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%s\n",
+               fp->ipl, fp->pc, fp->npc, bitmask_snprintf(fp->psr,
+                      PSR_BITS, bits, sizeof(bits)));
+}
+#endif /* DIAGNOSTIC */
+
+
 /*
  * Process software network interrupts.
  */
diff -r e6f8c8867d6e -r 50cfe9a7940b sys/arch/sparc/sparc/locore.s
--- a/sys/arch/sparc/sparc/locore.s     Sun Aug 04 14:43:47 2002 +0000
+++ b/sys/arch/sparc/sparc/locore.s     Sun Aug 04 14:57:34 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: locore.s,v 1.159 2002/07/17 16:59:09 thorpej Exp $     */
+/*     $NetBSD: locore.s,v 1.160 2002/08/04 14:57:34 uwe Exp $ */
 
 /*
  * Copyright (c) 1996 Paul Kranenburg
@@ -2470,32 +2470,103 @@
 #if defined(SUN4M)
 _ENTRY(_C_LABEL(sparc_interrupt4m))
 #if !defined(MSIIEP)   /* "normal" sun4m */
-       mov     1, %l4
        sethi   %hi(CPUINFO_VA+CPUINFO_INTREG), %l6
        ld      [%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6
+       mov     1, %l4
        ld      [%l6 + ICR_PI_PEND_OFFSET], %l5 ! get pending interrupts
-       sll     %l4, %l3, %l4                   ! test SOFTINT bit
-       andcc   %l5, %l4, %g0
-       bne     sparc_interrupt_common
+       sll     %l4, %l3, %l4   ! hw intr bits are in the lower halfword
+
+       btst    %l4, %l5        ! has pending hw intr at this level?
+       bnz     sparc_interrupt_common
         nop
 
-       ! a soft interrupt; clear bit in interrupt-pending register
-       sll     %l4, 16, %l5
-       st      %l5, [%l6 + ICR_PI_CLR_OFFSET]
-       b,a     softintr_common
+#ifdef DIAGNOSTIC
+       ! both softint pending and clear bits are in upper halfwords of
+       ! their respective registers so shift the test bit in %l4 up there
+       sll     %l4, 16, %l4
+       btst    %l4, %l5        ! make sure softint pending bit is set
+       bnz     softintr_common
+        st     %l4, [%l6 + ICR_PI_CLR_OFFSET]
+       /* FALLTHROUGH to sparc_interrupt4m_bogus */
+#else
+       b       softintr_common
+        st     %l4, [%l6 + ICR_PI_CLR_OFFSET]
+#endif
+
 #else /* MSIIEP */
        sethi   %hi(MSIIEP_PCIC_VA), %l6
        mov     1, %l4
        ld      [%l6 + PCIC_PROC_IPR_REG], %l5 ! get pending interrupts
-       sll     %l4, %l3, %l4
-       btst    %l4, %l5        !  has pending hw intr at this level?
+       sll     %l4, %l3, %l4   ! hw intr bits are in the lower halfword
+
+       btst    %l4, %l5        ! has pending hw intr at this level?
        bnz     sparc_interrupt_common
         nop
 
-       ! a soft interrupt; clear its bit in softintr clear register
+#ifdef DIAGNOSTIC
+       ! softint pending bits are in the upper halfword, but softint
+       ! clear bits are in the lower halfword so we want the bit in %l4
+       ! kept in the lower half and instead shift pending bits right
+       srl     %l5, 16, %l7
+       btst    %l4, %l7        ! make sure softint pending bit is set
+       bnz     softintr_common
+        sth    %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
+       /* FALLTHROUGH to sparc_interrupt4m_bogus */
+#else
        b       softintr_common
         sth    %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
+#endif
+
 #endif /* MSIIEP */
+
+#ifdef DIAGNOSTIC
+       /*
+        * sparc_interrupt4m detected that neither hardware nor software
+        * interrupt pending bit is set for this interrupt.  Report this
+        * situation, this is most probably a symptom of a driver bug.
+        */
+sparc_interrupt4m_bogus:
+       INTR_SETUP(-CCFSZ-80)
+       std     %g2, [%sp + CCFSZ + 24] ! save registers
+       INCR(_C_LABEL(uvmexp)+V_INTR)   ! cnt.v_intr++; (clobbers %o0,%o1)
+       mov     %g1, %l7
+       rd      %y, %l6
+       std     %g4, [%sp + CCFSZ + 32]
+       andn    %l0, PSR_PIL, %l4       ! %l4 = psr & ~PSR_PIL |
+       sll     %l3, 8, %l5             !       intlev << IPLSHIFT
+       std     %g6, [%sp + CCFSZ + 40]
+       or      %l5, %l4, %l4           !                       ;
+       wr      %l4, 0, %psr            ! the manual claims this
+       wr      %l4, PSR_ET, %psr       ! song and dance is necessary
+       std     %l0, [%sp + CCFSZ + 0]  ! set up intrframe/clockframe
+       sll     %l3, 2, %l5
+       set     _C_LABEL(intrcnt), %l4  ! intrcnt[intlev]++;
+       ld      [%l4 + %l5], %o0
+       std     %l2, [%sp + CCFSZ + 8]  ! set up intrframe/clockframe
+       inc     %o0
+       st      %o0, [%l4 + %l5]
+
+       st      %fp, [%sp + CCFSZ + 16]
+
+       /* Unhandled interrupts while cold cause IPL to be raised to `high' */
+       sethi   %hi(_C_LABEL(cold)), %o0
+       ld      [%o0 + %lo(_C_LABEL(cold))], %o0
+       tst     %o0                     ! if (cold) {
+       bnz,a   1f                      !       splhigh();
+        or     %l0, 0xf00, %l0         ! } else
+       
+       call    _C_LABEL(bogusintr)     !       strayintr(&intrframe)
+        add    %sp, CCFSZ, %o0
+       /* all done: restore registers and go return */
+1:
+       mov     %l7, %g1
+       wr      %l6, 0, %y
+       ldd     [%sp + CCFSZ + 24], %g2
+       ldd     [%sp + CCFSZ + 32], %g4
+       ldd     [%sp + CCFSZ + 40], %g6
+       b       return_from_trap
+        wr     %l0, 0, %psr
+#endif /* DIAGNOSTIC */
 #endif /* SUN4M */
 
 _ENTRY(_C_LABEL(sparc_interrupt44c))



Home | Main Index | Thread Index | Old Index