Commit ae88a23b authored by Ingo Molnar's avatar Ingo Molnar

irq: refactor and clean up the free_irq() code flow

Impact: cleanup

- separate out the loop from the actual freeing logic, this wins us
  two indentation levels allowing a number of followup prettifications

- turn the WARN_ON() into a more informative WARN().

- clean up the comments and the code flow some more

Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 327ec569
...@@ -575,35 +575,49 @@ int setup_irq(unsigned int irq, struct irqaction *act) ...@@ -575,35 +575,49 @@ int setup_irq(unsigned int irq, struct irqaction *act)
void free_irq(unsigned int irq, void *dev_id) void free_irq(unsigned int irq, void *dev_id)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
struct irqaction **p; struct irqaction *action, **p, **pp;
unsigned long flags; unsigned long flags;
WARN_ON(in_interrupt()); WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
if (!desc) if (!desc)
return; return;
spin_lock_irqsave(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
/*
* There can be multiple actions per IRQ descriptor, find the right
* one based on the dev_id:
*/
p = &desc->action; p = &desc->action;
for (;;) { for (;;) {
struct irqaction *action = *p; action = *p;
pp = p;
if (action) { if (!action) {
struct irqaction **pp = p; WARN(1, "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
return;
}
p = &action->next; p = &action->next;
if (action->dev_id != dev_id) if (action->dev_id != dev_id)
continue; continue;
/* Found it - now remove it from the list of entries */ break;
}
/* Found it - now remove it from the list of entries: */
*pp = action->next; *pp = action->next;
/* Currently used only by UML, might disappear one day.*/ /* Currently used only by UML, might disappear one day: */
#ifdef CONFIG_IRQ_RELEASE_METHOD #ifdef CONFIG_IRQ_RELEASE_METHOD
if (desc->chip->release) if (desc->chip->release)
desc->chip->release(irq, dev_id); desc->chip->release(irq, dev_id);
#endif #endif
/* If this was the last handler, shut down the IRQ line: */
if (!desc->action) { if (!desc->action) {
desc->status |= IRQ_DISABLED; desc->status |= IRQ_DISABLED;
if (desc->chip->shutdown) if (desc->chip->shutdown)
...@@ -612,18 +626,20 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -612,18 +626,20 @@ void free_irq(unsigned int irq, void *dev_id)
desc->chip->disable(irq); desc->chip->disable(irq);
} }
spin_unlock_irqrestore(&desc->lock, flags); spin_unlock_irqrestore(&desc->lock, flags);
unregister_handler_proc(irq, action); unregister_handler_proc(irq, action);
/* Make sure it's not being used on another CPU */ /* Make sure it's not being used on another CPU: */
synchronize_irq(irq); synchronize_irq(irq);
#ifdef CONFIG_DEBUG_SHIRQ #ifdef CONFIG_DEBUG_SHIRQ
/* /*
* It's a shared IRQ -- the driver ought to be * It's a shared IRQ -- the driver ought to be prepared for an IRQ
* prepared for it to happen even now it's * event to happen even now it's being freed, so let's make sure that
* being freed, so let's make sure.... We do * is so by doing an extra call to the handler ....
* this after actually deregistering it, to *
* make sure that a 'real' IRQ doesn't run in * ( We do this after actually deregistering it, to make sure that a
* parallel with our fake * 'real' IRQ doesn't run in * parallel with our fake. )
*/ */
if (action->flags & IRQF_SHARED) { if (action->flags & IRQF_SHARED) {
local_irq_save(flags); local_irq_save(flags);
...@@ -632,15 +648,6 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -632,15 +648,6 @@ void free_irq(unsigned int irq, void *dev_id)
} }
#endif #endif
kfree(action); kfree(action);
return;
}
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
#ifdef CONFIG_DEBUG_SHIRQ
dump_stack();
#endif
spin_unlock_irqrestore(&desc->lock, flags);
return;
}
} }
EXPORT_SYMBOL(free_irq); EXPORT_SYMBOL(free_irq);
......
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