diff options
author | Julien Thierry <julien.thierry@arm.com> | 2019-01-31 09:54:01 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2019-02-05 09:37:05 -0500 |
commit | 6e4933a006616343f66c4702dc4fc56bb25e7b02 (patch) | |
tree | d5637427d41431971b2037ccbff2c5bf9cdca3f0 | |
parent | 2dcf1fbcad352baaa5f47b17e57c5743c8eedbad (diff) |
irqdesc: Add domain handler for NMIs
NMI handling code should be executed between calls to nmi_enter and
nmi_exit.
Add a separate domain handler to properly setup NMI context when handling
an interrupt requested as NMI.
Signed-off-by: Julien Thierry <julien.thierry@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | include/linux/irqdesc.h | 5 | ||||
-rw-r--r-- | kernel/irq/irqdesc.c | 35 |
2 files changed, 40 insertions, 0 deletions
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index dd1e40ddac7d..ba05b0d6401a 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h | |||
@@ -171,6 +171,11 @@ static inline int handle_domain_irq(struct irq_domain *domain, | |||
171 | { | 171 | { |
172 | return __handle_domain_irq(domain, hwirq, true, regs); | 172 | return __handle_domain_irq(domain, hwirq, true, regs); |
173 | } | 173 | } |
174 | |||
175 | #ifdef CONFIG_IRQ_DOMAIN | ||
176 | int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq, | ||
177 | struct pt_regs *regs); | ||
178 | #endif | ||
174 | #endif | 179 | #endif |
175 | 180 | ||
176 | /* Test to see if a driver has successfully requested an irq */ | 181 | /* Test to see if a driver has successfully requested an irq */ |
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index ee062b7939d3..a1d7a7d484e0 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
@@ -669,6 +669,41 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, | |||
669 | set_irq_regs(old_regs); | 669 | set_irq_regs(old_regs); |
670 | return ret; | 670 | return ret; |
671 | } | 671 | } |
672 | |||
673 | #ifdef CONFIG_IRQ_DOMAIN | ||
674 | /** | ||
675 | * handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain | ||
676 | * @domain: The domain where to perform the lookup | ||
677 | * @hwirq: The HW irq number to convert to a logical one | ||
678 | * @regs: Register file coming from the low-level handling code | ||
679 | * | ||
680 | * Returns: 0 on success, or -EINVAL if conversion has failed | ||
681 | */ | ||
682 | int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq, | ||
683 | struct pt_regs *regs) | ||
684 | { | ||
685 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
686 | unsigned int irq; | ||
687 | int ret = 0; | ||
688 | |||
689 | nmi_enter(); | ||
690 | |||
691 | irq = irq_find_mapping(domain, hwirq); | ||
692 | |||
693 | /* | ||
694 | * ack_bad_irq is not NMI-safe, just report | ||
695 | * an invalid interrupt. | ||
696 | */ | ||
697 | if (likely(irq)) | ||
698 | generic_handle_irq(irq); | ||
699 | else | ||
700 | ret = -EINVAL; | ||
701 | |||
702 | nmi_exit(); | ||
703 | set_irq_regs(old_regs); | ||
704 | return ret; | ||
705 | } | ||
706 | #endif | ||
672 | #endif | 707 | #endif |
673 | 708 | ||
674 | /* Dynamic interrupt handling */ | 709 | /* Dynamic interrupt handling */ |