--- zzzz-none-000/linux-3.10.107/arch/xtensa/kernel/traps.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/xtensa/kernel/traps.c 2021-02-04 17:41:59.000000000 +0000 @@ -62,6 +62,7 @@ extern void do_illegal_instruction (struct pt_regs*); extern void do_interrupt (struct pt_regs*); +extern void do_nmi(struct pt_regs *); extern void do_unaligned_user (struct pt_regs*); extern void do_multihit (struct pt_regs*, unsigned long); extern void do_page_fault (struct pt_regs*, unsigned long); @@ -101,9 +102,8 @@ #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION #ifdef CONFIG_XTENSA_UNALIGNED_USER { EXCCAUSE_UNALIGNED, USER, fast_unaligned }, -#else -{ EXCCAUSE_UNALIGNED, 0, do_unaligned_user }, #endif +{ EXCCAUSE_UNALIGNED, 0, do_unaligned_user }, { EXCCAUSE_UNALIGNED, KRNL, fast_unaligned }, #endif #ifdef CONFIG_MMU @@ -147,6 +147,9 @@ #if XTENSA_HAVE_COPROCESSOR(7) COPROCESSOR(7), #endif +#if XTENSA_FAKE_NMI +{ EXCCAUSE_MAPPED_NMI, 0, do_nmi }, +#endif { EXCCAUSE_MAPPED_DEBUG, 0, do_debug }, { -1, -1, 0 } @@ -157,7 +160,7 @@ * 2. it is a temporary memory buffer for the exception handlers. */ -unsigned long exc_table[EXC_TABLE_SIZE/4]; +DEFINE_PER_CPU(unsigned long, exc_table[EXC_TABLE_SIZE/4]); void die(const char*, struct pt_regs*, long); @@ -200,6 +203,28 @@ extern void do_IRQ(int, struct pt_regs *); +#if XTENSA_FAKE_NMI + +irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id); + +DEFINE_PER_CPU(unsigned long, nmi_count); + +void do_nmi(struct pt_regs *regs) +{ + struct pt_regs *old_regs; + + if ((regs->ps & PS_INTLEVEL_MASK) < LOCKLEVEL) + trace_hardirqs_off(); + + old_regs = set_irq_regs(regs); + nmi_enter(); + ++*this_cpu_ptr(&nmi_count); + xtensa_pmu_irq_handler(0, NULL); + nmi_exit(); + set_irq_regs(old_regs); +} +#endif + void do_interrupt(struct pt_regs *regs) { static const unsigned int_level_mask[] = { @@ -212,6 +237,12 @@ XCHAL_INTLEVEL6_MASK, XCHAL_INTLEVEL7_MASK, }; + struct pt_regs *old_regs; + + trace_hardirqs_off(); + + old_regs = set_irq_regs(regs); + irq_enter(); for (;;) { unsigned intread = get_sr(interrupt); @@ -227,21 +258,13 @@ } if (level == 0) - return; + break; - /* - * Clear the interrupt before processing, in case it's - * edge-triggered or software-generated - */ - while (int_at_level) { - unsigned i = __ffs(int_at_level); - unsigned mask = 1 << i; - - int_at_level ^= mask; - set_sr(mask, intclear); - do_IRQ(i, regs); - } + do_IRQ(__ffs(int_at_level), regs); } + + irq_exit(); + set_irq_regs(old_regs); } /* @@ -269,7 +292,6 @@ */ #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION -#ifndef CONFIG_XTENSA_UNALIGNED_USER void do_unaligned_user (struct pt_regs *regs) { @@ -291,7 +313,6 @@ } #endif -#endif void do_debug(struct pt_regs *regs) @@ -318,17 +339,31 @@ } +static void set_handler(int idx, void *handler) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) + per_cpu(exc_table, cpu)[idx] = (unsigned long)handler; +} + /* Set exception C handler - for temporary use when probing exceptions */ void * __init trap_set_handler(int cause, void *handler) { - unsigned long *entry = &exc_table[EXC_TABLE_DEFAULT / 4 + cause]; - void *previous = (void *)*entry; - *entry = (unsigned long)handler; + void *previous = (void *)per_cpu(exc_table, 0)[ + EXC_TABLE_DEFAULT / 4 + cause]; + set_handler(EXC_TABLE_DEFAULT / 4 + cause, handler); return previous; } +static void trap_init_excsave(void) +{ + unsigned long excsave1 = (unsigned long)this_cpu_ptr(exc_table); + __asm__ __volatile__("wsr %0, excsave1\n" : : "a" (excsave1)); +} + /* * Initialize dispatch tables. * @@ -342,8 +377,6 @@ * See vectors.S for more details. */ -#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler)) - void __init trap_init(void) { int i; @@ -373,10 +406,15 @@ } /* Initialize EXCSAVE_1 to hold the address of the exception table. */ + trap_init_excsave(); +} - i = (unsigned long)exc_table; - __asm__ __volatile__("wsr %0, excsave1\n" : : "a" (i)); +#ifdef CONFIG_SMP +void secondary_trap_init(void) +{ + trap_init_excsave(); } +#endif /* * This function dumps the current valid window frame and other base registers.