Subject: Fix for SGImips interrupt nesting crashes
To: Rafal Boni <rafal@attbi.com>
From: Stephen Ma <stephenm@employees.org>
List: port-sgimips
Date: 04/20/2002 10:41:34
Rafal> 	Below is a simple patch to the sgimips cpu_intr() routine to
Rafal> prevent the arbitrary levels of interrupt nesting that were
Rafal> possible before and lead to really strange panic()s.

Some quick comments/suggestions:

> @@ -235,7 +239,8 @@ ip22_intr(status, cause, pc, ipending)
>  		cause &= ~MIPS_INT_MASK_4;
>  	}
>  
> -	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
> +	if (cause & MIPS_HARD_INT_MASK) 
> +		mips_spurint_evcnt.ev_count++;
>  }

I think you'll count masked interrupts as spurious interrupts here -
you probably want to check (cause & status & MIPS_HARD_INT_MASK).

In any case, I'm not sure that's going to be useful by itself - if
there are any unmasked interrupts not handled in ip22_intr(), then as
soon as the interrupt handler returns, the unhandled interrupt will
trigger again, causing the CPU to hang. What you really need to do is
to mask them off in the status register (unfortunately, it's a little
tricky to do this). Maybe a #ifdef DIAGNOSTIC panic() would be a
little more useful here.

>  	/* software simulated interrupt */
> -	if ((ipending & MIPS_SOFT_INT_MASK_1)
> -		    || (ssir && (status & MIPS_SOFT_INT_MASK_1))) {
> +	if (servicing_mask == 0 &&
> +		((ipending & MIPS_SOFT_INT_MASK_1) 
> +		 || (ssir && (status & MIPS_SOFT_INT_MASK_1)))) {
> +
> +		splhigh();
> +		servicing_mask |= ipending;
> +		_splset(MIPS_SR_INT_IE |
> +			    (status & ~servicing_mask & MIPS_HARD_INT_MASK));
> +
>  		_clrsoftintr(MIPS_SOFT_INT_MASK_1);
>  		softintr_dispatch();
> +
> +		splhigh();
> +		servicing_mask &= ~ipending;

Can this be simplified to just

  if ((ipending & MIPS_SOFT_INT_MASK_1)
	|| (ssir && (status & MIPS_SOFT_INT_MASK_1))) {
    _splset(MIPS_SR_INT_IE | (status & ~ipending & MIPS_HARD_INT_MASK));
    clrsoftintr(MIPS_SOFT_INT_MASK_1);
    softintr_dispatch();
  }

Each time cpu_intr() is recursively called, the status register will
cumulatively mask the pending interrupts, so it'll already mask out
whatever is contained in servicing_mask.

- S