diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2015-11-27 16:26:41 +0300 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2016-01-11 17:31:55 +0300 |
commit | e462919413547dcfe84e785380d0f47f1359878a (patch) | |
tree | 4c80bbd286f9c106d243149ec14634c2e9811a6f /arch/xtensa/kernel | |
parent | afd2ff9b7e1b367172f18ba7f693dfb62bdcb2dc (diff) | |
download | linux-e462919413547dcfe84e785380d0f47f1359878a.tar.gz linux-e462919413547dcfe84e785380d0f47f1359878a.tar.bz2 linux-e462919413547dcfe84e785380d0f47f1359878a.zip |
xtensa: make fake NMI configurable
Do not always use fake NMI when safe, provide Kconfig option instead.
Print a warning if fake NMI is chosen in unsafe configuration, but allow
it, because it may work if the user knows that interrupts with
priorities at or above PMM IRQ are not used. Add a check to NMI handler
that BUGs if any of these IRQs fire.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/kernel')
-rw-r--r-- | arch/xtensa/kernel/traps.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index 42d441f7898b..be0cae8082c7 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -205,6 +205,32 @@ extern void do_IRQ(int, struct pt_regs *); #if XTENSA_FAKE_NMI +#define IS_POW2(v) (((v) & ((v) - 1)) == 0) + +#if !(PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \ + IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL))) +#warning "Fake NMI is requested for PMM, but there are other IRQs at or above its level." +#warning "Fake NMI will be used, but there will be a bugcheck if one of those IRQs fire." + +static inline void check_valid_nmi(void) +{ + unsigned intread = get_sr(interrupt); + unsigned intenable = get_sr(intenable); + + BUG_ON(intread & intenable & + ~(XTENSA_INTLEVEL_ANDBELOW_MASK(PROFILING_INTLEVEL) ^ + XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL) ^ + BIT(XCHAL_PROFILING_INTERRUPT))); +} + +#else + +static inline void check_valid_nmi(void) +{ +} + +#endif + irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id); DEFINE_PER_CPU(unsigned long, nmi_count); @@ -219,6 +245,7 @@ void do_nmi(struct pt_regs *regs) old_regs = set_irq_regs(regs); nmi_enter(); ++*this_cpu_ptr(&nmi_count); + check_valid_nmi(); xtensa_pmu_irq_handler(0, NULL); nmi_exit(); set_irq_regs(old_regs); |