Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3901
b: refs/heads/master
c: 200803d
h: refs/heads/master
i:
  3899: 05a412d
v: v3
  • Loading branch information
Alan Cox authored and Linus Torvalds committed Jun 29, 2005
1 parent 49a591c commit c6c3564
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 21fe3471c3aaa5c489c5d3a4d705291eb7511248
refs/heads/master: 200803dfe4ff772740d63db725ab2f1b185ccf92
15 changes: 15 additions & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ running once the system is up.
Format: {"of[f]" | "sk[ipmbr]"}
See comment in arch/i386/boot/edd.S

edd [EDD]
Format: {"of[f]" | "sk[ipmbr]"}
See comment in arch/i386/boot/edd.S

eicon= [HW,ISDN]
Format: <id>,<membase>,<irq>

Expand Down Expand Up @@ -622,6 +626,17 @@ running once the system is up.
ips= [HW,SCSI] Adaptec / IBM ServeRAID controller
See header of drivers/scsi/ips.c.

irqfixup [HW]
When an interrupt is not handled search all handlers
for it. Intended to get systems with badly broken
firmware running.

irqpoll [HW]
When an interrupt is not handled search all handlers
for it. Also check all handlers each timer
interrupt. Intended to get systems with badly broken
firmware running.

isapnp= [ISAPNP]
Format: <RDP>, <reset>, <pci_scan>, <verbosity>

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/ppc64/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)

spin_lock(&desc->lock);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
note_interrupt(irq, desc, action_ret, regs);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
Expand Down
5 changes: 3 additions & 2 deletions trunk/include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ extern int no_irq_affinity;
extern int noirqdebug_setup(char *str);

extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
struct irqaction *action);
struct irqaction *action);
extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret);
extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
int action_ret, struct pt_regs *regs);
extern int can_request_irq(unsigned int irq, unsigned long irqflags);

extern void init_irq_proc(void);
Expand Down
2 changes: 1 addition & 1 deletion trunk/kernel/irq/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)

spin_lock(&desc->lock);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
note_interrupt(irq, desc, action_ret, regs);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
Expand Down
113 changes: 111 additions & 2 deletions trunk/kernel/irq/spurious.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,83 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>

static int irqfixup;

/*
* Recovery handler for misrouted interrupts.
*/

static int misrouted_irq(int irq, struct pt_regs *regs)
{
int i;
irq_desc_t *desc;
int ok = 0;
int work = 0; /* Did we do work for a real IRQ */

for(i = 1; i < NR_IRQS; i++) {
struct irqaction *action;

if (i == irq) /* Already tried */
continue;
desc = &irq_desc[i];
spin_lock(&desc->lock);
action = desc->action;
/* Already running on another processor */
if (desc->status & IRQ_INPROGRESS) {
/*
* Already running: If it is shared get the other
* CPU to go looking for our mystery interrupt too
*/
if (desc->action && (desc->action->flags & SA_SHIRQ))
desc->status |= IRQ_PENDING;
spin_unlock(&desc->lock);
continue;
}
/* Honour the normal IRQ locking */
desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);
while (action) {
/* Only shared IRQ handlers are safe to call */
if (action->flags & SA_SHIRQ) {
if (action->handler(i, action->dev_id, regs) ==
IRQ_HANDLED)
ok = 1;
}
action = action->next;
}
local_irq_disable();
/* Now clean up the flags */
spin_lock(&desc->lock);
action = desc->action;

/*
* While we were looking for a fixup someone queued a real
* IRQ clashing with our walk
*/

while ((desc->status & IRQ_PENDING) && action) {
/*
* Perform real IRQ processing for the IRQ we deferred
*/
work = 1;
spin_unlock(&desc->lock);
handle_IRQ_event(i, regs, action);
spin_lock(&desc->lock);
desc->status &= ~IRQ_PENDING;
}
desc->status &= ~IRQ_INPROGRESS;
/*
* If we did actual work for the real IRQ line we must let the
* IRQ controller clean up too
*/
if(work)
desc->handler->end(i);
spin_unlock(&desc->lock);
}
/* So the caller can adjust the irq error counts */
return ok;
}

/*
* 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
Expand All @@ -31,7 +108,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
printk(KERN_ERR "irq event %d: bogus return value %x\n",
irq, action_ret);
} else {
printk(KERN_ERR "irq %d: nobody cared!\n", irq);
printk(KERN_ERR "irq %d: nobody cared (try booting with "
"the \"irqpoll\" option)\n", irq);
}
dump_stack();
printk(KERN_ERR "handlers:\n");
Expand All @@ -55,14 +133,24 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio
}
}

void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
struct pt_regs *regs)
{
if (action_ret != IRQ_HANDLED) {
desc->irqs_unhandled++;
if (action_ret != IRQ_NONE)
report_bad_irq(irq, desc, action_ret);
}

if (unlikely(irqfixup)) {
/* Don't punish working computers */
if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
int ok = misrouted_irq(irq, regs);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
}
}

desc->irq_count++;
if (desc->irq_count < 100000)
return;
Expand Down Expand Up @@ -94,3 +182,24 @@ int __init noirqdebug_setup(char *str)

__setup("noirqdebug", noirqdebug_setup);

static int __init irqfixup_setup(char *str)
{
irqfixup = 1;
printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
printk(KERN_WARNING "This may impact system performance.\n");
return 1;
}

__setup("irqfixup", irqfixup_setup);

static int __init irqpoll_setup(char *str)
{
irqfixup = 2;
printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
"enabled\n");
printk(KERN_WARNING "This may significantly impact system "
"performance\n");
return 1;
}

__setup("irqpoll", irqpoll_setup);

0 comments on commit c6c3564

Please sign in to comment.