Loading arch/xtensa/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,22 @@ config XTENSA_VARIANT_HAVE_PERF_EVENTS If unsure, say N. config XTENSA_FAKE_NMI bool "Treat PMM IRQ as NMI" depends on XTENSA_VARIANT_HAVE_PERF_EVENTS default n help If PMM IRQ is the only IRQ at EXCM level it is safe to treat it as NMI, which improves accuracy of profiling. If there are other interrupts at or above PMM IRQ priority level but not above the EXCM level, PMM IRQ still may be treated as NMI, but only if these IRQs are not used. There will be a build warning saying that this is not safe, and a bugcheck if one of these IRQs actually fire. If unsure, say N. config XTENSA_UNALIGNED_USER bool "Unaligned memory access in use space" help Loading arch/xtensa/include/asm/io.h +13 −3 Original line number Diff line number Diff line Loading @@ -25,9 +25,12 @@ #ifdef CONFIG_MMU void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size); void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size); void xtensa_iounmap(volatile void __iomem *addr); /* * Return the virtual address for the specified bus memory. * Note that we currently don't support any address outside the KIO segment. */ static inline void __iomem *ioremap_nocache(unsigned long offset, unsigned long size) Loading @@ -36,7 +39,7 @@ static inline void __iomem *ioremap_nocache(unsigned long offset, && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); else BUG(); return xtensa_ioremap_nocache(offset, size); } static inline void __iomem *ioremap_cache(unsigned long offset, Loading @@ -46,7 +49,7 @@ static inline void __iomem *ioremap_cache(unsigned long offset, && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); else BUG(); return xtensa_ioremap_cache(offset, size); } #define ioremap_cache ioremap_cache Loading @@ -60,6 +63,13 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) static inline void iounmap(volatile void __iomem *addr) { unsigned long va = (unsigned long) addr; if (!(va >= XCHAL_KIO_CACHED_VADDR && va - XCHAL_KIO_CACHED_VADDR < XCHAL_KIO_SIZE) && !(va >= XCHAL_KIO_BYPASS_VADDR && va - XCHAL_KIO_BYPASS_VADDR < XCHAL_KIO_SIZE)) xtensa_iounmap(addr); } #define virt_to_bus virt_to_phys Loading arch/xtensa/include/asm/processor.h +5 −7 Original line number Diff line number Diff line Loading @@ -78,22 +78,20 @@ #define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level) #define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK) #define IS_POW2(v) (((v) & ((v) - 1)) == 0) #define XTENSA_INTLEVEL_ANDBELOW_MASK(l) _XTENSA_INTLEVEL_ANDBELOW_MASK(l) #define _XTENSA_INTLEVEL_ANDBELOW_MASK(l) (XCHAL_INTLEVEL##l##_ANDBELOW_MASK) #define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT) /* LOCKLEVEL defines the interrupt level that masks all * general-purpose interrupts. */ #if defined(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) && \ defined(XCHAL_PROFILING_INTERRUPT) && \ PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \ XCHAL_EXCM_LEVEL > 1 && \ IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL)) #define LOCKLEVEL (XCHAL_EXCM_LEVEL - 1) #if defined(CONFIG_XTENSA_FAKE_NMI) && defined(XCHAL_PROFILING_INTERRUPT) #define LOCKLEVEL (PROFILING_INTLEVEL - 1) #else #define LOCKLEVEL XCHAL_EXCM_LEVEL #endif #define TOPLEVEL XCHAL_EXCM_LEVEL #define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL) Loading arch/xtensa/include/asm/timex.h +3 −6 Original line number Diff line number Diff line Loading @@ -12,19 +12,16 @@ #include <asm/processor.h> #include <linux/stringify.h> #define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL #define INTLEVEL(x) _INTLEVEL(x) #if XCHAL_NUM_TIMERS > 0 && \ INTLEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 0 # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT #elif XCHAL_NUM_TIMERS > 1 && \ INTLEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 1 # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT #elif XCHAL_NUM_TIMERS > 2 && \ INTLEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 2 # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT #else Loading arch/xtensa/kernel/traps.c +27 −0 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); Loading Loading
arch/xtensa/Kconfig +16 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,22 @@ config XTENSA_VARIANT_HAVE_PERF_EVENTS If unsure, say N. config XTENSA_FAKE_NMI bool "Treat PMM IRQ as NMI" depends on XTENSA_VARIANT_HAVE_PERF_EVENTS default n help If PMM IRQ is the only IRQ at EXCM level it is safe to treat it as NMI, which improves accuracy of profiling. If there are other interrupts at or above PMM IRQ priority level but not above the EXCM level, PMM IRQ still may be treated as NMI, but only if these IRQs are not used. There will be a build warning saying that this is not safe, and a bugcheck if one of these IRQs actually fire. If unsure, say N. config XTENSA_UNALIGNED_USER bool "Unaligned memory access in use space" help Loading
arch/xtensa/include/asm/io.h +13 −3 Original line number Diff line number Diff line Loading @@ -25,9 +25,12 @@ #ifdef CONFIG_MMU void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size); void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size); void xtensa_iounmap(volatile void __iomem *addr); /* * Return the virtual address for the specified bus memory. * Note that we currently don't support any address outside the KIO segment. */ static inline void __iomem *ioremap_nocache(unsigned long offset, unsigned long size) Loading @@ -36,7 +39,7 @@ static inline void __iomem *ioremap_nocache(unsigned long offset, && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); else BUG(); return xtensa_ioremap_nocache(offset, size); } static inline void __iomem *ioremap_cache(unsigned long offset, Loading @@ -46,7 +49,7 @@ static inline void __iomem *ioremap_cache(unsigned long offset, && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); else BUG(); return xtensa_ioremap_cache(offset, size); } #define ioremap_cache ioremap_cache Loading @@ -60,6 +63,13 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) static inline void iounmap(volatile void __iomem *addr) { unsigned long va = (unsigned long) addr; if (!(va >= XCHAL_KIO_CACHED_VADDR && va - XCHAL_KIO_CACHED_VADDR < XCHAL_KIO_SIZE) && !(va >= XCHAL_KIO_BYPASS_VADDR && va - XCHAL_KIO_BYPASS_VADDR < XCHAL_KIO_SIZE)) xtensa_iounmap(addr); } #define virt_to_bus virt_to_phys Loading
arch/xtensa/include/asm/processor.h +5 −7 Original line number Diff line number Diff line Loading @@ -78,22 +78,20 @@ #define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level) #define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK) #define IS_POW2(v) (((v) & ((v) - 1)) == 0) #define XTENSA_INTLEVEL_ANDBELOW_MASK(l) _XTENSA_INTLEVEL_ANDBELOW_MASK(l) #define _XTENSA_INTLEVEL_ANDBELOW_MASK(l) (XCHAL_INTLEVEL##l##_ANDBELOW_MASK) #define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT) /* LOCKLEVEL defines the interrupt level that masks all * general-purpose interrupts. */ #if defined(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) && \ defined(XCHAL_PROFILING_INTERRUPT) && \ PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \ XCHAL_EXCM_LEVEL > 1 && \ IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL)) #define LOCKLEVEL (XCHAL_EXCM_LEVEL - 1) #if defined(CONFIG_XTENSA_FAKE_NMI) && defined(XCHAL_PROFILING_INTERRUPT) #define LOCKLEVEL (PROFILING_INTLEVEL - 1) #else #define LOCKLEVEL XCHAL_EXCM_LEVEL #endif #define TOPLEVEL XCHAL_EXCM_LEVEL #define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL) Loading
arch/xtensa/include/asm/timex.h +3 −6 Original line number Diff line number Diff line Loading @@ -12,19 +12,16 @@ #include <asm/processor.h> #include <linux/stringify.h> #define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL #define INTLEVEL(x) _INTLEVEL(x) #if XCHAL_NUM_TIMERS > 0 && \ INTLEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 0 # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT #elif XCHAL_NUM_TIMERS > 1 && \ INTLEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 1 # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT #elif XCHAL_NUM_TIMERS > 2 && \ INTLEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL XTENSA_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL # define LINUX_TIMER 2 # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT #else Loading
arch/xtensa/kernel/traps.c +27 −0 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); Loading