diff options
| author | Chris Zankel <chris@zankel.net> | 2016-01-21 00:17:09 -0500 |
|---|---|---|
| committer | Chris Zankel <chris@zankel.net> | 2016-01-21 00:17:09 -0500 |
| commit | bb2f3486041aa126cb7ce4929f1e45ede85f0051 (patch) | |
| tree | 144450f64cc6ad20d72026ed406ccedb524720d9 | |
| parent | d1208404dd477c142680437137c9996b95bfd508 (diff) | |
| parent | 5bb8def55dc562d81ec582368b4f27c8d432fbd5 (diff) | |
Merge tag 'xtensa-for-next-20160111' of git://github.com/jcmvbkbc/linux-xtensa
Xtensa improvements for 4.5:
- control whether perf IRQ is treated as NMI from Kconfig;
- implement ioremap for regions outside KIO segment.
| -rw-r--r-- | arch/xtensa/Kconfig | 16 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/io.h | 16 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/processor.h | 12 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/timex.h | 9 | ||||
| -rw-r--r-- | arch/xtensa/kernel/traps.c | 27 | ||||
| -rw-r--r-- | arch/xtensa/mm/Makefile | 2 | ||||
| -rw-r--r-- | arch/xtensa/mm/ioremap.c | 68 |
7 files changed, 133 insertions, 17 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 82044f732323..128e63d3a632 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig | |||
| @@ -139,6 +139,22 @@ config XTENSA_VARIANT_HAVE_PERF_EVENTS | |||
| 139 | 139 | ||
| 140 | If unsure, say N. | 140 | If unsure, say N. |
| 141 | 141 | ||
| 142 | config XTENSA_FAKE_NMI | ||
| 143 | bool "Treat PMM IRQ as NMI" | ||
| 144 | depends on XTENSA_VARIANT_HAVE_PERF_EVENTS | ||
| 145 | default n | ||
| 146 | help | ||
| 147 | If PMM IRQ is the only IRQ at EXCM level it is safe to | ||
| 148 | treat it as NMI, which improves accuracy of profiling. | ||
| 149 | |||
| 150 | If there are other interrupts at or above PMM IRQ priority level | ||
| 151 | but not above the EXCM level, PMM IRQ still may be treated as NMI, | ||
| 152 | but only if these IRQs are not used. There will be a build warning | ||
| 153 | saying that this is not safe, and a bugcheck if one of these IRQs | ||
| 154 | actually fire. | ||
| 155 | |||
| 156 | If unsure, say N. | ||
| 157 | |||
| 142 | config XTENSA_UNALIGNED_USER | 158 | config XTENSA_UNALIGNED_USER |
| 143 | bool "Unaligned memory access in use space" | 159 | bool "Unaligned memory access in use space" |
| 144 | help | 160 | help |
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h index 74fed0b4e2c2..c38e5a732d86 100644 --- a/arch/xtensa/include/asm/io.h +++ b/arch/xtensa/include/asm/io.h | |||
| @@ -25,9 +25,12 @@ | |||
| 25 | 25 | ||
| 26 | #ifdef CONFIG_MMU | 26 | #ifdef CONFIG_MMU |
| 27 | 27 | ||
| 28 | void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size); | ||
| 29 | void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size); | ||
| 30 | void xtensa_iounmap(volatile void __iomem *addr); | ||
| 31 | |||
| 28 | /* | 32 | /* |
| 29 | * Return the virtual address for the specified bus memory. | 33 | * Return the virtual address for the specified bus memory. |
| 30 | * Note that we currently don't support any address outside the KIO segment. | ||
| 31 | */ | 34 | */ |
| 32 | static inline void __iomem *ioremap_nocache(unsigned long offset, | 35 | static inline void __iomem *ioremap_nocache(unsigned long offset, |
| 33 | unsigned long size) | 36 | unsigned long size) |
| @@ -36,7 +39,7 @@ static inline void __iomem *ioremap_nocache(unsigned long offset, | |||
| 36 | && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) | 39 | && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) |
| 37 | return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); | 40 | return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); |
| 38 | else | 41 | else |
| 39 | BUG(); | 42 | return xtensa_ioremap_nocache(offset, size); |
| 40 | } | 43 | } |
| 41 | 44 | ||
| 42 | static inline void __iomem *ioremap_cache(unsigned long offset, | 45 | static inline void __iomem *ioremap_cache(unsigned long offset, |
| @@ -46,7 +49,7 @@ static inline void __iomem *ioremap_cache(unsigned long offset, | |||
| 46 | && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) | 49 | && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) |
| 47 | return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); | 50 | return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); |
| 48 | else | 51 | else |
| 49 | BUG(); | 52 | return xtensa_ioremap_cache(offset, size); |
| 50 | } | 53 | } |
| 51 | #define ioremap_cache ioremap_cache | 54 | #define ioremap_cache ioremap_cache |
| 52 | 55 | ||
| @@ -60,6 +63,13 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) | |||
| 60 | 63 | ||
| 61 | static inline void iounmap(volatile void __iomem *addr) | 64 | static inline void iounmap(volatile void __iomem *addr) |
| 62 | { | 65 | { |
| 66 | unsigned long va = (unsigned long) addr; | ||
| 67 | |||
| 68 | if (!(va >= XCHAL_KIO_CACHED_VADDR && | ||
| 69 | va - XCHAL_KIO_CACHED_VADDR < XCHAL_KIO_SIZE) && | ||
| 70 | !(va >= XCHAL_KIO_BYPASS_VADDR && | ||
| 71 | va - XCHAL_KIO_BYPASS_VADDR < XCHAL_KIO_SIZE)) | ||
| 72 | xtensa_iounmap(addr); | ||
| 63 | } | 73 | } |
| 64 | 74 | ||
| 65 | #define virt_to_bus virt_to_phys | 75 | #define virt_to_bus virt_to_phys |
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h index 83e2e4bc01ba..744ecf0dc3a4 100644 --- a/arch/xtensa/include/asm/processor.h +++ b/arch/xtensa/include/asm/processor.h | |||
| @@ -78,22 +78,20 @@ | |||
| 78 | #define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level) | 78 | #define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level) |
| 79 | #define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK) | 79 | #define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK) |
| 80 | 80 | ||
| 81 | #define IS_POW2(v) (((v) & ((v) - 1)) == 0) | 81 | #define XTENSA_INTLEVEL_ANDBELOW_MASK(l) _XTENSA_INTLEVEL_ANDBELOW_MASK(l) |
| 82 | #define _XTENSA_INTLEVEL_ANDBELOW_MASK(l) (XCHAL_INTLEVEL##l##_ANDBELOW_MASK) | ||
| 82 | 83 | ||
| 83 | #define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT) | 84 | #define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT) |
| 84 | 85 | ||
| 85 | /* LOCKLEVEL defines the interrupt level that masks all | 86 | /* LOCKLEVEL defines the interrupt level that masks all |
| 86 | * general-purpose interrupts. | 87 | * general-purpose interrupts. |
| 87 | */ | 88 | */ |
| 88 | #if defined(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) && \ | 89 | #if defined(CONFIG_XTENSA_FAKE_NMI) && defined(XCHAL_PROFILING_INTERRUPT) |
| 89 | defined(XCHAL_PROFILING_INTERRUPT) && \ | 90 | #define LOCKLEVEL (PROFILING_INTLEVEL - 1) |
| 90 | PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \ | ||
| 91 | XCHAL_EXCM_LEVEL > 1 && \ | ||
| 92 | IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL)) | ||
| 93 | #define LOCKLEVEL (XCHAL_EXCM_LEVEL - 1) | ||
| 94 | #else | 91 | #else |
| 95 | #define LOCKLEVEL XCHAL_EXCM_LEVEL | 92 | #define LOCKLEVEL XCHAL_EXCM_LEVEL |
| 96 | #endif | 93 | #endif |
| 94 | |||
| 97 | #define TOPLEVEL XCHAL_EXCM_LEVEL | 95 | #define TOPLEVEL XCHAL_EXCM_LEVEL |
| 98 | #define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL) | 96 | #define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL) |
| 99 | 97 | ||
diff --git a/arch/xtensa/include/asm/timex.h b/arch/xtensa/include/asm/timex.h index ca929e6a38b5..f9b389d4e973 100644 --- a/arch/xtensa/include/asm/timex.h +++ b/arch/xtensa/include/asm/timex.h | |||
| @@ -12,19 +12,16 @@ | |||
| 12 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
| 13 | #include <linux/stringify.h> | 13 | #include <linux/stringify.h> |
| 14 | 14 | ||
| 15 | #define _INTLEVEL(x) XCHAL_INT ## x ## _LEVEL | ||
| 16 | #define INTLEVEL(x) _INTLEVEL(x) | ||
| 17 | |||
| 18 | #if XCHAL_NUM_TIMERS > 0 && \ | 15 | #if XCHAL_NUM_TIMERS > 0 && \ |
| 19 | INTLEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL | 16 | XTENSA_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL |
| 20 | # define LINUX_TIMER 0 | 17 | # define LINUX_TIMER 0 |
| 21 | # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT | 18 | # define LINUX_TIMER_INT XCHAL_TIMER0_INTERRUPT |
| 22 | #elif XCHAL_NUM_TIMERS > 1 && \ | 19 | #elif XCHAL_NUM_TIMERS > 1 && \ |
| 23 | INTLEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL | 20 | XTENSA_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL |
| 24 | # define LINUX_TIMER 1 | 21 | # define LINUX_TIMER 1 |
| 25 | # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT | 22 | # define LINUX_TIMER_INT XCHAL_TIMER1_INTERRUPT |
| 26 | #elif XCHAL_NUM_TIMERS > 2 && \ | 23 | #elif XCHAL_NUM_TIMERS > 2 && \ |
| 27 | INTLEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL | 24 | XTENSA_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL |
| 28 | # define LINUX_TIMER 2 | 25 | # define LINUX_TIMER 2 |
| 29 | # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT | 26 | # define LINUX_TIMER_INT XCHAL_TIMER2_INTERRUPT |
| 30 | #else | 27 | #else |
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 *); | |||
| 205 | 205 | ||
| 206 | #if XTENSA_FAKE_NMI | 206 | #if XTENSA_FAKE_NMI |
| 207 | 207 | ||
| 208 | #define IS_POW2(v) (((v) & ((v) - 1)) == 0) | ||
| 209 | |||
| 210 | #if !(PROFILING_INTLEVEL == XCHAL_EXCM_LEVEL && \ | ||
| 211 | IS_POW2(XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL))) | ||
| 212 | #warning "Fake NMI is requested for PMM, but there are other IRQs at or above its level." | ||
| 213 | #warning "Fake NMI will be used, but there will be a bugcheck if one of those IRQs fire." | ||
| 214 | |||
| 215 | static inline void check_valid_nmi(void) | ||
| 216 | { | ||
| 217 | unsigned intread = get_sr(interrupt); | ||
| 218 | unsigned intenable = get_sr(intenable); | ||
| 219 | |||
| 220 | BUG_ON(intread & intenable & | ||
| 221 | ~(XTENSA_INTLEVEL_ANDBELOW_MASK(PROFILING_INTLEVEL) ^ | ||
| 222 | XTENSA_INTLEVEL_MASK(PROFILING_INTLEVEL) ^ | ||
| 223 | BIT(XCHAL_PROFILING_INTERRUPT))); | ||
| 224 | } | ||
| 225 | |||
| 226 | #else | ||
| 227 | |||
| 228 | static inline void check_valid_nmi(void) | ||
| 229 | { | ||
| 230 | } | ||
| 231 | |||
| 232 | #endif | ||
| 233 | |||
| 208 | irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id); | 234 | irqreturn_t xtensa_pmu_irq_handler(int irq, void *dev_id); |
| 209 | 235 | ||
| 210 | DEFINE_PER_CPU(unsigned long, nmi_count); | 236 | DEFINE_PER_CPU(unsigned long, nmi_count); |
| @@ -219,6 +245,7 @@ void do_nmi(struct pt_regs *regs) | |||
| 219 | old_regs = set_irq_regs(regs); | 245 | old_regs = set_irq_regs(regs); |
| 220 | nmi_enter(); | 246 | nmi_enter(); |
| 221 | ++*this_cpu_ptr(&nmi_count); | 247 | ++*this_cpu_ptr(&nmi_count); |
| 248 | check_valid_nmi(); | ||
| 222 | xtensa_pmu_irq_handler(0, NULL); | 249 | xtensa_pmu_irq_handler(0, NULL); |
| 223 | nmi_exit(); | 250 | nmi_exit(); |
| 224 | set_irq_regs(old_regs); | 251 | set_irq_regs(old_regs); |
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile index e601e2fbe8e6..0b3d296a016a 100644 --- a/arch/xtensa/mm/Makefile +++ b/arch/xtensa/mm/Makefile | |||
| @@ -3,5 +3,5 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := init.o misc.o | 5 | obj-y := init.o misc.o |
| 6 | obj-$(CONFIG_MMU) += cache.o fault.o mmu.o tlb.o | 6 | obj-$(CONFIG_MMU) += cache.o fault.o ioremap.o mmu.o tlb.o |
| 7 | obj-$(CONFIG_HIGHMEM) += highmem.o | 7 | obj-$(CONFIG_HIGHMEM) += highmem.o |
diff --git a/arch/xtensa/mm/ioremap.c b/arch/xtensa/mm/ioremap.c new file mode 100644 index 000000000000..d89c3c5fd962 --- /dev/null +++ b/arch/xtensa/mm/ioremap.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * ioremap implementation. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Cadence Design Systems Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/io.h> | ||
| 12 | #include <linux/vmalloc.h> | ||
| 13 | #include <asm/cacheflush.h> | ||
| 14 | #include <asm/io.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 16 | |||
| 17 | static void __iomem *xtensa_ioremap(unsigned long paddr, unsigned long size, | ||
| 18 | pgprot_t prot) | ||
| 19 | { | ||
| 20 | unsigned long offset = paddr & ~PAGE_MASK; | ||
| 21 | unsigned long pfn = __phys_to_pfn(paddr); | ||
| 22 | struct vm_struct *area; | ||
| 23 | unsigned long vaddr; | ||
| 24 | int err; | ||
| 25 | |||
| 26 | paddr &= PAGE_MASK; | ||
| 27 | |||
| 28 | WARN_ON(pfn_valid(pfn)); | ||
| 29 | |||
| 30 | size = PAGE_ALIGN(offset + size); | ||
| 31 | |||
| 32 | area = get_vm_area(size, VM_IOREMAP); | ||
| 33 | if (!area) | ||
| 34 | return NULL; | ||
| 35 | |||
| 36 | vaddr = (unsigned long)area->addr; | ||
| 37 | area->phys_addr = paddr; | ||
| 38 | |||
| 39 | err = ioremap_page_range(vaddr, vaddr + size, paddr, prot); | ||
| 40 | |||
| 41 | if (err) { | ||
| 42 | vunmap((void *)vaddr); | ||
| 43 | return NULL; | ||
| 44 | } | ||
| 45 | |||
| 46 | flush_cache_vmap(vaddr, vaddr + size); | ||
| 47 | return (void __iomem *)(offset + vaddr); | ||
| 48 | } | ||
| 49 | |||
| 50 | void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size) | ||
| 51 | { | ||
| 52 | return xtensa_ioremap(addr, size, pgprot_noncached(PAGE_KERNEL)); | ||
| 53 | } | ||
| 54 | EXPORT_SYMBOL(xtensa_ioremap_nocache); | ||
| 55 | |||
| 56 | void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size) | ||
| 57 | { | ||
| 58 | return xtensa_ioremap(addr, size, PAGE_KERNEL); | ||
| 59 | } | ||
| 60 | EXPORT_SYMBOL(xtensa_ioremap_cache); | ||
| 61 | |||
| 62 | void xtensa_iounmap(volatile void __iomem *io_addr) | ||
| 63 | { | ||
| 64 | void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); | ||
| 65 | |||
| 66 | vunmap(addr); | ||
| 67 | } | ||
| 68 | EXPORT_SYMBOL(xtensa_iounmap); | ||
