Re: [RFC] [patch 1/2] powerpc 2.6.21-rt1: fix kernel hang and/or panic
From: Tsutomu OWA <hidden>
Date: 2007-05-15 08:44:27
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 <redacted> -- 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);