diff options
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb6078ca60c7..69a3d7b9414c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -483,8 +483,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
483 | */ | 483 | */ |
484 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) | 484 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) |
485 | { | 485 | { |
486 | again: | ||
486 | chip_bus_lock(irq, desc); | 487 | chip_bus_lock(irq, desc); |
487 | raw_spin_lock_irq(&desc->lock); | 488 | raw_spin_lock_irq(&desc->lock); |
489 | |||
490 | /* | ||
491 | * Implausible though it may be we need to protect us against | ||
492 | * the following scenario: | ||
493 | * | ||
494 | * The thread is faster done than the hard interrupt handler | ||
495 | * on the other CPU. If we unmask the irq line then the | ||
496 | * interrupt can come in again and masks the line, leaves due | ||
497 | * to IRQ_INPROGRESS and the irq line is masked forever. | ||
498 | */ | ||
499 | if (unlikely(desc->status & IRQ_INPROGRESS)) { | ||
500 | raw_spin_unlock_irq(&desc->lock); | ||
501 | chip_bus_sync_unlock(irq, desc); | ||
502 | cpu_relax(); | ||
503 | goto again; | ||
504 | } | ||
505 | |||
488 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { | 506 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { |
489 | desc->status &= ~IRQ_MASKED; | 507 | desc->status &= ~IRQ_MASKED; |
490 | desc->chip->unmask(irq); | 508 | desc->chip->unmask(irq); |