[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