提交 ae88a23b 编写于 作者: I 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: NIngo Molnar <mingo@elte.hu>
上级 327ec569
...@@ -575,72 +575,79 @@ int setup_irq(unsigned int irq, struct irqaction *act) ...@@ -575,72 +575,79 @@ 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) {
WARN(1, "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
return;
}
if (action) { p = &action->next;
struct irqaction **pp = p; if (action->dev_id != dev_id)
continue;
p = &action->next; break;
if (action->dev_id != dev_id) }
continue;
/* Found it - now remove it from the list of entries */ /* 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 (!desc->action) { /* If this was the last handler, shut down the IRQ line: */
desc->status |= IRQ_DISABLED; if (!desc->action) {
if (desc->chip->shutdown) desc->status |= IRQ_DISABLED;
desc->chip->shutdown(irq); if (desc->chip->shutdown)
else desc->chip->shutdown(irq);
desc->chip->disable(irq); else
} desc->chip->disable(irq);
spin_unlock_irqrestore(&desc->lock, flags); }
unregister_handler_proc(irq, action); spin_unlock_irqrestore(&desc->lock, flags);
unregister_handler_proc(irq, action);
/* Make sure it's not being used on another CPU: */
synchronize_irq(irq);
/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
#ifdef CONFIG_DEBUG_SHIRQ
/*
* It's a shared IRQ -- the driver ought to be
* prepared for it to happen even now it's
* being freed, so let's make sure.... We do
* this after actually deregistering it, to
* make sure that a 'real' IRQ doesn't run in
* parallel with our fake
*/
if (action->flags & IRQF_SHARED) {
local_irq_save(flags);
action->handler(irq, dev_id);
local_irq_restore(flags);
}
#endif
kfree(action);
return;
}
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
#ifdef CONFIG_DEBUG_SHIRQ #ifdef CONFIG_DEBUG_SHIRQ
dump_stack(); /*
#endif * It's a shared IRQ -- the driver ought to be prepared for an IRQ
spin_unlock_irqrestore(&desc->lock, flags); * event to happen even now it's being freed, so let's make sure that
return; * is so by doing an extra call to the handler ....
*
* ( We do this after actually deregistering it, to make sure that a
* 'real' IRQ doesn't run in * parallel with our fake. )
*/
if (action->flags & IRQF_SHARED) {
local_irq_save(flags);
action->handler(irq, dev_id);
local_irq_restore(flags);
} }
#endif
kfree(action);
} }
EXPORT_SYMBOL(free_irq); EXPORT_SYMBOL(free_irq);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册