diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb6078ca60c7..704e488730a5 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -382,6 +382,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) | |||
| 382 | { | 382 | { |
| 383 | struct irq_desc *desc = irq_to_desc(irq); | 383 | struct irq_desc *desc = irq_to_desc(irq); |
| 384 | struct irqaction *action; | 384 | struct irqaction *action; |
| 385 | unsigned long flags; | ||
| 385 | 386 | ||
| 386 | if (!desc) | 387 | if (!desc) |
| 387 | return 0; | 388 | return 0; |
| @@ -389,11 +390,14 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) | |||
| 389 | if (desc->status & IRQ_NOREQUEST) | 390 | if (desc->status & IRQ_NOREQUEST) |
| 390 | return 0; | 391 | return 0; |
| 391 | 392 | ||
| 393 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 392 | action = desc->action; | 394 | action = desc->action; |
| 393 | if (action) | 395 | if (action) |
| 394 | if (irqflags & action->flags & IRQF_SHARED) | 396 | if (irqflags & action->flags & IRQF_SHARED) |
| 395 | action = NULL; | 397 | action = NULL; |
| 396 | 398 | ||
| 399 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 400 | |||
| 397 | return !action; | 401 | return !action; |
| 398 | } | 402 | } |
| 399 | 403 | ||
| @@ -483,8 +487,26 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
| 483 | */ | 487 | */ |
| 484 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) | 488 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) |
| 485 | { | 489 | { |
| 490 | again: | ||
| 486 | chip_bus_lock(irq, desc); | 491 | chip_bus_lock(irq, desc); |
| 487 | raw_spin_lock_irq(&desc->lock); | 492 | raw_spin_lock_irq(&desc->lock); |
| 493 | |||
| 494 | /* | ||
| 495 | * Implausible though it may be we need to protect us against | ||
| 496 | * the following scenario: | ||
| 497 | * | ||
| 498 | * The thread is faster done than the hard interrupt handler | ||
| 499 | * on the other CPU. If we unmask the irq line then the | ||
| 500 | * interrupt can come in again and masks the line, leaves due | ||
| 501 | * to IRQ_INPROGRESS and the irq line is masked forever. | ||
| 502 | */ | ||
| 503 | if (unlikely(desc->status & IRQ_INPROGRESS)) { | ||
| 504 | raw_spin_unlock_irq(&desc->lock); | ||
| 505 | chip_bus_sync_unlock(irq, desc); | ||
| 506 | cpu_relax(); | ||
| 507 | goto again; | ||
| 508 | } | ||
| 509 | |||
| 488 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { | 510 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { |
| 489 | desc->status &= ~IRQ_MASKED; | 511 | desc->status &= ~IRQ_MASKED; |
| 490 | desc->chip->unmask(irq); | 512 | desc->chip->unmask(irq); |
| @@ -735,6 +757,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 735 | if (new->flags & IRQF_ONESHOT) | 757 | if (new->flags & IRQF_ONESHOT) |
| 736 | desc->status |= IRQ_ONESHOT; | 758 | desc->status |= IRQ_ONESHOT; |
| 737 | 759 | ||
| 760 | /* | ||
| 761 | * Force MSI interrupts to run with interrupts | ||
| 762 | * disabled. The multi vector cards can cause stack | ||
| 763 | * overflows due to nested interrupts when enough of | ||
| 764 | * them are directed to a core and fire at the same | ||
| 765 | * time. | ||
| 766 | */ | ||
| 767 | if (desc->msi_desc) | ||
| 768 | new->flags |= IRQF_DISABLED; | ||
| 769 | |||
| 738 | if (!(desc->status & IRQ_NOAUTOEN)) { | 770 | if (!(desc->status & IRQ_NOAUTOEN)) { |
| 739 | desc->depth = 0; | 771 | desc->depth = 0; |
| 740 | desc->status &= ~IRQ_DISABLED; | 772 | desc->status &= ~IRQ_DISABLED; |
