Commit 309d1dcb authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'irq-fixes-for-linus' of...

Merge branch 'irq-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'irq-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  genirq: Move two IRQ functions from .init.text to .text
  genirq: Protect access to irq_desc->action in can_request_irq()
  genirq: Prevent oneshot irq thread race
parents 8128f55a 860652bf
...@@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) ...@@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
if (desc->chip->ack) if (desc->chip->ack)
desc->chip->ack(irq); desc->chip->ack(irq);
} }
desc->status |= IRQ_MASKED;
}
static inline void mask_irq(struct irq_desc *desc, int irq)
{
if (desc->chip->mask) {
desc->chip->mask(irq);
desc->status |= IRQ_MASKED;
}
}
static inline void unmask_irq(struct irq_desc *desc, int irq)
{
if (desc->chip->unmask) {
desc->chip->unmask(irq);
desc->status &= ~IRQ_MASKED;
}
} }
/* /*
...@@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) ...@@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
raw_spin_lock(&desc->lock); raw_spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS; desc->status &= ~IRQ_INPROGRESS;
if (unlikely(desc->status & IRQ_ONESHOT)) if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))
desc->status |= IRQ_MASKED; unmask_irq(desc, irq);
else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock: out_unlock:
raw_spin_unlock(&desc->lock); raw_spin_unlock(&desc->lock);
} }
...@@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) ...@@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
action = desc->action; action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED))) { if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
desc->status |= IRQ_PENDING; desc->status |= IRQ_PENDING;
if (desc->chip->mask) mask_irq(desc, irq);
desc->chip->mask(irq);
goto out; goto out;
} }
...@@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) ...@@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
irqreturn_t action_ret; irqreturn_t action_ret;
if (unlikely(!action)) { if (unlikely(!action)) {
desc->chip->mask(irq); mask_irq(desc, irq);
goto out_unlock; goto out_unlock;
} }
...@@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) ...@@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
if (unlikely((desc->status & if (unlikely((desc->status &
(IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
(IRQ_PENDING | IRQ_MASKED))) { (IRQ_PENDING | IRQ_MASKED))) {
desc->chip->unmask(irq); unmask_irq(desc, irq);
desc->status &= ~IRQ_MASKED;
} }
desc->status &= ~IRQ_PENDING; desc->status &= ~IRQ_PENDING;
...@@ -716,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, ...@@ -716,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
__set_irq_handler(irq, handle, 0, name); __set_irq_handler(irq, handle, 0, name);
} }
void __init set_irq_noprobe(unsigned int irq) void set_irq_noprobe(unsigned int irq)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
unsigned long flags; unsigned long flags;
...@@ -731,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq) ...@@ -731,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq)
raw_spin_unlock_irqrestore(&desc->lock, flags); raw_spin_unlock_irqrestore(&desc->lock, flags);
} }
void __init set_irq_probe(unsigned int irq) void set_irq_probe(unsigned int irq)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
unsigned long flags; unsigned long flags;
......
...@@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) ...@@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action; struct irqaction *action;
unsigned long flags;
if (!desc) if (!desc)
return 0; return 0;
...@@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) ...@@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
if (desc->status & IRQ_NOREQUEST) if (desc->status & IRQ_NOREQUEST)
return 0; return 0;
raw_spin_lock_irqsave(&desc->lock, flags);
action = desc->action; action = desc->action;
if (action) if (action)
if (irqflags & action->flags & IRQF_SHARED) if (irqflags & action->flags & IRQF_SHARED)
action = NULL; action = NULL;
raw_spin_unlock_irqrestore(&desc->lock, flags);
return !action; return !action;
} }
...@@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) ...@@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action)
*/ */
static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
{ {
again:
chip_bus_lock(irq, desc); chip_bus_lock(irq, desc);
raw_spin_lock_irq(&desc->lock); raw_spin_lock_irq(&desc->lock);
/*
* Implausible though it may be we need to protect us against
* the following scenario:
*
* The thread is faster done than the hard interrupt handler
* on the other CPU. If we unmask the irq line then the
* interrupt can come in again and masks the line, leaves due
* to IRQ_INPROGRESS and the irq line is masked forever.
*/
if (unlikely(desc->status & IRQ_INPROGRESS)) {
raw_spin_unlock_irq(&desc->lock);
chip_bus_sync_unlock(irq, desc);
cpu_relax();
goto again;
}
if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
desc->status &= ~IRQ_MASKED; desc->status &= ~IRQ_MASKED;
desc->chip->unmask(irq); desc->chip->unmask(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