Commit 5c1b9510 authored by Anton Blanchard's avatar Anton Blanchard

ppc64: Update unhandled irq code to match x86

parent 4348e62f
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/kallsyms.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
...@@ -350,14 +351,11 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -350,14 +351,11 @@ int show_interrupts(struct seq_file *p, void *v)
return 0; return 0;
} }
extern char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); static inline int handle_irq_event(int irq, struct pt_regs *regs,
struct irqaction *action)
static inline void handle_irq_event(int irq, struct pt_regs *regs,
struct irqaction *action)
{ {
int status = 0; int status = 0;
int retval = 0; int retval = 0;
struct irqaction *first_action = action;
if (!(action->flags & SA_INTERRUPT)) if (!(action->flags & SA_INTERRUPT))
local_irq_enable(); local_irq_enable();
...@@ -370,30 +368,90 @@ static inline void handle_irq_event(int irq, struct pt_regs *regs, ...@@ -370,30 +368,90 @@ static inline void handle_irq_event(int irq, struct pt_regs *regs,
if (status & SA_SAMPLE_RANDOM) if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq); add_interrupt_randomness(irq);
local_irq_disable(); local_irq_disable();
if (retval != 1) { return retval;
static int count = 100; }
char name_buf[256];
if (count) { static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
count--; {
if (retval) { struct irqaction *action;
printk("irq event %d: bogus retval mask %x\n",
irq, retval); if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
} else { printk(KERN_ERR "irq event %d: bogus return value %x\n",
printk("irq %d: nobody cared!\n", irq); irq, action_ret);
} } else {
dump_stack(); printk(KERN_ERR "irq %d: nobody cared!\n", irq);
printk("handlers:\n"); }
action = first_action; dump_stack();
do { printk(KERN_ERR "handlers:\n");
printk("[<%p>]", action->handler); action = desc->action;
printk(" (%s)\n", do {
ppc_find_proc_name((unsigned *)action->handler, name_buf, 256)); printk(KERN_ERR "[<%p>]", action->handler);
action = action->next; print_symbol(" (%s)",
} while (action); (unsigned long)action->handler);
} printk("\n");
action = action->next;
} while (action);
}
static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
{
static int count = 100;
if (count) {
count--;
__report_bad_irq(irq, desc, action_ret);
} }
} }
static int noirqdebug;
static int __init noirqdebug_setup(char *str)
{
noirqdebug = 1;
printk("IRQ lockup detection disabled\n");
return 1;
}
__setup("noirqdebug", noirqdebug_setup);
/*
* If 99,900 of the previous 100,000 interrupts have not been handled then
* assume that the IRQ is stuck in some manner. Drop a diagnostic and try to
* turn the IRQ off.
*
* (The other 100-of-100,000 interrupts may have been a correctly-functioning
* device sharing an IRQ with the failing one)
*
* Called under desc->lock
*/
static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
{
if (action_ret != IRQ_HANDLED) {
desc->irqs_unhandled++;
if (action_ret != IRQ_NONE)
report_bad_irq(irq, desc, action_ret);
}
desc->irq_count++;
if (desc->irq_count < 100000)
return;
desc->irq_count = 0;
if (desc->irqs_unhandled > 99900) {
/*
* The interrupt is stuck
*/
__report_bad_irq(irq, desc, action_ret);
/*
* Now kill the IRQ
*/
printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
desc->status |= IRQ_DISABLED;
desc->handler->disable(irq);
}
desc->irqs_unhandled = 0;
}
/* /*
* Eventually, this should take an array of interrupts and an array size * Eventually, this should take an array of interrupts and an array size
* so it can dispatch multiple interrupts. * so it can dispatch multiple interrupts.
...@@ -462,10 +520,13 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) ...@@ -462,10 +520,13 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
* SMP environment. * SMP environment.
*/ */
for (;;) { for (;;) {
irqreturn_t action_ret;
spin_unlock(&desc->lock); spin_unlock(&desc->lock);
handle_irq_event(irq, regs, action); action_ret = handle_irq_event(irq, regs, action);
spin_lock(&desc->lock); spin_lock(&desc->lock);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
if (likely(!(desc->status & IRQ_PENDING))) if (likely(!(desc->status & IRQ_PENDING)))
break; break;
desc->status &= ~IRQ_PENDING; desc->status &= ~IRQ_PENDING;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment