diff options
-rw-r--r-- | kernel/irq/chip.c | 31 | ||||
-rw-r--r-- | kernel/irq/manage.c | 18 |
2 files changed, 40 insertions, 9 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d70394f12ee9..71eba24a39a2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -359,6 +359,23 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) | |||
359 | if (desc->chip->ack) | 359 | if (desc->chip->ack) |
360 | desc->chip->ack(irq); | 360 | desc->chip->ack(irq); |
361 | } | 361 | } |
362 | desc->status |= IRQ_MASKED; | ||
363 | } | ||
364 | |||
365 | static inline void mask_irq(struct irq_desc *desc, int irq) | ||
366 | { | ||
367 | if (desc->chip->mask) { | ||
368 | desc->chip->mask(irq); | ||
369 | desc->status |= IRQ_MASKED; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | static inline void unmask_irq(struct irq_desc *desc, int irq) | ||
374 | { | ||
375 | if (desc->chip->unmask) { | ||
376 | desc->chip->unmask(irq); | ||
377 | desc->status &= ~IRQ_MASKED; | ||
378 | } | ||
362 | } | 379 | } |
363 | 380 | ||
364 | /* | 381 | /* |
@@ -484,10 +501,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
484 | raw_spin_lock(&desc->lock); | 501 | raw_spin_lock(&desc->lock); |
485 | desc->status &= ~IRQ_INPROGRESS; | 502 | desc->status &= ~IRQ_INPROGRESS; |
486 | 503 | ||
487 | if (unlikely(desc->status & IRQ_ONESHOT)) | 504 | if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) |
488 | desc->status |= IRQ_MASKED; | 505 | unmask_irq(desc, irq); |
489 | else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
490 | desc->chip->unmask(irq); | ||
491 | out_unlock: | 506 | out_unlock: |
492 | raw_spin_unlock(&desc->lock); | 507 | raw_spin_unlock(&desc->lock); |
493 | } | 508 | } |
@@ -524,8 +539,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
524 | action = desc->action; | 539 | action = desc->action; |
525 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) { | 540 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) { |
526 | desc->status |= IRQ_PENDING; | 541 | desc->status |= IRQ_PENDING; |
527 | if (desc->chip->mask) | 542 | mask_irq(desc, irq); |
528 | desc->chip->mask(irq); | ||
529 | goto out; | 543 | goto out; |
530 | } | 544 | } |
531 | 545 | ||
@@ -593,7 +607,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
593 | irqreturn_t action_ret; | 607 | irqreturn_t action_ret; |
594 | 608 | ||
595 | if (unlikely(!action)) { | 609 | if (unlikely(!action)) { |
596 | desc->chip->mask(irq); | 610 | mask_irq(desc, irq); |
597 | goto out_unlock; | 611 | goto out_unlock; |
598 | } | 612 | } |
599 | 613 | ||
@@ -605,8 +619,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
605 | if (unlikely((desc->status & | 619 | if (unlikely((desc->status & |
606 | (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == | 620 | (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == |
607 | (IRQ_PENDING | IRQ_MASKED))) { | 621 | (IRQ_PENDING | IRQ_MASKED))) { |
608 | desc->chip->unmask(irq); | 622 | unmask_irq(desc, irq); |
609 | desc->status &= ~IRQ_MASKED; | ||
610 | } | 623 | } |
611 | 624 | ||
612 | desc->status &= ~IRQ_PENDING; | 625 | desc->status &= ~IRQ_PENDING; |
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); |