mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
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
This commit is contained in:
commit
309d1dcb5b
@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
|
||||
if (desc->chip->ack)
|
||||
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)
|
||||
raw_spin_lock(&desc->lock);
|
||||
desc->status &= ~IRQ_INPROGRESS;
|
||||
|
||||
if (unlikely(desc->status & IRQ_ONESHOT))
|
||||
desc->status |= IRQ_MASKED;
|
||||
else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
|
||||
desc->chip->unmask(irq);
|
||||
if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))
|
||||
unmask_irq(desc, irq);
|
||||
out_unlock:
|
||||
raw_spin_unlock(&desc->lock);
|
||||
}
|
||||
@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
||||
action = desc->action;
|
||||
if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
|
||||
desc->status |= IRQ_PENDING;
|
||||
if (desc->chip->mask)
|
||||
desc->chip->mask(irq);
|
||||
mask_irq(desc, irq);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
|
||||
irqreturn_t action_ret;
|
||||
|
||||
if (unlikely(!action)) {
|
||||
desc->chip->mask(irq);
|
||||
mask_irq(desc, irq);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
|
||||
if (unlikely((desc->status &
|
||||
(IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
|
||||
(IRQ_PENDING | IRQ_MASKED))) {
|
||||
desc->chip->unmask(irq);
|
||||
desc->status &= ~IRQ_MASKED;
|
||||
unmask_irq(desc, irq);
|
||||
}
|
||||
|
||||
desc->status &= ~IRQ_PENDING;
|
||||
@ -716,7 +729,7 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
|
||||
__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);
|
||||
unsigned long flags;
|
||||
@ -731,7 +744,7 @@ void __init set_irq_noprobe(unsigned int irq)
|
||||
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);
|
||||
unsigned long flags;
|
||||
|
@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct irqaction *action;
|
||||
unsigned long flags;
|
||||
|
||||
if (!desc)
|
||||
return 0;
|
||||
@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
|
||||
if (desc->status & IRQ_NOREQUEST)
|
||||
return 0;
|
||||
|
||||
raw_spin_lock_irqsave(&desc->lock, flags);
|
||||
action = desc->action;
|
||||
if (action)
|
||||
if (irqflags & action->flags & IRQF_SHARED)
|
||||
action = NULL;
|
||||
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
return !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)
|
||||
{
|
||||
again:
|
||||
chip_bus_lock(irq, desc);
|
||||
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)) {
|
||||
desc->status &= ~IRQ_MASKED;
|
||||
desc->chip->unmask(irq);
|
||||
|
Loading…
Reference in New Issue
Block a user