Browse Source

[pxe] Avoid potential interrupt storms when using shared interrupts

Current gPXE code always returns "OURS" in response to
PXENV_UNDI_ISR:START.  This is harmless for non-shared interrupt
lines, and avoids the complexity of trying to determine whether or not
we really did cause the interrupt.  (This is a non-trivial
determination; some drivers don't have interrupt support and hook the
system timer interrupt instead, for example.)

A problem occurs when we have a shared interrupt line, the other
device asserts an interrupt, and the controlling ISR does not chain to
the other device's ISR when we return "OURS".  Under these
circumstances, the other device's ISR never executes, and so the
interrupt remains asserted, causing an interrupt storm.

Work around this by returning "OURS" if and only if our net device's
interrupt is currently recorded as being enabled.  Since we always
disable interrupts as a result of a call to PXENV_UNDI_ISR:START, this
guarantees that we will eventually (on the second call) return "NOT
OURS", allowing the other ISR to be called.  Under normal operation,
including a non-shared interrupt situation, this change will make no
difference since PXENV_UNDI_ISR:START would be called only when
interrupts were enabled anyway.

Signed-off-by: Michael Brown <mcb30@etherboot.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
9acf442c20
1 changed files with 21 additions and 4 deletions
  1. 21
    4
      src/arch/i386/interface/pxe/pxe_undi.c

+ 21
- 4
src/arch/i386/interface/pxe/pxe_undi.c View File

674
 		 */
674
 		 */
675
 		netdev_poll ( pxe_netdev );
675
 		netdev_poll ( pxe_netdev );
676
 
676
 
677
-		/* Disable interrupts to avoid interrupt storm */
677
+		/* A 100% accurate determination of "OURS" vs "NOT
678
+		 * OURS" is difficult to achieve without invasive and
679
+		 * unpleasant changes to the driver model.  We settle
680
+		 * for always returning "OURS" if interrupts are
681
+		 * currently enabled.
682
+		 *
683
+		 * Returning "NOT OURS" when interrupts are disabled
684
+		 * allows us to avoid a potential interrupt storm when
685
+		 * we are on a shared interrupt line; if we were to
686
+		 * always return "OURS" then the other device's ISR
687
+		 * may never be called.
688
+		 */
689
+		if ( netdev_irq_enabled ( pxe_netdev ) ) {
690
+			DBGC2 ( &pxenv_undi_isr, " OURS" );
691
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
692
+		} else {
693
+			DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
694
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
695
+		}
696
+
697
+		/* Disable interrupts */
678
 		netdev_irq ( pxe_netdev, 0 );
698
 		netdev_irq ( pxe_netdev, 0 );
679
 
699
 
680
-		/* Always say it was ours for the sake of simplicity */
681
-		DBGC2 ( &pxenv_undi_isr, " OURS" );
682
-		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
683
 		break;
700
 		break;
684
 	case PXENV_UNDI_ISR_IN_PROCESS :
701
 	case PXENV_UNDI_ISR_IN_PROCESS :
685
 	case PXENV_UNDI_ISR_IN_GET_NEXT :
702
 	case PXENV_UNDI_ISR_IN_GET_NEXT :

Loading…
Cancel
Save