[RFC] [patch 1/2] powerpc 2.6.21-rt1: fix kernel hang and/or panic

Tsutomu OWA tsutomu.owa at toshiba.co.jp
Tue May 15 18:44:07 EST 2007


>   It occurs on 2.6.21 + patch-2.6.21-rt1 + series of patches that I posted
> yesterday.

When doing 'hdparm -t /dev/hda' several times, it silently hangs.
I think it freezes since It does not response to ping as well.
On the other hand, PREEMPT_NONE kernel works just fine.

After looking into the rt interrupt handling code, I noticed 
that code path differs between PREEMPT_NONE and PREEMPT_RT;
  NONE: mask() -> unmask() -> eoi() 
  RT:   mask() -> eoi() -> unmask()

The hypervisor underlying the linux on Celleb wants to be called
in this "mask() -> unmask() -> eoi()" order.  This patch mimics
the behavior of PREEPT_NONE even if PREEMPT_RT is specified.

Or, would it be better to create/add a new (threaded) irq handler?

Any comments?

Thanks in advance

Signed-off-by: Tsutomu OWA <tsutomu.owa at toshiba.co.jp>
-- owa

--- linux-2.6.21-rt1/arch/powerpc/platforms/celleb/interrupt.c	2007-05-09 17:04:41.000000000 +0900
+++ rt/arch/powerpc/platforms/celleb/interrupt.c	2007-05-09 17:05:07.000000000 +0900
@@ -29,6 +29,10 @@
 #include "interrupt.h"
 #include "beat_wrapper.h"
 
+#ifdef CONFIG_PREEMPT_HARDIRQS
+extern int hardirq_preemption;
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 #define	MAX_IRQS	NR_IRQS
 static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);
 static uint64_t	beatic_irq_mask_enable[(MAX_IRQS+255)/64];
@@ -71,12 +75,35 @@ static void beatic_mask_irq(unsigned int
 	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
 }
 
+static void __beatic_eoi_irq(unsigned int irq_plug)
+{
+	s64 err;
+
+	if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
+		if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
+			panic("Failed to downcount IRQ! Error = %16lx", err);
+
+		printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
+	}
+}
+
 static void beatic_unmask_irq(unsigned int irq_plug)
 {
 	unsigned long flags;
 
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		__beatic_eoi_irq(irq_plug);
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
 	beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
 	beatic_update_irq_mask(irq_plug);
 	spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
 }
@@ -93,15 +120,15 @@ static void beatic_ack_irq(unsigned int 
 
 static void beatic_end_irq(unsigned int irq_plug)
 {
-	s64 err;
 	unsigned long flags;
 
-	if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
-		if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
-			panic("Failed to downcount IRQ! Error = %16lx", err);
+#ifdef CONFIG_PREEMPT_HARDIRQS
+	if (hardirq_preemption)
+		return;
+#endif /* CONFIG_PREEMPT_HARDIRQS */
+
+	__beatic_eoi_irq(irq_plug);
 
-		printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
-	}
 	spin_lock_irqsave(&beatic_irq_mask_lock, flags);
 	beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
 	beatic_update_irq_mask(irq_plug);





More information about the Linuxppc-dev mailing list