diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/kernel | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/kernel')
56 files changed, 7403 insertions, 4686 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 980b78e31328..a5b31af5c2b8 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) | 5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) |
6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
7 | 7 | ||
8 | ifdef CONFIG_DYNAMIC_FTRACE | 8 | ifdef CONFIG_FUNCTION_TRACER |
9 | CFLAGS_REMOVE_ftrace.o = -pg | 9 | CFLAGS_REMOVE_ftrace.o = -pg |
10 | endif | 10 | endif |
11 | 11 | ||
@@ -24,15 +24,18 @@ obj-$(CONFIG_OC_ETM) += etm.o | |||
24 | 24 | ||
25 | obj-$(CONFIG_ISA_DMA_API) += dma.o | 25 | obj-$(CONFIG_ISA_DMA_API) += dma.o |
26 | obj-$(CONFIG_ARCH_ACORN) += ecard.o | 26 | obj-$(CONFIG_ARCH_ACORN) += ecard.o |
27 | obj-$(CONFIG_FIQ) += fiq.o | 27 | obj-$(CONFIG_FIQ) += fiq.o fiqasm.o |
28 | obj-$(CONFIG_MODULES) += armksyms.o module.o | 28 | obj-$(CONFIG_MODULES) += armksyms.o module.o |
29 | obj-$(CONFIG_ARTHUR) += arthur.o | 29 | obj-$(CONFIG_ARTHUR) += arthur.o |
30 | obj-$(CONFIG_ISA_DMA) += dma-isa.o | 30 | obj-$(CONFIG_ISA_DMA) += dma-isa.o |
31 | obj-$(CONFIG_PCI) += bios32.o isa.o | 31 | obj-$(CONFIG_PCI) += bios32.o isa.o |
32 | obj-$(CONFIG_SMP) += smp.o | 32 | obj-$(CONFIG_PM_SLEEP) += sleep.o |
33 | obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o | ||
34 | obj-$(CONFIG_SMP) += smp.o smp_tlb.o | ||
33 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o | 35 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o |
34 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o | 36 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o |
35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 37 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
38 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
36 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 39 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
37 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | 40 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o |
38 | obj-$(CONFIG_ATAGS_PROC) += atags.o | 41 | obj-$(CONFIG_ATAGS_PROC) += atags.o |
@@ -41,7 +44,11 @@ obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | |||
41 | obj-$(CONFIG_KGDB) += kgdb.o | 44 | obj-$(CONFIG_KGDB) += kgdb.o |
42 | obj-$(CONFIG_ARM_UNWIND) += unwind.o | 45 | obj-$(CONFIG_ARM_UNWIND) += unwind.o |
43 | obj-$(CONFIG_HAVE_TCM) += tcm.o | 46 | obj-$(CONFIG_HAVE_TCM) += tcm.o |
47 | obj-$(CONFIG_OF) += devtree.o | ||
44 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 48 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
49 | obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o | ||
50 | CFLAGS_swp_emulate.o := -Wa,-march=armv7-a | ||
51 | obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o | ||
45 | 52 | ||
46 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o | 53 | obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o |
47 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | 54 | AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 |
@@ -49,6 +56,7 @@ AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312 | |||
49 | obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o | 56 | obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o |
50 | obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o | 57 | obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o |
51 | obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o | 58 | obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o |
59 | obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o | ||
52 | obj-$(CONFIG_IWMMXT) += iwmmxt.o | 60 | obj-$(CONFIG_IWMMXT) += iwmmxt.o |
53 | obj-$(CONFIG_CPU_HAS_PMU) += pmu.o | 61 | obj-$(CONFIG_CPU_HAS_PMU) += pmu.o |
54 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 62 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 8214bfebfaca..acca35aebe28 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c | |||
@@ -140,24 +140,18 @@ EXPORT_SYMBOL(__aeabi_ulcmp); | |||
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | /* bitops */ | 142 | /* bitops */ |
143 | EXPORT_SYMBOL(_set_bit_le); | 143 | EXPORT_SYMBOL(_set_bit); |
144 | EXPORT_SYMBOL(_test_and_set_bit_le); | 144 | EXPORT_SYMBOL(_test_and_set_bit); |
145 | EXPORT_SYMBOL(_clear_bit_le); | 145 | EXPORT_SYMBOL(_clear_bit); |
146 | EXPORT_SYMBOL(_test_and_clear_bit_le); | 146 | EXPORT_SYMBOL(_test_and_clear_bit); |
147 | EXPORT_SYMBOL(_change_bit_le); | 147 | EXPORT_SYMBOL(_change_bit); |
148 | EXPORT_SYMBOL(_test_and_change_bit_le); | 148 | EXPORT_SYMBOL(_test_and_change_bit); |
149 | EXPORT_SYMBOL(_find_first_zero_bit_le); | 149 | EXPORT_SYMBOL(_find_first_zero_bit_le); |
150 | EXPORT_SYMBOL(_find_next_zero_bit_le); | 150 | EXPORT_SYMBOL(_find_next_zero_bit_le); |
151 | EXPORT_SYMBOL(_find_first_bit_le); | 151 | EXPORT_SYMBOL(_find_first_bit_le); |
152 | EXPORT_SYMBOL(_find_next_bit_le); | 152 | EXPORT_SYMBOL(_find_next_bit_le); |
153 | 153 | ||
154 | #ifdef __ARMEB__ | 154 | #ifdef __ARMEB__ |
155 | EXPORT_SYMBOL(_set_bit_be); | ||
156 | EXPORT_SYMBOL(_test_and_set_bit_be); | ||
157 | EXPORT_SYMBOL(_clear_bit_be); | ||
158 | EXPORT_SYMBOL(_test_and_clear_bit_be); | ||
159 | EXPORT_SYMBOL(_change_bit_be); | ||
160 | EXPORT_SYMBOL(_test_and_change_bit_be); | ||
161 | EXPORT_SYMBOL(_find_first_zero_bit_be); | 155 | EXPORT_SYMBOL(_find_first_zero_bit_be); |
162 | EXPORT_SYMBOL(_find_next_zero_bit_be); | 156 | EXPORT_SYMBOL(_find_next_zero_bit_be); |
163 | EXPORT_SYMBOL(_find_first_bit_be); | 157 | EXPORT_SYMBOL(_find_first_bit_be); |
@@ -165,6 +159,12 @@ EXPORT_SYMBOL(_find_next_bit_be); | |||
165 | #endif | 159 | #endif |
166 | 160 | ||
167 | #ifdef CONFIG_FUNCTION_TRACER | 161 | #ifdef CONFIG_FUNCTION_TRACER |
162 | #ifdef CONFIG_OLD_MCOUNT | ||
168 | EXPORT_SYMBOL(mcount); | 163 | EXPORT_SYMBOL(mcount); |
164 | #endif | ||
169 | EXPORT_SYMBOL(__gnu_mcount_nc); | 165 | EXPORT_SYMBOL(__gnu_mcount_nc); |
170 | #endif | 166 | #endif |
167 | |||
168 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
169 | EXPORT_SYMBOL(__pv_phys_offset); | ||
170 | #endif | ||
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 85f2a019f77b..927522cfc12e 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -13,6 +13,9 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/glue-df.h> | ||
18 | #include <asm/glue-pf.h> | ||
16 | #include <asm/mach/arch.h> | 19 | #include <asm/mach/arch.h> |
17 | #include <asm/thread_info.h> | 20 | #include <asm/thread_info.h> |
18 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
@@ -102,8 +105,6 @@ int main(void) | |||
102 | DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc)); | 105 | DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc)); |
103 | DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr)); | 106 | DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr)); |
104 | DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name)); | 107 | DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name)); |
105 | DEFINE(MACHINFO_PHYSIO, offsetof(struct machine_desc, phys_io)); | ||
106 | DEFINE(MACHINFO_PGOFFIO, offsetof(struct machine_desc, io_pg_offst)); | ||
107 | BLANK(); | 108 | BLANK(); |
108 | DEFINE(PROC_INFO_SZ, sizeof(struct proc_info_list)); | 109 | DEFINE(PROC_INFO_SZ, sizeof(struct proc_info_list)); |
109 | DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); | 110 | DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush)); |
@@ -116,6 +117,14 @@ int main(void) | |||
116 | #ifdef MULTI_PABORT | 117 | #ifdef MULTI_PABORT |
117 | DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); | 118 | DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); |
118 | #endif | 119 | #endif |
120 | #ifdef MULTI_CPU | ||
121 | DEFINE(CPU_SLEEP_SIZE, offsetof(struct processor, suspend_size)); | ||
122 | DEFINE(CPU_DO_SUSPEND, offsetof(struct processor, do_suspend)); | ||
123 | DEFINE(CPU_DO_RESUME, offsetof(struct processor, do_resume)); | ||
124 | #endif | ||
125 | #ifdef MULTI_CACHE | ||
126 | DEFINE(CACHE_FLUSH_KERN_ALL, offsetof(struct cpu_cache_fns, flush_kern_all)); | ||
127 | #endif | ||
119 | BLANK(); | 128 | BLANK(); |
120 | DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); | 129 | DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); |
121 | DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); | 130 | DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); |
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index c6273a3bfc25..e4ee050aad7d 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -159,31 +159,6 @@ static void __devinit pci_fixup_dec21285(struct pci_dev *dev) | |||
159 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_dec21285); | 159 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_dec21285); |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Same as above. The PrPMC800 carrier board for the PrPMC1100 | ||
163 | * card maps the host-bridge @ 00:01:00 for some reason and it | ||
164 | * ends up getting scanned. Note that we only want to do this | ||
165 | * fixup when we find the IXP4xx on a PrPMC system, which is why | ||
166 | * we check the machine type. We could be running on a board | ||
167 | * with an IXP4xx target device and we don't want to kill the | ||
168 | * resources in that case. | ||
169 | */ | ||
170 | static void __devinit pci_fixup_prpmc1100(struct pci_dev *dev) | ||
171 | { | ||
172 | int i; | ||
173 | |||
174 | if (machine_is_prpmc1100()) { | ||
175 | dev->class &= 0xff; | ||
176 | dev->class |= PCI_CLASS_BRIDGE_HOST << 8; | ||
177 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | ||
178 | dev->resource[i].start = 0; | ||
179 | dev->resource[i].end = 0; | ||
180 | dev->resource[i].flags = 0; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP4XX, pci_fixup_prpmc1100); | ||
185 | |||
186 | /* | ||
187 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | 162 | * PCI IDE controllers use non-standard I/O port decoding, respect it. |
188 | */ | 163 | */ |
189 | static void __devinit pci_fixup_ide_bases(struct pci_dev *dev) | 164 | static void __devinit pci_fixup_ide_bases(struct pci_dev *dev) |
@@ -583,6 +558,11 @@ void __init pci_common_init(struct hw_pci *hw) | |||
583 | * Assign resources. | 558 | * Assign resources. |
584 | */ | 559 | */ |
585 | pci_bus_assign_resources(bus); | 560 | pci_bus_assign_resources(bus); |
561 | |||
562 | /* | ||
563 | * Enable bridges | ||
564 | */ | ||
565 | pci_enable_bridges(bus); | ||
586 | } | 566 | } |
587 | 567 | ||
588 | /* | 568 | /* |
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index b99087ac85b9..ed2ae934127e 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S | |||
@@ -379,17 +379,23 @@ | |||
379 | CALL(sys_fanotify_init) | 379 | CALL(sys_fanotify_init) |
380 | CALL(sys_fanotify_mark) | 380 | CALL(sys_fanotify_mark) |
381 | CALL(sys_prlimit64) | 381 | CALL(sys_prlimit64) |
382 | /* 370 */ CALL(sys_set_rt_task_param) | 382 | /* 370 */ CALL(sys_name_to_handle_at) |
383 | CALL(sys_open_by_handle_at) | ||
384 | CALL(sys_clock_adjtime) | ||
385 | CALL(sys_syncfs) | ||
386 | CALL(sys_sendmmsg) | ||
387 | /* 375 */ CALL(sys_setns) | ||
388 | CALL(sys_set_rt_task_param) | ||
383 | CALL(sys_get_rt_task_param) | 389 | CALL(sys_get_rt_task_param) |
384 | CALL(sys_complete_job) | 390 | CALL(sys_complete_job) |
385 | CALL(sys_od_open) | 391 | CALL(sys_od_open) |
386 | CALL(sys_od_close) | 392 | /* 380 */ CALL(sys_od_close) |
387 | /* 375 */ CALL(sys_litmus_lock) | 393 | CALL(sys_litmus_lock) |
388 | CALL(sys_litmus_unlock) | 394 | CALL(sys_litmus_unlock) |
389 | CALL(sys_query_job_no) | 395 | CALL(sys_query_job_no) |
390 | CALL(sys_wait_for_job_release) | 396 | CALL(sys_wait_for_job_release) |
391 | CALL(sys_wait_for_ts_release) | 397 | /* 385 */ CALL(sys_wait_for_ts_release) |
392 | /* 380 */ CALL(sys_release_ts) | 398 | CALL(sys_release_ts) |
393 | CALL(sys_null_call) | 399 | CALL(sys_null_call) |
394 | #ifndef syscalls_counted | 400 | #ifndef syscalls_counted |
395 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls | 401 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls |
diff --git a/arch/arm/kernel/crash_dump.c b/arch/arm/kernel/crash_dump.c index cd3b853a8a6d..90c50d4b43f7 100644 --- a/arch/arm/kernel/crash_dump.c +++ b/arch/arm/kernel/crash_dump.c | |||
@@ -18,9 +18,6 @@ | |||
18 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | 20 | ||
21 | /* stores the physical address of elf header of crash image */ | ||
22 | unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; | ||
23 | |||
24 | /** | 21 | /** |
25 | * copy_oldmem_page() - copy one page from old kernel memory | 22 | * copy_oldmem_page() - copy one page from old kernel memory |
26 | * @pfn: page frame number to be copied | 23 | * @pfn: page frame number to be copied |
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index a38b4879441d..bcd66e00bdbe 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S | |||
@@ -22,11 +22,11 @@ | |||
22 | #if defined(CONFIG_DEBUG_ICEDCC) | 22 | #if defined(CONFIG_DEBUG_ICEDCC) |
23 | @@ debug using ARM EmbeddedICE DCC channel | 23 | @@ debug using ARM EmbeddedICE DCC channel |
24 | 24 | ||
25 | #if defined(CONFIG_CPU_V6) | 25 | .macro addruart, rp, rv |
26 | |||
27 | .macro addruart, rx, tmp | ||
28 | .endm | 26 | .endm |
29 | 27 | ||
28 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) | ||
29 | |||
30 | .macro senduart, rd, rx | 30 | .macro senduart, rd, rx |
31 | mcr p14, 0, \rd, c0, c5, 0 | 31 | mcr p14, 0, \rd, c0, c5, 0 |
32 | .endm | 32 | .endm |
@@ -49,31 +49,8 @@ | |||
49 | 1002: | 49 | 1002: |
50 | .endm | 50 | .endm |
51 | 51 | ||
52 | #elif defined(CONFIG_CPU_V7) | ||
53 | |||
54 | .macro addruart, rx, tmp | ||
55 | .endm | ||
56 | |||
57 | .macro senduart, rd, rx | ||
58 | mcr p14, 0, \rd, c0, c5, 0 | ||
59 | .endm | ||
60 | |||
61 | .macro busyuart, rd, rx | ||
62 | busy: mrc p14, 0, pc, c0, c1, 0 | ||
63 | bcs busy | ||
64 | .endm | ||
65 | |||
66 | .macro waituart, rd, rx | ||
67 | wait: mrc p14, 0, pc, c0, c1, 0 | ||
68 | bcs wait | ||
69 | |||
70 | .endm | ||
71 | |||
72 | #elif defined(CONFIG_CPU_XSCALE) | 52 | #elif defined(CONFIG_CPU_XSCALE) |
73 | 53 | ||
74 | .macro addruart, rx, tmp | ||
75 | .endm | ||
76 | |||
77 | .macro senduart, rd, rx | 54 | .macro senduart, rd, rx |
78 | mcr p14, 0, \rd, c8, c0, 0 | 55 | mcr p14, 0, \rd, c8, c0, 0 |
79 | .endm | 56 | .endm |
@@ -98,9 +75,6 @@ wait: mrc p14, 0, pc, c0, c1, 0 | |||
98 | 75 | ||
99 | #else | 76 | #else |
100 | 77 | ||
101 | .macro addruart, rx, tmp | ||
102 | .endm | ||
103 | |||
104 | .macro senduart, rd, rx | 78 | .macro senduart, rd, rx |
105 | mcr p14, 0, \rd, c1, c0, 0 | 79 | mcr p14, 0, \rd, c1, c0, 0 |
106 | .endm | 80 | .endm |
@@ -130,6 +104,22 @@ wait: mrc p14, 0, pc, c0, c1, 0 | |||
130 | #include <mach/debug-macro.S> | 104 | #include <mach/debug-macro.S> |
131 | #endif /* CONFIG_DEBUG_ICEDCC */ | 105 | #endif /* CONFIG_DEBUG_ICEDCC */ |
132 | 106 | ||
107 | #ifdef CONFIG_MMU | ||
108 | .macro addruart_current, rx, tmp1, tmp2 | ||
109 | addruart \tmp1, \tmp2 | ||
110 | mrc p15, 0, \rx, c1, c0 | ||
111 | tst \rx, #1 | ||
112 | moveq \rx, \tmp1 | ||
113 | movne \rx, \tmp2 | ||
114 | .endm | ||
115 | |||
116 | #else /* !CONFIG_MMU */ | ||
117 | .macro addruart_current, rx, tmp1, tmp2 | ||
118 | addruart \rx, \tmp1 | ||
119 | .endm | ||
120 | |||
121 | #endif /* CONFIG_MMU */ | ||
122 | |||
133 | /* | 123 | /* |
134 | * Useful debugging routines | 124 | * Useful debugging routines |
135 | */ | 125 | */ |
@@ -164,7 +154,7 @@ ENDPROC(printhex2) | |||
164 | .ltorg | 154 | .ltorg |
165 | 155 | ||
166 | ENTRY(printascii) | 156 | ENTRY(printascii) |
167 | addruart r3, r1 | 157 | addruart_current r3, r1, r2 |
168 | b 2f | 158 | b 2f |
169 | 1: waituart r2, r3 | 159 | 1: waituart r2, r3 |
170 | senduart r1, r3 | 160 | senduart r1, r3 |
@@ -180,7 +170,7 @@ ENTRY(printascii) | |||
180 | ENDPROC(printascii) | 170 | ENDPROC(printascii) |
181 | 171 | ||
182 | ENTRY(printch) | 172 | ENTRY(printch) |
183 | addruart r3, r1 | 173 | addruart_current r3, r1, r2 |
184 | mov r1, r0 | 174 | mov r1, r0 |
185 | mov r0, #0 | 175 | mov r0, #0 |
186 | b 1b | 176 | b 1b |
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c new file mode 100644 index 000000000000..0cdd7b456cb2 --- /dev/null +++ b/arch/arm/kernel/devtree.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/devtree.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.com> | ||
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/init.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/bootmem.h> | ||
16 | #include <linux/memblock.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_fdt.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | |||
22 | #include <asm/setup.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | |||
27 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | ||
28 | { | ||
29 | arm_add_memory(base, size); | ||
30 | } | ||
31 | |||
32 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | ||
33 | { | ||
34 | return alloc_bootmem_align(size, align); | ||
35 | } | ||
36 | |||
37 | void __init arm_dt_memblock_reserve(void) | ||
38 | { | ||
39 | u64 *reserve_map, base, size; | ||
40 | |||
41 | if (!initial_boot_params) | ||
42 | return; | ||
43 | |||
44 | /* Reserve the dtb region */ | ||
45 | memblock_reserve(virt_to_phys(initial_boot_params), | ||
46 | be32_to_cpu(initial_boot_params->totalsize)); | ||
47 | |||
48 | /* | ||
49 | * Process the reserve map. This will probably overlap the initrd | ||
50 | * and dtb locations which are already reserved, but overlaping | ||
51 | * doesn't hurt anything | ||
52 | */ | ||
53 | reserve_map = ((void*)initial_boot_params) + | ||
54 | be32_to_cpu(initial_boot_params->off_mem_rsvmap); | ||
55 | while (1) { | ||
56 | base = be64_to_cpup(reserve_map++); | ||
57 | size = be64_to_cpup(reserve_map++); | ||
58 | if (!size) | ||
59 | break; | ||
60 | memblock_reserve(base, size); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * setup_machine_fdt - Machine setup when an dtb was passed to the kernel | ||
66 | * @dt_phys: physical address of dt blob | ||
67 | * | ||
68 | * If a dtb was passed to the kernel in r2, then use it to choose the | ||
69 | * correct machine_desc and to setup the system. | ||
70 | */ | ||
71 | struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) | ||
72 | { | ||
73 | struct boot_param_header *devtree; | ||
74 | struct machine_desc *mdesc, *mdesc_best = NULL; | ||
75 | unsigned int score, mdesc_score = ~1; | ||
76 | unsigned long dt_root; | ||
77 | const char *model; | ||
78 | |||
79 | if (!dt_phys) | ||
80 | return NULL; | ||
81 | |||
82 | devtree = phys_to_virt(dt_phys); | ||
83 | |||
84 | /* check device tree validity */ | ||
85 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) | ||
86 | return NULL; | ||
87 | |||
88 | /* Search the mdescs for the 'best' compatible value match */ | ||
89 | initial_boot_params = devtree; | ||
90 | dt_root = of_get_flat_dt_root(); | ||
91 | for_each_machine_desc(mdesc) { | ||
92 | score = of_flat_dt_match(dt_root, mdesc->dt_compat); | ||
93 | if (score > 0 && score < mdesc_score) { | ||
94 | mdesc_best = mdesc; | ||
95 | mdesc_score = score; | ||
96 | } | ||
97 | } | ||
98 | if (!mdesc_best) { | ||
99 | const char *prop; | ||
100 | long size; | ||
101 | |||
102 | early_print("\nError: unrecognized/unsupported " | ||
103 | "device tree compatible list:\n[ "); | ||
104 | |||
105 | prop = of_get_flat_dt_prop(dt_root, "compatible", &size); | ||
106 | while (size > 0) { | ||
107 | early_print("'%s' ", prop); | ||
108 | size -= strlen(prop) + 1; | ||
109 | prop += strlen(prop) + 1; | ||
110 | } | ||
111 | early_print("]\n\n"); | ||
112 | |||
113 | dump_machine_table(); /* does not return */ | ||
114 | } | ||
115 | |||
116 | model = of_get_flat_dt_prop(dt_root, "model", NULL); | ||
117 | if (!model) | ||
118 | model = of_get_flat_dt_prop(dt_root, "compatible", NULL); | ||
119 | if (!model) | ||
120 | model = "<unknown>"; | ||
121 | pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); | ||
122 | |||
123 | /* Retrieve various information from the /chosen node */ | ||
124 | of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); | ||
125 | /* Initialize {size,address}-cells info */ | ||
126 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | ||
127 | /* Setup memory, calling early_init_dt_add_memory_arch */ | ||
128 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||
129 | |||
130 | /* Change machine number to match the mdesc we're using */ | ||
131 | __machine_arch_type = mdesc_best->nr; | ||
132 | |||
133 | return mdesc_best; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# | ||
138 | * | ||
139 | * Currently the mapping mechanism is trivial; simple flat hwirq numbers are | ||
140 | * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not | ||
141 | * supported. | ||
142 | */ | ||
143 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
144 | const u32 *intspec, unsigned int intsize) | ||
145 | { | ||
146 | return intspec[0]; | ||
147 | } | ||
148 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | ||
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index eed2f795e1b3..d16500110ee9 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c | |||
@@ -443,40 +443,40 @@ static expansioncard_ops_t ecard_default_ops = { | |||
443 | * | 443 | * |
444 | * They are not meant to be called directly, but via enable/disable_irq. | 444 | * They are not meant to be called directly, but via enable/disable_irq. |
445 | */ | 445 | */ |
446 | static void ecard_irq_unmask(unsigned int irqnr) | 446 | static void ecard_irq_unmask(struct irq_data *d) |
447 | { | 447 | { |
448 | ecard_t *ec = slot_to_ecard(irqnr - 32); | 448 | ecard_t *ec = slot_to_ecard(d->irq - 32); |
449 | 449 | ||
450 | if (ec) { | 450 | if (ec) { |
451 | if (!ec->ops) | 451 | if (!ec->ops) |
452 | ec->ops = &ecard_default_ops; | 452 | ec->ops = &ecard_default_ops; |
453 | 453 | ||
454 | if (ec->claimed && ec->ops->irqenable) | 454 | if (ec->claimed && ec->ops->irqenable) |
455 | ec->ops->irqenable(ec, irqnr); | 455 | ec->ops->irqenable(ec, d->irq); |
456 | else | 456 | else |
457 | printk(KERN_ERR "ecard: rejecting request to " | 457 | printk(KERN_ERR "ecard: rejecting request to " |
458 | "enable IRQs for %d\n", irqnr); | 458 | "enable IRQs for %d\n", d->irq); |
459 | } | 459 | } |
460 | } | 460 | } |
461 | 461 | ||
462 | static void ecard_irq_mask(unsigned int irqnr) | 462 | static void ecard_irq_mask(struct irq_data *d) |
463 | { | 463 | { |
464 | ecard_t *ec = slot_to_ecard(irqnr - 32); | 464 | ecard_t *ec = slot_to_ecard(d->irq - 32); |
465 | 465 | ||
466 | if (ec) { | 466 | if (ec) { |
467 | if (!ec->ops) | 467 | if (!ec->ops) |
468 | ec->ops = &ecard_default_ops; | 468 | ec->ops = &ecard_default_ops; |
469 | 469 | ||
470 | if (ec->ops && ec->ops->irqdisable) | 470 | if (ec->ops && ec->ops->irqdisable) |
471 | ec->ops->irqdisable(ec, irqnr); | 471 | ec->ops->irqdisable(ec, d->irq); |
472 | } | 472 | } |
473 | } | 473 | } |
474 | 474 | ||
475 | static struct irq_chip ecard_chip = { | 475 | static struct irq_chip ecard_chip = { |
476 | .name = "ECARD", | 476 | .name = "ECARD", |
477 | .ack = ecard_irq_mask, | 477 | .irq_ack = ecard_irq_mask, |
478 | .mask = ecard_irq_mask, | 478 | .irq_mask = ecard_irq_mask, |
479 | .unmask = ecard_irq_unmask, | 479 | .irq_unmask = ecard_irq_unmask, |
480 | }; | 480 | }; |
481 | 481 | ||
482 | void ecard_enablefiq(unsigned int fiqnr) | 482 | void ecard_enablefiq(unsigned int fiqnr) |
@@ -551,7 +551,7 @@ static void ecard_check_lockup(struct irq_desc *desc) | |||
551 | printk(KERN_ERR "\nInterrupt lockup detected - " | 551 | printk(KERN_ERR "\nInterrupt lockup detected - " |
552 | "disabling all expansion card interrupts\n"); | 552 | "disabling all expansion card interrupts\n"); |
553 | 553 | ||
554 | desc->chip->mask(IRQ_EXPANSIONCARD); | 554 | desc->irq_data.chip->irq_mask(&desc->irq_data); |
555 | ecard_dump_irq_state(); | 555 | ecard_dump_irq_state(); |
556 | } | 556 | } |
557 | } else | 557 | } else |
@@ -574,7 +574,7 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
574 | ecard_t *ec; | 574 | ecard_t *ec; |
575 | int called = 0; | 575 | int called = 0; |
576 | 576 | ||
577 | desc->chip->mask(irq); | 577 | desc->irq_data.chip->irq_mask(&desc->irq_data); |
578 | for (ec = cards; ec; ec = ec->next) { | 578 | for (ec = cards; ec; ec = ec->next) { |
579 | int pending; | 579 | int pending; |
580 | 580 | ||
@@ -591,7 +591,7 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
591 | called ++; | 591 | called ++; |
592 | } | 592 | } |
593 | } | 593 | } |
594 | desc->chip->unmask(irq); | 594 | desc->irq_data.chip->irq_unmask(&desc->irq_data); |
595 | 595 | ||
596 | if (called == 0) | 596 | if (called == 0) |
597 | ecard_check_lockup(desc); | 597 | ecard_check_lockup(desc); |
@@ -1043,8 +1043,8 @@ ecard_probe(int slot, card_type_t type) | |||
1043 | */ | 1043 | */ |
1044 | if (slot < 8) { | 1044 | if (slot < 8) { |
1045 | ec->irq = 32 + slot; | 1045 | ec->irq = 32 + slot; |
1046 | set_irq_chip(ec->irq, &ecard_chip); | 1046 | irq_set_chip_and_handler(ec->irq, &ecard_chip, |
1047 | set_irq_handler(ec->irq, handle_level_irq); | 1047 | handle_level_irq); |
1048 | set_irq_flags(ec->irq, IRQF_VALID); | 1048 | set_irq_flags(ec->irq, IRQF_VALID); |
1049 | } | 1049 | } |
1050 | 1050 | ||
@@ -1103,7 +1103,7 @@ static int __init ecard_init(void) | |||
1103 | 1103 | ||
1104 | irqhw = ecard_probeirqhw(); | 1104 | irqhw = ecard_probeirqhw(); |
1105 | 1105 | ||
1106 | set_irq_chained_handler(IRQ_EXPANSIONCARD, | 1106 | irq_set_chained_handler(IRQ_EXPANSIONCARD, |
1107 | irqhw ? ecard_irqexp_handler : ecard_irq_handler); | 1107 | irqhw ? ecard_irqexp_handler : ecard_irq_handler); |
1108 | 1108 | ||
1109 | ecard_proc_init(); | 1109 | ecard_proc_init(); |
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c index d4a0da1e48f4..9b05c6a0dcea 100644 --- a/arch/arm/kernel/elf.c +++ b/arch/arm/kernel/elf.c | |||
@@ -40,15 +40,22 @@ EXPORT_SYMBOL(elf_check_arch); | |||
40 | void elf_set_personality(const struct elf32_hdr *x) | 40 | void elf_set_personality(const struct elf32_hdr *x) |
41 | { | 41 | { |
42 | unsigned int eflags = x->e_flags; | 42 | unsigned int eflags = x->e_flags; |
43 | unsigned int personality = PER_LINUX_32BIT; | 43 | unsigned int personality = current->personality & ~PER_MASK; |
44 | |||
45 | /* | ||
46 | * We only support Linux ELF executables, so always set the | ||
47 | * personality to LINUX. | ||
48 | */ | ||
49 | personality |= PER_LINUX; | ||
44 | 50 | ||
45 | /* | 51 | /* |
46 | * APCS-26 is only valid for OABI executables | 52 | * APCS-26 is only valid for OABI executables |
47 | */ | 53 | */ |
48 | if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) { | 54 | if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN && |
49 | if (eflags & EF_ARM_APCS_26) | 55 | (eflags & EF_ARM_APCS_26)) |
50 | personality = PER_LINUX; | 56 | personality &= ~ADDR_LIMIT_32BIT; |
51 | } | 57 | else |
58 | personality |= ADDR_LIMIT_32BIT; | ||
52 | 59 | ||
53 | set_personality(personality); | 60 | set_personality(personality); |
54 | 61 | ||
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bb8e93a76407..90c62cd51ca9 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -16,7 +16,8 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <asm/memory.h> | 18 | #include <asm/memory.h> |
19 | #include <asm/glue.h> | 19 | #include <asm/glue-df.h> |
20 | #include <asm/glue-pf.h> | ||
20 | #include <asm/vfpmacros.h> | 21 | #include <asm/vfpmacros.h> |
21 | #include <mach/entry-macro.S> | 22 | #include <mach/entry-macro.S> |
22 | #include <asm/thread_notify.h> | 23 | #include <asm/thread_notify.h> |
@@ -25,40 +26,22 @@ | |||
25 | #include <asm/tls.h> | 26 | #include <asm/tls.h> |
26 | 27 | ||
27 | #include "entry-header.S" | 28 | #include "entry-header.S" |
29 | #include <asm/entry-macro-multi.S> | ||
28 | 30 | ||
29 | /* | 31 | /* |
30 | * Interrupt handling. Preserves r7, r8, r9 | 32 | * Interrupt handling. Preserves r7, r8, r9 |
31 | */ | 33 | */ |
32 | .macro irq_handler | 34 | .macro irq_handler |
33 | get_irqnr_preamble r5, lr | 35 | #ifdef CONFIG_MULTI_IRQ_HANDLER |
34 | 1: get_irqnr_and_base r0, r6, r5, lr | 36 | ldr r5, =handle_arch_irq |
35 | movne r1, sp | 37 | mov r0, sp |
36 | @ | 38 | ldr r5, [r5] |
37 | @ routine called with r0 = irq number, r1 = struct pt_regs * | 39 | adr lr, BSYM(9997f) |
38 | @ | 40 | teq r5, #0 |
39 | adrne lr, BSYM(1b) | 41 | movne pc, r5 |
40 | bne asm_do_IRQ | ||
41 | |||
42 | #ifdef CONFIG_SMP | ||
43 | /* | ||
44 | * XXX | ||
45 | * | ||
46 | * this macro assumes that irqstat (r6) and base (r5) are | ||
47 | * preserved from get_irqnr_and_base above | ||
48 | */ | ||
49 | test_for_ipi r0, r6, r5, lr | ||
50 | movne r0, sp | ||
51 | adrne lr, BSYM(1b) | ||
52 | bne do_IPI | ||
53 | |||
54 | #ifdef CONFIG_LOCAL_TIMERS | ||
55 | test_for_ltirq r0, r6, r5, lr | ||
56 | movne r0, sp | ||
57 | adrne lr, BSYM(1b) | ||
58 | bne do_local_timer | ||
59 | #endif | ||
60 | #endif | 42 | #endif |
61 | 43 | arch_irq_handler_default | |
44 | 9997: | ||
62 | .endm | 45 | .endm |
63 | 46 | ||
64 | #ifdef CONFIG_KPROBES | 47 | #ifdef CONFIG_KPROBES |
@@ -196,6 +179,7 @@ __dabt_svc: | |||
196 | @ | 179 | @ |
197 | @ set desired IRQ state, then call main handler | 180 | @ set desired IRQ state, then call main handler |
198 | @ | 181 | @ |
182 | debug_entry r1 | ||
199 | msr cpsr_c, r9 | 183 | msr cpsr_c, r9 |
200 | mov r2, sp | 184 | mov r2, sp |
201 | bl do_DataAbort | 185 | bl do_DataAbort |
@@ -322,6 +306,7 @@ __pabt_svc: | |||
322 | #else | 306 | #else |
323 | bl CPU_PABORT_HANDLER | 307 | bl CPU_PABORT_HANDLER |
324 | #endif | 308 | #endif |
309 | debug_entry r1 | ||
325 | msr cpsr_c, r9 @ Maybe enable interrupts | 310 | msr cpsr_c, r9 @ Maybe enable interrupts |
326 | mov r2, sp @ regs | 311 | mov r2, sp @ regs |
327 | bl do_PrefetchAbort @ call abort handler | 312 | bl do_PrefetchAbort @ call abort handler |
@@ -437,6 +422,7 @@ __dabt_usr: | |||
437 | @ | 422 | @ |
438 | @ IRQs on, then call the main handler | 423 | @ IRQs on, then call the main handler |
439 | @ | 424 | @ |
425 | debug_entry r1 | ||
440 | enable_irq | 426 | enable_irq |
441 | mov r2, sp | 427 | mov r2, sp |
442 | adr lr, BSYM(ret_from_exception) | 428 | adr lr, BSYM(ret_from_exception) |
@@ -449,6 +435,10 @@ __irq_usr: | |||
449 | usr_entry | 435 | usr_entry |
450 | kuser_cmpxchg_check | 436 | kuser_cmpxchg_check |
451 | 437 | ||
438 | #ifdef CONFIG_IRQSOFF_TRACER | ||
439 | bl trace_hardirqs_off | ||
440 | #endif | ||
441 | |||
452 | get_thread_info tsk | 442 | get_thread_info tsk |
453 | #ifdef CONFIG_PREEMPT | 443 | #ifdef CONFIG_PREEMPT |
454 | ldr r8, [tsk, #TI_PREEMPT] @ get preempt count | 444 | ldr r8, [tsk, #TI_PREEMPT] @ get preempt count |
@@ -467,7 +457,7 @@ __irq_usr: | |||
467 | #endif | 457 | #endif |
468 | 458 | ||
469 | mov why, #0 | 459 | mov why, #0 |
470 | b ret_to_user | 460 | b ret_to_user_from_irq |
471 | UNWIND(.fnend ) | 461 | UNWIND(.fnend ) |
472 | ENDPROC(__irq_usr) | 462 | ENDPROC(__irq_usr) |
473 | 463 | ||
@@ -701,6 +691,7 @@ __pabt_usr: | |||
701 | #else | 691 | #else |
702 | bl CPU_PABORT_HANDLER | 692 | bl CPU_PABORT_HANDLER |
703 | #endif | 693 | #endif |
694 | debug_entry r1 | ||
704 | enable_irq @ Enable interrupts | 695 | enable_irq @ Enable interrupts |
705 | mov r2, sp @ regs | 696 | mov r2, sp @ regs |
706 | bl do_PrefetchAbort @ call abort handler | 697 | bl do_PrefetchAbort @ call abort handler |
@@ -733,7 +724,7 @@ ENTRY(__switch_to) | |||
733 | THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack | 724 | THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack |
734 | THUMB( str sp, [ip], #4 ) | 725 | THUMB( str sp, [ip], #4 ) |
735 | THUMB( str lr, [ip], #4 ) | 726 | THUMB( str lr, [ip], #4 ) |
736 | #ifdef CONFIG_MMU | 727 | #ifdef CONFIG_CPU_USE_DOMAINS |
737 | ldr r6, [r2, #TI_CPU_DOMAIN] | 728 | ldr r6, [r2, #TI_CPU_DOMAIN] |
738 | #endif | 729 | #endif |
739 | set_tls r3, r4, r5 | 730 | set_tls r3, r4, r5 |
@@ -742,7 +733,7 @@ ENTRY(__switch_to) | |||
742 | ldr r8, =__stack_chk_guard | 733 | ldr r8, =__stack_chk_guard |
743 | ldr r7, [r7, #TSK_STACK_CANARY] | 734 | ldr r7, [r7, #TSK_STACK_CANARY] |
744 | #endif | 735 | #endif |
745 | #ifdef CONFIG_MMU | 736 | #ifdef CONFIG_CPU_USE_DOMAINS |
746 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 737 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
747 | #endif | 738 | #endif |
748 | mov r5, r0 | 739 | mov r5, r0 |
@@ -840,7 +831,7 @@ __kuser_helper_start: | |||
840 | */ | 831 | */ |
841 | 832 | ||
842 | __kuser_memory_barrier: @ 0xffff0fa0 | 833 | __kuser_memory_barrier: @ 0xffff0fa0 |
843 | smp_dmb | 834 | smp_dmb arm |
844 | usr_ret lr | 835 | usr_ret lr |
845 | 836 | ||
846 | .align 5 | 837 | .align 5 |
@@ -909,7 +900,7 @@ __kuser_cmpxchg: @ 0xffff0fc0 | |||
909 | * A special ghost syscall is used for that (see traps.c). | 900 | * A special ghost syscall is used for that (see traps.c). |
910 | */ | 901 | */ |
911 | stmfd sp!, {r7, lr} | 902 | stmfd sp!, {r7, lr} |
912 | ldr r7, =1f @ it's 20 bits | 903 | ldr r7, 1f @ it's 20 bits |
913 | swi __ARM_NR_cmpxchg | 904 | swi __ARM_NR_cmpxchg |
914 | ldmfd sp!, {r7, pc} | 905 | ldmfd sp!, {r7, pc} |
915 | 1: .word __ARM_NR_cmpxchg | 906 | 1: .word __ARM_NR_cmpxchg |
@@ -957,7 +948,7 @@ kuser_cmpxchg_fixup: | |||
957 | 948 | ||
958 | #else | 949 | #else |
959 | 950 | ||
960 | smp_dmb | 951 | smp_dmb arm |
961 | 1: ldrex r3, [r2] | 952 | 1: ldrex r3, [r2] |
962 | subs r3, r3, r0 | 953 | subs r3, r3, r0 |
963 | strexeq r3, r1, [r2] | 954 | strexeq r3, r1, [r2] |
@@ -965,11 +956,8 @@ kuser_cmpxchg_fixup: | |||
965 | beq 1b | 956 | beq 1b |
966 | rsbs r0, r3, #0 | 957 | rsbs r0, r3, #0 |
967 | /* beware -- each __kuser slot must be 8 instructions max */ | 958 | /* beware -- each __kuser slot must be 8 instructions max */ |
968 | #ifdef CONFIG_SMP | 959 | ALT_SMP(b __kuser_memory_barrier) |
969 | b __kuser_memory_barrier | 960 | ALT_UP(usr_ret lr) |
970 | #else | ||
971 | usr_ret lr | ||
972 | #endif | ||
973 | 961 | ||
974 | #endif | 962 | #endif |
975 | 963 | ||
@@ -1246,3 +1234,9 @@ cr_alignment: | |||
1246 | .space 4 | 1234 | .space 4 |
1247 | cr_no_alignment: | 1235 | cr_no_alignment: |
1248 | .space 4 | 1236 | .space 4 |
1237 | |||
1238 | #ifdef CONFIG_MULTI_IRQ_HANDLER | ||
1239 | .globl handle_arch_irq | ||
1240 | handle_arch_irq: | ||
1241 | .space 4 | ||
1242 | #endif | ||
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 7885722bdf4e..b2a27b6b0046 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -29,6 +29,9 @@ ret_fast_syscall: | |||
29 | ldr r1, [tsk, #TI_FLAGS] | 29 | ldr r1, [tsk, #TI_FLAGS] |
30 | tst r1, #_TIF_WORK_MASK | 30 | tst r1, #_TIF_WORK_MASK |
31 | bne fast_work_pending | 31 | bne fast_work_pending |
32 | #if defined(CONFIG_IRQSOFF_TRACER) | ||
33 | asm_trace_hardirqs_on | ||
34 | #endif | ||
32 | 35 | ||
33 | /* perform architecture specific actions before user return */ | 36 | /* perform architecture specific actions before user return */ |
34 | arch_ret_to_user r1, lr | 37 | arch_ret_to_user r1, lr |
@@ -61,14 +64,19 @@ work_resched: | |||
61 | ENTRY(ret_to_user) | 64 | ENTRY(ret_to_user) |
62 | ret_slow_syscall: | 65 | ret_slow_syscall: |
63 | disable_irq @ disable interrupts | 66 | disable_irq @ disable interrupts |
67 | ENTRY(ret_to_user_from_irq) | ||
64 | ldr r1, [tsk, #TI_FLAGS] | 68 | ldr r1, [tsk, #TI_FLAGS] |
65 | tst r1, #_TIF_WORK_MASK | 69 | tst r1, #_TIF_WORK_MASK |
66 | bne work_pending | 70 | bne work_pending |
67 | no_work_pending: | 71 | no_work_pending: |
72 | #if defined(CONFIG_IRQSOFF_TRACER) | ||
73 | asm_trace_hardirqs_on | ||
74 | #endif | ||
68 | /* perform architecture specific actions before user return */ | 75 | /* perform architecture specific actions before user return */ |
69 | arch_ret_to_user r1, lr | 76 | arch_ret_to_user r1, lr |
70 | 77 | ||
71 | restore_user_regs fast = 0, offset = 0 | 78 | restore_user_regs fast = 0, offset = 0 |
79 | ENDPROC(ret_to_user_from_irq) | ||
72 | ENDPROC(ret_to_user) | 80 | ENDPROC(ret_to_user) |
73 | 81 | ||
74 | /* | 82 | /* |
@@ -129,76 +137,187 @@ ENDPROC(ret_from_fork) | |||
129 | * clobber the ip register. This is OK because the ARM calling convention | 137 | * clobber the ip register. This is OK because the ARM calling convention |
130 | * allows it to be clobbered in subroutines and doesn't use it to hold | 138 | * allows it to be clobbered in subroutines and doesn't use it to hold |
131 | * parameters.) | 139 | * parameters.) |
140 | * | ||
141 | * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0" | ||
142 | * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see | ||
143 | * arch/arm/kernel/ftrace.c). | ||
132 | */ | 144 | */ |
133 | #ifdef CONFIG_DYNAMIC_FTRACE | 145 | |
134 | ENTRY(mcount) | 146 | #ifndef CONFIG_OLD_MCOUNT |
135 | stmdb sp!, {r0-r3, lr} | 147 | #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) |
136 | mov r0, lr | 148 | #error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0. |
149 | #endif | ||
150 | #endif | ||
151 | |||
152 | .macro __mcount suffix | ||
153 | mcount_enter | ||
154 | ldr r0, =ftrace_trace_function | ||
155 | ldr r2, [r0] | ||
156 | adr r0, .Lftrace_stub | ||
157 | cmp r0, r2 | ||
158 | bne 1f | ||
159 | |||
160 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
161 | ldr r1, =ftrace_graph_return | ||
162 | ldr r2, [r1] | ||
163 | cmp r0, r2 | ||
164 | bne ftrace_graph_caller\suffix | ||
165 | |||
166 | ldr r1, =ftrace_graph_entry | ||
167 | ldr r2, [r1] | ||
168 | ldr r0, =ftrace_graph_entry_stub | ||
169 | cmp r0, r2 | ||
170 | bne ftrace_graph_caller\suffix | ||
171 | #endif | ||
172 | |||
173 | mcount_exit | ||
174 | |||
175 | 1: mcount_get_lr r1 @ lr of instrumented func | ||
176 | mov r0, lr @ instrumented function | ||
137 | sub r0, r0, #MCOUNT_INSN_SIZE | 177 | sub r0, r0, #MCOUNT_INSN_SIZE |
178 | adr lr, BSYM(2f) | ||
179 | mov pc, r2 | ||
180 | 2: mcount_exit | ||
181 | .endm | ||
138 | 182 | ||
139 | .globl mcount_call | 183 | .macro __ftrace_caller suffix |
140 | mcount_call: | 184 | mcount_enter |
141 | bl ftrace_stub | ||
142 | ldr lr, [fp, #-4] @ restore lr | ||
143 | ldmia sp!, {r0-r3, pc} | ||
144 | 185 | ||
145 | ENTRY(ftrace_caller) | 186 | mcount_get_lr r1 @ lr of instrumented func |
146 | stmdb sp!, {r0-r3, lr} | 187 | mov r0, lr @ instrumented function |
147 | ldr r1, [fp, #-4] | ||
148 | mov r0, lr | ||
149 | sub r0, r0, #MCOUNT_INSN_SIZE | 188 | sub r0, r0, #MCOUNT_INSN_SIZE |
150 | 189 | ||
151 | .globl ftrace_call | 190 | .globl ftrace_call\suffix |
152 | ftrace_call: | 191 | ftrace_call\suffix: |
153 | bl ftrace_stub | 192 | bl ftrace_stub |
154 | ldr lr, [fp, #-4] @ restore lr | 193 | |
194 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
195 | .globl ftrace_graph_call\suffix | ||
196 | ftrace_graph_call\suffix: | ||
197 | mov r0, r0 | ||
198 | #endif | ||
199 | |||
200 | mcount_exit | ||
201 | .endm | ||
202 | |||
203 | .macro __ftrace_graph_caller | ||
204 | sub r0, fp, #4 @ &lr of instrumented routine (&parent) | ||
205 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
206 | @ called from __ftrace_caller, saved in mcount_enter | ||
207 | ldr r1, [sp, #16] @ instrumented routine (func) | ||
208 | #else | ||
209 | @ called from __mcount, untouched in lr | ||
210 | mov r1, lr @ instrumented routine (func) | ||
211 | #endif | ||
212 | sub r1, r1, #MCOUNT_INSN_SIZE | ||
213 | mov r2, fp @ frame pointer | ||
214 | bl prepare_ftrace_return | ||
215 | mcount_exit | ||
216 | .endm | ||
217 | |||
218 | #ifdef CONFIG_OLD_MCOUNT | ||
219 | /* | ||
220 | * mcount | ||
221 | */ | ||
222 | |||
223 | .macro mcount_enter | ||
224 | stmdb sp!, {r0-r3, lr} | ||
225 | .endm | ||
226 | |||
227 | .macro mcount_get_lr reg | ||
228 | ldr \reg, [fp, #-4] | ||
229 | .endm | ||
230 | |||
231 | .macro mcount_exit | ||
232 | ldr lr, [fp, #-4] | ||
155 | ldmia sp!, {r0-r3, pc} | 233 | ldmia sp!, {r0-r3, pc} |
234 | .endm | ||
156 | 235 | ||
236 | ENTRY(mcount) | ||
237 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
238 | stmdb sp!, {lr} | ||
239 | ldr lr, [fp, #-4] | ||
240 | ldmia sp!, {pc} | ||
157 | #else | 241 | #else |
242 | __mcount _old | ||
243 | #endif | ||
244 | ENDPROC(mcount) | ||
158 | 245 | ||
159 | ENTRY(__gnu_mcount_nc) | 246 | #ifdef CONFIG_DYNAMIC_FTRACE |
247 | ENTRY(ftrace_caller_old) | ||
248 | __ftrace_caller _old | ||
249 | ENDPROC(ftrace_caller_old) | ||
250 | #endif | ||
251 | |||
252 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
253 | ENTRY(ftrace_graph_caller_old) | ||
254 | __ftrace_graph_caller | ||
255 | ENDPROC(ftrace_graph_caller_old) | ||
256 | #endif | ||
257 | |||
258 | .purgem mcount_enter | ||
259 | .purgem mcount_get_lr | ||
260 | .purgem mcount_exit | ||
261 | #endif | ||
262 | |||
263 | /* | ||
264 | * __gnu_mcount_nc | ||
265 | */ | ||
266 | |||
267 | .macro mcount_enter | ||
160 | stmdb sp!, {r0-r3, lr} | 268 | stmdb sp!, {r0-r3, lr} |
161 | ldr r0, =ftrace_trace_function | 269 | .endm |
162 | ldr r2, [r0] | 270 | |
163 | adr r0, ftrace_stub | 271 | .macro mcount_get_lr reg |
164 | cmp r0, r2 | 272 | ldr \reg, [sp, #20] |
165 | bne gnu_trace | 273 | .endm |
274 | |||
275 | .macro mcount_exit | ||
166 | ldmia sp!, {r0-r3, ip, lr} | 276 | ldmia sp!, {r0-r3, ip, lr} |
167 | mov pc, ip | 277 | mov pc, ip |
278 | .endm | ||
168 | 279 | ||
169 | gnu_trace: | 280 | ENTRY(__gnu_mcount_nc) |
170 | ldr r1, [sp, #20] @ lr of instrumented routine | 281 | #ifdef CONFIG_DYNAMIC_FTRACE |
171 | mov r0, lr | 282 | mov ip, lr |
172 | sub r0, r0, #MCOUNT_INSN_SIZE | 283 | ldmia sp!, {lr} |
173 | mov lr, pc | ||
174 | mov pc, r2 | ||
175 | ldmia sp!, {r0-r3, ip, lr} | ||
176 | mov pc, ip | 284 | mov pc, ip |
285 | #else | ||
286 | __mcount | ||
287 | #endif | ||
288 | ENDPROC(__gnu_mcount_nc) | ||
177 | 289 | ||
178 | ENTRY(mcount) | 290 | #ifdef CONFIG_DYNAMIC_FTRACE |
179 | stmdb sp!, {r0-r3, lr} | 291 | ENTRY(ftrace_caller) |
180 | ldr r0, =ftrace_trace_function | 292 | __ftrace_caller |
181 | ldr r2, [r0] | 293 | ENDPROC(ftrace_caller) |
182 | adr r0, ftrace_stub | 294 | #endif |
183 | cmp r0, r2 | ||
184 | bne trace | ||
185 | ldr lr, [fp, #-4] @ restore lr | ||
186 | ldmia sp!, {r0-r3, pc} | ||
187 | 295 | ||
188 | trace: | 296 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
189 | ldr r1, [fp, #-4] @ lr of instrumented routine | 297 | ENTRY(ftrace_graph_caller) |
190 | mov r0, lr | 298 | __ftrace_graph_caller |
191 | sub r0, r0, #MCOUNT_INSN_SIZE | 299 | ENDPROC(ftrace_graph_caller) |
192 | mov lr, pc | 300 | #endif |
193 | mov pc, r2 | ||
194 | ldr lr, [fp, #-4] @ restore lr | ||
195 | ldmia sp!, {r0-r3, pc} | ||
196 | 301 | ||
197 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 302 | .purgem mcount_enter |
303 | .purgem mcount_get_lr | ||
304 | .purgem mcount_exit | ||
305 | |||
306 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
307 | .globl return_to_handler | ||
308 | return_to_handler: | ||
309 | stmdb sp!, {r0-r3} | ||
310 | mov r0, fp @ frame pointer | ||
311 | bl ftrace_return_to_handler | ||
312 | mov lr, r0 @ r0 has real ret addr | ||
313 | ldmia sp!, {r0-r3} | ||
314 | mov pc, lr | ||
315 | #endif | ||
198 | 316 | ||
199 | .globl ftrace_stub | 317 | ENTRY(ftrace_stub) |
200 | ftrace_stub: | 318 | .Lftrace_stub: |
201 | mov pc, lr | 319 | mov pc, lr |
320 | ENDPROC(ftrace_stub) | ||
202 | 321 | ||
203 | #endif /* CONFIG_FUNCTION_TRACER */ | 322 | #endif /* CONFIG_FUNCTION_TRACER */ |
204 | 323 | ||
@@ -295,7 +414,6 @@ ENTRY(vector_swi) | |||
295 | 414 | ||
296 | get_thread_info tsk | 415 | get_thread_info tsk |
297 | adr tbl, sys_call_table @ load syscall table pointer | 416 | adr tbl, sys_call_table @ load syscall table pointer |
298 | ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing | ||
299 | 417 | ||
300 | #if defined(CONFIG_OABI_COMPAT) | 418 | #if defined(CONFIG_OABI_COMPAT) |
301 | /* | 419 | /* |
@@ -312,8 +430,20 @@ ENTRY(vector_swi) | |||
312 | eor scno, scno, #__NR_SYSCALL_BASE @ check OS number | 430 | eor scno, scno, #__NR_SYSCALL_BASE @ check OS number |
313 | #endif | 431 | #endif |
314 | 432 | ||
433 | ldr r10, [tsk, #TI_FLAGS] @ check for syscall tracing | ||
315 | stmdb sp!, {r4, r5} @ push fifth and sixth args | 434 | stmdb sp!, {r4, r5} @ push fifth and sixth args |
316 | tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? | 435 | |
436 | #ifdef CONFIG_SECCOMP | ||
437 | tst r10, #_TIF_SECCOMP | ||
438 | beq 1f | ||
439 | mov r0, scno | ||
440 | bl __secure_computing | ||
441 | add r0, sp, #S_R0 + S_OFF @ pointer to regs | ||
442 | ldmia r0, {r0 - r3} @ have to reload r0 - r3 | ||
443 | 1: | ||
444 | #endif | ||
445 | |||
446 | tst r10, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? | ||
317 | bne __sys_trace | 447 | bne __sys_trace |
318 | 448 | ||
319 | cmp scno, #NR_syscalls @ check upper syscall limit | 449 | cmp scno, #NR_syscalls @ check upper syscall limit |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index d93f976fb389..051166c2a932 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -76,13 +76,13 @@ | |||
76 | #ifndef CONFIG_THUMB2_KERNEL | 76 | #ifndef CONFIG_THUMB2_KERNEL |
77 | .macro svc_exit, rpsr | 77 | .macro svc_exit, rpsr |
78 | msr spsr_cxsf, \rpsr | 78 | msr spsr_cxsf, \rpsr |
79 | #if defined(CONFIG_CPU_32v6K) | 79 | #if defined(CONFIG_CPU_V6) |
80 | clrex @ clear the exclusive monitor | ||
81 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | ||
82 | #elif defined (CONFIG_CPU_V6) | ||
83 | ldr r0, [sp] | 80 | ldr r0, [sp] |
84 | strex r1, r2, [sp] @ clear the exclusive monitor | 81 | strex r1, r2, [sp] @ clear the exclusive monitor |
85 | ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr | 82 | ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr |
83 | #elif defined(CONFIG_CPU_32v6K) | ||
84 | clrex @ clear the exclusive monitor | ||
85 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | ||
86 | #else | 86 | #else |
87 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | 87 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr |
88 | #endif | 88 | #endif |
@@ -92,10 +92,10 @@ | |||
92 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr | 92 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr |
93 | ldr lr, [sp, #\offset + S_PC]! @ get pc | 93 | ldr lr, [sp, #\offset + S_PC]! @ get pc |
94 | msr spsr_cxsf, r1 @ save in spsr_svc | 94 | msr spsr_cxsf, r1 @ save in spsr_svc |
95 | #if defined(CONFIG_CPU_32v6K) | 95 | #if defined(CONFIG_CPU_V6) |
96 | clrex @ clear the exclusive monitor | ||
97 | #elif defined (CONFIG_CPU_V6) | ||
98 | strex r1, r2, [sp] @ clear the exclusive monitor | 96 | strex r1, r2, [sp] @ clear the exclusive monitor |
97 | #elif defined(CONFIG_CPU_32v6K) | ||
98 | clrex @ clear the exclusive monitor | ||
99 | #endif | 99 | #endif |
100 | .if \fast | 100 | .if \fast |
101 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr | 101 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr |
@@ -165,6 +165,25 @@ | |||
165 | .endm | 165 | .endm |
166 | #endif /* !CONFIG_THUMB2_KERNEL */ | 166 | #endif /* !CONFIG_THUMB2_KERNEL */ |
167 | 167 | ||
168 | @ | ||
169 | @ Debug exceptions are taken as prefetch or data aborts. | ||
170 | @ We must disable preemption during the handler so that | ||
171 | @ we can access the debug registers safely. | ||
172 | @ | ||
173 | .macro debug_entry, fsr | ||
174 | #if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT) | ||
175 | ldr r4, =0x40f @ mask out fsr.fs | ||
176 | and r5, r4, \fsr | ||
177 | cmp r5, #2 @ debug exception | ||
178 | bne 1f | ||
179 | get_thread_info r10 | ||
180 | ldr r6, [r10, #TI_PREEMPT] @ get preempt count | ||
181 | add r11, r6, #1 @ increment it | ||
182 | str r11, [r10, #TI_PREEMPT] | ||
183 | 1: | ||
184 | #endif | ||
185 | .endm | ||
186 | |||
168 | /* | 187 | /* |
169 | * These are the registers used in the syscall handler, and allow us to | 188 | * These are the registers used in the syscall handler, and allow us to |
170 | * have in theory up to 7 arguments to a function - r0 to r6. | 189 | * have in theory up to 7 arguments to a function - r0 to r6. |
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c index 33c7077174db..1bec8b5f22f0 100644 --- a/arch/arm/kernel/etm.c +++ b/arch/arm/kernel/etm.c | |||
@@ -30,6 +30,21 @@ | |||
30 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
31 | MODULE_AUTHOR("Alexander Shishkin"); | 31 | MODULE_AUTHOR("Alexander Shishkin"); |
32 | 32 | ||
33 | /* | ||
34 | * ETM tracer state | ||
35 | */ | ||
36 | struct tracectx { | ||
37 | unsigned int etb_bufsz; | ||
38 | void __iomem *etb_regs; | ||
39 | void __iomem *etm_regs; | ||
40 | unsigned long flags; | ||
41 | int ncmppairs; | ||
42 | int etm_portsz; | ||
43 | struct device *dev; | ||
44 | struct clk *emu_clk; | ||
45 | struct mutex mutex; | ||
46 | }; | ||
47 | |||
33 | static struct tracectx tracer; | 48 | static struct tracectx tracer; |
34 | 49 | ||
35 | static inline bool trace_isrunning(struct tracectx *t) | 50 | static inline bool trace_isrunning(struct tracectx *t) |
@@ -314,6 +329,7 @@ static const struct file_operations etb_fops = { | |||
314 | .read = etb_read, | 329 | .read = etb_read, |
315 | .open = etb_open, | 330 | .open = etb_open, |
316 | .release = etb_release, | 331 | .release = etb_release, |
332 | .llseek = no_llseek, | ||
317 | }; | 333 | }; |
318 | 334 | ||
319 | static struct miscdevice etb_miscdev = { | 335 | static struct miscdevice etb_miscdev = { |
@@ -322,7 +338,7 @@ static struct miscdevice etb_miscdev = { | |||
322 | .fops = &etb_fops, | 338 | .fops = &etb_fops, |
323 | }; | 339 | }; |
324 | 340 | ||
325 | static int __init etb_probe(struct amba_device *dev, struct amba_id *id) | 341 | static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id) |
326 | { | 342 | { |
327 | struct tracectx *t = &tracer; | 343 | struct tracectx *t = &tracer; |
328 | int ret = 0; | 344 | int ret = 0; |
@@ -514,7 +530,7 @@ static ssize_t trace_mode_store(struct kobject *kobj, | |||
514 | static struct kobj_attribute trace_mode_attr = | 530 | static struct kobj_attribute trace_mode_attr = |
515 | __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store); | 531 | __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store); |
516 | 532 | ||
517 | static int __init etm_probe(struct amba_device *dev, struct amba_id *id) | 533 | static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id) |
518 | { | 534 | { |
519 | struct tracectx *t = &tracer; | 535 | struct tracectx *t = &tracer; |
520 | int ret = 0; | 536 | int ret = 0; |
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6ff7919613d7..4c164ece5891 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/fiq.h> | 45 | #include <asm/fiq.h> |
46 | #include <asm/irq.h> | 46 | #include <asm/irq.h> |
47 | #include <asm/system.h> | 47 | #include <asm/system.h> |
48 | #include <asm/traps.h> | ||
48 | 49 | ||
49 | static unsigned long no_fiq_insn; | 50 | static unsigned long no_fiq_insn; |
50 | 51 | ||
@@ -67,63 +68,27 @@ static struct fiq_handler default_owner = { | |||
67 | 68 | ||
68 | static struct fiq_handler *current_fiq = &default_owner; | 69 | static struct fiq_handler *current_fiq = &default_owner; |
69 | 70 | ||
70 | int show_fiq_list(struct seq_file *p, void *v) | 71 | int show_fiq_list(struct seq_file *p, int prec) |
71 | { | 72 | { |
72 | if (current_fiq != &default_owner) | 73 | if (current_fiq != &default_owner) |
73 | seq_printf(p, "FIQ: %s\n", current_fiq->name); | 74 | seq_printf(p, "%*s: %s\n", prec, "FIQ", |
75 | current_fiq->name); | ||
74 | 76 | ||
75 | return 0; | 77 | return 0; |
76 | } | 78 | } |
77 | 79 | ||
78 | void set_fiq_handler(void *start, unsigned int length) | 80 | void set_fiq_handler(void *start, unsigned int length) |
79 | { | 81 | { |
82 | #if defined(CONFIG_CPU_USE_DOMAINS) | ||
80 | memcpy((void *)0xffff001c, start, length); | 83 | memcpy((void *)0xffff001c, start, length); |
84 | #else | ||
85 | memcpy(vectors_page + 0x1c, start, length); | ||
86 | #endif | ||
81 | flush_icache_range(0xffff001c, 0xffff001c + length); | 87 | flush_icache_range(0xffff001c, 0xffff001c + length); |
82 | if (!vectors_high()) | 88 | if (!vectors_high()) |
83 | flush_icache_range(0x1c, 0x1c + length); | 89 | flush_icache_range(0x1c, 0x1c + length); |
84 | } | 90 | } |
85 | 91 | ||
86 | /* | ||
87 | * Taking an interrupt in FIQ mode is death, so both these functions | ||
88 | * disable irqs for the duration. Note - these functions are almost | ||
89 | * entirely coded in assembly. | ||
90 | */ | ||
91 | void __naked set_fiq_regs(struct pt_regs *regs) | ||
92 | { | ||
93 | register unsigned long tmp; | ||
94 | asm volatile ( | ||
95 | "mov ip, sp\n\ | ||
96 | stmfd sp!, {fp, ip, lr, pc}\n\ | ||
97 | sub fp, ip, #4\n\ | ||
98 | mrs %0, cpsr\n\ | ||
99 | msr cpsr_c, %2 @ select FIQ mode\n\ | ||
100 | mov r0, r0\n\ | ||
101 | ldmia %1, {r8 - r14}\n\ | ||
102 | msr cpsr_c, %0 @ return to SVC mode\n\ | ||
103 | mov r0, r0\n\ | ||
104 | ldmfd sp, {fp, sp, pc}" | ||
105 | : "=&r" (tmp) | ||
106 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); | ||
107 | } | ||
108 | |||
109 | void __naked get_fiq_regs(struct pt_regs *regs) | ||
110 | { | ||
111 | register unsigned long tmp; | ||
112 | asm volatile ( | ||
113 | "mov ip, sp\n\ | ||
114 | stmfd sp!, {fp, ip, lr, pc}\n\ | ||
115 | sub fp, ip, #4\n\ | ||
116 | mrs %0, cpsr\n\ | ||
117 | msr cpsr_c, %2 @ select FIQ mode\n\ | ||
118 | mov r0, r0\n\ | ||
119 | stmia %1, {r8 - r14}\n\ | ||
120 | msr cpsr_c, %0 @ return to SVC mode\n\ | ||
121 | mov r0, r0\n\ | ||
122 | ldmfd sp, {fp, sp, pc}" | ||
123 | : "=&r" (tmp) | ||
124 | : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE)); | ||
125 | } | ||
126 | |||
127 | int claim_fiq(struct fiq_handler *f) | 92 | int claim_fiq(struct fiq_handler *f) |
128 | { | 93 | { |
129 | int ret = 0; | 94 | int ret = 0; |
@@ -168,8 +133,8 @@ void disable_fiq(int fiq) | |||
168 | } | 133 | } |
169 | 134 | ||
170 | EXPORT_SYMBOL(set_fiq_handler); | 135 | EXPORT_SYMBOL(set_fiq_handler); |
171 | EXPORT_SYMBOL(set_fiq_regs); | 136 | EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */ |
172 | EXPORT_SYMBOL(get_fiq_regs); | 137 | EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */ |
173 | EXPORT_SYMBOL(claim_fiq); | 138 | EXPORT_SYMBOL(claim_fiq); |
174 | EXPORT_SYMBOL(release_fiq); | 139 | EXPORT_SYMBOL(release_fiq); |
175 | EXPORT_SYMBOL(enable_fiq); | 140 | EXPORT_SYMBOL(enable_fiq); |
diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S new file mode 100644 index 000000000000..207f9d652010 --- /dev/null +++ b/arch/arm/kernel/fiqasm.S | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/fiqasm.S | ||
3 | * | ||
4 | * Derived from code originally in linux/arch/arm/kernel/fiq.c: | ||
5 | * | ||
6 | * Copyright (C) 1998 Russell King | ||
7 | * Copyright (C) 1998, 1999 Phil Blundell | ||
8 | * Copyright (C) 2011, Linaro Limited | ||
9 | * | ||
10 | * FIQ support written by Philip Blundell <philb@gnu.org>, 1998. | ||
11 | * | ||
12 | * FIQ support re-written by Russell King to be more generic | ||
13 | * | ||
14 | * v7/Thumb-2 compatibility modifications by Linaro Limited, 2011. | ||
15 | */ | ||
16 | |||
17 | #include <linux/linkage.h> | ||
18 | #include <asm/assembler.h> | ||
19 | |||
20 | /* | ||
21 | * Taking an interrupt in FIQ mode is death, so both these functions | ||
22 | * disable irqs for the duration. | ||
23 | */ | ||
24 | |||
25 | ENTRY(__set_fiq_regs) | ||
26 | mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE | ||
27 | mrs r1, cpsr | ||
28 | msr cpsr_c, r2 @ select FIQ mode | ||
29 | mov r0, r0 @ avoid hazard prior to ARMv4 | ||
30 | ldmia r0!, {r8 - r12} | ||
31 | ldr sp, [r0], #4 | ||
32 | ldr lr, [r0] | ||
33 | msr cpsr_c, r1 @ return to SVC mode | ||
34 | mov r0, r0 @ avoid hazard prior to ARMv4 | ||
35 | mov pc, lr | ||
36 | ENDPROC(__set_fiq_regs) | ||
37 | |||
38 | ENTRY(__get_fiq_regs) | ||
39 | mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE | ||
40 | mrs r1, cpsr | ||
41 | msr cpsr_c, r2 @ select FIQ mode | ||
42 | mov r0, r0 @ avoid hazard prior to ARMv4 | ||
43 | stmia r0!, {r8 - r12} | ||
44 | str sp, [r0], #4 | ||
45 | str lr, [r0] | ||
46 | msr cpsr_c, r1 @ return to SVC mode | ||
47 | mov r0, r0 @ avoid hazard prior to ARMv4 | ||
48 | mov pc, lr | ||
49 | ENDPROC(__get_fiq_regs) | ||
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 0298286ad4ad..c0062ad1e847 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c | |||
@@ -2,102 +2,287 @@ | |||
2 | * Dynamic function tracing support. | 2 | * Dynamic function tracing support. |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com> | 4 | * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com> |
5 | * Copyright (C) 2010 Rabin Vincent <rabin@rab.in> | ||
5 | * | 6 | * |
6 | * For licencing details, see COPYING. | 7 | * For licencing details, see COPYING. |
7 | * | 8 | * |
8 | * Defines low-level handling of mcount calls when the kernel | 9 | * Defines low-level handling of mcount calls when the kernel |
9 | * is compiled with the -pg flag. When using dynamic ftrace, the | 10 | * is compiled with the -pg flag. When using dynamic ftrace, the |
10 | * mcount call-sites get patched lazily with NOP till they are | 11 | * mcount call-sites get patched with NOP till they are enabled. |
11 | * enabled. All code mutation routines here take effect atomically. | 12 | * All code mutation routines here are called under stop_machine(). |
12 | */ | 13 | */ |
13 | 14 | ||
14 | #include <linux/ftrace.h> | 15 | #include <linux/ftrace.h> |
16 | #include <linux/uaccess.h> | ||
15 | 17 | ||
16 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
17 | #include <asm/ftrace.h> | 19 | #include <asm/ftrace.h> |
18 | 20 | ||
19 | #define PC_OFFSET 8 | 21 | #ifdef CONFIG_THUMB2_KERNEL |
20 | #define BL_OPCODE 0xeb000000 | 22 | #define NOP 0xeb04f85d /* pop.w {lr} */ |
21 | #define BL_OFFSET_MASK 0x00ffffff | 23 | #else |
24 | #define NOP 0xe8bd4000 /* pop {lr} */ | ||
25 | #endif | ||
22 | 26 | ||
23 | static unsigned long bl_insn; | 27 | #ifdef CONFIG_DYNAMIC_FTRACE |
24 | static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */ | 28 | #ifdef CONFIG_OLD_MCOUNT |
29 | #define OLD_MCOUNT_ADDR ((unsigned long) mcount) | ||
30 | #define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) | ||
25 | 31 | ||
26 | unsigned char *ftrace_nop_replace(void) | 32 | #define OLD_NOP 0xe1a00000 /* mov r0, r0 */ |
33 | |||
34 | static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) | ||
35 | { | ||
36 | return rec->arch.old_mcount ? OLD_NOP : NOP; | ||
37 | } | ||
38 | |||
39 | static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) | ||
40 | { | ||
41 | if (!rec->arch.old_mcount) | ||
42 | return addr; | ||
43 | |||
44 | if (addr == MCOUNT_ADDR) | ||
45 | addr = OLD_MCOUNT_ADDR; | ||
46 | else if (addr == FTRACE_ADDR) | ||
47 | addr = OLD_FTRACE_ADDR; | ||
48 | |||
49 | return addr; | ||
50 | } | ||
51 | #else | ||
52 | static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) | ||
53 | { | ||
54 | return NOP; | ||
55 | } | ||
56 | |||
57 | static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) | ||
27 | { | 58 | { |
28 | return (char *)&NOP; | 59 | return addr; |
29 | } | 60 | } |
61 | #endif | ||
62 | |||
63 | #ifdef CONFIG_THUMB2_KERNEL | ||
64 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
65 | bool link) | ||
66 | { | ||
67 | unsigned long s, j1, j2, i1, i2, imm10, imm11; | ||
68 | unsigned long first, second; | ||
69 | long offset; | ||
70 | |||
71 | offset = (long)addr - (long)(pc + 4); | ||
72 | if (offset < -16777216 || offset > 16777214) { | ||
73 | WARN_ON_ONCE(1); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | s = (offset >> 24) & 0x1; | ||
78 | i1 = (offset >> 23) & 0x1; | ||
79 | i2 = (offset >> 22) & 0x1; | ||
80 | imm10 = (offset >> 12) & 0x3ff; | ||
81 | imm11 = (offset >> 1) & 0x7ff; | ||
82 | |||
83 | j1 = (!i1) ^ s; | ||
84 | j2 = (!i2) ^ s; | ||
85 | |||
86 | first = 0xf000 | (s << 10) | imm10; | ||
87 | second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; | ||
88 | if (link) | ||
89 | second |= 1 << 14; | ||
30 | 90 | ||
31 | /* construct a branch (BL) instruction to addr */ | 91 | return (second << 16) | first; |
32 | unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr) | 92 | } |
93 | #else | ||
94 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
95 | bool link) | ||
33 | { | 96 | { |
97 | unsigned long opcode = 0xea000000; | ||
34 | long offset; | 98 | long offset; |
35 | 99 | ||
36 | offset = (long)addr - (long)(pc + PC_OFFSET); | 100 | if (link) |
101 | opcode |= 1 << 24; | ||
102 | |||
103 | offset = (long)addr - (long)(pc + 8); | ||
37 | if (unlikely(offset < -33554432 || offset > 33554428)) { | 104 | if (unlikely(offset < -33554432 || offset > 33554428)) { |
38 | /* Can't generate branches that far (from ARM ARM). Ftrace | 105 | /* Can't generate branches that far (from ARM ARM). Ftrace |
39 | * doesn't generate branches outside of kernel text. | 106 | * doesn't generate branches outside of kernel text. |
40 | */ | 107 | */ |
41 | WARN_ON_ONCE(1); | 108 | WARN_ON_ONCE(1); |
42 | return NULL; | 109 | return 0; |
43 | } | 110 | } |
44 | offset = (offset >> 2) & BL_OFFSET_MASK; | 111 | |
45 | bl_insn = BL_OPCODE | offset; | 112 | offset = (offset >> 2) & 0x00ffffff; |
46 | return (unsigned char *)&bl_insn; | 113 | |
114 | return opcode | offset; | ||
47 | } | 115 | } |
116 | #endif | ||
48 | 117 | ||
49 | int ftrace_modify_code(unsigned long pc, unsigned char *old_code, | 118 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) |
50 | unsigned char *new_code) | ||
51 | { | 119 | { |
52 | unsigned long err = 0, replaced = 0, old, new; | 120 | return ftrace_gen_branch(pc, addr, true); |
53 | 121 | } | |
54 | old = *(unsigned long *)old_code; | ||
55 | new = *(unsigned long *)new_code; | ||
56 | 122 | ||
57 | __asm__ __volatile__ ( | 123 | static int ftrace_modify_code(unsigned long pc, unsigned long old, |
58 | "1: ldr %1, [%2] \n" | 124 | unsigned long new) |
59 | " cmp %1, %4 \n" | 125 | { |
60 | "2: streq %3, [%2] \n" | 126 | unsigned long replaced; |
61 | " cmpne %1, %3 \n" | ||
62 | " movne %0, #2 \n" | ||
63 | "3:\n" | ||
64 | 127 | ||
65 | ".pushsection .fixup, \"ax\"\n" | 128 | if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) |
66 | "4: mov %0, #1 \n" | 129 | return -EFAULT; |
67 | " b 3b \n" | ||
68 | ".popsection\n" | ||
69 | 130 | ||
70 | ".pushsection __ex_table, \"a\"\n" | 131 | if (replaced != old) |
71 | " .long 1b, 4b \n" | 132 | return -EINVAL; |
72 | " .long 2b, 4b \n" | ||
73 | ".popsection\n" | ||
74 | 133 | ||
75 | : "=r"(err), "=r"(replaced) | 134 | if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE)) |
76 | : "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced) | 135 | return -EPERM; |
77 | : "memory"); | ||
78 | 136 | ||
79 | if (!err && (replaced == old)) | 137 | flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); |
80 | flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); | ||
81 | 138 | ||
82 | return err; | 139 | return 0; |
83 | } | 140 | } |
84 | 141 | ||
85 | int ftrace_update_ftrace_func(ftrace_func_t func) | 142 | int ftrace_update_ftrace_func(ftrace_func_t func) |
86 | { | 143 | { |
87 | int ret; | ||
88 | unsigned long pc, old; | 144 | unsigned long pc, old; |
89 | unsigned char *new; | 145 | unsigned long new; |
146 | int ret; | ||
90 | 147 | ||
91 | pc = (unsigned long)&ftrace_call; | 148 | pc = (unsigned long)&ftrace_call; |
92 | memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); | 149 | memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); |
93 | new = ftrace_call_replace(pc, (unsigned long)func); | 150 | new = ftrace_call_replace(pc, (unsigned long)func); |
94 | ret = ftrace_modify_code(pc, (unsigned char *)&old, new); | 151 | |
152 | ret = ftrace_modify_code(pc, old, new); | ||
153 | |||
154 | #ifdef CONFIG_OLD_MCOUNT | ||
155 | if (!ret) { | ||
156 | pc = (unsigned long)&ftrace_call_old; | ||
157 | memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE); | ||
158 | new = ftrace_call_replace(pc, (unsigned long)func); | ||
159 | |||
160 | ret = ftrace_modify_code(pc, old, new); | ||
161 | } | ||
162 | #endif | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
168 | { | ||
169 | unsigned long new, old; | ||
170 | unsigned long ip = rec->ip; | ||
171 | |||
172 | old = ftrace_nop_replace(rec); | ||
173 | new = ftrace_call_replace(ip, adjust_address(rec, addr)); | ||
174 | |||
175 | return ftrace_modify_code(rec->ip, old, new); | ||
176 | } | ||
177 | |||
178 | int ftrace_make_nop(struct module *mod, | ||
179 | struct dyn_ftrace *rec, unsigned long addr) | ||
180 | { | ||
181 | unsigned long ip = rec->ip; | ||
182 | unsigned long old; | ||
183 | unsigned long new; | ||
184 | int ret; | ||
185 | |||
186 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); | ||
187 | new = ftrace_nop_replace(rec); | ||
188 | ret = ftrace_modify_code(ip, old, new); | ||
189 | |||
190 | #ifdef CONFIG_OLD_MCOUNT | ||
191 | if (ret == -EINVAL && addr == MCOUNT_ADDR) { | ||
192 | rec->arch.old_mcount = true; | ||
193 | |||
194 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); | ||
195 | new = ftrace_nop_replace(rec); | ||
196 | ret = ftrace_modify_code(ip, old, new); | ||
197 | } | ||
198 | #endif | ||
199 | |||
95 | return ret; | 200 | return ret; |
96 | } | 201 | } |
97 | 202 | ||
98 | /* run from ftrace_init with irqs disabled */ | ||
99 | int __init ftrace_dyn_arch_init(void *data) | 203 | int __init ftrace_dyn_arch_init(void *data) |
100 | { | 204 | { |
101 | ftrace_mcount_set(data); | 205 | *(unsigned long *)data = 0; |
206 | |||
102 | return 0; | 207 | return 0; |
103 | } | 208 | } |
209 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
210 | |||
211 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
212 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | ||
213 | unsigned long frame_pointer) | ||
214 | { | ||
215 | unsigned long return_hooker = (unsigned long) &return_to_handler; | ||
216 | struct ftrace_graph_ent trace; | ||
217 | unsigned long old; | ||
218 | int err; | ||
219 | |||
220 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
221 | return; | ||
222 | |||
223 | old = *parent; | ||
224 | *parent = return_hooker; | ||
225 | |||
226 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, | ||
227 | frame_pointer); | ||
228 | if (err == -EBUSY) { | ||
229 | *parent = old; | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | trace.func = self_addr; | ||
234 | |||
235 | /* Only trace if the calling function expects to */ | ||
236 | if (!ftrace_graph_entry(&trace)) { | ||
237 | current->curr_ret_stack--; | ||
238 | *parent = old; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
243 | extern unsigned long ftrace_graph_call; | ||
244 | extern unsigned long ftrace_graph_call_old; | ||
245 | extern void ftrace_graph_caller_old(void); | ||
246 | |||
247 | static int __ftrace_modify_caller(unsigned long *callsite, | ||
248 | void (*func) (void), bool enable) | ||
249 | { | ||
250 | unsigned long caller_fn = (unsigned long) func; | ||
251 | unsigned long pc = (unsigned long) callsite; | ||
252 | unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); | ||
253 | unsigned long nop = 0xe1a00000; /* mov r0, r0 */ | ||
254 | unsigned long old = enable ? nop : branch; | ||
255 | unsigned long new = enable ? branch : nop; | ||
256 | |||
257 | return ftrace_modify_code(pc, old, new); | ||
258 | } | ||
259 | |||
260 | static int ftrace_modify_graph_caller(bool enable) | ||
261 | { | ||
262 | int ret; | ||
263 | |||
264 | ret = __ftrace_modify_caller(&ftrace_graph_call, | ||
265 | ftrace_graph_caller, | ||
266 | enable); | ||
267 | |||
268 | #ifdef CONFIG_OLD_MCOUNT | ||
269 | if (!ret) | ||
270 | ret = __ftrace_modify_caller(&ftrace_graph_call_old, | ||
271 | ftrace_graph_caller_old, | ||
272 | enable); | ||
273 | #endif | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | int ftrace_enable_ftrace_graph_caller(void) | ||
279 | { | ||
280 | return ftrace_modify_graph_caller(true); | ||
281 | } | ||
282 | |||
283 | int ftrace_disable_ftrace_graph_caller(void) | ||
284 | { | ||
285 | return ftrace_modify_graph_caller(false); | ||
286 | } | ||
287 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
288 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index b9505aa267c0..854bd22380d3 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S | |||
@@ -15,19 +15,57 @@ | |||
15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) | 15 | #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) |
16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) | 16 | #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2) |
17 | 17 | ||
18 | .align 2 | 18 | #ifdef CONFIG_CPU_BIG_ENDIAN |
19 | .type __switch_data, %object | 19 | #define OF_DT_MAGIC 0xd00dfeed |
20 | __switch_data: | 20 | #else |
21 | .long __mmap_switched | 21 | #define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */ |
22 | .long __data_loc @ r4 | 22 | #endif |
23 | .long _data @ r5 | 23 | |
24 | .long __bss_start @ r6 | 24 | /* |
25 | .long _end @ r7 | 25 | * Exception handling. Something went wrong and we can't proceed. We |
26 | .long processor_id @ r4 | 26 | * ought to tell the user, but since we don't have any guarantee that |
27 | .long __machine_arch_type @ r5 | 27 | * we're even running on the right architecture, we do virtually nothing. |
28 | .long __atags_pointer @ r6 | 28 | * |
29 | .long cr_alignment @ r7 | 29 | * If CONFIG_DEBUG_LL is set we try to print out something about the error |
30 | .long init_thread_union + THREAD_START_SP @ sp | 30 | * and hope for the best (useful if bootloader fails to pass a proper |
31 | * machine ID for example). | ||
32 | */ | ||
33 | __HEAD | ||
34 | |||
35 | /* Determine validity of the r2 atags pointer. The heuristic requires | ||
36 | * that the pointer be aligned, in the first 16k of physical RAM and | ||
37 | * that the ATAG_CORE marker is first and present. If CONFIG_OF_FLATTREE | ||
38 | * is selected, then it will also accept a dtb pointer. Future revisions | ||
39 | * of this function may be more lenient with the physical address and | ||
40 | * may also be able to move the ATAGS block if necessary. | ||
41 | * | ||
42 | * Returns: | ||
43 | * r2 either valid atags pointer, valid dtb pointer, or zero | ||
44 | * r5, r6 corrupted | ||
45 | */ | ||
46 | __vet_atags: | ||
47 | tst r2, #0x3 @ aligned? | ||
48 | bne 1f | ||
49 | |||
50 | ldr r5, [r2, #0] | ||
51 | #ifdef CONFIG_OF_FLATTREE | ||
52 | ldr r6, =OF_DT_MAGIC @ is it a DTB? | ||
53 | cmp r5, r6 | ||
54 | beq 2f | ||
55 | #endif | ||
56 | cmp r5, #ATAG_CORE_SIZE @ is first tag ATAG_CORE? | ||
57 | cmpne r5, #ATAG_CORE_SIZE_EMPTY | ||
58 | bne 1f | ||
59 | ldr r5, [r2, #4] | ||
60 | ldr r6, =ATAG_CORE | ||
61 | cmp r5, r6 | ||
62 | bne 1f | ||
63 | |||
64 | 2: mov pc, lr @ atag/dtb pointer is ok | ||
65 | |||
66 | 1: mov r2, #0 | ||
67 | mov pc, lr | ||
68 | ENDPROC(__vet_atags) | ||
31 | 69 | ||
32 | /* | 70 | /* |
33 | * The following fragment of code is executed with the MMU on in MMU mode, | 71 | * The following fragment of code is executed with the MMU on in MMU mode, |
@@ -35,11 +73,12 @@ __switch_data: | |||
35 | * | 73 | * |
36 | * r0 = cp#15 control register | 74 | * r0 = cp#15 control register |
37 | * r1 = machine ID | 75 | * r1 = machine ID |
38 | * r2 = atags pointer | 76 | * r2 = atags/dtb pointer |
39 | * r9 = processor ID | 77 | * r9 = processor ID |
40 | */ | 78 | */ |
79 | __INIT | ||
41 | __mmap_switched: | 80 | __mmap_switched: |
42 | adr r3, __switch_data + 4 | 81 | adr r3, __mmap_switched_data |
43 | 82 | ||
44 | ldmia r3!, {r4, r5, r6, r7} | 83 | ldmia r3!, {r4, r5, r6, r7} |
45 | cmp r4, r5 @ Copy data segment if needed | 84 | cmp r4, r5 @ Copy data segment if needed |
@@ -64,85 +103,30 @@ __mmap_switched: | |||
64 | b start_kernel | 103 | b start_kernel |
65 | ENDPROC(__mmap_switched) | 104 | ENDPROC(__mmap_switched) |
66 | 105 | ||
67 | /* | 106 | .align 2 |
68 | * Exception handling. Something went wrong and we can't proceed. We | 107 | .type __mmap_switched_data, %object |
69 | * ought to tell the user, but since we don't have any guarantee that | 108 | __mmap_switched_data: |
70 | * we're even running on the right architecture, we do virtually nothing. | 109 | .long __data_loc @ r4 |
71 | * | 110 | .long _sdata @ r5 |
72 | * If CONFIG_DEBUG_LL is set we try to print out something about the error | 111 | .long __bss_start @ r6 |
73 | * and hope for the best (useful if bootloader fails to pass a proper | 112 | .long _end @ r7 |
74 | * machine ID for example). | 113 | .long processor_id @ r4 |
75 | */ | 114 | .long __machine_arch_type @ r5 |
76 | __error_p: | 115 | .long __atags_pointer @ r6 |
77 | #ifdef CONFIG_DEBUG_LL | 116 | .long cr_alignment @ r7 |
78 | adr r0, str_p1 | 117 | .long init_thread_union + THREAD_START_SP @ sp |
79 | bl printascii | 118 | .size __mmap_switched_data, . - __mmap_switched_data |
80 | mov r0, r9 | ||
81 | bl printhex8 | ||
82 | adr r0, str_p2 | ||
83 | bl printascii | ||
84 | b __error | ||
85 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" | ||
86 | str_p2: .asciz ").\n" | ||
87 | .align | ||
88 | #endif | ||
89 | ENDPROC(__error_p) | ||
90 | |||
91 | __error_a: | ||
92 | #ifdef CONFIG_DEBUG_LL | ||
93 | mov r4, r1 @ preserve machine ID | ||
94 | adr r0, str_a1 | ||
95 | bl printascii | ||
96 | mov r0, r4 | ||
97 | bl printhex8 | ||
98 | adr r0, str_a2 | ||
99 | bl printascii | ||
100 | adr r3, 4f | ||
101 | ldmia r3, {r4, r5, r6} @ get machine desc list | ||
102 | sub r4, r3, r4 @ get offset between virt&phys | ||
103 | add r5, r5, r4 @ convert virt addresses to | ||
104 | add r6, r6, r4 @ physical address space | ||
105 | 1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type | ||
106 | bl printhex8 | ||
107 | mov r0, #'\t' | ||
108 | bl printch | ||
109 | ldr r0, [r5, #MACHINFO_NAME] @ get machine name | ||
110 | add r0, r0, r4 | ||
111 | bl printascii | ||
112 | mov r0, #'\n' | ||
113 | bl printch | ||
114 | add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc | ||
115 | cmp r5, r6 | ||
116 | blo 1b | ||
117 | adr r0, str_a3 | ||
118 | bl printascii | ||
119 | b __error | ||
120 | ENDPROC(__error_a) | ||
121 | |||
122 | str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" | ||
123 | str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" | ||
124 | str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" | ||
125 | .align | ||
126 | #endif | ||
127 | 119 | ||
128 | __error: | ||
129 | #ifdef CONFIG_ARCH_RPC | ||
130 | /* | 120 | /* |
131 | * Turn the screen red on a error - RiscPC only. | 121 | * This provides a C-API version of __lookup_processor_type |
132 | */ | 122 | */ |
133 | mov r0, #0x02000000 | 123 | ENTRY(lookup_processor_type) |
134 | mov r3, #0x11 | 124 | stmfd sp!, {r4 - r6, r9, lr} |
135 | orr r3, r3, r3, lsl #8 | 125 | mov r9, r0 |
136 | orr r3, r3, r3, lsl #16 | 126 | bl __lookup_processor_type |
137 | str r3, [r0], #4 | 127 | mov r0, r5 |
138 | str r3, [r0], #4 | 128 | ldmfd sp!, {r4 - r6, r9, pc} |
139 | str r3, [r0], #4 | 129 | ENDPROC(lookup_processor_type) |
140 | str r3, [r0], #4 | ||
141 | #endif | ||
142 | 1: mov r0, r0 | ||
143 | b 1b | ||
144 | ENDPROC(__error) | ||
145 | |||
146 | 130 | ||
147 | /* | 131 | /* |
148 | * Read processor ID register (CP#15, CR0), and look up in the linker-built | 132 | * Read processor ID register (CP#15, CR0), and look up in the linker-built |
@@ -157,11 +141,11 @@ ENDPROC(__error) | |||
157 | * r5 = proc_info pointer in physical address space | 141 | * r5 = proc_info pointer in physical address space |
158 | * r9 = cpuid (preserved) | 142 | * r9 = cpuid (preserved) |
159 | */ | 143 | */ |
144 | __CPUINIT | ||
160 | __lookup_processor_type: | 145 | __lookup_processor_type: |
161 | adr r3, 3f | 146 | adr r3, __lookup_processor_type_data |
162 | ldmia r3, {r5 - r7} | 147 | ldmia r3, {r4 - r6} |
163 | add r3, r3, #8 | 148 | sub r3, r3, r4 @ get offset between virt&phys |
164 | sub r3, r3, r7 @ get offset between virt&phys | ||
165 | add r5, r5, r3 @ convert virt addresses to | 149 | add r5, r5, r3 @ convert virt addresses to |
166 | add r6, r6, r3 @ physical address space | 150 | add r6, r6, r3 @ physical address space |
167 | 1: ldmia r5, {r3, r4} @ value, mask | 151 | 1: ldmia r5, {r3, r4} @ value, mask |
@@ -176,92 +160,45 @@ __lookup_processor_type: | |||
176 | ENDPROC(__lookup_processor_type) | 160 | ENDPROC(__lookup_processor_type) |
177 | 161 | ||
178 | /* | 162 | /* |
179 | * This provides a C-API version of the above function. | 163 | * Look in <asm/procinfo.h> for information about the __proc_info structure. |
180 | */ | ||
181 | ENTRY(lookup_processor_type) | ||
182 | stmfd sp!, {r4 - r7, r9, lr} | ||
183 | mov r9, r0 | ||
184 | bl __lookup_processor_type | ||
185 | mov r0, r5 | ||
186 | ldmfd sp!, {r4 - r7, r9, pc} | ||
187 | ENDPROC(lookup_processor_type) | ||
188 | |||
189 | /* | ||
190 | * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for | ||
191 | * more information about the __proc_info and __arch_info structures. | ||
192 | */ | 164 | */ |
193 | .align 2 | 165 | .align 2 |
194 | 3: .long __proc_info_begin | 166 | .type __lookup_processor_type_data, %object |
167 | __lookup_processor_type_data: | ||
168 | .long . | ||
169 | .long __proc_info_begin | ||
195 | .long __proc_info_end | 170 | .long __proc_info_end |
196 | 4: .long . | 171 | .size __lookup_processor_type_data, . - __lookup_processor_type_data |
197 | .long __arch_info_begin | ||
198 | .long __arch_info_end | ||
199 | 172 | ||
200 | /* | 173 | __error_p: |
201 | * Lookup machine architecture in the linker-build list of architectures. | 174 | #ifdef CONFIG_DEBUG_LL |
202 | * Note that we can't use the absolute addresses for the __arch_info | 175 | adr r0, str_p1 |
203 | * lists since we aren't running with the MMU on (and therefore, we are | 176 | bl printascii |
204 | * not in the correct address space). We have to calculate the offset. | 177 | mov r0, r9 |
205 | * | 178 | bl printhex8 |
206 | * r1 = machine architecture number | 179 | adr r0, str_p2 |
207 | * Returns: | 180 | bl printascii |
208 | * r3, r4, r6 corrupted | 181 | b __error |
209 | * r5 = mach_info pointer in physical address space | 182 | str_p1: .asciz "\nError: unrecognized/unsupported processor variant (0x" |
210 | */ | 183 | str_p2: .asciz ").\n" |
211 | __lookup_machine_type: | 184 | .align |
212 | adr r3, 4b | 185 | #endif |
213 | ldmia r3, {r4, r5, r6} | 186 | ENDPROC(__error_p) |
214 | sub r3, r3, r4 @ get offset between virt&phys | ||
215 | add r5, r5, r3 @ convert virt addresses to | ||
216 | add r6, r6, r3 @ physical address space | ||
217 | 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type | ||
218 | teq r3, r1 @ matches loader number? | ||
219 | beq 2f @ found | ||
220 | add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc | ||
221 | cmp r5, r6 | ||
222 | blo 1b | ||
223 | mov r5, #0 @ unknown machine | ||
224 | 2: mov pc, lr | ||
225 | ENDPROC(__lookup_machine_type) | ||
226 | 187 | ||
188 | __error: | ||
189 | #ifdef CONFIG_ARCH_RPC | ||
227 | /* | 190 | /* |
228 | * This provides a C-API version of the above function. | 191 | * Turn the screen red on a error - RiscPC only. |
229 | */ | ||
230 | ENTRY(lookup_machine_type) | ||
231 | stmfd sp!, {r4 - r6, lr} | ||
232 | mov r1, r0 | ||
233 | bl __lookup_machine_type | ||
234 | mov r0, r5 | ||
235 | ldmfd sp!, {r4 - r6, pc} | ||
236 | ENDPROC(lookup_machine_type) | ||
237 | |||
238 | /* Determine validity of the r2 atags pointer. The heuristic requires | ||
239 | * that the pointer be aligned, in the first 16k of physical RAM and | ||
240 | * that the ATAG_CORE marker is first and present. Future revisions | ||
241 | * of this function may be more lenient with the physical address and | ||
242 | * may also be able to move the ATAGS block if necessary. | ||
243 | * | ||
244 | * r8 = machinfo | ||
245 | * | ||
246 | * Returns: | ||
247 | * r2 either valid atags pointer, or zero | ||
248 | * r5, r6 corrupted | ||
249 | */ | 192 | */ |
250 | __vet_atags: | 193 | mov r0, #0x02000000 |
251 | tst r2, #0x3 @ aligned? | 194 | mov r3, #0x11 |
252 | bne 1f | 195 | orr r3, r3, r3, lsl #8 |
253 | 196 | orr r3, r3, r3, lsl #16 | |
254 | ldr r5, [r2, #0] @ is first tag ATAG_CORE? | 197 | str r3, [r0], #4 |
255 | cmp r5, #ATAG_CORE_SIZE | 198 | str r3, [r0], #4 |
256 | cmpne r5, #ATAG_CORE_SIZE_EMPTY | 199 | str r3, [r0], #4 |
257 | bne 1f | 200 | str r3, [r0], #4 |
258 | ldr r5, [r2, #4] | 201 | #endif |
259 | ldr r6, =ATAG_CORE | 202 | 1: mov r0, r0 |
260 | cmp r5, r6 | 203 | b 1b |
261 | bne 1f | 204 | ENDPROC(__error) |
262 | |||
263 | mov pc, lr @ atag pointer is ok | ||
264 | |||
265 | 1: mov r2, #0 | ||
266 | mov pc, lr | ||
267 | ENDPROC(__vet_atags) | ||
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 573b803dc6bf..6b1e0ad9ec3b 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -44,12 +44,7 @@ ENTRY(stext) | |||
44 | bl __lookup_processor_type @ r5=procinfo r9=cpuid | 44 | bl __lookup_processor_type @ r5=procinfo r9=cpuid |
45 | movs r10, r5 @ invalid processor (r5=0)? | 45 | movs r10, r5 @ invalid processor (r5=0)? |
46 | beq __error_p @ yes, error 'p' | 46 | beq __error_p @ yes, error 'p' |
47 | bl __lookup_machine_type @ r5=machinfo | ||
48 | movs r8, r5 @ invalid machine (r5=0)? | ||
49 | beq __error_a @ yes, error 'a' | ||
50 | 47 | ||
51 | ldr r13, __switch_data @ address to jump to after | ||
52 | @ the initialization is done | ||
53 | adr lr, BSYM(__after_proc_init) @ return (PIC) address | 48 | adr lr, BSYM(__after_proc_init) @ return (PIC) address |
54 | ARM( add pc, r10, #PROCINFO_INITFUNC ) | 49 | ARM( add pc, r10, #PROCINFO_INITFUNC ) |
55 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) | 50 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) |
@@ -87,8 +82,7 @@ __after_proc_init: | |||
87 | mcr p15, 0, r0, c1, c0, 0 @ write control reg | 82 | mcr p15, 0, r0, c1, c0, 0 @ write control reg |
88 | #endif /* CONFIG_CPU_CP15 */ | 83 | #endif /* CONFIG_CPU_CP15 */ |
89 | 84 | ||
90 | mov r3, r13 | 85 | b __mmap_switched @ clear the BSS and jump |
91 | mov pc, r3 @ clear the BSS and jump | ||
92 | @ to start_kernel | 86 | @ to start_kernel |
93 | ENDPROC(__after_proc_init) | 87 | ENDPROC(__after_proc_init) |
94 | .ltorg | 88 | .ltorg |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index eb62bf947212..278c1b0ebb2e 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -22,14 +22,10 @@ | |||
22 | #include <asm/thread_info.h> | 22 | #include <asm/thread_info.h> |
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | #if (PHYS_OFFSET & 0x001fffff) | 25 | #ifdef CONFIG_DEBUG_LL |
26 | #error "PHYS_OFFSET must be at an even 2MiB boundary!" | 26 | #include <mach/debug-macro.S> |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | ||
30 | #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) | ||
31 | |||
32 | |||
33 | /* | 29 | /* |
34 | * swapper_pg_dir is the virtual address of the initial page table. | 30 | * swapper_pg_dir is the virtual address of the initial page table. |
35 | * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must | 31 | * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must |
@@ -37,6 +33,7 @@ | |||
37 | * the least significant 16 bits to be 0x8000, but we could probably | 33 | * the least significant 16 bits to be 0x8000, but we could probably |
38 | * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. | 34 | * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. |
39 | */ | 35 | */ |
36 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | ||
40 | #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 | 37 | #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 |
41 | #error KERNEL_RAM_VADDR must start at 0xXXXX8000 | 38 | #error KERNEL_RAM_VADDR must start at 0xXXXX8000 |
42 | #endif | 39 | #endif |
@@ -44,8 +41,8 @@ | |||
44 | .globl swapper_pg_dir | 41 | .globl swapper_pg_dir |
45 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 | 42 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 |
46 | 43 | ||
47 | .macro pgtbl, rd | 44 | .macro pgtbl, rd, phys |
48 | ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) | 45 | add \rd, \phys, #TEXT_OFFSET - 0x4000 |
49 | .endm | 46 | .endm |
50 | 47 | ||
51 | #ifdef CONFIG_XIP_KERNEL | 48 | #ifdef CONFIG_XIP_KERNEL |
@@ -62,7 +59,7 @@ | |||
62 | * | 59 | * |
63 | * This is normally called from the decompressor code. The requirements | 60 | * This is normally called from the decompressor code. The requirements |
64 | * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, | 61 | * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, |
65 | * r1 = machine nr, r2 = atags pointer. | 62 | * r1 = machine nr, r2 = atags or dtb pointer. |
66 | * | 63 | * |
67 | * This code is mostly position independent, so if you link the kernel at | 64 | * This code is mostly position independent, so if you link the kernel at |
68 | * 0xc0008000, you call this at __pa(0xc0008000). | 65 | * 0xc0008000, you call this at __pa(0xc0008000). |
@@ -81,29 +78,210 @@ ENTRY(stext) | |||
81 | mrc p15, 0, r9, c0, c0 @ get processor id | 78 | mrc p15, 0, r9, c0, c0 @ get processor id |
82 | bl __lookup_processor_type @ r5=procinfo r9=cpuid | 79 | bl __lookup_processor_type @ r5=procinfo r9=cpuid |
83 | movs r10, r5 @ invalid processor (r5=0)? | 80 | movs r10, r5 @ invalid processor (r5=0)? |
81 | THUMB( it eq ) @ force fixup-able long branch encoding | ||
84 | beq __error_p @ yes, error 'p' | 82 | beq __error_p @ yes, error 'p' |
85 | bl __lookup_machine_type @ r5=machinfo | 83 | |
86 | movs r8, r5 @ invalid machine (r5=0)? | 84 | #ifndef CONFIG_XIP_KERNEL |
87 | beq __error_a @ yes, error 'a' | 85 | adr r3, 2f |
86 | ldmia r3, {r4, r8} | ||
87 | sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET) | ||
88 | add r8, r8, r4 @ PHYS_OFFSET | ||
89 | #else | ||
90 | ldr r8, =PLAT_PHYS_OFFSET | ||
91 | #endif | ||
92 | |||
93 | /* | ||
94 | * r1 = machine no, r2 = atags or dtb, | ||
95 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo | ||
96 | */ | ||
88 | bl __vet_atags | 97 | bl __vet_atags |
98 | #ifdef CONFIG_SMP_ON_UP | ||
99 | bl __fixup_smp | ||
100 | #endif | ||
101 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
102 | bl __fixup_pv_table | ||
103 | #endif | ||
89 | bl __create_page_tables | 104 | bl __create_page_tables |
90 | 105 | ||
91 | /* | 106 | /* |
92 | * The following calls CPU specific code in a position independent | 107 | * The following calls CPU specific code in a position independent |
93 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of | 108 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of |
94 | * xxx_proc_info structure selected by __lookup_machine_type | 109 | * xxx_proc_info structure selected by __lookup_processor_type |
95 | * above. On return, the CPU will be ready for the MMU to be | 110 | * above. On return, the CPU will be ready for the MMU to be |
96 | * turned on, and r0 will hold the CPU control register value. | 111 | * turned on, and r0 will hold the CPU control register value. |
97 | */ | 112 | */ |
98 | ldr r13, __switch_data @ address to jump to after | 113 | ldr r13, =__mmap_switched @ address to jump to after |
99 | @ mmu has been enabled | 114 | @ mmu has been enabled |
100 | adr lr, BSYM(__enable_mmu) @ return (PIC) address | 115 | adr lr, BSYM(1f) @ return (PIC) address |
116 | mov r8, r4 @ set TTBR1 to swapper_pg_dir | ||
101 | ARM( add pc, r10, #PROCINFO_INITFUNC ) | 117 | ARM( add pc, r10, #PROCINFO_INITFUNC ) |
102 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) | 118 | THUMB( add r12, r10, #PROCINFO_INITFUNC ) |
103 | THUMB( mov pc, r12 ) | 119 | THUMB( mov pc, r12 ) |
120 | 1: b __enable_mmu | ||
104 | ENDPROC(stext) | 121 | ENDPROC(stext) |
122 | .ltorg | ||
123 | #ifndef CONFIG_XIP_KERNEL | ||
124 | 2: .long . | ||
125 | .long PAGE_OFFSET | ||
126 | #endif | ||
127 | |||
128 | /* | ||
129 | * Setup the initial page tables. We only setup the barest | ||
130 | * amount which are required to get the kernel running, which | ||
131 | * generally means mapping in the kernel code. | ||
132 | * | ||
133 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo | ||
134 | * | ||
135 | * Returns: | ||
136 | * r0, r3, r5-r7 corrupted | ||
137 | * r4 = physical page table address | ||
138 | */ | ||
139 | __create_page_tables: | ||
140 | pgtbl r4, r8 @ page table address | ||
141 | |||
142 | /* | ||
143 | * Clear the 16K level 1 swapper page table | ||
144 | */ | ||
145 | mov r0, r4 | ||
146 | mov r3, #0 | ||
147 | add r6, r0, #0x4000 | ||
148 | 1: str r3, [r0], #4 | ||
149 | str r3, [r0], #4 | ||
150 | str r3, [r0], #4 | ||
151 | str r3, [r0], #4 | ||
152 | teq r0, r6 | ||
153 | bne 1b | ||
154 | |||
155 | ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags | ||
156 | |||
157 | /* | ||
158 | * Create identity mapping to cater for __enable_mmu. | ||
159 | * This identity mapping will be removed by paging_init(). | ||
160 | */ | ||
161 | adr r0, __enable_mmu_loc | ||
162 | ldmia r0, {r3, r5, r6} | ||
163 | sub r0, r0, r3 @ virt->phys offset | ||
164 | add r5, r5, r0 @ phys __enable_mmu | ||
165 | add r6, r6, r0 @ phys __enable_mmu_end | ||
166 | mov r5, r5, lsr #20 | ||
167 | mov r6, r6, lsr #20 | ||
168 | |||
169 | 1: orr r3, r7, r5, lsl #20 @ flags + kernel base | ||
170 | str r3, [r4, r5, lsl #2] @ identity mapping | ||
171 | teq r5, r6 | ||
172 | addne r5, r5, #1 @ next section | ||
173 | bne 1b | ||
174 | |||
175 | /* | ||
176 | * Now setup the pagetables for our kernel direct | ||
177 | * mapped region. | ||
178 | */ | ||
179 | mov r3, pc | ||
180 | mov r3, r3, lsr #20 | ||
181 | orr r3, r7, r3, lsl #20 | ||
182 | add r0, r4, #(KERNEL_START & 0xff000000) >> 18 | ||
183 | str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]! | ||
184 | ldr r6, =(KERNEL_END - 1) | ||
185 | add r0, r0, #4 | ||
186 | add r6, r4, r6, lsr #18 | ||
187 | 1: cmp r0, r6 | ||
188 | add r3, r3, #1 << 20 | ||
189 | strls r3, [r0], #4 | ||
190 | bls 1b | ||
191 | |||
192 | #ifdef CONFIG_XIP_KERNEL | ||
193 | /* | ||
194 | * Map some ram to cover our .data and .bss areas. | ||
195 | */ | ||
196 | add r3, r8, #TEXT_OFFSET | ||
197 | orr r3, r3, r7 | ||
198 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 | ||
199 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! | ||
200 | ldr r6, =(_end - 1) | ||
201 | add r0, r0, #4 | ||
202 | add r6, r4, r6, lsr #18 | ||
203 | 1: cmp r0, r6 | ||
204 | add r3, r3, #1 << 20 | ||
205 | strls r3, [r0], #4 | ||
206 | bls 1b | ||
207 | #endif | ||
208 | |||
209 | /* | ||
210 | * Then map boot params address in r2 or | ||
211 | * the first 1MB of ram if boot params address is not specified. | ||
212 | */ | ||
213 | mov r0, r2, lsr #20 | ||
214 | movs r0, r0, lsl #20 | ||
215 | moveq r0, r8 | ||
216 | sub r3, r0, r8 | ||
217 | add r3, r3, #PAGE_OFFSET | ||
218 | add r3, r4, r3, lsr #18 | ||
219 | orr r6, r7, r0 | ||
220 | str r6, [r3] | ||
221 | |||
222 | #ifdef CONFIG_DEBUG_LL | ||
223 | #ifndef CONFIG_DEBUG_ICEDCC | ||
224 | /* | ||
225 | * Map in IO space for serial debugging. | ||
226 | * This allows debug messages to be output | ||
227 | * via a serial console before paging_init. | ||
228 | */ | ||
229 | addruart r7, r3 | ||
230 | |||
231 | mov r3, r3, lsr #20 | ||
232 | mov r3, r3, lsl #2 | ||
233 | |||
234 | add r0, r4, r3 | ||
235 | rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) | ||
236 | cmp r3, #0x0800 @ limit to 512MB | ||
237 | movhi r3, #0x0800 | ||
238 | add r6, r0, r3 | ||
239 | mov r3, r7, lsr #20 | ||
240 | ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags | ||
241 | orr r3, r7, r3, lsl #20 | ||
242 | 1: str r3, [r0], #4 | ||
243 | add r3, r3, #1 << 20 | ||
244 | teq r0, r6 | ||
245 | bne 1b | ||
246 | |||
247 | #else /* CONFIG_DEBUG_ICEDCC */ | ||
248 | /* we don't need any serial debugging mappings for ICEDCC */ | ||
249 | ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags | ||
250 | #endif /* !CONFIG_DEBUG_ICEDCC */ | ||
251 | |||
252 | #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) | ||
253 | /* | ||
254 | * If we're using the NetWinder or CATS, we also need to map | ||
255 | * in the 16550-type serial port for the debug messages | ||
256 | */ | ||
257 | add r0, r4, #0xff000000 >> 18 | ||
258 | orr r3, r7, #0x7c000000 | ||
259 | str r3, [r0] | ||
260 | #endif | ||
261 | #ifdef CONFIG_ARCH_RPC | ||
262 | /* | ||
263 | * Map in screen at 0x02000000 & SCREEN2_BASE | ||
264 | * Similar reasons here - for debug. This is | ||
265 | * only for Acorn RiscPC architectures. | ||
266 | */ | ||
267 | add r0, r4, #0x02000000 >> 18 | ||
268 | orr r3, r7, #0x02000000 | ||
269 | str r3, [r0] | ||
270 | add r0, r4, #0xd8000000 >> 18 | ||
271 | str r3, [r0] | ||
272 | #endif | ||
273 | #endif | ||
274 | mov pc, lr | ||
275 | ENDPROC(__create_page_tables) | ||
276 | .ltorg | ||
277 | .align | ||
278 | __enable_mmu_loc: | ||
279 | .long . | ||
280 | .long __enable_mmu | ||
281 | .long __enable_mmu_end | ||
105 | 282 | ||
106 | #if defined(CONFIG_SMP) | 283 | #if defined(CONFIG_SMP) |
284 | __CPUINIT | ||
107 | ENTRY(secondary_startup) | 285 | ENTRY(secondary_startup) |
108 | /* | 286 | /* |
109 | * Common entry point for secondary CPUs. | 287 | * Common entry point for secondary CPUs. |
@@ -117,15 +295,18 @@ ENTRY(secondary_startup) | |||
117 | bl __lookup_processor_type | 295 | bl __lookup_processor_type |
118 | movs r10, r5 @ invalid processor? | 296 | movs r10, r5 @ invalid processor? |
119 | moveq r0, #'p' @ yes, error 'p' | 297 | moveq r0, #'p' @ yes, error 'p' |
120 | beq __error | 298 | THUMB( it eq ) @ force fixup-able long branch encoding |
299 | beq __error_p | ||
121 | 300 | ||
122 | /* | 301 | /* |
123 | * Use the page tables supplied from __cpu_up. | 302 | * Use the page tables supplied from __cpu_up. |
124 | */ | 303 | */ |
125 | adr r4, __secondary_data | 304 | adr r4, __secondary_data |
126 | ldmia r4, {r5, r7, r12} @ address to jump to after | 305 | ldmia r4, {r5, r7, r12} @ address to jump to after |
127 | sub r4, r4, r5 @ mmu has been enabled | 306 | sub lr, r4, r5 @ mmu has been enabled |
128 | ldr r4, [r7, r4] @ get secondary_data.pgdir | 307 | ldr r4, [r7, lr] @ get secondary_data.pgdir |
308 | add r7, r7, #4 | ||
309 | ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir | ||
129 | adr lr, BSYM(__enable_mmu) @ return address | 310 | adr lr, BSYM(__enable_mmu) @ return address |
130 | mov r13, r12 @ __secondary_switched address | 311 | mov r13, r12 @ __secondary_switched address |
131 | ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor | 312 | ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor |
@@ -143,6 +324,8 @@ ENTRY(__secondary_switched) | |||
143 | b secondary_start_kernel | 324 | b secondary_start_kernel |
144 | ENDPROC(__secondary_switched) | 325 | ENDPROC(__secondary_switched) |
145 | 326 | ||
327 | .align | ||
328 | |||
146 | .type __secondary_data, %object | 329 | .type __secondary_data, %object |
147 | __secondary_data: | 330 | __secondary_data: |
148 | .long . | 331 | .long . |
@@ -156,6 +339,13 @@ __secondary_data: | |||
156 | * Setup common bits before finally enabling the MMU. Essentially | 339 | * Setup common bits before finally enabling the MMU. Essentially |
157 | * this is just loading the page table pointer and domain access | 340 | * this is just loading the page table pointer and domain access |
158 | * registers. | 341 | * registers. |
342 | * | ||
343 | * r0 = cp#15 control register | ||
344 | * r1 = machine ID | ||
345 | * r2 = atags or dtb pointer | ||
346 | * r4 = page table pointer | ||
347 | * r9 = processor ID | ||
348 | * r13 = *virtual* address to jump to upon completion | ||
159 | */ | 349 | */ |
160 | __enable_mmu: | 350 | __enable_mmu: |
161 | #ifdef CONFIG_ALIGNMENT_TRAP | 351 | #ifdef CONFIG_ALIGNMENT_TRAP |
@@ -188,6 +378,9 @@ ENDPROC(__enable_mmu) | |||
188 | * mailing list archives BEFORE sending another post to the list. | 378 | * mailing list archives BEFORE sending another post to the list. |
189 | * | 379 | * |
190 | * r0 = cp#15 control register | 380 | * r0 = cp#15 control register |
381 | * r1 = machine ID | ||
382 | * r2 = atags or dtb pointer | ||
383 | * r9 = processor ID | ||
191 | * r13 = *virtual* address to jump to upon completion | 384 | * r13 = *virtual* address to jump to upon completion |
192 | * | 385 | * |
193 | * other registers depend on the function called upon completion | 386 | * other registers depend on the function called upon completion |
@@ -200,137 +393,200 @@ __turn_mmu_on: | |||
200 | mov r3, r3 | 393 | mov r3, r3 |
201 | mov r3, r13 | 394 | mov r3, r13 |
202 | mov pc, r3 | 395 | mov pc, r3 |
396 | __enable_mmu_end: | ||
203 | ENDPROC(__turn_mmu_on) | 397 | ENDPROC(__turn_mmu_on) |
204 | 398 | ||
205 | 399 | ||
206 | /* | 400 | #ifdef CONFIG_SMP_ON_UP |
207 | * Setup the initial page tables. We only setup the barest | 401 | __INIT |
208 | * amount which are required to get the kernel running, which | 402 | __fixup_smp: |
209 | * generally means mapping in the kernel code. | 403 | and r3, r9, #0x000f0000 @ architecture version |
210 | * | 404 | teq r3, #0x000f0000 @ CPU ID supported? |
211 | * r8 = machinfo | 405 | bne __fixup_smp_on_up @ no, assume UP |
212 | * r9 = cpuid | ||
213 | * r10 = procinfo | ||
214 | * | ||
215 | * Returns: | ||
216 | * r0, r3, r6, r7 corrupted | ||
217 | * r4 = physical page table address | ||
218 | */ | ||
219 | __create_page_tables: | ||
220 | pgtbl r4 @ page table address | ||
221 | 406 | ||
222 | /* | 407 | bic r3, r9, #0x00ff0000 |
223 | * Clear the 16K level 1 swapper page table | 408 | bic r3, r3, #0x0000000f @ mask 0xff00fff0 |
224 | */ | 409 | mov r4, #0x41000000 |
225 | mov r0, r4 | 410 | orr r4, r4, #0x0000b000 |
226 | mov r3, #0 | 411 | orr r4, r4, #0x00000020 @ val 0x4100b020 |
227 | add r6, r0, #0x4000 | 412 | teq r3, r4 @ ARM 11MPCore? |
228 | 1: str r3, [r0], #4 | 413 | moveq pc, lr @ yes, assume SMP |
229 | str r3, [r0], #4 | ||
230 | str r3, [r0], #4 | ||
231 | str r3, [r0], #4 | ||
232 | teq r0, r6 | ||
233 | bne 1b | ||
234 | 414 | ||
235 | ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags | 415 | mrc p15, 0, r0, c0, c0, 5 @ read MPIDR |
416 | and r0, r0, #0xc0000000 @ multiprocessing extensions and | ||
417 | teq r0, #0x80000000 @ not part of a uniprocessor system? | ||
418 | moveq pc, lr @ yes, assume SMP | ||
236 | 419 | ||
237 | /* | 420 | __fixup_smp_on_up: |
238 | * Create identity mapping for first MB of kernel to | 421 | adr r0, 1f |
239 | * cater for the MMU enable. This identity mapping | 422 | ldmia r0, {r3 - r5} |
240 | * will be removed by paging_init(). We use our current program | 423 | sub r3, r0, r3 |
241 | * counter to determine corresponding section base address. | 424 | add r4, r4, r3 |
242 | */ | 425 | add r5, r5, r3 |
243 | mov r6, pc | 426 | b __do_fixup_smp_on_up |
244 | mov r6, r6, lsr #20 @ start of kernel section | 427 | ENDPROC(__fixup_smp) |
245 | orr r3, r7, r6, lsl #20 @ flags + kernel base | ||
246 | str r3, [r4, r6, lsl #2] @ identity mapping | ||
247 | 428 | ||
248 | /* | 429 | .align |
249 | * Now setup the pagetables for our kernel direct | 430 | 1: .word . |
250 | * mapped region. | 431 | .word __smpalt_begin |
251 | */ | 432 | .word __smpalt_end |
252 | add r0, r4, #(KERNEL_START & 0xff000000) >> 18 | ||
253 | str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]! | ||
254 | ldr r6, =(KERNEL_END - 1) | ||
255 | add r0, r0, #4 | ||
256 | add r6, r4, r6, lsr #18 | ||
257 | 1: cmp r0, r6 | ||
258 | add r3, r3, #1 << 20 | ||
259 | strls r3, [r0], #4 | ||
260 | bls 1b | ||
261 | 433 | ||
262 | #ifdef CONFIG_XIP_KERNEL | 434 | .pushsection .data |
263 | /* | 435 | .globl smp_on_up |
264 | * Map some ram to cover our .data and .bss areas. | 436 | smp_on_up: |
265 | */ | 437 | ALT_SMP(.long 1) |
266 | orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) | 438 | ALT_UP(.long 0) |
267 | .if (KERNEL_RAM_PADDR & 0x00f00000) | 439 | .popsection |
268 | orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) | ||
269 | .endif | ||
270 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 | ||
271 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! | ||
272 | ldr r6, =(_end - 1) | ||
273 | add r0, r0, #4 | ||
274 | add r6, r4, r6, lsr #18 | ||
275 | 1: cmp r0, r6 | ||
276 | add r3, r3, #1 << 20 | ||
277 | strls r3, [r0], #4 | ||
278 | bls 1b | ||
279 | #endif | 440 | #endif |
280 | 441 | ||
281 | /* | 442 | .text |
282 | * Then map first 1MB of ram in case it contains our boot params. | 443 | __do_fixup_smp_on_up: |
283 | */ | 444 | cmp r4, r5 |
284 | add r0, r4, #PAGE_OFFSET >> 18 | 445 | movhs pc, lr |
285 | orr r6, r7, #(PHYS_OFFSET & 0xff000000) | 446 | ldmia r4!, {r0, r6} |
286 | .if (PHYS_OFFSET & 0x00f00000) | 447 | ARM( str r6, [r0, r3] ) |
287 | orr r6, r6, #(PHYS_OFFSET & 0x00f00000) | 448 | THUMB( add r0, r0, r3 ) |
288 | .endif | 449 | #ifdef __ARMEB__ |
289 | str r6, [r0] | 450 | THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. |
451 | #endif | ||
452 | THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords | ||
453 | THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. | ||
454 | THUMB( strh r6, [r0] ) | ||
455 | b __do_fixup_smp_on_up | ||
456 | ENDPROC(__do_fixup_smp_on_up) | ||
290 | 457 | ||
291 | #ifdef CONFIG_DEBUG_LL | 458 | ENTRY(fixup_smp) |
292 | ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags | 459 | stmfd sp!, {r4 - r6, lr} |
293 | /* | 460 | mov r4, r0 |
294 | * Map in IO space for serial debugging. | 461 | add r5, r0, r1 |
295 | * This allows debug messages to be output | 462 | mov r3, #0 |
296 | * via a serial console before paging_init. | 463 | bl __do_fixup_smp_on_up |
297 | */ | 464 | ldmfd sp!, {r4 - r6, pc} |
298 | ldr r3, [r8, #MACHINFO_PGOFFIO] | 465 | ENDPROC(fixup_smp) |
299 | add r0, r4, r3 | 466 | |
300 | rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) | 467 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT |
301 | cmp r3, #0x0800 @ limit to 512MB | 468 | |
302 | movhi r3, #0x0800 | 469 | /* __fixup_pv_table - patch the stub instructions with the delta between |
303 | add r6, r0, r3 | 470 | * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and |
304 | ldr r3, [r8, #MACHINFO_PHYSIO] | 471 | * can be expressed by an immediate shifter operand. The stub instruction |
305 | orr r3, r3, r7 | 472 | * has a form of '(add|sub) rd, rn, #imm'. |
306 | 1: str r3, [r0], #4 | 473 | */ |
307 | add r3, r3, #1 << 20 | 474 | __HEAD |
308 | teq r0, r6 | 475 | __fixup_pv_table: |
309 | bne 1b | 476 | adr r0, 1f |
310 | #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) | 477 | ldmia r0, {r3-r5, r7} |
311 | /* | 478 | sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET |
312 | * If we're using the NetWinder or CATS, we also need to map | 479 | add r4, r4, r3 @ adjust table start address |
313 | * in the 16550-type serial port for the debug messages | 480 | add r5, r5, r3 @ adjust table end address |
314 | */ | 481 | add r7, r7, r3 @ adjust __pv_phys_offset address |
315 | add r0, r4, #0xff000000 >> 18 | 482 | str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset |
316 | orr r3, r7, #0x7c000000 | 483 | #ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT |
317 | str r3, [r0] | 484 | mov r6, r3, lsr #24 @ constant for add/sub instructions |
485 | teq r3, r6, lsl #24 @ must be 16MiB aligned | ||
486 | #else | ||
487 | mov r6, r3, lsr #16 @ constant for add/sub instructions | ||
488 | teq r3, r6, lsl #16 @ must be 64kiB aligned | ||
318 | #endif | 489 | #endif |
319 | #ifdef CONFIG_ARCH_RPC | 490 | THUMB( it ne @ cross section branch ) |
320 | /* | 491 | bne __error |
321 | * Map in screen at 0x02000000 & SCREEN2_BASE | 492 | str r6, [r7, #4] @ save to __pv_offset |
322 | * Similar reasons here - for debug. This is | 493 | b __fixup_a_pv_table |
323 | * only for Acorn RiscPC architectures. | 494 | ENDPROC(__fixup_pv_table) |
324 | */ | 495 | |
325 | add r0, r4, #0x02000000 >> 18 | 496 | .align |
326 | orr r3, r7, #0x02000000 | 497 | 1: .long . |
327 | str r3, [r0] | 498 | .long __pv_table_begin |
328 | add r0, r4, #0xd8000000 >> 18 | 499 | .long __pv_table_end |
329 | str r3, [r0] | 500 | 2: .long __pv_phys_offset |
501 | |||
502 | .text | ||
503 | __fixup_a_pv_table: | ||
504 | #ifdef CONFIG_THUMB2_KERNEL | ||
505 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
506 | lsls r0, r6, #24 | ||
507 | lsr r6, #8 | ||
508 | beq 1f | ||
509 | clz r7, r0 | ||
510 | lsr r0, #24 | ||
511 | lsl r0, r7 | ||
512 | bic r0, 0x0080 | ||
513 | lsrs r7, #1 | ||
514 | orrcs r0, #0x0080 | ||
515 | orr r0, r0, r7, lsl #12 | ||
330 | #endif | 516 | #endif |
517 | 1: lsls r6, #24 | ||
518 | beq 4f | ||
519 | clz r7, r6 | ||
520 | lsr r6, #24 | ||
521 | lsl r6, r7 | ||
522 | bic r6, #0x0080 | ||
523 | lsrs r7, #1 | ||
524 | orrcs r6, #0x0080 | ||
525 | orr r6, r6, r7, lsl #12 | ||
526 | orr r6, #0x4000 | ||
527 | b 4f | ||
528 | 2: @ at this point the C flag is always clear | ||
529 | add r7, r3 | ||
530 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
531 | ldrh ip, [r7] | ||
532 | tst ip, 0x0400 @ the i bit tells us LS or MS byte | ||
533 | beq 3f | ||
534 | cmp r0, #0 @ set C flag, and ... | ||
535 | biceq ip, 0x0400 @ immediate zero value has a special encoding | ||
536 | streqh ip, [r7] @ that requires the i bit cleared | ||
537 | #endif | ||
538 | 3: ldrh ip, [r7, #2] | ||
539 | and ip, 0x8f00 | ||
540 | orrcc ip, r6 @ mask in offset bits 31-24 | ||
541 | orrcs ip, r0 @ mask in offset bits 23-16 | ||
542 | strh ip, [r7, #2] | ||
543 | 4: cmp r4, r5 | ||
544 | ldrcc r7, [r4], #4 @ use branch for delay slot | ||
545 | bcc 2b | ||
546 | bx lr | ||
547 | #else | ||
548 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
549 | and r0, r6, #255 @ offset bits 23-16 | ||
550 | mov r6, r6, lsr #8 @ offset bits 31-24 | ||
551 | #else | ||
552 | mov r0, #0 @ just in case... | ||
331 | #endif | 553 | #endif |
554 | b 3f | ||
555 | 2: ldr ip, [r7, r3] | ||
556 | bic ip, ip, #0x000000ff | ||
557 | tst ip, #0x400 @ rotate shift tells us LS or MS byte | ||
558 | orrne ip, ip, r6 @ mask in offset bits 31-24 | ||
559 | orreq ip, ip, r0 @ mask in offset bits 23-16 | ||
560 | str ip, [r7, r3] | ||
561 | 3: cmp r4, r5 | ||
562 | ldrcc r7, [r4], #4 @ use branch for delay slot | ||
563 | bcc 2b | ||
332 | mov pc, lr | 564 | mov pc, lr |
333 | ENDPROC(__create_page_tables) | 565 | #endif |
334 | .ltorg | 566 | ENDPROC(__fixup_a_pv_table) |
567 | |||
568 | ENTRY(fixup_pv_table) | ||
569 | stmfd sp!, {r4 - r7, lr} | ||
570 | ldr r2, 2f @ get address of __pv_phys_offset | ||
571 | mov r3, #0 @ no offset | ||
572 | mov r4, r0 @ r0 = table start | ||
573 | add r5, r0, r1 @ r1 = table size | ||
574 | ldr r6, [r2, #4] @ get __pv_offset | ||
575 | bl __fixup_a_pv_table | ||
576 | ldmfd sp!, {r4 - r7, pc} | ||
577 | ENDPROC(fixup_pv_table) | ||
578 | |||
579 | .align | ||
580 | 2: .long __pv_phys_offset | ||
581 | |||
582 | .data | ||
583 | .globl __pv_phys_offset | ||
584 | .type __pv_phys_offset, %object | ||
585 | __pv_phys_offset: | ||
586 | .long 0 | ||
587 | .size __pv_phys_offset, . - __pv_phys_offset | ||
588 | __pv_offset: | ||
589 | .long 0 | ||
590 | #endif | ||
335 | 591 | ||
336 | #include "head-common.S" | 592 | #include "head-common.S" |
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c new file mode 100644 index 000000000000..87acc25d7a3e --- /dev/null +++ b/arch/arm/kernel/hw_breakpoint.c | |||
@@ -0,0 +1,978 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
14 | * | ||
15 | * Copyright (C) 2009, 2010 ARM Limited | ||
16 | * | ||
17 | * Author: Will Deacon <will.deacon@arm.com> | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, | ||
22 | * using the CPU's debug registers. | ||
23 | */ | ||
24 | #define pr_fmt(fmt) "hw-breakpoint: " fmt | ||
25 | |||
26 | #include <linux/errno.h> | ||
27 | #include <linux/hardirq.h> | ||
28 | #include <linux/perf_event.h> | ||
29 | #include <linux/hw_breakpoint.h> | ||
30 | #include <linux/smp.h> | ||
31 | |||
32 | #include <asm/cacheflush.h> | ||
33 | #include <asm/cputype.h> | ||
34 | #include <asm/current.h> | ||
35 | #include <asm/hw_breakpoint.h> | ||
36 | #include <asm/kdebug.h> | ||
37 | #include <asm/system.h> | ||
38 | #include <asm/traps.h> | ||
39 | |||
40 | /* Breakpoint currently in use for each BRP. */ | ||
41 | static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); | ||
42 | |||
43 | /* Watchpoint currently in use for each WRP. */ | ||
44 | static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); | ||
45 | |||
46 | /* Number of BRP/WRP registers on this CPU. */ | ||
47 | static int core_num_brps; | ||
48 | static int core_num_reserved_brps; | ||
49 | static int core_num_wrps; | ||
50 | |||
51 | /* Debug architecture version. */ | ||
52 | static u8 debug_arch; | ||
53 | |||
54 | /* Maximum supported watchpoint length. */ | ||
55 | static u8 max_watchpoint_len; | ||
56 | |||
57 | #define READ_WB_REG_CASE(OP2, M, VAL) \ | ||
58 | case ((OP2 << 4) + M): \ | ||
59 | ARM_DBG_READ(c ## M, OP2, VAL); \ | ||
60 | break | ||
61 | |||
62 | #define WRITE_WB_REG_CASE(OP2, M, VAL) \ | ||
63 | case ((OP2 << 4) + M): \ | ||
64 | ARM_DBG_WRITE(c ## M, OP2, VAL);\ | ||
65 | break | ||
66 | |||
67 | #define GEN_READ_WB_REG_CASES(OP2, VAL) \ | ||
68 | READ_WB_REG_CASE(OP2, 0, VAL); \ | ||
69 | READ_WB_REG_CASE(OP2, 1, VAL); \ | ||
70 | READ_WB_REG_CASE(OP2, 2, VAL); \ | ||
71 | READ_WB_REG_CASE(OP2, 3, VAL); \ | ||
72 | READ_WB_REG_CASE(OP2, 4, VAL); \ | ||
73 | READ_WB_REG_CASE(OP2, 5, VAL); \ | ||
74 | READ_WB_REG_CASE(OP2, 6, VAL); \ | ||
75 | READ_WB_REG_CASE(OP2, 7, VAL); \ | ||
76 | READ_WB_REG_CASE(OP2, 8, VAL); \ | ||
77 | READ_WB_REG_CASE(OP2, 9, VAL); \ | ||
78 | READ_WB_REG_CASE(OP2, 10, VAL); \ | ||
79 | READ_WB_REG_CASE(OP2, 11, VAL); \ | ||
80 | READ_WB_REG_CASE(OP2, 12, VAL); \ | ||
81 | READ_WB_REG_CASE(OP2, 13, VAL); \ | ||
82 | READ_WB_REG_CASE(OP2, 14, VAL); \ | ||
83 | READ_WB_REG_CASE(OP2, 15, VAL) | ||
84 | |||
85 | #define GEN_WRITE_WB_REG_CASES(OP2, VAL) \ | ||
86 | WRITE_WB_REG_CASE(OP2, 0, VAL); \ | ||
87 | WRITE_WB_REG_CASE(OP2, 1, VAL); \ | ||
88 | WRITE_WB_REG_CASE(OP2, 2, VAL); \ | ||
89 | WRITE_WB_REG_CASE(OP2, 3, VAL); \ | ||
90 | WRITE_WB_REG_CASE(OP2, 4, VAL); \ | ||
91 | WRITE_WB_REG_CASE(OP2, 5, VAL); \ | ||
92 | WRITE_WB_REG_CASE(OP2, 6, VAL); \ | ||
93 | WRITE_WB_REG_CASE(OP2, 7, VAL); \ | ||
94 | WRITE_WB_REG_CASE(OP2, 8, VAL); \ | ||
95 | WRITE_WB_REG_CASE(OP2, 9, VAL); \ | ||
96 | WRITE_WB_REG_CASE(OP2, 10, VAL); \ | ||
97 | WRITE_WB_REG_CASE(OP2, 11, VAL); \ | ||
98 | WRITE_WB_REG_CASE(OP2, 12, VAL); \ | ||
99 | WRITE_WB_REG_CASE(OP2, 13, VAL); \ | ||
100 | WRITE_WB_REG_CASE(OP2, 14, VAL); \ | ||
101 | WRITE_WB_REG_CASE(OP2, 15, VAL) | ||
102 | |||
103 | static u32 read_wb_reg(int n) | ||
104 | { | ||
105 | u32 val = 0; | ||
106 | |||
107 | switch (n) { | ||
108 | GEN_READ_WB_REG_CASES(ARM_OP2_BVR, val); | ||
109 | GEN_READ_WB_REG_CASES(ARM_OP2_BCR, val); | ||
110 | GEN_READ_WB_REG_CASES(ARM_OP2_WVR, val); | ||
111 | GEN_READ_WB_REG_CASES(ARM_OP2_WCR, val); | ||
112 | default: | ||
113 | pr_warning("attempt to read from unknown breakpoint " | ||
114 | "register %d\n", n); | ||
115 | } | ||
116 | |||
117 | return val; | ||
118 | } | ||
119 | |||
120 | static void write_wb_reg(int n, u32 val) | ||
121 | { | ||
122 | switch (n) { | ||
123 | GEN_WRITE_WB_REG_CASES(ARM_OP2_BVR, val); | ||
124 | GEN_WRITE_WB_REG_CASES(ARM_OP2_BCR, val); | ||
125 | GEN_WRITE_WB_REG_CASES(ARM_OP2_WVR, val); | ||
126 | GEN_WRITE_WB_REG_CASES(ARM_OP2_WCR, val); | ||
127 | default: | ||
128 | pr_warning("attempt to write to unknown breakpoint " | ||
129 | "register %d\n", n); | ||
130 | } | ||
131 | isb(); | ||
132 | } | ||
133 | |||
134 | /* Determine debug architecture. */ | ||
135 | static u8 get_debug_arch(void) | ||
136 | { | ||
137 | u32 didr; | ||
138 | |||
139 | /* Do we implement the extended CPUID interface? */ | ||
140 | if (WARN_ONCE((((read_cpuid_id() >> 16) & 0xf) != 0xf), | ||
141 | "CPUID feature registers not supported. " | ||
142 | "Assuming v6 debug is present.\n")) | ||
143 | return ARM_DEBUG_ARCH_V6; | ||
144 | |||
145 | ARM_DBG_READ(c0, 0, didr); | ||
146 | return (didr >> 16) & 0xf; | ||
147 | } | ||
148 | |||
149 | u8 arch_get_debug_arch(void) | ||
150 | { | ||
151 | return debug_arch; | ||
152 | } | ||
153 | |||
154 | static int debug_arch_supported(void) | ||
155 | { | ||
156 | u8 arch = get_debug_arch(); | ||
157 | return arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14; | ||
158 | } | ||
159 | |||
160 | /* Determine number of BRP register available. */ | ||
161 | static int get_num_brp_resources(void) | ||
162 | { | ||
163 | u32 didr; | ||
164 | ARM_DBG_READ(c0, 0, didr); | ||
165 | return ((didr >> 24) & 0xf) + 1; | ||
166 | } | ||
167 | |||
168 | /* Does this core support mismatch breakpoints? */ | ||
169 | static int core_has_mismatch_brps(void) | ||
170 | { | ||
171 | return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 && | ||
172 | get_num_brp_resources() > 1); | ||
173 | } | ||
174 | |||
175 | /* Determine number of usable WRPs available. */ | ||
176 | static int get_num_wrps(void) | ||
177 | { | ||
178 | /* | ||
179 | * FIXME: When a watchpoint fires, the only way to work out which | ||
180 | * watchpoint it was is by disassembling the faulting instruction | ||
181 | * and working out the address of the memory access. | ||
182 | * | ||
183 | * Furthermore, we can only do this if the watchpoint was precise | ||
184 | * since imprecise watchpoints prevent us from calculating register | ||
185 | * based addresses. | ||
186 | * | ||
187 | * Providing we have more than 1 breakpoint register, we only report | ||
188 | * a single watchpoint register for the time being. This way, we always | ||
189 | * know which watchpoint fired. In the future we can either add a | ||
190 | * disassembler and address generation emulator, or we can insert a | ||
191 | * check to see if the DFAR is set on watchpoint exception entry | ||
192 | * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows | ||
193 | * that it is set on some implementations]. | ||
194 | */ | ||
195 | |||
196 | #if 0 | ||
197 | int wrps; | ||
198 | u32 didr; | ||
199 | ARM_DBG_READ(c0, 0, didr); | ||
200 | wrps = ((didr >> 28) & 0xf) + 1; | ||
201 | #endif | ||
202 | int wrps = 1; | ||
203 | |||
204 | if (core_has_mismatch_brps() && wrps >= get_num_brp_resources()) | ||
205 | wrps = get_num_brp_resources() - 1; | ||
206 | |||
207 | return wrps; | ||
208 | } | ||
209 | |||
210 | /* We reserve one breakpoint for each watchpoint. */ | ||
211 | static int get_num_reserved_brps(void) | ||
212 | { | ||
213 | if (core_has_mismatch_brps()) | ||
214 | return get_num_wrps(); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* Determine number of usable BRPs available. */ | ||
219 | static int get_num_brps(void) | ||
220 | { | ||
221 | int brps = get_num_brp_resources(); | ||
222 | if (core_has_mismatch_brps()) | ||
223 | brps -= get_num_reserved_brps(); | ||
224 | return brps; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * In order to access the breakpoint/watchpoint control registers, | ||
229 | * we must be running in debug monitor mode. Unfortunately, we can | ||
230 | * be put into halting debug mode at any time by an external debugger | ||
231 | * but there is nothing we can do to prevent that. | ||
232 | */ | ||
233 | static int enable_monitor_mode(void) | ||
234 | { | ||
235 | u32 dscr; | ||
236 | int ret = 0; | ||
237 | |||
238 | ARM_DBG_READ(c1, 0, dscr); | ||
239 | |||
240 | /* Ensure that halting mode is disabled. */ | ||
241 | if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, | ||
242 | "halting debug mode enabled. Unable to access hardware resources.\n")) { | ||
243 | ret = -EPERM; | ||
244 | goto out; | ||
245 | } | ||
246 | |||
247 | /* If monitor mode is already enabled, just return. */ | ||
248 | if (dscr & ARM_DSCR_MDBGEN) | ||
249 | goto out; | ||
250 | |||
251 | /* Write to the corresponding DSCR. */ | ||
252 | switch (get_debug_arch()) { | ||
253 | case ARM_DEBUG_ARCH_V6: | ||
254 | case ARM_DEBUG_ARCH_V6_1: | ||
255 | ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN)); | ||
256 | break; | ||
257 | case ARM_DEBUG_ARCH_V7_ECP14: | ||
258 | ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN)); | ||
259 | break; | ||
260 | default: | ||
261 | ret = -ENODEV; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | /* Check that the write made it through. */ | ||
266 | ARM_DBG_READ(c1, 0, dscr); | ||
267 | if (!(dscr & ARM_DSCR_MDBGEN)) | ||
268 | ret = -EPERM; | ||
269 | |||
270 | out: | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | int hw_breakpoint_slots(int type) | ||
275 | { | ||
276 | if (!debug_arch_supported()) | ||
277 | return 0; | ||
278 | |||
279 | /* | ||
280 | * We can be called early, so don't rely on | ||
281 | * our static variables being initialised. | ||
282 | */ | ||
283 | switch (type) { | ||
284 | case TYPE_INST: | ||
285 | return get_num_brps(); | ||
286 | case TYPE_DATA: | ||
287 | return get_num_wrps(); | ||
288 | default: | ||
289 | pr_warning("unknown slot type: %d\n", type); | ||
290 | return 0; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Check if 8-bit byte-address select is available. | ||
296 | * This clobbers WRP 0. | ||
297 | */ | ||
298 | static u8 get_max_wp_len(void) | ||
299 | { | ||
300 | u32 ctrl_reg; | ||
301 | struct arch_hw_breakpoint_ctrl ctrl; | ||
302 | u8 size = 4; | ||
303 | |||
304 | if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14) | ||
305 | goto out; | ||
306 | |||
307 | memset(&ctrl, 0, sizeof(ctrl)); | ||
308 | ctrl.len = ARM_BREAKPOINT_LEN_8; | ||
309 | ctrl_reg = encode_ctrl_reg(ctrl); | ||
310 | |||
311 | write_wb_reg(ARM_BASE_WVR, 0); | ||
312 | write_wb_reg(ARM_BASE_WCR, ctrl_reg); | ||
313 | if ((read_wb_reg(ARM_BASE_WCR) & ctrl_reg) == ctrl_reg) | ||
314 | size = 8; | ||
315 | |||
316 | out: | ||
317 | return size; | ||
318 | } | ||
319 | |||
320 | u8 arch_get_max_wp_len(void) | ||
321 | { | ||
322 | return max_watchpoint_len; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Install a perf counter breakpoint. | ||
327 | */ | ||
328 | int arch_install_hw_breakpoint(struct perf_event *bp) | ||
329 | { | ||
330 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
331 | struct perf_event **slot, **slots; | ||
332 | int i, max_slots, ctrl_base, val_base, ret = 0; | ||
333 | u32 addr, ctrl; | ||
334 | |||
335 | /* Ensure that we are in monitor mode and halting mode is disabled. */ | ||
336 | ret = enable_monitor_mode(); | ||
337 | if (ret) | ||
338 | goto out; | ||
339 | |||
340 | addr = info->address; | ||
341 | ctrl = encode_ctrl_reg(info->ctrl) | 0x1; | ||
342 | |||
343 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
344 | /* Breakpoint */ | ||
345 | ctrl_base = ARM_BASE_BCR; | ||
346 | val_base = ARM_BASE_BVR; | ||
347 | slots = (struct perf_event **)__get_cpu_var(bp_on_reg); | ||
348 | max_slots = core_num_brps; | ||
349 | if (info->step_ctrl.enabled) { | ||
350 | /* Override the breakpoint data with the step data. */ | ||
351 | addr = info->trigger & ~0x3; | ||
352 | ctrl = encode_ctrl_reg(info->step_ctrl); | ||
353 | } | ||
354 | } else { | ||
355 | /* Watchpoint */ | ||
356 | if (info->step_ctrl.enabled) { | ||
357 | /* Install into the reserved breakpoint region. */ | ||
358 | ctrl_base = ARM_BASE_BCR + core_num_brps; | ||
359 | val_base = ARM_BASE_BVR + core_num_brps; | ||
360 | /* Override the watchpoint data with the step data. */ | ||
361 | addr = info->trigger & ~0x3; | ||
362 | ctrl = encode_ctrl_reg(info->step_ctrl); | ||
363 | } else { | ||
364 | ctrl_base = ARM_BASE_WCR; | ||
365 | val_base = ARM_BASE_WVR; | ||
366 | } | ||
367 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | ||
368 | max_slots = core_num_wrps; | ||
369 | } | ||
370 | |||
371 | for (i = 0; i < max_slots; ++i) { | ||
372 | slot = &slots[i]; | ||
373 | |||
374 | if (!*slot) { | ||
375 | *slot = bp; | ||
376 | break; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) { | ||
381 | ret = -EBUSY; | ||
382 | goto out; | ||
383 | } | ||
384 | |||
385 | /* Setup the address register. */ | ||
386 | write_wb_reg(val_base + i, addr); | ||
387 | |||
388 | /* Setup the control register. */ | ||
389 | write_wb_reg(ctrl_base + i, ctrl); | ||
390 | |||
391 | out: | ||
392 | return ret; | ||
393 | } | ||
394 | |||
395 | void arch_uninstall_hw_breakpoint(struct perf_event *bp) | ||
396 | { | ||
397 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
398 | struct perf_event **slot, **slots; | ||
399 | int i, max_slots, base; | ||
400 | |||
401 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
402 | /* Breakpoint */ | ||
403 | base = ARM_BASE_BCR; | ||
404 | slots = (struct perf_event **)__get_cpu_var(bp_on_reg); | ||
405 | max_slots = core_num_brps; | ||
406 | } else { | ||
407 | /* Watchpoint */ | ||
408 | if (info->step_ctrl.enabled) | ||
409 | base = ARM_BASE_BCR + core_num_brps; | ||
410 | else | ||
411 | base = ARM_BASE_WCR; | ||
412 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | ||
413 | max_slots = core_num_wrps; | ||
414 | } | ||
415 | |||
416 | /* Remove the breakpoint. */ | ||
417 | for (i = 0; i < max_slots; ++i) { | ||
418 | slot = &slots[i]; | ||
419 | |||
420 | if (*slot == bp) { | ||
421 | *slot = NULL; | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) | ||
427 | return; | ||
428 | |||
429 | /* Reset the control register. */ | ||
430 | write_wb_reg(base + i, 0); | ||
431 | } | ||
432 | |||
433 | static int get_hbp_len(u8 hbp_len) | ||
434 | { | ||
435 | unsigned int len_in_bytes = 0; | ||
436 | |||
437 | switch (hbp_len) { | ||
438 | case ARM_BREAKPOINT_LEN_1: | ||
439 | len_in_bytes = 1; | ||
440 | break; | ||
441 | case ARM_BREAKPOINT_LEN_2: | ||
442 | len_in_bytes = 2; | ||
443 | break; | ||
444 | case ARM_BREAKPOINT_LEN_4: | ||
445 | len_in_bytes = 4; | ||
446 | break; | ||
447 | case ARM_BREAKPOINT_LEN_8: | ||
448 | len_in_bytes = 8; | ||
449 | break; | ||
450 | } | ||
451 | |||
452 | return len_in_bytes; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Check whether bp virtual address is in kernel space. | ||
457 | */ | ||
458 | int arch_check_bp_in_kernelspace(struct perf_event *bp) | ||
459 | { | ||
460 | unsigned int len; | ||
461 | unsigned long va; | ||
462 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
463 | |||
464 | va = info->address; | ||
465 | len = get_hbp_len(info->ctrl.len); | ||
466 | |||
467 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl. | ||
472 | * Hopefully this will disappear when ptrace can bypass the conversion | ||
473 | * to generic breakpoint descriptions. | ||
474 | */ | ||
475 | int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, | ||
476 | int *gen_len, int *gen_type) | ||
477 | { | ||
478 | /* Type */ | ||
479 | switch (ctrl.type) { | ||
480 | case ARM_BREAKPOINT_EXECUTE: | ||
481 | *gen_type = HW_BREAKPOINT_X; | ||
482 | break; | ||
483 | case ARM_BREAKPOINT_LOAD: | ||
484 | *gen_type = HW_BREAKPOINT_R; | ||
485 | break; | ||
486 | case ARM_BREAKPOINT_STORE: | ||
487 | *gen_type = HW_BREAKPOINT_W; | ||
488 | break; | ||
489 | case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE: | ||
490 | *gen_type = HW_BREAKPOINT_RW; | ||
491 | break; | ||
492 | default: | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | /* Len */ | ||
497 | switch (ctrl.len) { | ||
498 | case ARM_BREAKPOINT_LEN_1: | ||
499 | *gen_len = HW_BREAKPOINT_LEN_1; | ||
500 | break; | ||
501 | case ARM_BREAKPOINT_LEN_2: | ||
502 | *gen_len = HW_BREAKPOINT_LEN_2; | ||
503 | break; | ||
504 | case ARM_BREAKPOINT_LEN_4: | ||
505 | *gen_len = HW_BREAKPOINT_LEN_4; | ||
506 | break; | ||
507 | case ARM_BREAKPOINT_LEN_8: | ||
508 | *gen_len = HW_BREAKPOINT_LEN_8; | ||
509 | break; | ||
510 | default: | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Construct an arch_hw_breakpoint from a perf_event. | ||
519 | */ | ||
520 | static int arch_build_bp_info(struct perf_event *bp) | ||
521 | { | ||
522 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
523 | |||
524 | /* Type */ | ||
525 | switch (bp->attr.bp_type) { | ||
526 | case HW_BREAKPOINT_X: | ||
527 | info->ctrl.type = ARM_BREAKPOINT_EXECUTE; | ||
528 | break; | ||
529 | case HW_BREAKPOINT_R: | ||
530 | info->ctrl.type = ARM_BREAKPOINT_LOAD; | ||
531 | break; | ||
532 | case HW_BREAKPOINT_W: | ||
533 | info->ctrl.type = ARM_BREAKPOINT_STORE; | ||
534 | break; | ||
535 | case HW_BREAKPOINT_RW: | ||
536 | info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; | ||
537 | break; | ||
538 | default: | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | /* Len */ | ||
543 | switch (bp->attr.bp_len) { | ||
544 | case HW_BREAKPOINT_LEN_1: | ||
545 | info->ctrl.len = ARM_BREAKPOINT_LEN_1; | ||
546 | break; | ||
547 | case HW_BREAKPOINT_LEN_2: | ||
548 | info->ctrl.len = ARM_BREAKPOINT_LEN_2; | ||
549 | break; | ||
550 | case HW_BREAKPOINT_LEN_4: | ||
551 | info->ctrl.len = ARM_BREAKPOINT_LEN_4; | ||
552 | break; | ||
553 | case HW_BREAKPOINT_LEN_8: | ||
554 | info->ctrl.len = ARM_BREAKPOINT_LEN_8; | ||
555 | if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE) | ||
556 | && max_watchpoint_len >= 8) | ||
557 | break; | ||
558 | default: | ||
559 | return -EINVAL; | ||
560 | } | ||
561 | |||
562 | /* | ||
563 | * Breakpoints must be of length 2 (thumb) or 4 (ARM) bytes. | ||
564 | * Watchpoints can be of length 1, 2, 4 or 8 bytes if supported | ||
565 | * by the hardware and must be aligned to the appropriate number of | ||
566 | * bytes. | ||
567 | */ | ||
568 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE && | ||
569 | info->ctrl.len != ARM_BREAKPOINT_LEN_2 && | ||
570 | info->ctrl.len != ARM_BREAKPOINT_LEN_4) | ||
571 | return -EINVAL; | ||
572 | |||
573 | /* Address */ | ||
574 | info->address = bp->attr.bp_addr; | ||
575 | |||
576 | /* Privilege */ | ||
577 | info->ctrl.privilege = ARM_BREAKPOINT_USER; | ||
578 | if (arch_check_bp_in_kernelspace(bp)) | ||
579 | info->ctrl.privilege |= ARM_BREAKPOINT_PRIV; | ||
580 | |||
581 | /* Enabled? */ | ||
582 | info->ctrl.enabled = !bp->attr.disabled; | ||
583 | |||
584 | /* Mismatch */ | ||
585 | info->ctrl.mismatch = 0; | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | * Validate the arch-specific HW Breakpoint register settings. | ||
592 | */ | ||
593 | int arch_validate_hwbkpt_settings(struct perf_event *bp) | ||
594 | { | ||
595 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
596 | int ret = 0; | ||
597 | u32 offset, alignment_mask = 0x3; | ||
598 | |||
599 | /* Build the arch_hw_breakpoint. */ | ||
600 | ret = arch_build_bp_info(bp); | ||
601 | if (ret) | ||
602 | goto out; | ||
603 | |||
604 | /* Check address alignment. */ | ||
605 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) | ||
606 | alignment_mask = 0x7; | ||
607 | offset = info->address & alignment_mask; | ||
608 | switch (offset) { | ||
609 | case 0: | ||
610 | /* Aligned */ | ||
611 | break; | ||
612 | case 1: | ||
613 | /* Allow single byte watchpoint. */ | ||
614 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) | ||
615 | break; | ||
616 | case 2: | ||
617 | /* Allow halfword watchpoints and breakpoints. */ | ||
618 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) | ||
619 | break; | ||
620 | default: | ||
621 | ret = -EINVAL; | ||
622 | goto out; | ||
623 | } | ||
624 | |||
625 | info->address &= ~alignment_mask; | ||
626 | info->ctrl.len <<= offset; | ||
627 | |||
628 | /* | ||
629 | * Currently we rely on an overflow handler to take | ||
630 | * care of single-stepping the breakpoint when it fires. | ||
631 | * In the case of userspace breakpoints on a core with V7 debug, | ||
632 | * we can use the mismatch feature as a poor-man's hardware | ||
633 | * single-step, but this only works for per-task breakpoints. | ||
634 | */ | ||
635 | if (WARN_ONCE(!bp->overflow_handler && | ||
636 | (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps() | ||
637 | || !bp->hw.bp_target), | ||
638 | "overflow handler required but none found\n")) { | ||
639 | ret = -EINVAL; | ||
640 | } | ||
641 | out: | ||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * Enable/disable single-stepping over the breakpoint bp at address addr. | ||
647 | */ | ||
648 | static void enable_single_step(struct perf_event *bp, u32 addr) | ||
649 | { | ||
650 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
651 | |||
652 | arch_uninstall_hw_breakpoint(bp); | ||
653 | info->step_ctrl.mismatch = 1; | ||
654 | info->step_ctrl.len = ARM_BREAKPOINT_LEN_4; | ||
655 | info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE; | ||
656 | info->step_ctrl.privilege = info->ctrl.privilege; | ||
657 | info->step_ctrl.enabled = 1; | ||
658 | info->trigger = addr; | ||
659 | arch_install_hw_breakpoint(bp); | ||
660 | } | ||
661 | |||
662 | static void disable_single_step(struct perf_event *bp) | ||
663 | { | ||
664 | arch_uninstall_hw_breakpoint(bp); | ||
665 | counter_arch_bp(bp)->step_ctrl.enabled = 0; | ||
666 | arch_install_hw_breakpoint(bp); | ||
667 | } | ||
668 | |||
669 | static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) | ||
670 | { | ||
671 | int i; | ||
672 | struct perf_event *wp, **slots; | ||
673 | struct arch_hw_breakpoint *info; | ||
674 | |||
675 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | ||
676 | |||
677 | /* Without a disassembler, we can only handle 1 watchpoint. */ | ||
678 | BUG_ON(core_num_wrps > 1); | ||
679 | |||
680 | for (i = 0; i < core_num_wrps; ++i) { | ||
681 | rcu_read_lock(); | ||
682 | |||
683 | wp = slots[i]; | ||
684 | |||
685 | if (wp == NULL) { | ||
686 | rcu_read_unlock(); | ||
687 | continue; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * The DFAR is an unknown value. Since we only allow a | ||
692 | * single watchpoint, we can set the trigger to the lowest | ||
693 | * possible faulting address. | ||
694 | */ | ||
695 | info = counter_arch_bp(wp); | ||
696 | info->trigger = wp->attr.bp_addr; | ||
697 | pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); | ||
698 | perf_bp_event(wp, regs); | ||
699 | |||
700 | /* | ||
701 | * If no overflow handler is present, insert a temporary | ||
702 | * mismatch breakpoint so we can single-step over the | ||
703 | * watchpoint trigger. | ||
704 | */ | ||
705 | if (!wp->overflow_handler) | ||
706 | enable_single_step(wp, instruction_pointer(regs)); | ||
707 | |||
708 | rcu_read_unlock(); | ||
709 | } | ||
710 | } | ||
711 | |||
712 | static void watchpoint_single_step_handler(unsigned long pc) | ||
713 | { | ||
714 | int i; | ||
715 | struct perf_event *wp, **slots; | ||
716 | struct arch_hw_breakpoint *info; | ||
717 | |||
718 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | ||
719 | |||
720 | for (i = 0; i < core_num_reserved_brps; ++i) { | ||
721 | rcu_read_lock(); | ||
722 | |||
723 | wp = slots[i]; | ||
724 | |||
725 | if (wp == NULL) | ||
726 | goto unlock; | ||
727 | |||
728 | info = counter_arch_bp(wp); | ||
729 | if (!info->step_ctrl.enabled) | ||
730 | goto unlock; | ||
731 | |||
732 | /* | ||
733 | * Restore the original watchpoint if we've completed the | ||
734 | * single-step. | ||
735 | */ | ||
736 | if (info->trigger != pc) | ||
737 | disable_single_step(wp); | ||
738 | |||
739 | unlock: | ||
740 | rcu_read_unlock(); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) | ||
745 | { | ||
746 | int i; | ||
747 | u32 ctrl_reg, val, addr; | ||
748 | struct perf_event *bp, **slots; | ||
749 | struct arch_hw_breakpoint *info; | ||
750 | struct arch_hw_breakpoint_ctrl ctrl; | ||
751 | |||
752 | slots = (struct perf_event **)__get_cpu_var(bp_on_reg); | ||
753 | |||
754 | /* The exception entry code places the amended lr in the PC. */ | ||
755 | addr = regs->ARM_pc; | ||
756 | |||
757 | /* Check the currently installed breakpoints first. */ | ||
758 | for (i = 0; i < core_num_brps; ++i) { | ||
759 | rcu_read_lock(); | ||
760 | |||
761 | bp = slots[i]; | ||
762 | |||
763 | if (bp == NULL) | ||
764 | goto unlock; | ||
765 | |||
766 | info = counter_arch_bp(bp); | ||
767 | |||
768 | /* Check if the breakpoint value matches. */ | ||
769 | val = read_wb_reg(ARM_BASE_BVR + i); | ||
770 | if (val != (addr & ~0x3)) | ||
771 | goto mismatch; | ||
772 | |||
773 | /* Possible match, check the byte address select to confirm. */ | ||
774 | ctrl_reg = read_wb_reg(ARM_BASE_BCR + i); | ||
775 | decode_ctrl_reg(ctrl_reg, &ctrl); | ||
776 | if ((1 << (addr & 0x3)) & ctrl.len) { | ||
777 | info->trigger = addr; | ||
778 | pr_debug("breakpoint fired: address = 0x%x\n", addr); | ||
779 | perf_bp_event(bp, regs); | ||
780 | if (!bp->overflow_handler) | ||
781 | enable_single_step(bp, addr); | ||
782 | goto unlock; | ||
783 | } | ||
784 | |||
785 | mismatch: | ||
786 | /* If we're stepping a breakpoint, it can now be restored. */ | ||
787 | if (info->step_ctrl.enabled) | ||
788 | disable_single_step(bp); | ||
789 | unlock: | ||
790 | rcu_read_unlock(); | ||
791 | } | ||
792 | |||
793 | /* Handle any pending watchpoint single-step breakpoints. */ | ||
794 | watchpoint_single_step_handler(addr); | ||
795 | } | ||
796 | |||
797 | /* | ||
798 | * Called from either the Data Abort Handler [watchpoint] or the | ||
799 | * Prefetch Abort Handler [breakpoint] with preemption disabled. | ||
800 | */ | ||
801 | static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, | ||
802 | struct pt_regs *regs) | ||
803 | { | ||
804 | int ret = 0; | ||
805 | u32 dscr; | ||
806 | |||
807 | /* We must be called with preemption disabled. */ | ||
808 | WARN_ON(preemptible()); | ||
809 | |||
810 | /* We only handle watchpoints and hardware breakpoints. */ | ||
811 | ARM_DBG_READ(c1, 0, dscr); | ||
812 | |||
813 | /* Perform perf callbacks. */ | ||
814 | switch (ARM_DSCR_MOE(dscr)) { | ||
815 | case ARM_ENTRY_BREAKPOINT: | ||
816 | breakpoint_handler(addr, regs); | ||
817 | break; | ||
818 | case ARM_ENTRY_ASYNC_WATCHPOINT: | ||
819 | WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); | ||
820 | case ARM_ENTRY_SYNC_WATCHPOINT: | ||
821 | watchpoint_handler(addr, regs); | ||
822 | break; | ||
823 | default: | ||
824 | ret = 1; /* Unhandled fault. */ | ||
825 | } | ||
826 | |||
827 | /* | ||
828 | * Re-enable preemption after it was disabled in the | ||
829 | * low-level exception handling code. | ||
830 | */ | ||
831 | preempt_enable(); | ||
832 | |||
833 | return ret; | ||
834 | } | ||
835 | |||
836 | /* | ||
837 | * One-time initialisation. | ||
838 | */ | ||
839 | static void reset_ctrl_regs(void *info) | ||
840 | { | ||
841 | int i, cpu = smp_processor_id(); | ||
842 | u32 dbg_power; | ||
843 | cpumask_t *cpumask = info; | ||
844 | |||
845 | /* | ||
846 | * v7 debug contains save and restore registers so that debug state | ||
847 | * can be maintained across low-power modes without leaving the debug | ||
848 | * logic powered up. It is IMPLEMENTATION DEFINED whether we can access | ||
849 | * the debug registers out of reset, so we must unlock the OS Lock | ||
850 | * Access Register to avoid taking undefined instruction exceptions | ||
851 | * later on. | ||
852 | */ | ||
853 | if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) { | ||
854 | /* | ||
855 | * Ensure sticky power-down is clear (i.e. debug logic is | ||
856 | * powered up). | ||
857 | */ | ||
858 | asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power)); | ||
859 | if ((dbg_power & 0x1) == 0) { | ||
860 | pr_warning("CPU %d debug is powered down!\n", cpu); | ||
861 | cpumask_or(cpumask, cpumask, cpumask_of(cpu)); | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | /* | ||
866 | * Unconditionally clear the lock by writing a value | ||
867 | * other than 0xC5ACCE55 to the access register. | ||
868 | */ | ||
869 | asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0)); | ||
870 | isb(); | ||
871 | |||
872 | /* | ||
873 | * Clear any configured vector-catch events before | ||
874 | * enabling monitor mode. | ||
875 | */ | ||
876 | asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0)); | ||
877 | isb(); | ||
878 | } | ||
879 | |||
880 | if (enable_monitor_mode()) | ||
881 | return; | ||
882 | |||
883 | /* We must also reset any reserved registers. */ | ||
884 | for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { | ||
885 | write_wb_reg(ARM_BASE_BCR + i, 0UL); | ||
886 | write_wb_reg(ARM_BASE_BVR + i, 0UL); | ||
887 | } | ||
888 | |||
889 | for (i = 0; i < core_num_wrps; ++i) { | ||
890 | write_wb_reg(ARM_BASE_WCR + i, 0UL); | ||
891 | write_wb_reg(ARM_BASE_WVR + i, 0UL); | ||
892 | } | ||
893 | } | ||
894 | |||
895 | static int __cpuinit dbg_reset_notify(struct notifier_block *self, | ||
896 | unsigned long action, void *cpu) | ||
897 | { | ||
898 | if (action == CPU_ONLINE) | ||
899 | smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1); | ||
900 | return NOTIFY_OK; | ||
901 | } | ||
902 | |||
903 | static struct notifier_block __cpuinitdata dbg_reset_nb = { | ||
904 | .notifier_call = dbg_reset_notify, | ||
905 | }; | ||
906 | |||
907 | static int __init arch_hw_breakpoint_init(void) | ||
908 | { | ||
909 | u32 dscr; | ||
910 | cpumask_t cpumask = { CPU_BITS_NONE }; | ||
911 | |||
912 | debug_arch = get_debug_arch(); | ||
913 | |||
914 | if (!debug_arch_supported()) { | ||
915 | pr_info("debug architecture 0x%x unsupported.\n", debug_arch); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | /* Determine how many BRPs/WRPs are available. */ | ||
920 | core_num_brps = get_num_brps(); | ||
921 | core_num_reserved_brps = get_num_reserved_brps(); | ||
922 | core_num_wrps = get_num_wrps(); | ||
923 | |||
924 | pr_info("found %d breakpoint and %d watchpoint registers.\n", | ||
925 | core_num_brps + core_num_reserved_brps, core_num_wrps); | ||
926 | |||
927 | if (core_num_reserved_brps) | ||
928 | pr_info("%d breakpoint(s) reserved for watchpoint " | ||
929 | "single-step.\n", core_num_reserved_brps); | ||
930 | |||
931 | /* | ||
932 | * Reset the breakpoint resources. We assume that a halting | ||
933 | * debugger will leave the world in a nice state for us. | ||
934 | */ | ||
935 | on_each_cpu(reset_ctrl_regs, &cpumask, 1); | ||
936 | if (!cpumask_empty(&cpumask)) { | ||
937 | core_num_brps = 0; | ||
938 | core_num_reserved_brps = 0; | ||
939 | core_num_wrps = 0; | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | ARM_DBG_READ(c1, 0, dscr); | ||
944 | if (dscr & ARM_DSCR_HDBGEN) { | ||
945 | max_watchpoint_len = 4; | ||
946 | pr_warning("halting debug mode enabled. Assuming maximum watchpoint size of %u bytes.\n", | ||
947 | max_watchpoint_len); | ||
948 | } else { | ||
949 | /* Work out the maximum supported watchpoint length. */ | ||
950 | max_watchpoint_len = get_max_wp_len(); | ||
951 | pr_info("maximum watchpoint size is %u bytes.\n", | ||
952 | max_watchpoint_len); | ||
953 | } | ||
954 | |||
955 | /* Register debug fault handler. */ | ||
956 | hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, | ||
957 | "watchpoint debug exception"); | ||
958 | hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, | ||
959 | "breakpoint debug exception"); | ||
960 | |||
961 | /* Register hotplug notifier. */ | ||
962 | register_cpu_notifier(&dbg_reset_nb); | ||
963 | return 0; | ||
964 | } | ||
965 | arch_initcall(arch_hw_breakpoint_init); | ||
966 | |||
967 | void hw_breakpoint_pmu_read(struct perf_event *bp) | ||
968 | { | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | * Dummy function to register with die_notifier. | ||
973 | */ | ||
974 | int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | ||
975 | unsigned long val, void *data) | ||
976 | { | ||
977 | return NOTIFY_DONE; | ||
978 | } | ||
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index c0d5c3b3a760..83bbad03fcc6 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -35,8 +35,10 @@ | |||
35 | #include <linux/list.h> | 35 | #include <linux/list.h> |
36 | #include <linux/kallsyms.h> | 36 | #include <linux/kallsyms.h> |
37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
38 | #include <linux/ftrace.h> | ||
38 | 39 | ||
39 | #include <asm/system.h> | 40 | #include <asm/system.h> |
41 | #include <asm/mach/arch.h> | ||
40 | #include <asm/mach/irq.h> | 42 | #include <asm/mach/irq.h> |
41 | #include <asm/mach/time.h> | 43 | #include <asm/mach/time.h> |
42 | 44 | ||
@@ -47,56 +49,20 @@ | |||
47 | #define irq_finish(irq) do { } while (0) | 49 | #define irq_finish(irq) do { } while (0) |
48 | #endif | 50 | #endif |
49 | 51 | ||
50 | unsigned int arch_nr_irqs; | ||
51 | void (*init_arch_irq)(void) __initdata = NULL; | ||
52 | unsigned long irq_err_count; | 52 | unsigned long irq_err_count; |
53 | 53 | ||
54 | int show_interrupts(struct seq_file *p, void *v) | 54 | int arch_show_interrupts(struct seq_file *p, int prec) |
55 | { | 55 | { |
56 | int i = *(loff_t *) v, cpu; | ||
57 | struct irq_desc *desc; | ||
58 | struct irqaction * action; | ||
59 | unsigned long flags; | ||
60 | |||
61 | if (i == 0) { | ||
62 | char cpuname[12]; | ||
63 | |||
64 | seq_printf(p, " "); | ||
65 | for_each_present_cpu(cpu) { | ||
66 | sprintf(cpuname, "CPU%d", cpu); | ||
67 | seq_printf(p, " %10s", cpuname); | ||
68 | } | ||
69 | seq_putc(p, '\n'); | ||
70 | } | ||
71 | |||
72 | if (i < nr_irqs) { | ||
73 | desc = irq_to_desc(i); | ||
74 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
75 | action = desc->action; | ||
76 | if (!action) | ||
77 | goto unlock; | ||
78 | |||
79 | seq_printf(p, "%3d: ", i); | ||
80 | for_each_present_cpu(cpu) | ||
81 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); | ||
82 | seq_printf(p, " %10s", desc->chip->name ? : "-"); | ||
83 | seq_printf(p, " %s", action->name); | ||
84 | for (action = action->next; action; action = action->next) | ||
85 | seq_printf(p, ", %s", action->name); | ||
86 | |||
87 | seq_putc(p, '\n'); | ||
88 | unlock: | ||
89 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
90 | } else if (i == nr_irqs) { | ||
91 | #ifdef CONFIG_FIQ | 56 | #ifdef CONFIG_FIQ |
92 | show_fiq_list(p, v); | 57 | show_fiq_list(p, prec); |
93 | #endif | 58 | #endif |
94 | #ifdef CONFIG_SMP | 59 | #ifdef CONFIG_SMP |
95 | show_ipi_list(p); | 60 | show_ipi_list(p, prec); |
96 | show_local_irqs(p); | ||
97 | #endif | 61 | #endif |
98 | seq_printf(p, "Err: %10lu\n", irq_err_count); | 62 | #ifdef CONFIG_LOCAL_TIMERS |
99 | } | 63 | show_local_irqs(p, prec); |
64 | #endif | ||
65 | seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); | ||
100 | return 0; | 66 | return 0; |
101 | } | 67 | } |
102 | 68 | ||
@@ -105,7 +71,8 @@ unlock: | |||
105 | * come via this function. Instead, they should provide their | 71 | * come via this function. Instead, they should provide their |
106 | * own 'handler' | 72 | * own 'handler' |
107 | */ | 73 | */ |
108 | asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | 74 | asmlinkage void __exception_irq_entry |
75 | asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | ||
109 | { | 76 | { |
110 | struct pt_regs *old_regs = set_irq_regs(regs); | 77 | struct pt_regs *old_regs = set_irq_regs(regs); |
111 | 78 | ||
@@ -132,56 +99,53 @@ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | |||
132 | 99 | ||
133 | void set_irq_flags(unsigned int irq, unsigned int iflags) | 100 | void set_irq_flags(unsigned int irq, unsigned int iflags) |
134 | { | 101 | { |
135 | struct irq_desc *desc; | 102 | unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; |
136 | unsigned long flags; | ||
137 | 103 | ||
138 | if (irq >= nr_irqs) { | 104 | if (irq >= nr_irqs) { |
139 | printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); | 105 | printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); |
140 | return; | 106 | return; |
141 | } | 107 | } |
142 | 108 | ||
143 | desc = irq_to_desc(irq); | ||
144 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
145 | desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
146 | if (iflags & IRQF_VALID) | 109 | if (iflags & IRQF_VALID) |
147 | desc->status &= ~IRQ_NOREQUEST; | 110 | clr |= IRQ_NOREQUEST; |
148 | if (iflags & IRQF_PROBE) | 111 | if (iflags & IRQF_PROBE) |
149 | desc->status &= ~IRQ_NOPROBE; | 112 | clr |= IRQ_NOPROBE; |
150 | if (!(iflags & IRQF_NOAUTOEN)) | 113 | if (!(iflags & IRQF_NOAUTOEN)) |
151 | desc->status &= ~IRQ_NOAUTOEN; | 114 | clr |= IRQ_NOAUTOEN; |
152 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 115 | /* Order is clear bits in "clr" then set bits in "set" */ |
116 | irq_modify_status(irq, clr, set & ~clr); | ||
153 | } | 117 | } |
154 | 118 | ||
155 | void __init init_IRQ(void) | 119 | void __init init_IRQ(void) |
156 | { | 120 | { |
157 | struct irq_desc *desc; | 121 | machine_desc->init_irq(); |
158 | int irq; | ||
159 | |||
160 | for (irq = 0; irq < nr_irqs; irq++) { | ||
161 | desc = irq_to_desc_alloc_node(irq, 0); | ||
162 | desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; | ||
163 | } | ||
164 | |||
165 | init_arch_irq(); | ||
166 | } | 122 | } |
167 | 123 | ||
168 | #ifdef CONFIG_SPARSE_IRQ | 124 | #ifdef CONFIG_SPARSE_IRQ |
169 | int __init arch_probe_nr_irqs(void) | 125 | int __init arch_probe_nr_irqs(void) |
170 | { | 126 | { |
171 | nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS; | 127 | nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS; |
172 | return 0; | 128 | return nr_irqs; |
173 | } | 129 | } |
174 | #endif | 130 | #endif |
175 | 131 | ||
176 | #ifdef CONFIG_HOTPLUG_CPU | 132 | #ifdef CONFIG_HOTPLUG_CPU |
177 | 133 | ||
178 | static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) | 134 | static bool migrate_one_irq(struct irq_data *d) |
179 | { | 135 | { |
180 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->node, cpu); | 136 | unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); |
137 | bool ret = false; | ||
138 | |||
139 | if (cpu >= nr_cpu_ids) { | ||
140 | cpu = cpumask_any(cpu_online_mask); | ||
141 | ret = true; | ||
142 | } | ||
181 | 143 | ||
182 | raw_spin_lock_irq(&desc->lock); | 144 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); |
183 | desc->chip->set_affinity(irq, cpumask_of(cpu)); | 145 | |
184 | raw_spin_unlock_irq(&desc->lock); | 146 | d->chip->irq_set_affinity(d, cpumask_of(cpu), true); |
147 | |||
148 | return ret; | ||
185 | } | 149 | } |
186 | 150 | ||
187 | /* | 151 | /* |
@@ -193,23 +157,30 @@ void migrate_irqs(void) | |||
193 | { | 157 | { |
194 | unsigned int i, cpu = smp_processor_id(); | 158 | unsigned int i, cpu = smp_processor_id(); |
195 | struct irq_desc *desc; | 159 | struct irq_desc *desc; |
160 | unsigned long flags; | ||
161 | |||
162 | local_irq_save(flags); | ||
196 | 163 | ||
197 | for_each_irq_desc(i, desc) { | 164 | for_each_irq_desc(i, desc) { |
198 | if (desc->node == cpu) { | 165 | struct irq_data *d = &desc->irq_data; |
199 | unsigned int newcpu = cpumask_any_and(desc->affinity, | 166 | bool affinity_broken = false; |
200 | cpu_online_mask); | 167 | |
201 | if (newcpu >= nr_cpu_ids) { | 168 | raw_spin_lock(&desc->lock); |
202 | if (printk_ratelimit()) | 169 | do { |
203 | printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n", | 170 | if (desc->action == NULL) |
204 | i, cpu); | 171 | break; |
205 | 172 | ||
206 | cpumask_setall(desc->affinity); | 173 | if (d->node != cpu) |
207 | newcpu = cpumask_any_and(desc->affinity, | 174 | break; |
208 | cpu_online_mask); | 175 | |
209 | } | 176 | affinity_broken = migrate_one_irq(d); |
210 | 177 | } while (0); | |
211 | route_irq(desc, i, newcpu); | 178 | raw_spin_unlock(&desc->lock); |
212 | } | 179 | |
180 | if (affinity_broken && printk_ratelimit()) | ||
181 | pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); | ||
213 | } | 182 | } |
183 | |||
184 | local_irq_restore(flags); | ||
214 | } | 185 | } |
215 | #endif /* CONFIG_HOTPLUG_CPU */ | 186 | #endif /* CONFIG_HOTPLUG_CPU */ |
diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index b63b528f22a6..7fa3bb0d2397 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S | |||
@@ -19,6 +19,14 @@ | |||
19 | #include <asm/thread_info.h> | 19 | #include <asm/thread_info.h> |
20 | #include <asm/asm-offsets.h> | 20 | #include <asm/asm-offsets.h> |
21 | 21 | ||
22 | #if defined(CONFIG_CPU_PJ4) | ||
23 | #define PJ4(code...) code | ||
24 | #define XSC(code...) | ||
25 | #else | ||
26 | #define PJ4(code...) | ||
27 | #define XSC(code...) code | ||
28 | #endif | ||
29 | |||
22 | #define MMX_WR0 (0x00) | 30 | #define MMX_WR0 (0x00) |
23 | #define MMX_WR1 (0x08) | 31 | #define MMX_WR1 (0x08) |
24 | #define MMX_WR2 (0x10) | 32 | #define MMX_WR2 (0x10) |
@@ -58,11 +66,17 @@ | |||
58 | 66 | ||
59 | ENTRY(iwmmxt_task_enable) | 67 | ENTRY(iwmmxt_task_enable) |
60 | 68 | ||
61 | mrc p15, 0, r2, c15, c1, 0 | 69 | XSC(mrc p15, 0, r2, c15, c1, 0) |
62 | tst r2, #0x3 @ CP0 and CP1 accessible? | 70 | PJ4(mrc p15, 0, r2, c1, c0, 2) |
71 | @ CP0 and CP1 accessible? | ||
72 | XSC(tst r2, #0x3) | ||
73 | PJ4(tst r2, #0xf) | ||
63 | movne pc, lr @ if so no business here | 74 | movne pc, lr @ if so no business here |
64 | orr r2, r2, #0x3 @ enable access to CP0 and CP1 | 75 | @ enable access to CP0 and CP1 |
65 | mcr p15, 0, r2, c15, c1, 0 | 76 | XSC(orr r2, r2, #0x3) |
77 | XSC(mcr p15, 0, r2, c15, c1, 0) | ||
78 | PJ4(orr r2, r2, #0xf) | ||
79 | PJ4(mcr p15, 0, r2, c1, c0, 2) | ||
66 | 80 | ||
67 | ldr r3, =concan_owner | 81 | ldr r3, =concan_owner |
68 | add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area | 82 | add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area |
@@ -179,17 +193,26 @@ ENTRY(iwmmxt_task_disable) | |||
179 | teqne r1, r2 @ or specified one? | 193 | teqne r1, r2 @ or specified one? |
180 | bne 1f @ no: quit | 194 | bne 1f @ no: quit |
181 | 195 | ||
182 | mrc p15, 0, r4, c15, c1, 0 | 196 | @ enable access to CP0 and CP1 |
183 | orr r4, r4, #0x3 @ enable access to CP0 and CP1 | 197 | XSC(mrc p15, 0, r4, c15, c1, 0) |
184 | mcr p15, 0, r4, c15, c1, 0 | 198 | XSC(orr r4, r4, #0xf) |
199 | XSC(mcr p15, 0, r4, c15, c1, 0) | ||
200 | PJ4(mrc p15, 0, r4, c1, c0, 2) | ||
201 | PJ4(orr r4, r4, #0x3) | ||
202 | PJ4(mcr p15, 0, r4, c1, c0, 2) | ||
203 | |||
185 | mov r0, #0 @ nothing to load | 204 | mov r0, #0 @ nothing to load |
186 | str r0, [r3] @ no more current owner | 205 | str r0, [r3] @ no more current owner |
187 | mrc p15, 0, r2, c2, c0, 0 | 206 | mrc p15, 0, r2, c2, c0, 0 |
188 | mov r2, r2 @ cpwait | 207 | mov r2, r2 @ cpwait |
189 | bl concan_save | 208 | bl concan_save |
190 | 209 | ||
191 | bic r4, r4, #0x3 @ disable access to CP0 and CP1 | 210 | @ disable access to CP0 and CP1 |
192 | mcr p15, 0, r4, c15, c1, 0 | 211 | XSC(bic r4, r4, #0x3) |
212 | XSC(mcr p15, 0, r4, c15, c1, 0) | ||
213 | PJ4(bic r4, r4, #0xf) | ||
214 | PJ4(mcr p15, 0, r4, c1, c0, 2) | ||
215 | |||
193 | mrc p15, 0, r2, c2, c0, 0 | 216 | mrc p15, 0, r2, c2, c0, 0 |
194 | mov r2, r2 @ cpwait | 217 | mov r2, r2 @ cpwait |
195 | 218 | ||
@@ -277,8 +300,11 @@ ENTRY(iwmmxt_task_restore) | |||
277 | */ | 300 | */ |
278 | ENTRY(iwmmxt_task_switch) | 301 | ENTRY(iwmmxt_task_switch) |
279 | 302 | ||
280 | mrc p15, 0, r1, c15, c1, 0 | 303 | XSC(mrc p15, 0, r1, c15, c1, 0) |
281 | tst r1, #0x3 @ CP0 and CP1 accessible? | 304 | PJ4(mrc p15, 0, r1, c1, c0, 2) |
305 | @ CP0 and CP1 accessible? | ||
306 | XSC(tst r1, #0x3) | ||
307 | PJ4(tst r1, #0xf) | ||
282 | bne 1f @ yes: block them for next task | 308 | bne 1f @ yes: block them for next task |
283 | 309 | ||
284 | ldr r2, =concan_owner | 310 | ldr r2, =concan_owner |
@@ -287,8 +313,11 @@ ENTRY(iwmmxt_task_switch) | |||
287 | teq r2, r3 @ next task owns it? | 313 | teq r2, r3 @ next task owns it? |
288 | movne pc, lr @ no: leave Concan disabled | 314 | movne pc, lr @ no: leave Concan disabled |
289 | 315 | ||
290 | 1: eor r1, r1, #3 @ flip Concan access | 316 | 1: @ flip Conan access |
291 | mcr p15, 0, r1, c15, c1, 0 | 317 | XSC(eor r1, r1, #0x3) |
318 | XSC(mcr p15, 0, r1, c15, c1, 0) | ||
319 | PJ4(eor r1, r1, #0xf) | ||
320 | PJ4(mcr p15, 0, r1, c1, c0, 2) | ||
292 | 321 | ||
293 | mrc p15, 0, r1, c2, c0, 0 | 322 | mrc p15, 0, r1, c2, c0, 0 |
294 | sub pc, lr, r1, lsr #32 @ cpwait and return | 323 | sub pc, lr, r1, lsr #32 @ cpwait and return |
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index d6e8b4d2e60d..778c2f7024ff 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
@@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) | |||
79 | return; | 79 | return; |
80 | 80 | ||
81 | /* Initialize to zero */ | 81 | /* Initialize to zero */ |
82 | for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) | 82 | for (regno = 0; regno < GDB_MAX_REGS; regno++) |
83 | gdb_regs[regno] = 0; | 83 | gdb_regs[regno] = 0; |
84 | 84 | ||
85 | /* Otherwise, we have only some registers from switch_to() */ | 85 | /* Otherwise, we have only some registers from switch_to() */ |
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c index 2c1f0050c9c4..15eeff6aea0e 100644 --- a/arch/arm/kernel/kprobes-decode.c +++ b/arch/arm/kernel/kprobes-decode.c | |||
@@ -34,9 +34,6 @@ | |||
34 | * | 34 | * |
35 | * *) If the PC is written to by the instruction, the | 35 | * *) If the PC is written to by the instruction, the |
36 | * instruction must be fully simulated in software. | 36 | * instruction must be fully simulated in software. |
37 | * If it is a conditional instruction, the handler | ||
38 | * will use insn[0] to copy its condition code to | ||
39 | * set r0 to 1 and insn[1] to "mov pc, lr" to return. | ||
40 | * | 37 | * |
41 | * *) Otherwise, a modified form of the instruction is | 38 | * *) Otherwise, a modified form of the instruction is |
42 | * directly executed. Its handler calls the | 39 | * directly executed. Its handler calls the |
@@ -68,13 +65,17 @@ | |||
68 | 65 | ||
69 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | 66 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) |
70 | 67 | ||
68 | #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) | ||
69 | |||
70 | /* | ||
71 | * Test if load/store instructions writeback the address register. | ||
72 | * if P (bit 24) == 0 or W (bit 21) == 1 | ||
73 | */ | ||
74 | #define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) | ||
75 | |||
71 | #define PSR_fs (PSR_f|PSR_s) | 76 | #define PSR_fs (PSR_f|PSR_s) |
72 | 77 | ||
73 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | 78 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ |
74 | #define SET_R0_TRUE_INSTRUCTION 0xe3a00001 /* mov r0, #1 */ | ||
75 | |||
76 | #define truecc_insn(insn) (((insn) & 0xf0000000) | \ | ||
77 | (SET_R0_TRUE_INSTRUCTION & 0x0fffffff)) | ||
78 | 79 | ||
79 | typedef long (insn_0arg_fn_t)(void); | 80 | typedef long (insn_0arg_fn_t)(void); |
80 | typedef long (insn_1arg_fn_t)(long); | 81 | typedef long (insn_1arg_fn_t)(long); |
@@ -419,14 +420,10 @@ insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | |||
419 | 420 | ||
420 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | 421 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) |
421 | { | 422 | { |
422 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
423 | kprobe_opcode_t insn = p->opcode; | 423 | kprobe_opcode_t insn = p->opcode; |
424 | long iaddr = (long)p->addr; | 424 | long iaddr = (long)p->addr; |
425 | int disp = branch_displacement(insn); | 425 | int disp = branch_displacement(insn); |
426 | 426 | ||
427 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
428 | return; | ||
429 | |||
430 | if (insn & (1 << 24)) | 427 | if (insn & (1 << 24)) |
431 | regs->ARM_lr = iaddr + 4; | 428 | regs->ARM_lr = iaddr + 4; |
432 | 429 | ||
@@ -446,14 +443,10 @@ static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | |||
446 | 443 | ||
447 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | 444 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) |
448 | { | 445 | { |
449 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
450 | kprobe_opcode_t insn = p->opcode; | 446 | kprobe_opcode_t insn = p->opcode; |
451 | int rm = insn & 0xf; | 447 | int rm = insn & 0xf; |
452 | long rmv = regs->uregs[rm]; | 448 | long rmv = regs->uregs[rm]; |
453 | 449 | ||
454 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
455 | return; | ||
456 | |||
457 | if (insn & (1 << 5)) | 450 | if (insn & (1 << 5)) |
458 | regs->ARM_lr = (long)p->addr + 4; | 451 | regs->ARM_lr = (long)p->addr + 4; |
459 | 452 | ||
@@ -463,9 +456,16 @@ static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | |||
463 | regs->ARM_cpsr |= PSR_T_BIT; | 456 | regs->ARM_cpsr |= PSR_T_BIT; |
464 | } | 457 | } |
465 | 458 | ||
459 | static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
460 | { | ||
461 | kprobe_opcode_t insn = p->opcode; | ||
462 | int rd = (insn >> 12) & 0xf; | ||
463 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
464 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
465 | } | ||
466 | |||
466 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | 467 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) |
467 | { | 468 | { |
468 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
469 | kprobe_opcode_t insn = p->opcode; | 469 | kprobe_opcode_t insn = p->opcode; |
470 | int rn = (insn >> 16) & 0xf; | 470 | int rn = (insn >> 16) & 0xf; |
471 | int lbit = insn & (1 << 20); | 471 | int lbit = insn & (1 << 20); |
@@ -476,9 +476,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | |||
476 | int reg_bit_vector; | 476 | int reg_bit_vector; |
477 | int reg_count; | 477 | int reg_count; |
478 | 478 | ||
479 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
480 | return; | ||
481 | |||
482 | reg_count = 0; | 479 | reg_count = 0; |
483 | reg_bit_vector = insn & 0xffff; | 480 | reg_bit_vector = insn & 0xffff; |
484 | while (reg_bit_vector) { | 481 | while (reg_bit_vector) { |
@@ -510,11 +507,6 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | |||
510 | 507 | ||
511 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) | 508 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) |
512 | { | 509 | { |
513 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
514 | |||
515 | if (!insnslot_1arg_rflags(0, regs->ARM_cpsr, i_fn)) | ||
516 | return; | ||
517 | |||
518 | regs->ARM_pc = (long)p->addr + str_pc_offset; | 510 | regs->ARM_pc = (long)p->addr + str_pc_offset; |
519 | simulate_ldm1stm1(p, regs); | 511 | simulate_ldm1stm1(p, regs); |
520 | regs->ARM_pc = (long)p->addr + 4; | 512 | regs->ARM_pc = (long)p->addr + 4; |
@@ -525,24 +517,16 @@ static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | |||
525 | regs->uregs[12] = regs->uregs[13]; | 517 | regs->uregs[12] = regs->uregs[13]; |
526 | } | 518 | } |
527 | 519 | ||
528 | static void __kprobes emulate_ldcstc(struct kprobe *p, struct pt_regs *regs) | ||
529 | { | ||
530 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
531 | kprobe_opcode_t insn = p->opcode; | ||
532 | int rn = (insn >> 16) & 0xf; | ||
533 | long rnv = regs->uregs[rn]; | ||
534 | |||
535 | /* Save Rn in case of writeback. */ | ||
536 | regs->uregs[rn] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
537 | } | ||
538 | |||
539 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | 520 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) |
540 | { | 521 | { |
541 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | 522 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; |
542 | kprobe_opcode_t insn = p->opcode; | 523 | kprobe_opcode_t insn = p->opcode; |
524 | long ppc = (long)p->addr + 8; | ||
543 | int rd = (insn >> 12) & 0xf; | 525 | int rd = (insn >> 12) & 0xf; |
544 | int rn = (insn >> 16) & 0xf; | 526 | int rn = (insn >> 16) & 0xf; |
545 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ | 527 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ |
528 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
529 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
546 | 530 | ||
547 | /* Not following the C calling convention here, so need asm(). */ | 531 | /* Not following the C calling convention here, so need asm(). */ |
548 | __asm__ __volatile__ ( | 532 | __asm__ __volatile__ ( |
@@ -554,29 +538,36 @@ static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | |||
554 | "str r0, %[rn] \n\t" /* in case of writeback */ | 538 | "str r0, %[rn] \n\t" /* in case of writeback */ |
555 | "str r2, %[rd0] \n\t" | 539 | "str r2, %[rd0] \n\t" |
556 | "str r3, %[rd1] \n\t" | 540 | "str r3, %[rd1] \n\t" |
557 | : [rn] "+m" (regs->uregs[rn]), | 541 | : [rn] "+m" (rnv), |
558 | [rd0] "=m" (regs->uregs[rd]), | 542 | [rd0] "=m" (regs->uregs[rd]), |
559 | [rd1] "=m" (regs->uregs[rd+1]) | 543 | [rd1] "=m" (regs->uregs[rd+1]) |
560 | : [rm] "m" (regs->uregs[rm]), | 544 | : [rm] "m" (rmv), |
561 | [cpsr] "r" (regs->ARM_cpsr), | 545 | [cpsr] "r" (regs->ARM_cpsr), |
562 | [i_fn] "r" (i_fn) | 546 | [i_fn] "r" (i_fn) |
563 | : "r0", "r1", "r2", "r3", "lr", "cc" | 547 | : "r0", "r1", "r2", "r3", "lr", "cc" |
564 | ); | 548 | ); |
549 | if (is_writeback(insn)) | ||
550 | regs->uregs[rn] = rnv; | ||
565 | } | 551 | } |
566 | 552 | ||
567 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | 553 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) |
568 | { | 554 | { |
569 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; | 555 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; |
570 | kprobe_opcode_t insn = p->opcode; | 556 | kprobe_opcode_t insn = p->opcode; |
557 | long ppc = (long)p->addr + 8; | ||
571 | int rd = (insn >> 12) & 0xf; | 558 | int rd = (insn >> 12) & 0xf; |
572 | int rn = (insn >> 16) & 0xf; | 559 | int rn = (insn >> 16) & 0xf; |
573 | int rm = insn & 0xf; | 560 | int rm = insn & 0xf; |
574 | long rnv = regs->uregs[rn]; | 561 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; |
575 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | 562 | /* rm/rmv may be invalid, don't care. */ |
563 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
564 | long rnv_wb; | ||
576 | 565 | ||
577 | regs->uregs[rn] = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], | 566 | rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], |
578 | regs->uregs[rd+1], | 567 | regs->uregs[rd+1], |
579 | regs->ARM_cpsr, i_fn); | 568 | regs->ARM_cpsr, i_fn); |
569 | if (is_writeback(insn)) | ||
570 | regs->uregs[rn] = rnv_wb; | ||
580 | } | 571 | } |
581 | 572 | ||
582 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | 573 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) |
@@ -594,7 +585,8 @@ static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | |||
594 | long cpsr = regs->ARM_cpsr; | 585 | long cpsr = regs->ARM_cpsr; |
595 | 586 | ||
596 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | 587 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); |
597 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | 588 | if (rn != 15) |
589 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | ||
598 | rdv = fnr.r1; | 590 | rdv = fnr.r1; |
599 | 591 | ||
600 | if (rd == 15) { | 592 | if (rd == 15) { |
@@ -622,35 +614,11 @@ static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | |||
622 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | 614 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; |
623 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | 615 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; |
624 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | 616 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ |
617 | long rnv_wb; | ||
625 | 618 | ||
626 | /* Save Rn in case of writeback. */ | 619 | rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); |
627 | regs->uregs[rn] = | 620 | if (rn != 15) |
628 | insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | 621 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ |
629 | } | ||
630 | |||
631 | static void __kprobes emulate_mrrc(struct kprobe *p, struct pt_regs *regs) | ||
632 | { | ||
633 | insn_llret_0arg_fn_t *i_fn = (insn_llret_0arg_fn_t *)&p->ainsn.insn[0]; | ||
634 | kprobe_opcode_t insn = p->opcode; | ||
635 | union reg_pair fnr; | ||
636 | int rd = (insn >> 12) & 0xf; | ||
637 | int rn = (insn >> 16) & 0xf; | ||
638 | |||
639 | fnr.dr = insnslot_llret_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
640 | regs->uregs[rn] = fnr.r0; | ||
641 | regs->uregs[rd] = fnr.r1; | ||
642 | } | ||
643 | |||
644 | static void __kprobes emulate_mcrr(struct kprobe *p, struct pt_regs *regs) | ||
645 | { | ||
646 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
647 | kprobe_opcode_t insn = p->opcode; | ||
648 | int rd = (insn >> 12) & 0xf; | ||
649 | int rn = (insn >> 16) & 0xf; | ||
650 | long rnv = regs->uregs[rn]; | ||
651 | long rdv = regs->uregs[rd]; | ||
652 | |||
653 | insnslot_2arg_rflags(rnv, rdv, regs->ARM_cpsr, i_fn); | ||
654 | } | 622 | } |
655 | 623 | ||
656 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | 624 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) |
@@ -686,32 +654,32 @@ static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | |||
686 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | 654 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); |
687 | } | 655 | } |
688 | 656 | ||
689 | static void __kprobes emulate_rd12(struct kprobe *p, struct pt_regs *regs) | 657 | static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) |
690 | { | 658 | { |
691 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
692 | kprobe_opcode_t insn = p->opcode; | ||
693 | int rd = (insn >> 12) & 0xf; | ||
694 | |||
695 | regs->uregs[rd] = insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
696 | } | 659 | } |
697 | 660 | ||
698 | static void __kprobes emulate_ird12(struct kprobe *p, struct pt_regs *regs) | 661 | static void __kprobes |
662 | emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | ||
699 | { | 663 | { |
700 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 664 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; |
701 | kprobe_opcode_t insn = p->opcode; | 665 | kprobe_opcode_t insn = p->opcode; |
702 | int ird = (insn >> 12) & 0xf; | 666 | int rd = (insn >> 12) & 0xf; |
667 | long rdv = regs->uregs[rd]; | ||
703 | 668 | ||
704 | insnslot_1arg_rflags(regs->uregs[ird], regs->ARM_cpsr, i_fn); | 669 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); |
705 | } | 670 | } |
706 | 671 | ||
707 | static void __kprobes emulate_rn16(struct kprobe *p, struct pt_regs *regs) | 672 | static void __kprobes |
673 | emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) | ||
708 | { | 674 | { |
709 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | 675 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; |
710 | kprobe_opcode_t insn = p->opcode; | 676 | kprobe_opcode_t insn = p->opcode; |
711 | int rn = (insn >> 16) & 0xf; | 677 | int rd = (insn >> 12) & 0xf; |
678 | int rn = insn & 0xf; | ||
679 | long rdv = regs->uregs[rd]; | ||
712 | long rnv = regs->uregs[rn]; | 680 | long rnv = regs->uregs[rn]; |
713 | 681 | ||
714 | insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | 682 | regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); |
715 | } | 683 | } |
716 | 684 | ||
717 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | 685 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) |
@@ -817,6 +785,17 @@ emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | |||
817 | } | 785 | } |
818 | 786 | ||
819 | static void __kprobes | 787 | static void __kprobes |
788 | emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) | ||
789 | { | ||
790 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
791 | kprobe_opcode_t insn = p->opcode; | ||
792 | int rn = (insn >> 16) & 0xf; | ||
793 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
794 | |||
795 | insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
796 | } | ||
797 | |||
798 | static void __kprobes | ||
820 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | 799 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) |
821 | { | 800 | { |
822 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | 801 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; |
@@ -852,14 +831,34 @@ emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | |||
852 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | 831 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); |
853 | } | 832 | } |
854 | 833 | ||
834 | static void __kprobes | ||
835 | emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) | ||
836 | { | ||
837 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
838 | kprobe_opcode_t insn = p->opcode; | ||
839 | long ppc = (long)p->addr + 8; | ||
840 | int rn = (insn >> 16) & 0xf; | ||
841 | int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ | ||
842 | int rm = insn & 0xf; | ||
843 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
844 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
845 | long rsv = regs->uregs[rs]; | ||
846 | |||
847 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
848 | } | ||
849 | |||
855 | static enum kprobe_insn __kprobes | 850 | static enum kprobe_insn __kprobes |
856 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 851 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
857 | { | 852 | { |
858 | int ibit = (insn & (1 << 26)) ? 25 : 22; | 853 | int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) |
854 | : (~insn & (1 << 22)); | ||
855 | |||
856 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
857 | return INSN_REJECTED; /* Writeback to PC */ | ||
859 | 858 | ||
860 | insn &= 0xfff00fff; | 859 | insn &= 0xfff00fff; |
861 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | 860 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ |
862 | if (insn & (1 << ibit)) { | 861 | if (not_imm) { |
863 | insn &= ~0xf; | 862 | insn &= ~0xf; |
864 | insn |= 2; /* Rm = r2 */ | 863 | insn |= 2; /* Rm = r2 */ |
865 | } | 864 | } |
@@ -869,20 +868,40 @@ prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
869 | } | 868 | } |
870 | 869 | ||
871 | static enum kprobe_insn __kprobes | 870 | static enum kprobe_insn __kprobes |
872 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 871 | prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
873 | { | 872 | { |
874 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | 873 | if (is_r15(insn, 12)) |
874 | return INSN_REJECTED; /* Rd is PC */ | ||
875 | |||
876 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
875 | asi->insn[0] = insn; | 877 | asi->insn[0] = insn; |
876 | asi->insn_handler = emulate_rd12rm0; | 878 | asi->insn_handler = emulate_rd12_modify; |
877 | return INSN_GOOD; | 879 | return INSN_GOOD; |
878 | } | 880 | } |
879 | 881 | ||
880 | static enum kprobe_insn __kprobes | 882 | static enum kprobe_insn __kprobes |
881 | prep_emulate_rd12(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 883 | prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, |
884 | struct arch_specific_insn *asi) | ||
882 | { | 885 | { |
883 | insn &= 0xffff0fff; /* Rd = r0 */ | 886 | if (is_r15(insn, 12)) |
887 | return INSN_REJECTED; /* Rd is PC */ | ||
888 | |||
889 | insn &= 0xffff0ff0; /* Rd = r0 */ | ||
890 | insn |= 0x00000001; /* Rn = r1 */ | ||
891 | asi->insn[0] = insn; | ||
892 | asi->insn_handler = emulate_rd12rn0_modify; | ||
893 | return INSN_GOOD; | ||
894 | } | ||
895 | |||
896 | static enum kprobe_insn __kprobes | ||
897 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
898 | { | ||
899 | if (is_r15(insn, 12)) | ||
900 | return INSN_REJECTED; /* Rd is PC */ | ||
901 | |||
902 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
884 | asi->insn[0] = insn; | 903 | asi->insn[0] = insn; |
885 | asi->insn_handler = emulate_rd12; | 904 | asi->insn_handler = emulate_rd12rm0; |
886 | return INSN_GOOD; | 905 | return INSN_GOOD; |
887 | } | 906 | } |
888 | 907 | ||
@@ -890,6 +909,9 @@ static enum kprobe_insn __kprobes | |||
890 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | 909 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, |
891 | struct arch_specific_insn *asi) | 910 | struct arch_specific_insn *asi) |
892 | { | 911 | { |
912 | if (is_r15(insn, 12)) | ||
913 | return INSN_REJECTED; /* Rd is PC */ | ||
914 | |||
893 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | 915 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ |
894 | insn |= 0x00000001; /* Rm = r1 */ | 916 | insn |= 0x00000001; /* Rm = r1 */ |
895 | asi->insn[0] = insn; | 917 | asi->insn[0] = insn; |
@@ -901,6 +923,9 @@ static enum kprobe_insn __kprobes | |||
901 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | 923 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, |
902 | struct arch_specific_insn *asi) | 924 | struct arch_specific_insn *asi) |
903 | { | 925 | { |
926 | if (is_r15(insn, 16)) | ||
927 | return INSN_REJECTED; /* Rd is PC */ | ||
928 | |||
904 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | 929 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ |
905 | insn |= 0x00000001; /* Rm = r1 */ | 930 | insn |= 0x00000001; /* Rm = r1 */ |
906 | asi->insn[0] = insn; | 931 | asi->insn[0] = insn; |
@@ -912,6 +937,9 @@ static enum kprobe_insn __kprobes | |||
912 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | 937 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, |
913 | struct arch_specific_insn *asi) | 938 | struct arch_specific_insn *asi) |
914 | { | 939 | { |
940 | if (is_r15(insn, 16)) | ||
941 | return INSN_REJECTED; /* Rd is PC */ | ||
942 | |||
915 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | 943 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ |
916 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | 944 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ |
917 | asi->insn[0] = insn; | 945 | asi->insn[0] = insn; |
@@ -923,6 +951,9 @@ static enum kprobe_insn __kprobes | |||
923 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | 951 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, |
924 | struct arch_specific_insn *asi) | 952 | struct arch_specific_insn *asi) |
925 | { | 953 | { |
954 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
955 | return INSN_REJECTED; /* RdHi or RdLo is PC */ | ||
956 | |||
926 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | 957 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ |
927 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | 958 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ |
928 | asi->insn[0] = insn; | 959 | asi->insn[0] = insn; |
@@ -943,20 +974,13 @@ prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | |||
943 | static enum kprobe_insn __kprobes | 974 | static enum kprobe_insn __kprobes |
944 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 975 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
945 | { | 976 | { |
946 | /* CPS mmod == 1 : 1111 0001 0000 xx10 xxxx xxxx xx0x xxxx */ | 977 | /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ |
947 | /* RFE : 1111 100x x0x1 xxxx xxxx 1010 xxxx xxxx */ | 978 | /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ |
948 | /* SRS : 1111 100x x1x0 1101 xxxx 0101 xxxx xxxx */ | 979 | /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ |
949 | if ((insn & 0xfff30020) == 0xf1020000 || | 980 | /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ |
950 | (insn & 0xfe500f00) == 0xf8100a00 || | 981 | if ((insn & 0xfe300000) == 0xf4100000) { |
951 | (insn & 0xfe5f0f00) == 0xf84d0500) | 982 | asi->insn_handler = emulate_nop; |
952 | return INSN_REJECTED; | 983 | return INSN_GOOD_NO_SLOT; |
953 | |||
954 | /* PLD : 1111 01x1 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
955 | if ((insn & 0xfd700000) == 0xf4500000) { | ||
956 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
957 | asi->insn[0] = insn; | ||
958 | asi->insn_handler = emulate_rn16; | ||
959 | return INSN_GOOD; | ||
960 | } | 984 | } |
961 | 985 | ||
962 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ | 986 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ |
@@ -965,41 +989,22 @@ space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
965 | return INSN_GOOD_NO_SLOT; | 989 | return INSN_GOOD_NO_SLOT; |
966 | } | 990 | } |
967 | 991 | ||
968 | /* SETEND : 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | 992 | /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ |
969 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | 993 | /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ |
970 | if ((insn & 0xffff00f0) == 0xf1010000 || | 994 | |
971 | (insn & 0xff000010) == 0xfe000000) { | 995 | /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ |
972 | asi->insn[0] = insn; | 996 | /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ |
973 | asi->insn_handler = emulate_none; | ||
974 | return INSN_GOOD; | ||
975 | } | ||
976 | 997 | ||
998 | /* Coprocessor instructions... */ | ||
977 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | 999 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ |
978 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | 1000 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ |
979 | if ((insn & 0xffe00000) == 0xfc400000) { | 1001 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ |
980 | insn &= 0xfff00fff; /* Rn = r0 */ | 1002 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ |
981 | insn |= 0x00001000; /* Rd = r1 */ | 1003 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ |
982 | asi->insn[0] = insn; | 1004 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ |
983 | asi->insn_handler = | 1005 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ |
984 | (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | ||
985 | return INSN_GOOD; | ||
986 | } | ||
987 | 1006 | ||
988 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | 1007 | return INSN_REJECTED; |
989 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
990 | if ((insn & 0xfe000000) == 0xfc000000) { | ||
991 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
992 | asi->insn[0] = insn; | ||
993 | asi->insn_handler = emulate_ldcstc; | ||
994 | return INSN_GOOD; | ||
995 | } | ||
996 | |||
997 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
998 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
999 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
1000 | asi->insn[0] = insn; | ||
1001 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1002 | return INSN_GOOD; | ||
1003 | } | 1008 | } |
1004 | 1009 | ||
1005 | static enum kprobe_insn __kprobes | 1010 | static enum kprobe_insn __kprobes |
@@ -1008,19 +1013,18 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1008 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ | 1013 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ |
1009 | if ((insn & 0x0f900010) == 0x01000000) { | 1014 | if ((insn & 0x0f900010) == 0x01000000) { |
1010 | 1015 | ||
1011 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | 1016 | /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ |
1012 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | 1017 | if ((insn & 0x0ff000f0) == 0x01000000) { |
1013 | if ((insn & 0x0ff000f0) == 0x01200020 || | 1018 | if (is_r15(insn, 12)) |
1014 | (insn & 0x0fb000f0) == 0x01200000) | 1019 | return INSN_REJECTED; /* Rd is PC */ |
1015 | return INSN_REJECTED; | 1020 | asi->insn_handler = simulate_mrs; |
1016 | 1021 | return INSN_GOOD_NO_SLOT; | |
1017 | /* MRS : cccc 0001 0x00 xxxx xxxx xxxx 0000 xxxx */ | 1022 | } |
1018 | if ((insn & 0x0fb00010) == 0x01000000) | ||
1019 | return prep_emulate_rd12(insn, asi); | ||
1020 | 1023 | ||
1021 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | 1024 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ |
1022 | if ((insn & 0x0ff00090) == 0x01400080) | 1025 | if ((insn & 0x0ff00090) == 0x01400080) |
1023 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | 1026 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, |
1027 | asi); | ||
1024 | 1028 | ||
1025 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | 1029 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ |
1026 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | 1030 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ |
@@ -1029,24 +1033,29 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1029 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | 1033 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); |
1030 | 1034 | ||
1031 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ | 1035 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ |
1032 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 0x00 xxxx : Q */ | 1036 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ |
1033 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | 1037 | if ((insn & 0x0ff00090) == 0x01000080 || |
1038 | (insn & 0x0ff000b0) == 0x01200080) | ||
1039 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1034 | 1040 | ||
1041 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
1042 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
1043 | /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ | ||
1044 | |||
1045 | /* Other instruction encodings aren't yet defined */ | ||
1046 | return INSN_REJECTED; | ||
1035 | } | 1047 | } |
1036 | 1048 | ||
1037 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ | 1049 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ |
1038 | else if ((insn & 0x0f900090) == 0x01000010) { | 1050 | else if ((insn & 0x0f900090) == 0x01000010) { |
1039 | 1051 | ||
1040 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1041 | if ((insn & 0xfff000f0) == 0xe1200070) | ||
1042 | return INSN_REJECTED; | ||
1043 | |||
1044 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | 1052 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ |
1045 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | 1053 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ |
1046 | if ((insn & 0x0ff000d0) == 0x01200010) { | 1054 | if ((insn & 0x0ff000d0) == 0x01200010) { |
1047 | asi->insn[0] = truecc_insn(insn); | 1055 | if ((insn & 0x0ff000ff) == 0x0120003f) |
1056 | return INSN_REJECTED; /* BLX pc */ | ||
1048 | asi->insn_handler = simulate_blx2bx; | 1057 | asi->insn_handler = simulate_blx2bx; |
1049 | return INSN_GOOD; | 1058 | return INSN_GOOD_NO_SLOT; |
1050 | } | 1059 | } |
1051 | 1060 | ||
1052 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | 1061 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ |
@@ -1057,17 +1066,27 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1057 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ | 1066 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ |
1058 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ | 1067 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ |
1059 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ | 1068 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ |
1060 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | 1069 | if ((insn & 0x0f9000f0) == 0x01000050) |
1070 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1071 | |||
1072 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1073 | /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
1074 | |||
1075 | /* Other instruction encodings aren't yet defined */ | ||
1076 | return INSN_REJECTED; | ||
1061 | } | 1077 | } |
1062 | 1078 | ||
1063 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ | 1079 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ |
1064 | else if ((insn & 0x0f000090) == 0x00000090) { | 1080 | else if ((insn & 0x0f0000f0) == 0x00000090) { |
1065 | 1081 | ||
1066 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ | 1082 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ |
1067 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ | 1083 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ |
1068 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ | 1084 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ |
1069 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ | 1085 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ |
1070 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ | 1086 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ |
1087 | /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ | ||
1088 | /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1089 | /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1071 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ | 1090 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ |
1072 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ | 1091 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ |
1073 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ | 1092 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ |
@@ -1076,13 +1095,15 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1076 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ | 1095 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ |
1077 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ | 1096 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ |
1078 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ | 1097 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ |
1079 | if ((insn & 0x0fe000f0) == 0x00000090) { | 1098 | if ((insn & 0x00d00000) == 0x00500000) |
1080 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | 1099 | return INSN_REJECTED; |
1081 | } else if ((insn & 0x0fe000f0) == 0x00200090) { | 1100 | else if ((insn & 0x00e00000) == 0x00000000) |
1082 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | 1101 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); |
1083 | } else { | 1102 | else if ((insn & 0x00a00000) == 0x00200000) |
1084 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | 1103 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); |
1085 | } | 1104 | else |
1105 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, | ||
1106 | asi); | ||
1086 | } | 1107 | } |
1087 | 1108 | ||
1088 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ | 1109 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ |
@@ -1090,23 +1111,45 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1090 | 1111 | ||
1091 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ | 1112 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ |
1092 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ | 1113 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ |
1093 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | 1114 | /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ |
1094 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | 1115 | /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ |
1116 | /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ | ||
1095 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ | 1117 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ |
1096 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ | 1118 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ |
1119 | /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ | ||
1120 | /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ | ||
1121 | /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ | ||
1122 | /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ | ||
1123 | /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ | ||
1124 | /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ | ||
1125 | |||
1126 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | ||
1127 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | ||
1097 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ | 1128 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ |
1098 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ | 1129 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ |
1099 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ | 1130 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ |
1100 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ | 1131 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ |
1101 | if ((insn & 0x0fb000f0) == 0x01000090) { | 1132 | if ((insn & 0x0f0000f0) == 0x01000090) { |
1102 | /* SWP/SWPB */ | 1133 | if ((insn & 0x0fb000f0) == 0x01000090) { |
1103 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | 1134 | /* SWP/SWPB */ |
1135 | return prep_emulate_rd12rn16rm0_wflags(insn, | ||
1136 | asi); | ||
1137 | } else { | ||
1138 | /* STREX/LDREX variants and unallocaed space */ | ||
1139 | return INSN_REJECTED; | ||
1140 | } | ||
1141 | |||
1104 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { | 1142 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { |
1105 | /* STRD/LDRD */ | 1143 | /* STRD/LDRD */ |
1144 | if ((insn & 0x0000e000) == 0x0000e000) | ||
1145 | return INSN_REJECTED; /* Rd is LR or PC */ | ||
1146 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
1147 | return INSN_REJECTED; /* Writeback to PC */ | ||
1148 | |||
1106 | insn &= 0xfff00fff; | 1149 | insn &= 0xfff00fff; |
1107 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ | 1150 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ |
1108 | if (insn & (1 << 22)) { | 1151 | if (!(insn & (1 << 22))) { |
1109 | /* I bit */ | 1152 | /* Register index */ |
1110 | insn &= ~0xf; | 1153 | insn &= ~0xf; |
1111 | insn |= 1; /* Rm = r1 */ | 1154 | insn |= 1; /* Rm = r1 */ |
1112 | } | 1155 | } |
@@ -1116,6 +1159,9 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1116 | return INSN_GOOD; | 1159 | return INSN_GOOD; |
1117 | } | 1160 | } |
1118 | 1161 | ||
1162 | /* LDRH/STRH/LDRSB/LDRSH */ | ||
1163 | if (is_r15(insn, 12)) | ||
1164 | return INSN_REJECTED; /* Rd is PC */ | ||
1119 | return prep_emulate_ldr_str(insn, asi); | 1165 | return prep_emulate_ldr_str(insn, asi); |
1120 | } | 1166 | } |
1121 | 1167 | ||
@@ -1123,7 +1169,7 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1123 | 1169 | ||
1124 | /* | 1170 | /* |
1125 | * ALU op with S bit and Rd == 15 : | 1171 | * ALU op with S bit and Rd == 15 : |
1126 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx | 1172 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx |
1127 | */ | 1173 | */ |
1128 | if ((insn & 0x0e10f000) == 0x0010f000) | 1174 | if ((insn & 0x0e10f000) == 0x0010f000) |
1129 | return INSN_REJECTED; | 1175 | return INSN_REJECTED; |
@@ -1152,22 +1198,61 @@ space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1152 | insn |= 0x00000200; /* Rs = r2 */ | 1198 | insn |= 0x00000200; /* Rs = r2 */ |
1153 | } | 1199 | } |
1154 | asi->insn[0] = insn; | 1200 | asi->insn[0] = insn; |
1155 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | 1201 | |
1202 | if ((insn & 0x0f900000) == 0x01100000) { | ||
1203 | /* | ||
1204 | * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx | ||
1205 | * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx | ||
1206 | * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx | ||
1207 | * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx | ||
1208 | */ | ||
1209 | asi->insn_handler = emulate_alu_tests; | ||
1210 | } else { | ||
1211 | /* ALU ops which write to Rd */ | ||
1212 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1156 | emulate_alu_rwflags : emulate_alu_rflags; | 1213 | emulate_alu_rwflags : emulate_alu_rflags; |
1214 | } | ||
1157 | return INSN_GOOD; | 1215 | return INSN_GOOD; |
1158 | } | 1216 | } |
1159 | 1217 | ||
1160 | static enum kprobe_insn __kprobes | 1218 | static enum kprobe_insn __kprobes |
1161 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1219 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
1162 | { | 1220 | { |
1221 | /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
1222 | /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
1223 | if ((insn & 0x0fb00000) == 0x03000000) | ||
1224 | return prep_emulate_rd12_modify(insn, asi); | ||
1225 | |||
1226 | /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | ||
1227 | if ((insn & 0x0fff0000) == 0x03200000) { | ||
1228 | unsigned op2 = insn & 0x000000ff; | ||
1229 | if (op2 == 0x01 || op2 == 0x04) { | ||
1230 | /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | ||
1231 | /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | ||
1232 | asi->insn[0] = insn; | ||
1233 | asi->insn_handler = emulate_none; | ||
1234 | return INSN_GOOD; | ||
1235 | } else if (op2 <= 0x03) { | ||
1236 | /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | ||
1237 | /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | ||
1238 | /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | ||
1239 | /* | ||
1240 | * We make WFE and WFI true NOPs to avoid stalls due | ||
1241 | * to missing events whilst processing the probe. | ||
1242 | */ | ||
1243 | asi->insn_handler = emulate_nop; | ||
1244 | return INSN_GOOD_NO_SLOT; | ||
1245 | } | ||
1246 | /* For DBG and unallocated hints it's safest to reject them */ | ||
1247 | return INSN_REJECTED; | ||
1248 | } | ||
1249 | |||
1163 | /* | 1250 | /* |
1164 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | 1251 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx |
1165 | * Undef : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx | ||
1166 | * ALU op with S bit and Rd == 15 : | 1252 | * ALU op with S bit and Rd == 15 : |
1167 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | 1253 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx |
1168 | */ | 1254 | */ |
1169 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ | 1255 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ |
1170 | (insn & 0x0ff00000) == 0x03400000 || /* Undef */ | ||
1171 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ | 1256 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ |
1172 | return INSN_REJECTED; | 1257 | return INSN_REJECTED; |
1173 | 1258 | ||
@@ -1178,10 +1263,22 @@ space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1178 | * *S (bit 20) updates condition codes | 1263 | * *S (bit 20) updates condition codes |
1179 | * ADC/SBC/RSC reads the C flag | 1264 | * ADC/SBC/RSC reads the C flag |
1180 | */ | 1265 | */ |
1181 | insn &= 0xffff0fff; /* Rd = r0 */ | 1266 | insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ |
1182 | asi->insn[0] = insn; | 1267 | asi->insn[0] = insn; |
1183 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | 1268 | |
1269 | if ((insn & 0x0f900000) == 0x03100000) { | ||
1270 | /* | ||
1271 | * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx | ||
1272 | * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx | ||
1273 | * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx | ||
1274 | * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx | ||
1275 | */ | ||
1276 | asi->insn_handler = emulate_alu_tests_imm; | ||
1277 | } else { | ||
1278 | /* ALU ops which write to Rd */ | ||
1279 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1184 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; | 1280 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; |
1281 | } | ||
1185 | return INSN_GOOD; | 1282 | return INSN_GOOD; |
1186 | } | 1283 | } |
1187 | 1284 | ||
@@ -1190,6 +1287,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1190 | { | 1287 | { |
1191 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | 1288 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ |
1192 | if ((insn & 0x0ff000f0) == 0x068000b0) { | 1289 | if ((insn & 0x0ff000f0) == 0x068000b0) { |
1290 | if (is_r15(insn, 12)) | ||
1291 | return INSN_REJECTED; /* Rd is PC */ | ||
1193 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | 1292 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ |
1194 | insn |= 0x00000001; /* Rm = r1 */ | 1293 | insn |= 0x00000001; /* Rm = r1 */ |
1195 | asi->insn[0] = insn; | 1294 | asi->insn[0] = insn; |
@@ -1203,6 +1302,8 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1203 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | 1302 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ |
1204 | if ((insn & 0x0fa00030) == 0x06a00010 || | 1303 | if ((insn & 0x0fa00030) == 0x06a00010 || |
1205 | (insn & 0x0fb000f0) == 0x06a00030) { | 1304 | (insn & 0x0fb000f0) == 0x06a00030) { |
1305 | if (is_r15(insn, 12)) | ||
1306 | return INSN_REJECTED; /* Rd is PC */ | ||
1206 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | 1307 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ |
1207 | asi->insn[0] = insn; | 1308 | asi->insn[0] = insn; |
1208 | asi->insn_handler = emulate_sat; | 1309 | asi->insn_handler = emulate_sat; |
@@ -1211,57 +1312,101 @@ space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1211 | 1312 | ||
1212 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | 1313 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ |
1213 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | 1314 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ |
1315 | /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ | ||
1214 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | 1316 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ |
1215 | if ((insn & 0x0ff00070) == 0x06b00030 || | 1317 | if ((insn & 0x0ff00070) == 0x06b00030 || |
1216 | (insn & 0x0ff000f0) == 0x06f000b0) | 1318 | (insn & 0x0ff00070) == 0x06f00030) |
1217 | return prep_emulate_rd12rm0(insn, asi); | 1319 | return prep_emulate_rd12rm0(insn, asi); |
1218 | 1320 | ||
1321 | /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1219 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ | 1322 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ |
1220 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ | 1323 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ |
1221 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ | 1324 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ |
1222 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ | 1325 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ |
1223 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ | 1326 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ |
1327 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ | ||
1328 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ | ||
1224 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ | 1329 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ |
1225 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ | 1330 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ |
1226 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ | 1331 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ |
1227 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ | 1332 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ |
1228 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ | 1333 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ |
1229 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ | 1334 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ |
1335 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ | ||
1336 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ | ||
1230 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ | 1337 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ |
1231 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ | 1338 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ |
1232 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ | 1339 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ |
1233 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ | 1340 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ |
1234 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ | 1341 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ |
1235 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ | 1342 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ |
1343 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ | ||
1344 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ | ||
1236 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ | 1345 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ |
1346 | /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1237 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ | 1347 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ |
1238 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ | 1348 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ |
1239 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ | 1349 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ |
1240 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ | 1350 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ |
1241 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ | 1351 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ |
1352 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ | ||
1353 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ | ||
1242 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ | 1354 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ |
1243 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ | 1355 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ |
1244 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ | 1356 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ |
1245 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ | 1357 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ |
1246 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ | 1358 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ |
1247 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ | 1359 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ |
1360 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ | ||
1361 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ | ||
1248 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ | 1362 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ |
1249 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ | 1363 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ |
1250 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ | 1364 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ |
1251 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ | 1365 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ |
1252 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ | 1366 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ |
1253 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ | 1367 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ |
1368 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ | ||
1369 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ | ||
1254 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ | 1370 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ |
1371 | if ((insn & 0x0f800010) == 0x06000010) { | ||
1372 | if ((insn & 0x00300000) == 0x00000000 || | ||
1373 | (insn & 0x000000e0) == 0x000000a0 || | ||
1374 | (insn & 0x000000e0) == 0x000000c0) | ||
1375 | return INSN_REJECTED; /* Unallocated space */ | ||
1376 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1377 | } | ||
1378 | |||
1255 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ | 1379 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ |
1256 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ | 1380 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ |
1381 | if ((insn & 0x0ff00030) == 0x06800010) | ||
1382 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1383 | |||
1257 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ | 1384 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ |
1258 | /* SXTB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | 1385 | /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ |
1386 | /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ | ||
1259 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | 1387 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ |
1388 | /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ | ||
1260 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ | 1389 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ |
1390 | /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ | ||
1261 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ | 1391 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ |
1392 | /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ | ||
1393 | /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ | ||
1262 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ | 1394 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ |
1395 | /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ | ||
1263 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ | 1396 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ |
1264 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | 1397 | /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ |
1398 | if ((insn & 0x0f8000f0) == 0x06800070) { | ||
1399 | if ((insn & 0x00300000) == 0x00100000) | ||
1400 | return INSN_REJECTED; /* Unallocated space */ | ||
1401 | |||
1402 | if ((insn & 0x000f0000) == 0x000f0000) | ||
1403 | return prep_emulate_rd12rm0(insn, asi); | ||
1404 | else | ||
1405 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1406 | } | ||
1407 | |||
1408 | /* Other instruction encodings aren't yet defined */ | ||
1409 | return INSN_REJECTED; | ||
1265 | } | 1410 | } |
1266 | 1411 | ||
1267 | static enum kprobe_insn __kprobes | 1412 | static enum kprobe_insn __kprobes |
@@ -1271,29 +1416,49 @@ space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1271 | if ((insn & 0x0ff000f0) == 0x03f000f0) | 1416 | if ((insn & 0x0ff000f0) == 0x03f000f0) |
1272 | return INSN_REJECTED; | 1417 | return INSN_REJECTED; |
1273 | 1418 | ||
1274 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ | ||
1275 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
1276 | if ((insn & 0x0ff000f0) == 0x07800010) | ||
1277 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1278 | |||
1279 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | 1419 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ |
1280 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | 1420 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ |
1281 | if ((insn & 0x0ff00090) == 0x07400010) | 1421 | if ((insn & 0x0ff00090) == 0x07400010) |
1282 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | 1422 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); |
1283 | 1423 | ||
1284 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ | 1424 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ |
1425 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | ||
1285 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ | 1426 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ |
1427 | /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ | ||
1286 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ | 1428 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ |
1287 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | 1429 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ |
1430 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ | ||
1431 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ | ||
1288 | if ((insn & 0x0ff00090) == 0x07000010 || | 1432 | if ((insn & 0x0ff00090) == 0x07000010 || |
1289 | (insn & 0x0ff000d0) == 0x07500010 || | 1433 | (insn & 0x0ff000d0) == 0x07500010 || |
1290 | (insn & 0x0ff000d0) == 0x075000d0) | 1434 | (insn & 0x0ff000f0) == 0x07800010) { |
1435 | |||
1436 | if ((insn & 0x0000f000) == 0x0000f000) | ||
1437 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1438 | else | ||
1439 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1440 | } | ||
1441 | |||
1442 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | ||
1443 | if ((insn & 0x0ff000d0) == 0x075000d0) | ||
1291 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | 1444 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); |
1292 | 1445 | ||
1293 | /* SMUSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx : */ | 1446 | /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ |
1294 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | 1447 | /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ |
1295 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ | 1448 | if ((insn & 0x0fa00070) == 0x07a00050) |
1296 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | 1449 | return prep_emulate_rd12rm0(insn, asi); |
1450 | |||
1451 | /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ | ||
1452 | /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ | ||
1453 | if ((insn & 0x0fe00070) == 0x07c00010) { | ||
1454 | |||
1455 | if ((insn & 0x0000000f) == 0x0000000f) | ||
1456 | return prep_emulate_rd12_modify(insn, asi); | ||
1457 | else | ||
1458 | return prep_emulate_rd12rn0_modify(insn, asi); | ||
1459 | } | ||
1460 | |||
1461 | return INSN_REJECTED; | ||
1297 | } | 1462 | } |
1298 | 1463 | ||
1299 | static enum kprobe_insn __kprobes | 1464 | static enum kprobe_insn __kprobes |
@@ -1307,6 +1472,10 @@ space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1307 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ | 1472 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ |
1308 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | 1473 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ |
1309 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | 1474 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ |
1475 | |||
1476 | if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) | ||
1477 | return INSN_REJECTED; /* LDRB into PC */ | ||
1478 | |||
1310 | return prep_emulate_ldr_str(insn, asi); | 1479 | return prep_emulate_ldr_str(insn, asi); |
1311 | } | 1480 | } |
1312 | 1481 | ||
@@ -1321,10 +1490,9 @@ space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1321 | 1490 | ||
1322 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | 1491 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ |
1323 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | 1492 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ |
1324 | asi->insn[0] = truecc_insn(insn); | ||
1325 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ | 1493 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ |
1326 | simulate_stm1_pc : simulate_ldm1stm1; | 1494 | simulate_stm1_pc : simulate_ldm1stm1; |
1327 | return INSN_GOOD; | 1495 | return INSN_GOOD_NO_SLOT; |
1328 | } | 1496 | } |
1329 | 1497 | ||
1330 | static enum kprobe_insn __kprobes | 1498 | static enum kprobe_insn __kprobes |
@@ -1332,58 +1500,117 @@ space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1332 | { | 1500 | { |
1333 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | 1501 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ |
1334 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | 1502 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ |
1335 | asi->insn[0] = truecc_insn(insn); | ||
1336 | asi->insn_handler = simulate_bbl; | 1503 | asi->insn_handler = simulate_bbl; |
1337 | return INSN_GOOD; | 1504 | return INSN_GOOD_NO_SLOT; |
1338 | } | 1505 | } |
1339 | 1506 | ||
1340 | static enum kprobe_insn __kprobes | 1507 | static enum kprobe_insn __kprobes |
1341 | space_cccc_1100_010x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1508 | space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
1342 | { | 1509 | { |
1510 | /* Coprocessor instructions... */ | ||
1343 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1511 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1344 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | 1512 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ |
1345 | insn &= 0xfff00fff; | 1513 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ |
1346 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | 1514 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ |
1347 | asi->insn[0] = insn; | 1515 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ |
1348 | asi->insn_handler = (insn & (1 << 20)) ? emulate_mrrc : emulate_mcrr; | 1516 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ |
1349 | return INSN_GOOD; | 1517 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ |
1518 | |||
1519 | /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1520 | |||
1521 | return INSN_REJECTED; | ||
1350 | } | 1522 | } |
1351 | 1523 | ||
1352 | static enum kprobe_insn __kprobes | 1524 | static unsigned long __kprobes __check_eq(unsigned long cpsr) |
1353 | space_cccc_110x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1354 | { | 1525 | { |
1355 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | 1526 | return cpsr & PSR_Z_BIT; |
1356 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1357 | insn &= 0xfff0ffff; /* Rn = r0 */ | ||
1358 | asi->insn[0] = insn; | ||
1359 | asi->insn_handler = emulate_ldcstc; | ||
1360 | return INSN_GOOD; | ||
1361 | } | 1527 | } |
1362 | 1528 | ||
1363 | static enum kprobe_insn __kprobes | 1529 | static unsigned long __kprobes __check_ne(unsigned long cpsr) |
1364 | space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1365 | { | 1530 | { |
1366 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | 1531 | return (~cpsr) & PSR_Z_BIT; |
1367 | /* SWI : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | 1532 | } |
1368 | if ((insn & 0xfff000f0) == 0xe1200070 || | ||
1369 | (insn & 0x0f000000) == 0x0f000000) | ||
1370 | return INSN_REJECTED; | ||
1371 | 1533 | ||
1372 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | 1534 | static unsigned long __kprobes __check_cs(unsigned long cpsr) |
1373 | if ((insn & 0x0f000010) == 0x0e000000) { | 1535 | { |
1374 | asi->insn[0] = insn; | 1536 | return cpsr & PSR_C_BIT; |
1375 | asi->insn_handler = emulate_none; | 1537 | } |
1376 | return INSN_GOOD; | ||
1377 | } | ||
1378 | 1538 | ||
1379 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | 1539 | static unsigned long __kprobes __check_cc(unsigned long cpsr) |
1380 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | 1540 | { |
1381 | insn &= 0xffff0fff; /* Rd = r0 */ | 1541 | return (~cpsr) & PSR_C_BIT; |
1382 | asi->insn[0] = insn; | ||
1383 | asi->insn_handler = (insn & (1 << 20)) ? emulate_rd12 : emulate_ird12; | ||
1384 | return INSN_GOOD; | ||
1385 | } | 1542 | } |
1386 | 1543 | ||
1544 | static unsigned long __kprobes __check_mi(unsigned long cpsr) | ||
1545 | { | ||
1546 | return cpsr & PSR_N_BIT; | ||
1547 | } | ||
1548 | |||
1549 | static unsigned long __kprobes __check_pl(unsigned long cpsr) | ||
1550 | { | ||
1551 | return (~cpsr) & PSR_N_BIT; | ||
1552 | } | ||
1553 | |||
1554 | static unsigned long __kprobes __check_vs(unsigned long cpsr) | ||
1555 | { | ||
1556 | return cpsr & PSR_V_BIT; | ||
1557 | } | ||
1558 | |||
1559 | static unsigned long __kprobes __check_vc(unsigned long cpsr) | ||
1560 | { | ||
1561 | return (~cpsr) & PSR_V_BIT; | ||
1562 | } | ||
1563 | |||
1564 | static unsigned long __kprobes __check_hi(unsigned long cpsr) | ||
1565 | { | ||
1566 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1567 | return cpsr & PSR_C_BIT; | ||
1568 | } | ||
1569 | |||
1570 | static unsigned long __kprobes __check_ls(unsigned long cpsr) | ||
1571 | { | ||
1572 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1573 | return (~cpsr) & PSR_C_BIT; | ||
1574 | } | ||
1575 | |||
1576 | static unsigned long __kprobes __check_ge(unsigned long cpsr) | ||
1577 | { | ||
1578 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1579 | return (~cpsr) & PSR_N_BIT; | ||
1580 | } | ||
1581 | |||
1582 | static unsigned long __kprobes __check_lt(unsigned long cpsr) | ||
1583 | { | ||
1584 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1585 | return cpsr & PSR_N_BIT; | ||
1586 | } | ||
1587 | |||
1588 | static unsigned long __kprobes __check_gt(unsigned long cpsr) | ||
1589 | { | ||
1590 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1591 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1592 | return (~temp) & PSR_N_BIT; | ||
1593 | } | ||
1594 | |||
1595 | static unsigned long __kprobes __check_le(unsigned long cpsr) | ||
1596 | { | ||
1597 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1598 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1599 | return temp & PSR_N_BIT; | ||
1600 | } | ||
1601 | |||
1602 | static unsigned long __kprobes __check_al(unsigned long cpsr) | ||
1603 | { | ||
1604 | return true; | ||
1605 | } | ||
1606 | |||
1607 | static kprobe_check_cc * const condition_checks[16] = { | ||
1608 | &__check_eq, &__check_ne, &__check_cs, &__check_cc, | ||
1609 | &__check_mi, &__check_pl, &__check_vs, &__check_vc, | ||
1610 | &__check_hi, &__check_ls, &__check_ge, &__check_lt, | ||
1611 | &__check_gt, &__check_le, &__check_al, &__check_al | ||
1612 | }; | ||
1613 | |||
1387 | /* Return: | 1614 | /* Return: |
1388 | * INSN_REJECTED If instruction is one not allowed to kprobe, | 1615 | * INSN_REJECTED If instruction is one not allowed to kprobe, |
1389 | * INSN_GOOD If instruction is supported and uses instruction slot, | 1616 | * INSN_GOOD If instruction is supported and uses instruction slot, |
@@ -1399,133 +1626,45 @@ space_cccc_111x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |||
1399 | enum kprobe_insn __kprobes | 1626 | enum kprobe_insn __kprobes |
1400 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 1627 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
1401 | { | 1628 | { |
1629 | asi->insn_check_cc = condition_checks[insn>>28]; | ||
1402 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | 1630 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; |
1403 | 1631 | ||
1404 | if ((insn & 0xf0000000) == 0xf0000000) { | 1632 | if ((insn & 0xf0000000) == 0xf0000000) |
1405 | 1633 | ||
1406 | return space_1111(insn, asi); | 1634 | return space_1111(insn, asi); |
1407 | 1635 | ||
1408 | } else if ((insn & 0x0e000000) == 0x00000000) { | 1636 | else if ((insn & 0x0e000000) == 0x00000000) |
1409 | 1637 | ||
1410 | return space_cccc_000x(insn, asi); | 1638 | return space_cccc_000x(insn, asi); |
1411 | 1639 | ||
1412 | } else if ((insn & 0x0e000000) == 0x02000000) { | 1640 | else if ((insn & 0x0e000000) == 0x02000000) |
1413 | 1641 | ||
1414 | return space_cccc_001x(insn, asi); | 1642 | return space_cccc_001x(insn, asi); |
1415 | 1643 | ||
1416 | } else if ((insn & 0x0f000010) == 0x06000010) { | 1644 | else if ((insn & 0x0f000010) == 0x06000010) |
1417 | 1645 | ||
1418 | return space_cccc_0110__1(insn, asi); | 1646 | return space_cccc_0110__1(insn, asi); |
1419 | 1647 | ||
1420 | } else if ((insn & 0x0f000010) == 0x07000010) { | 1648 | else if ((insn & 0x0f000010) == 0x07000010) |
1421 | 1649 | ||
1422 | return space_cccc_0111__1(insn, asi); | 1650 | return space_cccc_0111__1(insn, asi); |
1423 | 1651 | ||
1424 | } else if ((insn & 0x0c000000) == 0x04000000) { | 1652 | else if ((insn & 0x0c000000) == 0x04000000) |
1425 | 1653 | ||
1426 | return space_cccc_01xx(insn, asi); | 1654 | return space_cccc_01xx(insn, asi); |
1427 | 1655 | ||
1428 | } else if ((insn & 0x0e000000) == 0x08000000) { | 1656 | else if ((insn & 0x0e000000) == 0x08000000) |
1429 | 1657 | ||
1430 | return space_cccc_100x(insn, asi); | 1658 | return space_cccc_100x(insn, asi); |
1431 | 1659 | ||
1432 | } else if ((insn & 0x0e000000) == 0x0a000000) { | 1660 | else if ((insn & 0x0e000000) == 0x0a000000) |
1433 | 1661 | ||
1434 | return space_cccc_101x(insn, asi); | 1662 | return space_cccc_101x(insn, asi); |
1435 | 1663 | ||
1436 | } else if ((insn & 0x0fe00000) == 0x0c400000) { | 1664 | return space_cccc_11xx(insn, asi); |
1437 | |||
1438 | return space_cccc_1100_010x(insn, asi); | ||
1439 | |||
1440 | } else if ((insn & 0x0e000000) == 0x0c400000) { | ||
1441 | |||
1442 | return space_cccc_110x(insn, asi); | ||
1443 | |||
1444 | } | ||
1445 | |||
1446 | return space_cccc_111x(insn, asi); | ||
1447 | } | 1665 | } |
1448 | 1666 | ||
1449 | void __init arm_kprobe_decode_init(void) | 1667 | void __init arm_kprobe_decode_init(void) |
1450 | { | 1668 | { |
1451 | find_str_pc_offset(); | 1669 | find_str_pc_offset(); |
1452 | } | 1670 | } |
1453 | |||
1454 | |||
1455 | /* | ||
1456 | * All ARM instructions listed below. | ||
1457 | * | ||
1458 | * Instructions and their general purpose registers are given. | ||
1459 | * If a particular register may not use R15, it is prefixed with a "!". | ||
1460 | * If marked with a "*" means the value returned by reading R15 | ||
1461 | * is implementation defined. | ||
1462 | * | ||
1463 | * ADC/ADD/AND/BIC/CMN/CMP/EOR/MOV/MVN/ORR/RSB/RSC/SBC/SUB/TEQ | ||
1464 | * TST: Rd, Rn, Rm, !Rs | ||
1465 | * BX: Rm | ||
1466 | * BLX(2): !Rm | ||
1467 | * BX: Rm (R15 legal, but discouraged) | ||
1468 | * BXJ: !Rm, | ||
1469 | * CLZ: !Rd, !Rm | ||
1470 | * CPY: Rd, Rm | ||
1471 | * LDC/2,STC/2 immediate offset & unindex: Rn | ||
1472 | * LDC/2,STC/2 immediate pre/post-indexed: !Rn | ||
1473 | * LDM(1/3): !Rn, register_list | ||
1474 | * LDM(2): !Rn, !register_list | ||
1475 | * LDR,STR,PLD immediate offset: Rd, Rn | ||
1476 | * LDR,STR,PLD register offset: Rd, Rn, !Rm | ||
1477 | * LDR,STR,PLD scaled register offset: Rd, !Rn, !Rm | ||
1478 | * LDR,STR immediate pre/post-indexed: Rd, !Rn | ||
1479 | * LDR,STR register pre/post-indexed: Rd, !Rn, !Rm | ||
1480 | * LDR,STR scaled register pre/post-indexed: Rd, !Rn, !Rm | ||
1481 | * LDRB,STRB immediate offset: !Rd, Rn | ||
1482 | * LDRB,STRB register offset: !Rd, Rn, !Rm | ||
1483 | * LDRB,STRB scaled register offset: !Rd, !Rn, !Rm | ||
1484 | * LDRB,STRB immediate pre/post-indexed: !Rd, !Rn | ||
1485 | * LDRB,STRB register pre/post-indexed: !Rd, !Rn, !Rm | ||
1486 | * LDRB,STRB scaled register pre/post-indexed: !Rd, !Rn, !Rm | ||
1487 | * LDRT,LDRBT,STRBT immediate pre/post-indexed: !Rd, !Rn | ||
1488 | * LDRT,LDRBT,STRBT register pre/post-indexed: !Rd, !Rn, !Rm | ||
1489 | * LDRT,LDRBT,STRBT scaled register pre/post-indexed: !Rd, !Rn, !Rm | ||
1490 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate offset: !Rd, Rn | ||
1491 | * LDRH/SH/SB/D,STRH/SH/SB/D register offset: !Rd, Rn, !Rm | ||
1492 | * LDRH/SH/SB/D,STRH/SH/SB/D immediate pre/post-indexed: !Rd, !Rn | ||
1493 | * LDRH/SH/SB/D,STRH/SH/SB/D register pre/post-indexed: !Rd, !Rn, !Rm | ||
1494 | * LDREX: !Rd, !Rn | ||
1495 | * MCR/2: !Rd | ||
1496 | * MCRR/2,MRRC/2: !Rd, !Rn | ||
1497 | * MLA: !Rd, !Rn, !Rm, !Rs | ||
1498 | * MOV: Rd | ||
1499 | * MRC/2: !Rd (if Rd==15, only changes cond codes, not the register) | ||
1500 | * MRS,MSR: !Rd | ||
1501 | * MUL: !Rd, !Rm, !Rs | ||
1502 | * PKH{BT,TB}: !Rd, !Rn, !Rm | ||
1503 | * QDADD,[U]QADD/16/8/SUBX: !Rd, !Rm, !Rn | ||
1504 | * QDSUB,[U]QSUB/16/8/ADDX: !Rd, !Rm, !Rn | ||
1505 | * REV/16/SH: !Rd, !Rm | ||
1506 | * RFE: !Rn | ||
1507 | * {S,U}[H]ADD{16,8,SUBX},{S,U}[H]SUB{16,8,ADDX}: !Rd, !Rn, !Rm | ||
1508 | * SEL: !Rd, !Rn, !Rm | ||
1509 | * SMLA<x><y>,SMLA{D,W<y>},SMLSD,SMML{A,S}: !Rd, !Rn, !Rm, !Rs | ||
1510 | * SMLAL<x><y>,SMLA{D,LD},SMLSLD,SMMULL,SMULW<y>: !RdHi, !RdLo, !Rm, !Rs | ||
1511 | * SMMUL,SMUAD,SMUL<x><y>,SMUSD: !Rd, !Rm, !Rs | ||
1512 | * SSAT/16: !Rd, !Rm | ||
1513 | * STM(1/2): !Rn, register_list* (R15 in reg list not recommended) | ||
1514 | * STRT immediate pre/post-indexed: Rd*, !Rn | ||
1515 | * STRT register pre/post-indexed: Rd*, !Rn, !Rm | ||
1516 | * STRT scaled register pre/post-indexed: Rd*, !Rn, !Rm | ||
1517 | * STREX: !Rd, !Rn, !Rm | ||
1518 | * SWP/B: !Rd, !Rn, !Rm | ||
1519 | * {S,U}XTA{B,B16,H}: !Rd, !Rn, !Rm | ||
1520 | * {S,U}XT{B,B16,H}: !Rd, !Rm | ||
1521 | * UM{AA,LA,UL}L: !RdHi, !RdLo, !Rm, !Rs | ||
1522 | * USA{D8,A8,T,T16}: !Rd, !Rm, !Rs | ||
1523 | * | ||
1524 | * May transfer control by writing R15 (possible mode changes or alternate | ||
1525 | * mode accesses marked by "*"): | ||
1526 | * ALU op (* with s-bit), B, BL, BKPT, BLX(1/2), BX, BXJ, CPS*, CPY, | ||
1527 | * LDM(1), LDM(2/3)*, LDR, MOV, RFE*, SWI* | ||
1528 | * | ||
1529 | * Instructions that do not take general registers, nor transfer control: | ||
1530 | * CDP/2, SETEND, SRS* | ||
1531 | */ | ||
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 2ba7deb3072e..1656c87501c0 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c | |||
@@ -134,7 +134,8 @@ static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, | |||
134 | struct kprobe_ctlblk *kcb) | 134 | struct kprobe_ctlblk *kcb) |
135 | { | 135 | { |
136 | regs->ARM_pc += 4; | 136 | regs->ARM_pc += 4; |
137 | p->ainsn.insn_handler(p, regs); | 137 | if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) |
138 | p->ainsn.insn_handler(p, regs); | ||
138 | } | 139 | } |
139 | 140 | ||
140 | /* | 141 | /* |
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c index 31a316c1777b..0f107dcb0347 100644 --- a/arch/arm/kernel/leds.c +++ b/arch/arm/kernel/leds.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/sysdev.h> | 12 | #include <linux/sysdev.h> |
13 | #include <linux/syscore_ops.h> | ||
13 | 14 | ||
14 | #include <asm/leds.h> | 15 | #include <asm/leds.h> |
15 | 16 | ||
@@ -69,36 +70,37 @@ static ssize_t leds_store(struct sys_device *dev, | |||
69 | 70 | ||
70 | static SYSDEV_ATTR(event, 0200, NULL, leds_store); | 71 | static SYSDEV_ATTR(event, 0200, NULL, leds_store); |
71 | 72 | ||
72 | static int leds_suspend(struct sys_device *dev, pm_message_t state) | 73 | static struct sysdev_class leds_sysclass = { |
74 | .name = "leds", | ||
75 | }; | ||
76 | |||
77 | static struct sys_device leds_device = { | ||
78 | .id = 0, | ||
79 | .cls = &leds_sysclass, | ||
80 | }; | ||
81 | |||
82 | static int leds_suspend(void) | ||
73 | { | 83 | { |
74 | leds_event(led_stop); | 84 | leds_event(led_stop); |
75 | return 0; | 85 | return 0; |
76 | } | 86 | } |
77 | 87 | ||
78 | static int leds_resume(struct sys_device *dev) | 88 | static void leds_resume(void) |
79 | { | 89 | { |
80 | leds_event(led_start); | 90 | leds_event(led_start); |
81 | return 0; | ||
82 | } | 91 | } |
83 | 92 | ||
84 | static int leds_shutdown(struct sys_device *dev) | 93 | static void leds_shutdown(void) |
85 | { | 94 | { |
86 | leds_event(led_halted); | 95 | leds_event(led_halted); |
87 | return 0; | ||
88 | } | 96 | } |
89 | 97 | ||
90 | static struct sysdev_class leds_sysclass = { | 98 | static struct syscore_ops leds_syscore_ops = { |
91 | .name = "leds", | ||
92 | .shutdown = leds_shutdown, | 99 | .shutdown = leds_shutdown, |
93 | .suspend = leds_suspend, | 100 | .suspend = leds_suspend, |
94 | .resume = leds_resume, | 101 | .resume = leds_resume, |
95 | }; | 102 | }; |
96 | 103 | ||
97 | static struct sys_device leds_device = { | ||
98 | .id = 0, | ||
99 | .cls = &leds_sysclass, | ||
100 | }; | ||
101 | |||
102 | static int __init leds_init(void) | 104 | static int __init leds_init(void) |
103 | { | 105 | { |
104 | int ret; | 106 | int ret; |
@@ -107,6 +109,8 @@ static int __init leds_init(void) | |||
107 | ret = sysdev_register(&leds_device); | 109 | ret = sysdev_register(&leds_device); |
108 | if (ret == 0) | 110 | if (ret == 0) |
109 | ret = sysdev_create_file(&leds_device, &attr_event); | 111 | ret = sysdev_create_file(&leds_device, &attr_event); |
112 | if (ret == 0) | ||
113 | register_syscore_ops(&leds_syscore_ops); | ||
110 | return ret; | 114 | return ret; |
111 | } | 115 | } |
112 | 116 | ||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 1fc74cbd1a19..e59bbd496c39 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
@@ -23,6 +23,8 @@ extern unsigned long kexec_indirection_page; | |||
23 | extern unsigned long kexec_mach_type; | 23 | extern unsigned long kexec_mach_type; |
24 | extern unsigned long kexec_boot_atags; | 24 | extern unsigned long kexec_boot_atags; |
25 | 25 | ||
26 | static atomic_t waiting_for_crash_ipi; | ||
27 | |||
26 | /* | 28 | /* |
27 | * Provide a dummy crash_notes definition while crash dump arrives to arm. | 29 | * Provide a dummy crash_notes definition while crash dump arrives to arm. |
28 | * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. | 30 | * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. |
@@ -37,14 +39,47 @@ void machine_kexec_cleanup(struct kimage *image) | |||
37 | { | 39 | { |
38 | } | 40 | } |
39 | 41 | ||
42 | void machine_crash_nonpanic_core(void *unused) | ||
43 | { | ||
44 | struct pt_regs regs; | ||
45 | |||
46 | crash_setup_regs(®s, NULL); | ||
47 | printk(KERN_DEBUG "CPU %u will stop doing anything useful since another CPU has crashed\n", | ||
48 | smp_processor_id()); | ||
49 | crash_save_cpu(®s, smp_processor_id()); | ||
50 | flush_cache_all(); | ||
51 | |||
52 | atomic_dec(&waiting_for_crash_ipi); | ||
53 | while (1) | ||
54 | cpu_relax(); | ||
55 | } | ||
56 | |||
40 | void machine_crash_shutdown(struct pt_regs *regs) | 57 | void machine_crash_shutdown(struct pt_regs *regs) |
41 | { | 58 | { |
59 | unsigned long msecs; | ||
60 | |||
42 | local_irq_disable(); | 61 | local_irq_disable(); |
62 | |||
63 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | ||
64 | smp_call_function(machine_crash_nonpanic_core, NULL, false); | ||
65 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ | ||
66 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { | ||
67 | mdelay(1); | ||
68 | msecs--; | ||
69 | } | ||
70 | if (atomic_read(&waiting_for_crash_ipi) > 0) | ||
71 | printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n"); | ||
72 | |||
43 | crash_save_cpu(regs, smp_processor_id()); | 73 | crash_save_cpu(regs, smp_processor_id()); |
44 | 74 | ||
45 | printk(KERN_INFO "Loading crashdump kernel...\n"); | 75 | printk(KERN_INFO "Loading crashdump kernel...\n"); |
46 | } | 76 | } |
47 | 77 | ||
78 | /* | ||
79 | * Function pointer to optional machine-specific reinitialization | ||
80 | */ | ||
81 | void (*kexec_reinit)(void); | ||
82 | |||
48 | void machine_kexec(struct kimage *image) | 83 | void machine_kexec(struct kimage *image) |
49 | { | 84 | { |
50 | unsigned long page_list; | 85 | unsigned long page_list; |
@@ -74,11 +109,16 @@ void machine_kexec(struct kimage *image) | |||
74 | (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE); | 109 | (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE); |
75 | printk(KERN_INFO "Bye!\n"); | 110 | printk(KERN_INFO "Bye!\n"); |
76 | 111 | ||
112 | if (kexec_reinit) | ||
113 | kexec_reinit(); | ||
77 | local_irq_disable(); | 114 | local_irq_disable(); |
78 | local_fiq_disable(); | 115 | local_fiq_disable(); |
79 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ | 116 | setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ |
80 | flush_cache_all(); | 117 | flush_cache_all(); |
118 | outer_flush_all(); | ||
119 | outer_disable(); | ||
81 | cpu_proc_fin(); | 120 | cpu_proc_fin(); |
121 | outer_inv_all(); | ||
82 | flush_cache_all(); | 122 | flush_cache_all(); |
83 | cpu_reset(reboot_code_buffer_phys); | 123 | cpu_reset(reboot_code_buffer_phys); |
84 | } | 124 | } |
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 6b4605893f1e..016d6a0830a3 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
25 | #include <asm/smp_plat.h> | ||
25 | #include <asm/unwind.h> | 26 | #include <asm/unwind.h> |
26 | 27 | ||
27 | #ifdef CONFIG_XIP_KERNEL | 28 | #ifdef CONFIG_XIP_KERNEL |
@@ -38,17 +39,9 @@ | |||
38 | #ifdef CONFIG_MMU | 39 | #ifdef CONFIG_MMU |
39 | void *module_alloc(unsigned long size) | 40 | void *module_alloc(unsigned long size) |
40 | { | 41 | { |
41 | struct vm_struct *area; | 42 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, |
42 | 43 | GFP_KERNEL, PAGE_KERNEL_EXEC, -1, | |
43 | size = PAGE_ALIGN(size); | 44 | __builtin_return_address(0)); |
44 | if (!size) | ||
45 | return NULL; | ||
46 | |||
47 | area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); | ||
48 | if (!area) | ||
49 | return NULL; | ||
50 | |||
51 | return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); | ||
52 | } | 45 | } |
53 | #else /* CONFIG_MMU */ | 46 | #else /* CONFIG_MMU */ |
54 | void *module_alloc(unsigned long size) | 47 | void *module_alloc(unsigned long size) |
@@ -67,24 +60,6 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, | |||
67 | char *secstrings, | 60 | char *secstrings, |
68 | struct module *mod) | 61 | struct module *mod) |
69 | { | 62 | { |
70 | #ifdef CONFIG_ARM_UNWIND | ||
71 | Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; | ||
72 | |||
73 | for (s = sechdrs; s < sechdrs_end; s++) { | ||
74 | if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0) | ||
75 | mod->arch.unw_sec_init = s; | ||
76 | else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0) | ||
77 | mod->arch.unw_sec_devinit = s; | ||
78 | else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0) | ||
79 | mod->arch.unw_sec_core = s; | ||
80 | else if (strcmp(".init.text", secstrings + s->sh_name) == 0) | ||
81 | mod->arch.sec_init_text = s; | ||
82 | else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0) | ||
83 | mod->arch.sec_devinit_text = s; | ||
84 | else if (strcmp(".text", secstrings + s->sh_name) == 0) | ||
85 | mod->arch.sec_core_text = s; | ||
86 | } | ||
87 | #endif | ||
88 | return 0; | 63 | return 0; |
89 | } | 64 | } |
90 | 65 | ||
@@ -101,6 +76,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
101 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { | 76 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { |
102 | unsigned long loc; | 77 | unsigned long loc; |
103 | Elf32_Sym *sym; | 78 | Elf32_Sym *sym; |
79 | const char *symname; | ||
104 | s32 offset; | 80 | s32 offset; |
105 | #ifdef CONFIG_THUMB2_KERNEL | 81 | #ifdef CONFIG_THUMB2_KERNEL |
106 | u32 upper, lower, sign, j1, j2; | 82 | u32 upper, lower, sign, j1, j2; |
@@ -108,18 +84,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
108 | 84 | ||
109 | offset = ELF32_R_SYM(rel->r_info); | 85 | offset = ELF32_R_SYM(rel->r_info); |
110 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { | 86 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { |
111 | printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n", | 87 | pr_err("%s: section %u reloc %u: bad relocation sym offset\n", |
112 | module->name, relindex, i); | 88 | module->name, relindex, i); |
113 | return -ENOEXEC; | 89 | return -ENOEXEC; |
114 | } | 90 | } |
115 | 91 | ||
116 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; | 92 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; |
93 | symname = strtab + sym->st_name; | ||
117 | 94 | ||
118 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { | 95 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { |
119 | printk(KERN_ERR "%s: out of bounds relocation, " | 96 | pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n", |
120 | "section %d reloc %d offset %d size %d\n", | 97 | module->name, relindex, i, symname, |
121 | module->name, relindex, i, rel->r_offset, | 98 | rel->r_offset, dstsec->sh_size); |
122 | dstsec->sh_size); | ||
123 | return -ENOEXEC; | 99 | return -ENOEXEC; |
124 | } | 100 | } |
125 | 101 | ||
@@ -145,10 +121,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
145 | if (offset & 3 || | 121 | if (offset & 3 || |
146 | offset <= (s32)0xfe000000 || | 122 | offset <= (s32)0xfe000000 || |
147 | offset >= (s32)0x02000000) { | 123 | offset >= (s32)0x02000000) { |
148 | printk(KERN_ERR | 124 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
149 | "%s: relocation out of range, section " | 125 | module->name, relindex, i, symname, |
150 | "%d reloc %d sym '%s'\n", module->name, | 126 | ELF32_R_TYPE(rel->r_info), loc, |
151 | relindex, i, strtab + sym->st_name); | 127 | sym->st_value); |
152 | return -ENOEXEC; | 128 | return -ENOEXEC; |
153 | } | 129 | } |
154 | 130 | ||
@@ -217,14 +193,23 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
217 | offset -= 0x02000000; | 193 | offset -= 0x02000000; |
218 | offset += sym->st_value - loc; | 194 | offset += sym->st_value - loc; |
219 | 195 | ||
220 | /* only Thumb addresses allowed (no interworking) */ | 196 | /* |
221 | if (!(offset & 1) || | 197 | * For function symbols, only Thumb addresses are |
198 | * allowed (no interworking). | ||
199 | * | ||
200 | * For non-function symbols, the destination | ||
201 | * has no specific ARM/Thumb disposition, so | ||
202 | * the branch is resolved under the assumption | ||
203 | * that interworking is not required. | ||
204 | */ | ||
205 | if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC && | ||
206 | !(offset & 1)) || | ||
222 | offset <= (s32)0xff000000 || | 207 | offset <= (s32)0xff000000 || |
223 | offset >= (s32)0x01000000) { | 208 | offset >= (s32)0x01000000) { |
224 | printk(KERN_ERR | 209 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
225 | "%s: relocation out of range, section " | 210 | module->name, relindex, i, symname, |
226 | "%d reloc %d sym '%s'\n", module->name, | 211 | ELF32_R_TYPE(rel->r_info), loc, |
227 | relindex, i, strtab + sym->st_name); | 212 | sym->st_value); |
228 | return -ENOEXEC; | 213 | return -ENOEXEC; |
229 | } | 214 | } |
230 | 215 | ||
@@ -289,50 +274,94 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, | |||
289 | return -ENOEXEC; | 274 | return -ENOEXEC; |
290 | } | 275 | } |
291 | 276 | ||
292 | #ifdef CONFIG_ARM_UNWIND | 277 | struct mod_unwind_map { |
293 | static void register_unwind_tables(struct module *mod) | 278 | const Elf_Shdr *unw_sec; |
294 | { | 279 | const Elf_Shdr *txt_sec; |
295 | if (mod->arch.unw_sec_init && mod->arch.sec_init_text) | 280 | }; |
296 | mod->arch.unwind_init = | ||
297 | unwind_table_add(mod->arch.unw_sec_init->sh_addr, | ||
298 | mod->arch.unw_sec_init->sh_size, | ||
299 | mod->arch.sec_init_text->sh_addr, | ||
300 | mod->arch.sec_init_text->sh_size); | ||
301 | if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text) | ||
302 | mod->arch.unwind_devinit = | ||
303 | unwind_table_add(mod->arch.unw_sec_devinit->sh_addr, | ||
304 | mod->arch.unw_sec_devinit->sh_size, | ||
305 | mod->arch.sec_devinit_text->sh_addr, | ||
306 | mod->arch.sec_devinit_text->sh_size); | ||
307 | if (mod->arch.unw_sec_core && mod->arch.sec_core_text) | ||
308 | mod->arch.unwind_core = | ||
309 | unwind_table_add(mod->arch.unw_sec_core->sh_addr, | ||
310 | mod->arch.unw_sec_core->sh_size, | ||
311 | mod->arch.sec_core_text->sh_addr, | ||
312 | mod->arch.sec_core_text->sh_size); | ||
313 | } | ||
314 | 281 | ||
315 | static void unregister_unwind_tables(struct module *mod) | 282 | static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, |
283 | const Elf_Shdr *sechdrs, const char *name) | ||
316 | { | 284 | { |
317 | unwind_table_del(mod->arch.unwind_init); | 285 | const Elf_Shdr *s, *se; |
318 | unwind_table_del(mod->arch.unwind_devinit); | 286 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
319 | unwind_table_del(mod->arch.unwind_core); | 287 | |
288 | for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) | ||
289 | if (strcmp(name, secstrs + s->sh_name) == 0) | ||
290 | return s; | ||
291 | |||
292 | return NULL; | ||
320 | } | 293 | } |
321 | #else | ||
322 | static inline void register_unwind_tables(struct module *mod) { } | ||
323 | static inline void unregister_unwind_tables(struct module *mod) { } | ||
324 | #endif | ||
325 | 294 | ||
326 | int | 295 | extern void fixup_pv_table(const void *, unsigned long); |
327 | module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | 296 | extern void fixup_smp(const void *, unsigned long); |
328 | struct module *module) | 297 | |
298 | int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
299 | struct module *mod) | ||
329 | { | 300 | { |
330 | register_unwind_tables(module); | 301 | const Elf_Shdr *s = NULL; |
302 | #ifdef CONFIG_ARM_UNWIND | ||
303 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
304 | const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; | ||
305 | struct mod_unwind_map maps[ARM_SEC_MAX]; | ||
306 | int i; | ||
307 | |||
308 | memset(maps, 0, sizeof(maps)); | ||
309 | |||
310 | for (s = sechdrs; s < sechdrs_end; s++) { | ||
311 | const char *secname = secstrs + s->sh_name; | ||
312 | |||
313 | if (!(s->sh_flags & SHF_ALLOC)) | ||
314 | continue; | ||
315 | |||
316 | if (strcmp(".ARM.exidx.init.text", secname) == 0) | ||
317 | maps[ARM_SEC_INIT].unw_sec = s; | ||
318 | else if (strcmp(".ARM.exidx.devinit.text", secname) == 0) | ||
319 | maps[ARM_SEC_DEVINIT].unw_sec = s; | ||
320 | else if (strcmp(".ARM.exidx", secname) == 0) | ||
321 | maps[ARM_SEC_CORE].unw_sec = s; | ||
322 | else if (strcmp(".ARM.exidx.exit.text", secname) == 0) | ||
323 | maps[ARM_SEC_EXIT].unw_sec = s; | ||
324 | else if (strcmp(".ARM.exidx.devexit.text", secname) == 0) | ||
325 | maps[ARM_SEC_DEVEXIT].unw_sec = s; | ||
326 | else if (strcmp(".init.text", secname) == 0) | ||
327 | maps[ARM_SEC_INIT].txt_sec = s; | ||
328 | else if (strcmp(".devinit.text", secname) == 0) | ||
329 | maps[ARM_SEC_DEVINIT].txt_sec = s; | ||
330 | else if (strcmp(".text", secname) == 0) | ||
331 | maps[ARM_SEC_CORE].txt_sec = s; | ||
332 | else if (strcmp(".exit.text", secname) == 0) | ||
333 | maps[ARM_SEC_EXIT].txt_sec = s; | ||
334 | else if (strcmp(".devexit.text", secname) == 0) | ||
335 | maps[ARM_SEC_DEVEXIT].txt_sec = s; | ||
336 | } | ||
337 | |||
338 | for (i = 0; i < ARM_SEC_MAX; i++) | ||
339 | if (maps[i].unw_sec && maps[i].txt_sec) | ||
340 | mod->arch.unwind[i] = | ||
341 | unwind_table_add(maps[i].unw_sec->sh_addr, | ||
342 | maps[i].unw_sec->sh_size, | ||
343 | maps[i].txt_sec->sh_addr, | ||
344 | maps[i].txt_sec->sh_size); | ||
345 | #endif | ||
346 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
347 | s = find_mod_section(hdr, sechdrs, ".pv_table"); | ||
348 | if (s) | ||
349 | fixup_pv_table((void *)s->sh_addr, s->sh_size); | ||
350 | #endif | ||
351 | s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); | ||
352 | if (s && !is_smp()) | ||
353 | fixup_smp((void *)s->sh_addr, s->sh_size); | ||
331 | return 0; | 354 | return 0; |
332 | } | 355 | } |
333 | 356 | ||
334 | void | 357 | void |
335 | module_arch_cleanup(struct module *mod) | 358 | module_arch_cleanup(struct module *mod) |
336 | { | 359 | { |
337 | unregister_unwind_tables(mod); | 360 | #ifdef CONFIG_ARM_UNWIND |
361 | int i; | ||
362 | |||
363 | for (i = 0; i < ARM_SEC_MAX; i++) | ||
364 | if (mod->arch.unwind[i]) | ||
365 | unwind_table_del(mod->arch.unwind[i]); | ||
366 | #endif | ||
338 | } | 367 | } |
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index ecbb0288e5dd..2b5b1421596c 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -4,9 +4,7 @@ | |||
4 | * ARM performance counter support. | 4 | * ARM performance counter support. |
5 | * | 5 | * |
6 | * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles | 6 | * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles |
7 | * | 7 | * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com> |
8 | * ARMv7 support: Jean Pihet <jpihet@mvista.com> | ||
9 | * 2010 (c) MontaVista Software, LLC. | ||
10 | * | 8 | * |
11 | * This code is based on the sparc64 perf event code, which is in turn based | 9 | * This code is based on the sparc64 perf event code, which is in turn based |
12 | * on the x86 code. Callchain code is based on the ARM OProfile backtrace | 10 | * on the x86 code. Callchain code is based on the ARM OProfile backtrace |
@@ -34,7 +32,7 @@ static struct platform_device *pmu_device; | |||
34 | * Hardware lock to serialize accesses to PMU registers. Needed for the | 32 | * Hardware lock to serialize accesses to PMU registers. Needed for the |
35 | * read/modify/write sequences. | 33 | * read/modify/write sequences. |
36 | */ | 34 | */ |
37 | DEFINE_SPINLOCK(pmu_lock); | 35 | static DEFINE_RAW_SPINLOCK(pmu_lock); |
38 | 36 | ||
39 | /* | 37 | /* |
40 | * ARMv6 supports a maximum of 3 events, starting from index 1. If we add | 38 | * ARMv6 supports a maximum of 3 events, starting from index 1. If we add |
@@ -67,31 +65,26 @@ struct cpu_hw_events { | |||
67 | */ | 65 | */ |
68 | unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; | 66 | unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; |
69 | }; | 67 | }; |
70 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); | 68 | static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); |
71 | |||
72 | /* PMU names. */ | ||
73 | static const char *arm_pmu_names[] = { | ||
74 | [ARM_PERF_PMU_ID_XSCALE1] = "xscale1", | ||
75 | [ARM_PERF_PMU_ID_XSCALE2] = "xscale2", | ||
76 | [ARM_PERF_PMU_ID_V6] = "v6", | ||
77 | [ARM_PERF_PMU_ID_V6MP] = "v6mpcore", | ||
78 | [ARM_PERF_PMU_ID_CA8] = "ARMv7 Cortex-A8", | ||
79 | [ARM_PERF_PMU_ID_CA9] = "ARMv7 Cortex-A9", | ||
80 | }; | ||
81 | 69 | ||
82 | struct arm_pmu { | 70 | struct arm_pmu { |
83 | enum arm_perf_pmu_ids id; | 71 | enum arm_perf_pmu_ids id; |
72 | const char *name; | ||
84 | irqreturn_t (*handle_irq)(int irq_num, void *dev); | 73 | irqreturn_t (*handle_irq)(int irq_num, void *dev); |
85 | void (*enable)(struct hw_perf_event *evt, int idx); | 74 | void (*enable)(struct hw_perf_event *evt, int idx); |
86 | void (*disable)(struct hw_perf_event *evt, int idx); | 75 | void (*disable)(struct hw_perf_event *evt, int idx); |
87 | int (*event_map)(int evt); | ||
88 | u64 (*raw_event)(u64); | ||
89 | int (*get_event_idx)(struct cpu_hw_events *cpuc, | 76 | int (*get_event_idx)(struct cpu_hw_events *cpuc, |
90 | struct hw_perf_event *hwc); | 77 | struct hw_perf_event *hwc); |
91 | u32 (*read_counter)(int idx); | 78 | u32 (*read_counter)(int idx); |
92 | void (*write_counter)(int idx, u32 val); | 79 | void (*write_counter)(int idx, u32 val); |
93 | void (*start)(void); | 80 | void (*start)(void); |
94 | void (*stop)(void); | 81 | void (*stop)(void); |
82 | void (*reset)(void *); | ||
83 | const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] | ||
84 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
85 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
86 | const unsigned (*event_map)[PERF_COUNT_HW_MAX]; | ||
87 | u32 raw_event_mask; | ||
95 | int num_events; | 88 | int num_events; |
96 | u64 max_period; | 89 | u64 max_period; |
97 | }; | 90 | }; |
@@ -123,6 +116,12 @@ armpmu_get_max_events(void) | |||
123 | } | 116 | } |
124 | EXPORT_SYMBOL_GPL(armpmu_get_max_events); | 117 | EXPORT_SYMBOL_GPL(armpmu_get_max_events); |
125 | 118 | ||
119 | int perf_num_counters(void) | ||
120 | { | ||
121 | return armpmu_get_max_events(); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
124 | |||
126 | #define HW_OP_UNSUPPORTED 0xFFFF | 125 | #define HW_OP_UNSUPPORTED 0xFFFF |
127 | 126 | ||
128 | #define C(_x) \ | 127 | #define C(_x) \ |
@@ -130,10 +129,6 @@ EXPORT_SYMBOL_GPL(armpmu_get_max_events); | |||
130 | 129 | ||
131 | #define CACHE_OP_UNSUPPORTED 0xFFFF | 130 | #define CACHE_OP_UNSUPPORTED 0xFFFF |
132 | 131 | ||
133 | static unsigned armpmu_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
134 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
135 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
136 | |||
137 | static int | 132 | static int |
138 | armpmu_map_cache_event(u64 config) | 133 | armpmu_map_cache_event(u64 config) |
139 | { | 134 | { |
@@ -151,7 +146,7 @@ armpmu_map_cache_event(u64 config) | |||
151 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | 146 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) |
152 | return -EINVAL; | 147 | return -EINVAL; |
153 | 148 | ||
154 | ret = (int)armpmu_perf_cache_map[cache_type][cache_op][cache_result]; | 149 | ret = (int)(*armpmu->cache_map)[cache_type][cache_op][cache_result]; |
155 | 150 | ||
156 | if (ret == CACHE_OP_UNSUPPORTED) | 151 | if (ret == CACHE_OP_UNSUPPORTED) |
157 | return -ENOENT; | 152 | return -ENOENT; |
@@ -160,6 +155,19 @@ armpmu_map_cache_event(u64 config) | |||
160 | } | 155 | } |
161 | 156 | ||
162 | static int | 157 | static int |
158 | armpmu_map_event(u64 config) | ||
159 | { | ||
160 | int mapping = (*armpmu->event_map)[config]; | ||
161 | return mapping == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : mapping; | ||
162 | } | ||
163 | |||
164 | static int | ||
165 | armpmu_map_raw_event(u64 config) | ||
166 | { | ||
167 | return (int)(config & armpmu->raw_event_mask); | ||
168 | } | ||
169 | |||
170 | static int | ||
163 | armpmu_event_set_period(struct perf_event *event, | 171 | armpmu_event_set_period(struct perf_event *event, |
164 | struct hw_perf_event *hwc, | 172 | struct hw_perf_event *hwc, |
165 | int idx) | 173 | int idx) |
@@ -197,11 +205,9 @@ armpmu_event_set_period(struct perf_event *event, | |||
197 | static u64 | 205 | static u64 |
198 | armpmu_event_update(struct perf_event *event, | 206 | armpmu_event_update(struct perf_event *event, |
199 | struct hw_perf_event *hwc, | 207 | struct hw_perf_event *hwc, |
200 | int idx) | 208 | int idx, int overflow) |
201 | { | 209 | { |
202 | int shift = 64 - 32; | 210 | u64 delta, prev_raw_count, new_raw_count; |
203 | s64 prev_raw_count, new_raw_count; | ||
204 | u64 delta; | ||
205 | 211 | ||
206 | again: | 212 | again: |
207 | prev_raw_count = local64_read(&hwc->prev_count); | 213 | prev_raw_count = local64_read(&hwc->prev_count); |
@@ -211,8 +217,13 @@ again: | |||
211 | new_raw_count) != prev_raw_count) | 217 | new_raw_count) != prev_raw_count) |
212 | goto again; | 218 | goto again; |
213 | 219 | ||
214 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | 220 | new_raw_count &= armpmu->max_period; |
215 | delta >>= shift; | 221 | prev_raw_count &= armpmu->max_period; |
222 | |||
223 | if (overflow) | ||
224 | delta = armpmu->max_period - prev_raw_count + new_raw_count + 1; | ||
225 | else | ||
226 | delta = new_raw_count - prev_raw_count; | ||
216 | 227 | ||
217 | local64_add(delta, &event->count); | 228 | local64_add(delta, &event->count); |
218 | local64_sub(delta, &hwc->period_left); | 229 | local64_sub(delta, &hwc->period_left); |
@@ -221,46 +232,56 @@ again: | |||
221 | } | 232 | } |
222 | 233 | ||
223 | static void | 234 | static void |
224 | armpmu_disable(struct perf_event *event) | 235 | armpmu_read(struct perf_event *event) |
225 | { | 236 | { |
226 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
227 | struct hw_perf_event *hwc = &event->hw; | 237 | struct hw_perf_event *hwc = &event->hw; |
228 | int idx = hwc->idx; | ||
229 | |||
230 | WARN_ON(idx < 0); | ||
231 | |||
232 | clear_bit(idx, cpuc->active_mask); | ||
233 | armpmu->disable(hwc, idx); | ||
234 | 238 | ||
235 | barrier(); | 239 | /* Don't read disabled counters! */ |
236 | 240 | if (hwc->idx < 0) | |
237 | armpmu_event_update(event, hwc, idx); | 241 | return; |
238 | cpuc->events[idx] = NULL; | ||
239 | clear_bit(idx, cpuc->used_mask); | ||
240 | 242 | ||
241 | perf_event_update_userpage(event); | 243 | armpmu_event_update(event, hwc, hwc->idx, 0); |
242 | } | 244 | } |
243 | 245 | ||
244 | static void | 246 | static void |
245 | armpmu_read(struct perf_event *event) | 247 | armpmu_stop(struct perf_event *event, int flags) |
246 | { | 248 | { |
247 | struct hw_perf_event *hwc = &event->hw; | 249 | struct hw_perf_event *hwc = &event->hw; |
248 | 250 | ||
249 | /* Don't read disabled counters! */ | 251 | if (!armpmu) |
250 | if (hwc->idx < 0) | ||
251 | return; | 252 | return; |
252 | 253 | ||
253 | armpmu_event_update(event, hwc, hwc->idx); | 254 | /* |
255 | * ARM pmu always has to update the counter, so ignore | ||
256 | * PERF_EF_UPDATE, see comments in armpmu_start(). | ||
257 | */ | ||
258 | if (!(hwc->state & PERF_HES_STOPPED)) { | ||
259 | armpmu->disable(hwc, hwc->idx); | ||
260 | barrier(); /* why? */ | ||
261 | armpmu_event_update(event, hwc, hwc->idx, 0); | ||
262 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | ||
263 | } | ||
254 | } | 264 | } |
255 | 265 | ||
256 | static void | 266 | static void |
257 | armpmu_unthrottle(struct perf_event *event) | 267 | armpmu_start(struct perf_event *event, int flags) |
258 | { | 268 | { |
259 | struct hw_perf_event *hwc = &event->hw; | 269 | struct hw_perf_event *hwc = &event->hw; |
260 | 270 | ||
271 | if (!armpmu) | ||
272 | return; | ||
273 | |||
274 | /* | ||
275 | * ARM pmu always has to reprogram the period, so ignore | ||
276 | * PERF_EF_RELOAD, see the comment below. | ||
277 | */ | ||
278 | if (flags & PERF_EF_RELOAD) | ||
279 | WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); | ||
280 | |||
281 | hwc->state = 0; | ||
261 | /* | 282 | /* |
262 | * Set the period again. Some counters can't be stopped, so when we | 283 | * Set the period again. Some counters can't be stopped, so when we |
263 | * were throttled we simply disabled the IRQ source and the counter | 284 | * were stopped we simply disabled the IRQ source and the counter |
264 | * may have been left counting. If we don't do this step then we may | 285 | * may have been left counting. If we don't do this step then we may |
265 | * get an interrupt too soon or *way* too late if the overflow has | 286 | * get an interrupt too soon or *way* too late if the overflow has |
266 | * happened since disabling. | 287 | * happened since disabling. |
@@ -269,14 +290,33 @@ armpmu_unthrottle(struct perf_event *event) | |||
269 | armpmu->enable(hwc, hwc->idx); | 290 | armpmu->enable(hwc, hwc->idx); |
270 | } | 291 | } |
271 | 292 | ||
293 | static void | ||
294 | armpmu_del(struct perf_event *event, int flags) | ||
295 | { | ||
296 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
297 | struct hw_perf_event *hwc = &event->hw; | ||
298 | int idx = hwc->idx; | ||
299 | |||
300 | WARN_ON(idx < 0); | ||
301 | |||
302 | clear_bit(idx, cpuc->active_mask); | ||
303 | armpmu_stop(event, PERF_EF_UPDATE); | ||
304 | cpuc->events[idx] = NULL; | ||
305 | clear_bit(idx, cpuc->used_mask); | ||
306 | |||
307 | perf_event_update_userpage(event); | ||
308 | } | ||
309 | |||
272 | static int | 310 | static int |
273 | armpmu_enable(struct perf_event *event) | 311 | armpmu_add(struct perf_event *event, int flags) |
274 | { | 312 | { |
275 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 313 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
276 | struct hw_perf_event *hwc = &event->hw; | 314 | struct hw_perf_event *hwc = &event->hw; |
277 | int idx; | 315 | int idx; |
278 | int err = 0; | 316 | int err = 0; |
279 | 317 | ||
318 | perf_pmu_disable(event->pmu); | ||
319 | |||
280 | /* If we don't have a space for the counter then finish early. */ | 320 | /* If we don't have a space for the counter then finish early. */ |
281 | idx = armpmu->get_event_idx(cpuc, hwc); | 321 | idx = armpmu->get_event_idx(cpuc, hwc); |
282 | if (idx < 0) { | 322 | if (idx < 0) { |
@@ -293,25 +333,19 @@ armpmu_enable(struct perf_event *event) | |||
293 | cpuc->events[idx] = event; | 333 | cpuc->events[idx] = event; |
294 | set_bit(idx, cpuc->active_mask); | 334 | set_bit(idx, cpuc->active_mask); |
295 | 335 | ||
296 | /* Set the period for the event. */ | 336 | hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; |
297 | armpmu_event_set_period(event, hwc, idx); | 337 | if (flags & PERF_EF_START) |
298 | 338 | armpmu_start(event, PERF_EF_RELOAD); | |
299 | /* Enable the event. */ | ||
300 | armpmu->enable(hwc, idx); | ||
301 | 339 | ||
302 | /* Propagate our changes to the userspace mapping. */ | 340 | /* Propagate our changes to the userspace mapping. */ |
303 | perf_event_update_userpage(event); | 341 | perf_event_update_userpage(event); |
304 | 342 | ||
305 | out: | 343 | out: |
344 | perf_pmu_enable(event->pmu); | ||
306 | return err; | 345 | return err; |
307 | } | 346 | } |
308 | 347 | ||
309 | static struct pmu pmu = { | 348 | static struct pmu pmu; |
310 | .enable = armpmu_enable, | ||
311 | .disable = armpmu_disable, | ||
312 | .unthrottle = armpmu_unthrottle, | ||
313 | .read = armpmu_read, | ||
314 | }; | ||
315 | 349 | ||
316 | static int | 350 | static int |
317 | validate_event(struct cpu_hw_events *cpuc, | 351 | validate_event(struct cpu_hw_events *cpuc, |
@@ -347,9 +381,18 @@ validate_group(struct perf_event *event) | |||
347 | return 0; | 381 | return 0; |
348 | } | 382 | } |
349 | 383 | ||
384 | static irqreturn_t armpmu_platform_irq(int irq, void *dev) | ||
385 | { | ||
386 | struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev); | ||
387 | |||
388 | return plat->handle_irq(irq, dev, armpmu->handle_irq); | ||
389 | } | ||
390 | |||
350 | static int | 391 | static int |
351 | armpmu_reserve_hardware(void) | 392 | armpmu_reserve_hardware(void) |
352 | { | 393 | { |
394 | struct arm_pmu_platdata *plat; | ||
395 | irq_handler_t handle_irq; | ||
353 | int i, err = -ENODEV, irq; | 396 | int i, err = -ENODEV, irq; |
354 | 397 | ||
355 | pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU); | 398 | pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU); |
@@ -360,6 +403,12 @@ armpmu_reserve_hardware(void) | |||
360 | 403 | ||
361 | init_pmu(ARM_PMU_DEVICE_CPU); | 404 | init_pmu(ARM_PMU_DEVICE_CPU); |
362 | 405 | ||
406 | plat = dev_get_platdata(&pmu_device->dev); | ||
407 | if (plat && plat->handle_irq) | ||
408 | handle_irq = armpmu_platform_irq; | ||
409 | else | ||
410 | handle_irq = armpmu->handle_irq; | ||
411 | |||
363 | if (pmu_device->num_resources < 1) { | 412 | if (pmu_device->num_resources < 1) { |
364 | pr_err("no irqs for PMUs defined\n"); | 413 | pr_err("no irqs for PMUs defined\n"); |
365 | return -ENODEV; | 414 | return -ENODEV; |
@@ -370,7 +419,7 @@ armpmu_reserve_hardware(void) | |||
370 | if (irq < 0) | 419 | if (irq < 0) |
371 | continue; | 420 | continue; |
372 | 421 | ||
373 | err = request_irq(irq, armpmu->handle_irq, | 422 | err = request_irq(irq, handle_irq, |
374 | IRQF_DISABLED | IRQF_NOBALANCING, | 423 | IRQF_DISABLED | IRQF_NOBALANCING, |
375 | "armpmu", NULL); | 424 | "armpmu", NULL); |
376 | if (err) { | 425 | if (err) { |
@@ -429,11 +478,11 @@ __hw_perf_event_init(struct perf_event *event) | |||
429 | 478 | ||
430 | /* Decode the generic type into an ARM event identifier. */ | 479 | /* Decode the generic type into an ARM event identifier. */ |
431 | if (PERF_TYPE_HARDWARE == event->attr.type) { | 480 | if (PERF_TYPE_HARDWARE == event->attr.type) { |
432 | mapping = armpmu->event_map(event->attr.config); | 481 | mapping = armpmu_map_event(event->attr.config); |
433 | } else if (PERF_TYPE_HW_CACHE == event->attr.type) { | 482 | } else if (PERF_TYPE_HW_CACHE == event->attr.type) { |
434 | mapping = armpmu_map_cache_event(event->attr.config); | 483 | mapping = armpmu_map_cache_event(event->attr.config); |
435 | } else if (PERF_TYPE_RAW == event->attr.type) { | 484 | } else if (PERF_TYPE_RAW == event->attr.type) { |
436 | mapping = armpmu->raw_event(event->attr.config); | 485 | mapping = armpmu_map_raw_event(event->attr.config); |
437 | } else { | 486 | } else { |
438 | pr_debug("event type %x not supported\n", event->attr.type); | 487 | pr_debug("event type %x not supported\n", event->attr.type); |
439 | return -EOPNOTSUPP; | 488 | return -EOPNOTSUPP; |
@@ -491,22 +540,26 @@ __hw_perf_event_init(struct perf_event *event) | |||
491 | return err; | 540 | return err; |
492 | } | 541 | } |
493 | 542 | ||
494 | const struct pmu * | 543 | static int armpmu_event_init(struct perf_event *event) |
495 | hw_perf_event_init(struct perf_event *event) | ||
496 | { | 544 | { |
497 | int err = 0; | 545 | int err = 0; |
498 | 546 | ||
547 | switch (event->attr.type) { | ||
548 | case PERF_TYPE_RAW: | ||
549 | case PERF_TYPE_HARDWARE: | ||
550 | case PERF_TYPE_HW_CACHE: | ||
551 | break; | ||
552 | |||
553 | default: | ||
554 | return -ENOENT; | ||
555 | } | ||
556 | |||
499 | if (!armpmu) | 557 | if (!armpmu) |
500 | return ERR_PTR(-ENODEV); | 558 | return -ENODEV; |
501 | 559 | ||
502 | event->destroy = hw_perf_event_destroy; | 560 | event->destroy = hw_perf_event_destroy; |
503 | 561 | ||
504 | if (!atomic_inc_not_zero(&active_events)) { | 562 | if (!atomic_inc_not_zero(&active_events)) { |
505 | if (atomic_read(&active_events) > perf_max_events) { | ||
506 | atomic_dec(&active_events); | ||
507 | return ERR_PTR(-ENOSPC); | ||
508 | } | ||
509 | |||
510 | mutex_lock(&pmu_reserve_mutex); | 563 | mutex_lock(&pmu_reserve_mutex); |
511 | if (atomic_read(&active_events) == 0) { | 564 | if (atomic_read(&active_events) == 0) { |
512 | err = armpmu_reserve_hardware(); | 565 | err = armpmu_reserve_hardware(); |
@@ -518,20 +571,19 @@ hw_perf_event_init(struct perf_event *event) | |||
518 | } | 571 | } |
519 | 572 | ||
520 | if (err) | 573 | if (err) |
521 | return ERR_PTR(err); | 574 | return err; |
522 | 575 | ||
523 | err = __hw_perf_event_init(event); | 576 | err = __hw_perf_event_init(event); |
524 | if (err) | 577 | if (err) |
525 | hw_perf_event_destroy(event); | 578 | hw_perf_event_destroy(event); |
526 | 579 | ||
527 | return err ? ERR_PTR(err) : &pmu; | 580 | return err; |
528 | } | 581 | } |
529 | 582 | ||
530 | void | 583 | static void armpmu_enable(struct pmu *pmu) |
531 | hw_perf_enable(void) | ||
532 | { | 584 | { |
533 | /* Enable all of the perf events on hardware. */ | 585 | /* Enable all of the perf events on hardware. */ |
534 | int idx; | 586 | int idx, enabled = 0; |
535 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 587 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
536 | 588 | ||
537 | if (!armpmu) | 589 | if (!armpmu) |
@@ -544,2378 +596,47 @@ hw_perf_enable(void) | |||
544 | continue; | 596 | continue; |
545 | 597 | ||
546 | armpmu->enable(&event->hw, idx); | 598 | armpmu->enable(&event->hw, idx); |
599 | enabled = 1; | ||
547 | } | 600 | } |
548 | 601 | ||
549 | armpmu->start(); | 602 | if (enabled) |
603 | armpmu->start(); | ||
550 | } | 604 | } |
551 | 605 | ||
552 | void | 606 | static void armpmu_disable(struct pmu *pmu) |
553 | hw_perf_disable(void) | ||
554 | { | 607 | { |
555 | if (armpmu) | 608 | if (armpmu) |
556 | armpmu->stop(); | 609 | armpmu->stop(); |
557 | } | 610 | } |
558 | 611 | ||
559 | /* | 612 | static struct pmu pmu = { |
560 | * ARMv6 Performance counter handling code. | 613 | .pmu_enable = armpmu_enable, |
561 | * | 614 | .pmu_disable = armpmu_disable, |
562 | * ARMv6 has 2 configurable performance counters and a single cycle counter. | 615 | .event_init = armpmu_event_init, |
563 | * They all share a single reset bit but can be written to zero so we can use | 616 | .add = armpmu_add, |
564 | * that for a reset. | 617 | .del = armpmu_del, |
565 | * | 618 | .start = armpmu_start, |
566 | * The counters can't be individually enabled or disabled so when we remove | 619 | .stop = armpmu_stop, |
567 | * one event and replace it with another we could get spurious counts from the | 620 | .read = armpmu_read, |
568 | * wrong event. However, we can take advantage of the fact that the | ||
569 | * performance counters can export events to the event bus, and the event bus | ||
570 | * itself can be monitored. This requires that we *don't* export the events to | ||
571 | * the event bus. The procedure for disabling a configurable counter is: | ||
572 | * - change the counter to count the ETMEXTOUT[0] signal (0x20). This | ||
573 | * effectively stops the counter from counting. | ||
574 | * - disable the counter's interrupt generation (each counter has it's | ||
575 | * own interrupt enable bit). | ||
576 | * Once stopped, the counter value can be written as 0 to reset. | ||
577 | * | ||
578 | * To enable a counter: | ||
579 | * - enable the counter's interrupt generation. | ||
580 | * - set the new event type. | ||
581 | * | ||
582 | * Note: the dedicated cycle counter only counts cycles and can't be | ||
583 | * enabled/disabled independently of the others. When we want to disable the | ||
584 | * cycle counter, we have to just disable the interrupt reporting and start | ||
585 | * ignoring that counter. When re-enabling, we have to reset the value and | ||
586 | * enable the interrupt. | ||
587 | */ | ||
588 | |||
589 | enum armv6_perf_types { | ||
590 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, | ||
591 | ARMV6_PERFCTR_IBUF_STALL = 0x1, | ||
592 | ARMV6_PERFCTR_DDEP_STALL = 0x2, | ||
593 | ARMV6_PERFCTR_ITLB_MISS = 0x3, | ||
594 | ARMV6_PERFCTR_DTLB_MISS = 0x4, | ||
595 | ARMV6_PERFCTR_BR_EXEC = 0x5, | ||
596 | ARMV6_PERFCTR_BR_MISPREDICT = 0x6, | ||
597 | ARMV6_PERFCTR_INSTR_EXEC = 0x7, | ||
598 | ARMV6_PERFCTR_DCACHE_HIT = 0x9, | ||
599 | ARMV6_PERFCTR_DCACHE_ACCESS = 0xA, | ||
600 | ARMV6_PERFCTR_DCACHE_MISS = 0xB, | ||
601 | ARMV6_PERFCTR_DCACHE_WBACK = 0xC, | ||
602 | ARMV6_PERFCTR_SW_PC_CHANGE = 0xD, | ||
603 | ARMV6_PERFCTR_MAIN_TLB_MISS = 0xF, | ||
604 | ARMV6_PERFCTR_EXPL_D_ACCESS = 0x10, | ||
605 | ARMV6_PERFCTR_LSU_FULL_STALL = 0x11, | ||
606 | ARMV6_PERFCTR_WBUF_DRAINED = 0x12, | ||
607 | ARMV6_PERFCTR_CPU_CYCLES = 0xFF, | ||
608 | ARMV6_PERFCTR_NOP = 0x20, | ||
609 | }; | ||
610 | |||
611 | enum armv6_counters { | ||
612 | ARMV6_CYCLE_COUNTER = 1, | ||
613 | ARMV6_COUNTER0, | ||
614 | ARMV6_COUNTER1, | ||
615 | }; | ||
616 | |||
617 | /* | ||
618 | * The hardware events that we support. We do support cache operations but | ||
619 | * we have harvard caches and no way to combine instruction and data | ||
620 | * accesses/misses in hardware. | ||
621 | */ | ||
622 | static const unsigned armv6_perf_map[PERF_COUNT_HW_MAX] = { | ||
623 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV6_PERFCTR_CPU_CYCLES, | ||
624 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6_PERFCTR_INSTR_EXEC, | ||
625 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
626 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
627 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6_PERFCTR_BR_EXEC, | ||
628 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6_PERFCTR_BR_MISPREDICT, | ||
629 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
630 | }; | ||
631 | |||
632 | static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
633 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
634 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
635 | [C(L1D)] = { | ||
636 | /* | ||
637 | * The performance counters don't differentiate between read | ||
638 | * and write accesses/misses so this isn't strictly correct, | ||
639 | * but it's the best we can do. Writes and reads get | ||
640 | * combined. | ||
641 | */ | ||
642 | [C(OP_READ)] = { | ||
643 | [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, | ||
644 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, | ||
645 | }, | ||
646 | [C(OP_WRITE)] = { | ||
647 | [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, | ||
648 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, | ||
649 | }, | ||
650 | [C(OP_PREFETCH)] = { | ||
651 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
652 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
653 | }, | ||
654 | }, | ||
655 | [C(L1I)] = { | ||
656 | [C(OP_READ)] = { | ||
657 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
658 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, | ||
659 | }, | ||
660 | [C(OP_WRITE)] = { | ||
661 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
662 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, | ||
663 | }, | ||
664 | [C(OP_PREFETCH)] = { | ||
665 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
666 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
667 | }, | ||
668 | }, | ||
669 | [C(LL)] = { | ||
670 | [C(OP_READ)] = { | ||
671 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
672 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
673 | }, | ||
674 | [C(OP_WRITE)] = { | ||
675 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
676 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
677 | }, | ||
678 | [C(OP_PREFETCH)] = { | ||
679 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
680 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
681 | }, | ||
682 | }, | ||
683 | [C(DTLB)] = { | ||
684 | /* | ||
685 | * The ARM performance counters can count micro DTLB misses, | ||
686 | * micro ITLB misses and main TLB misses. There isn't an event | ||
687 | * for TLB misses, so use the micro misses here and if users | ||
688 | * want the main TLB misses they can use a raw counter. | ||
689 | */ | ||
690 | [C(OP_READ)] = { | ||
691 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
692 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, | ||
693 | }, | ||
694 | [C(OP_WRITE)] = { | ||
695 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
696 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, | ||
697 | }, | ||
698 | [C(OP_PREFETCH)] = { | ||
699 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
700 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
701 | }, | ||
702 | }, | ||
703 | [C(ITLB)] = { | ||
704 | [C(OP_READ)] = { | ||
705 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
706 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, | ||
707 | }, | ||
708 | [C(OP_WRITE)] = { | ||
709 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
710 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, | ||
711 | }, | ||
712 | [C(OP_PREFETCH)] = { | ||
713 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
714 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
715 | }, | ||
716 | }, | ||
717 | [C(BPU)] = { | ||
718 | [C(OP_READ)] = { | ||
719 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
720 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
721 | }, | ||
722 | [C(OP_WRITE)] = { | ||
723 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
724 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
725 | }, | ||
726 | [C(OP_PREFETCH)] = { | ||
727 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
728 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
729 | }, | ||
730 | }, | ||
731 | }; | ||
732 | |||
733 | enum armv6mpcore_perf_types { | ||
734 | ARMV6MPCORE_PERFCTR_ICACHE_MISS = 0x0, | ||
735 | ARMV6MPCORE_PERFCTR_IBUF_STALL = 0x1, | ||
736 | ARMV6MPCORE_PERFCTR_DDEP_STALL = 0x2, | ||
737 | ARMV6MPCORE_PERFCTR_ITLB_MISS = 0x3, | ||
738 | ARMV6MPCORE_PERFCTR_DTLB_MISS = 0x4, | ||
739 | ARMV6MPCORE_PERFCTR_BR_EXEC = 0x5, | ||
740 | ARMV6MPCORE_PERFCTR_BR_NOTPREDICT = 0x6, | ||
741 | ARMV6MPCORE_PERFCTR_BR_MISPREDICT = 0x7, | ||
742 | ARMV6MPCORE_PERFCTR_INSTR_EXEC = 0x8, | ||
743 | ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS = 0xA, | ||
744 | ARMV6MPCORE_PERFCTR_DCACHE_RDMISS = 0xB, | ||
745 | ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS = 0xC, | ||
746 | ARMV6MPCORE_PERFCTR_DCACHE_WRMISS = 0xD, | ||
747 | ARMV6MPCORE_PERFCTR_DCACHE_EVICTION = 0xE, | ||
748 | ARMV6MPCORE_PERFCTR_SW_PC_CHANGE = 0xF, | ||
749 | ARMV6MPCORE_PERFCTR_MAIN_TLB_MISS = 0x10, | ||
750 | ARMV6MPCORE_PERFCTR_EXPL_MEM_ACCESS = 0x11, | ||
751 | ARMV6MPCORE_PERFCTR_LSU_FULL_STALL = 0x12, | ||
752 | ARMV6MPCORE_PERFCTR_WBUF_DRAINED = 0x13, | ||
753 | ARMV6MPCORE_PERFCTR_CPU_CYCLES = 0xFF, | ||
754 | }; | ||
755 | |||
756 | /* | ||
757 | * The hardware events that we support. We do support cache operations but | ||
758 | * we have harvard caches and no way to combine instruction and data | ||
759 | * accesses/misses in hardware. | ||
760 | */ | ||
761 | static const unsigned armv6mpcore_perf_map[PERF_COUNT_HW_MAX] = { | ||
762 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV6MPCORE_PERFCTR_CPU_CYCLES, | ||
763 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_INSTR_EXEC, | ||
764 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
765 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
766 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_BR_EXEC, | ||
767 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6MPCORE_PERFCTR_BR_MISPREDICT, | ||
768 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
769 | }; | ||
770 | |||
771 | static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
772 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
773 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
774 | [C(L1D)] = { | ||
775 | [C(OP_READ)] = { | ||
776 | [C(RESULT_ACCESS)] = | ||
777 | ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS, | ||
778 | [C(RESULT_MISS)] = | ||
779 | ARMV6MPCORE_PERFCTR_DCACHE_RDMISS, | ||
780 | }, | ||
781 | [C(OP_WRITE)] = { | ||
782 | [C(RESULT_ACCESS)] = | ||
783 | ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS, | ||
784 | [C(RESULT_MISS)] = | ||
785 | ARMV6MPCORE_PERFCTR_DCACHE_WRMISS, | ||
786 | }, | ||
787 | [C(OP_PREFETCH)] = { | ||
788 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
789 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
790 | }, | ||
791 | }, | ||
792 | [C(L1I)] = { | ||
793 | [C(OP_READ)] = { | ||
794 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
795 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, | ||
796 | }, | ||
797 | [C(OP_WRITE)] = { | ||
798 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
799 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, | ||
800 | }, | ||
801 | [C(OP_PREFETCH)] = { | ||
802 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
803 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
804 | }, | ||
805 | }, | ||
806 | [C(LL)] = { | ||
807 | [C(OP_READ)] = { | ||
808 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
809 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
810 | }, | ||
811 | [C(OP_WRITE)] = { | ||
812 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
813 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
814 | }, | ||
815 | [C(OP_PREFETCH)] = { | ||
816 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
817 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
818 | }, | ||
819 | }, | ||
820 | [C(DTLB)] = { | ||
821 | /* | ||
822 | * The ARM performance counters can count micro DTLB misses, | ||
823 | * micro ITLB misses and main TLB misses. There isn't an event | ||
824 | * for TLB misses, so use the micro misses here and if users | ||
825 | * want the main TLB misses they can use a raw counter. | ||
826 | */ | ||
827 | [C(OP_READ)] = { | ||
828 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
829 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, | ||
830 | }, | ||
831 | [C(OP_WRITE)] = { | ||
832 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
833 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, | ||
834 | }, | ||
835 | [C(OP_PREFETCH)] = { | ||
836 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
837 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
838 | }, | ||
839 | }, | ||
840 | [C(ITLB)] = { | ||
841 | [C(OP_READ)] = { | ||
842 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
843 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, | ||
844 | }, | ||
845 | [C(OP_WRITE)] = { | ||
846 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
847 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, | ||
848 | }, | ||
849 | [C(OP_PREFETCH)] = { | ||
850 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
851 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
852 | }, | ||
853 | }, | ||
854 | [C(BPU)] = { | ||
855 | [C(OP_READ)] = { | ||
856 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
857 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
858 | }, | ||
859 | [C(OP_WRITE)] = { | ||
860 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
861 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
862 | }, | ||
863 | [C(OP_PREFETCH)] = { | ||
864 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
865 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
866 | }, | ||
867 | }, | ||
868 | }; | ||
869 | |||
870 | static inline unsigned long | ||
871 | armv6_pmcr_read(void) | ||
872 | { | ||
873 | u32 val; | ||
874 | asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r"(val)); | ||
875 | return val; | ||
876 | } | ||
877 | |||
878 | static inline void | ||
879 | armv6_pmcr_write(unsigned long val) | ||
880 | { | ||
881 | asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r"(val)); | ||
882 | } | ||
883 | |||
884 | #define ARMV6_PMCR_ENABLE (1 << 0) | ||
885 | #define ARMV6_PMCR_CTR01_RESET (1 << 1) | ||
886 | #define ARMV6_PMCR_CCOUNT_RESET (1 << 2) | ||
887 | #define ARMV6_PMCR_CCOUNT_DIV (1 << 3) | ||
888 | #define ARMV6_PMCR_COUNT0_IEN (1 << 4) | ||
889 | #define ARMV6_PMCR_COUNT1_IEN (1 << 5) | ||
890 | #define ARMV6_PMCR_CCOUNT_IEN (1 << 6) | ||
891 | #define ARMV6_PMCR_COUNT0_OVERFLOW (1 << 8) | ||
892 | #define ARMV6_PMCR_COUNT1_OVERFLOW (1 << 9) | ||
893 | #define ARMV6_PMCR_CCOUNT_OVERFLOW (1 << 10) | ||
894 | #define ARMV6_PMCR_EVT_COUNT0_SHIFT 20 | ||
895 | #define ARMV6_PMCR_EVT_COUNT0_MASK (0xFF << ARMV6_PMCR_EVT_COUNT0_SHIFT) | ||
896 | #define ARMV6_PMCR_EVT_COUNT1_SHIFT 12 | ||
897 | #define ARMV6_PMCR_EVT_COUNT1_MASK (0xFF << ARMV6_PMCR_EVT_COUNT1_SHIFT) | ||
898 | |||
899 | #define ARMV6_PMCR_OVERFLOWED_MASK \ | ||
900 | (ARMV6_PMCR_COUNT0_OVERFLOW | ARMV6_PMCR_COUNT1_OVERFLOW | \ | ||
901 | ARMV6_PMCR_CCOUNT_OVERFLOW) | ||
902 | |||
903 | static inline int | ||
904 | armv6_pmcr_has_overflowed(unsigned long pmcr) | ||
905 | { | ||
906 | return (pmcr & ARMV6_PMCR_OVERFLOWED_MASK); | ||
907 | } | ||
908 | |||
909 | static inline int | ||
910 | armv6_pmcr_counter_has_overflowed(unsigned long pmcr, | ||
911 | enum armv6_counters counter) | ||
912 | { | ||
913 | int ret = 0; | ||
914 | |||
915 | if (ARMV6_CYCLE_COUNTER == counter) | ||
916 | ret = pmcr & ARMV6_PMCR_CCOUNT_OVERFLOW; | ||
917 | else if (ARMV6_COUNTER0 == counter) | ||
918 | ret = pmcr & ARMV6_PMCR_COUNT0_OVERFLOW; | ||
919 | else if (ARMV6_COUNTER1 == counter) | ||
920 | ret = pmcr & ARMV6_PMCR_COUNT1_OVERFLOW; | ||
921 | else | ||
922 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
923 | |||
924 | return ret; | ||
925 | } | ||
926 | |||
927 | static inline u32 | ||
928 | armv6pmu_read_counter(int counter) | ||
929 | { | ||
930 | unsigned long value = 0; | ||
931 | |||
932 | if (ARMV6_CYCLE_COUNTER == counter) | ||
933 | asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(value)); | ||
934 | else if (ARMV6_COUNTER0 == counter) | ||
935 | asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r"(value)); | ||
936 | else if (ARMV6_COUNTER1 == counter) | ||
937 | asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r"(value)); | ||
938 | else | ||
939 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
940 | |||
941 | return value; | ||
942 | } | ||
943 | |||
944 | static inline void | ||
945 | armv6pmu_write_counter(int counter, | ||
946 | u32 value) | ||
947 | { | ||
948 | if (ARMV6_CYCLE_COUNTER == counter) | ||
949 | asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r"(value)); | ||
950 | else if (ARMV6_COUNTER0 == counter) | ||
951 | asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r"(value)); | ||
952 | else if (ARMV6_COUNTER1 == counter) | ||
953 | asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r"(value)); | ||
954 | else | ||
955 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
956 | } | ||
957 | |||
958 | void | ||
959 | armv6pmu_enable_event(struct hw_perf_event *hwc, | ||
960 | int idx) | ||
961 | { | ||
962 | unsigned long val, mask, evt, flags; | ||
963 | |||
964 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
965 | mask = 0; | ||
966 | evt = ARMV6_PMCR_CCOUNT_IEN; | ||
967 | } else if (ARMV6_COUNTER0 == idx) { | ||
968 | mask = ARMV6_PMCR_EVT_COUNT0_MASK; | ||
969 | evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT0_SHIFT) | | ||
970 | ARMV6_PMCR_COUNT0_IEN; | ||
971 | } else if (ARMV6_COUNTER1 == idx) { | ||
972 | mask = ARMV6_PMCR_EVT_COUNT1_MASK; | ||
973 | evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT1_SHIFT) | | ||
974 | ARMV6_PMCR_COUNT1_IEN; | ||
975 | } else { | ||
976 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
977 | return; | ||
978 | } | ||
979 | |||
980 | /* | ||
981 | * Mask out the current event and set the counter to count the event | ||
982 | * that we're interested in. | ||
983 | */ | ||
984 | spin_lock_irqsave(&pmu_lock, flags); | ||
985 | val = armv6_pmcr_read(); | ||
986 | val &= ~mask; | ||
987 | val |= evt; | ||
988 | armv6_pmcr_write(val); | ||
989 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
990 | } | ||
991 | |||
992 | static irqreturn_t | ||
993 | armv6pmu_handle_irq(int irq_num, | ||
994 | void *dev) | ||
995 | { | ||
996 | unsigned long pmcr = armv6_pmcr_read(); | ||
997 | struct perf_sample_data data; | ||
998 | struct cpu_hw_events *cpuc; | ||
999 | struct pt_regs *regs; | ||
1000 | int idx; | ||
1001 | |||
1002 | if (!armv6_pmcr_has_overflowed(pmcr)) | ||
1003 | return IRQ_NONE; | ||
1004 | |||
1005 | regs = get_irq_regs(); | ||
1006 | |||
1007 | /* | ||
1008 | * The interrupts are cleared by writing the overflow flags back to | ||
1009 | * the control register. All of the other bits don't have any effect | ||
1010 | * if they are rewritten, so write the whole value back. | ||
1011 | */ | ||
1012 | armv6_pmcr_write(pmcr); | ||
1013 | |||
1014 | perf_sample_data_init(&data, 0); | ||
1015 | |||
1016 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
1017 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
1018 | struct perf_event *event = cpuc->events[idx]; | ||
1019 | struct hw_perf_event *hwc; | ||
1020 | |||
1021 | if (!test_bit(idx, cpuc->active_mask)) | ||
1022 | continue; | ||
1023 | |||
1024 | /* | ||
1025 | * We have a single interrupt for all counters. Check that | ||
1026 | * each counter has overflowed before we process it. | ||
1027 | */ | ||
1028 | if (!armv6_pmcr_counter_has_overflowed(pmcr, idx)) | ||
1029 | continue; | ||
1030 | |||
1031 | hwc = &event->hw; | ||
1032 | armpmu_event_update(event, hwc, idx); | ||
1033 | data.period = event->hw.last_period; | ||
1034 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
1035 | continue; | ||
1036 | |||
1037 | if (perf_event_overflow(event, 0, &data, regs)) | ||
1038 | armpmu->disable(hwc, idx); | ||
1039 | } | ||
1040 | |||
1041 | /* | ||
1042 | * Handle the pending perf events. | ||
1043 | * | ||
1044 | * Note: this call *must* be run with interrupts disabled. For | ||
1045 | * platforms that can have the PMU interrupts raised as an NMI, this | ||
1046 | * will not work. | ||
1047 | */ | ||
1048 | perf_event_do_pending(); | ||
1049 | |||
1050 | return IRQ_HANDLED; | ||
1051 | } | ||
1052 | |||
1053 | static void | ||
1054 | armv6pmu_start(void) | ||
1055 | { | ||
1056 | unsigned long flags, val; | ||
1057 | |||
1058 | spin_lock_irqsave(&pmu_lock, flags); | ||
1059 | val = armv6_pmcr_read(); | ||
1060 | val |= ARMV6_PMCR_ENABLE; | ||
1061 | armv6_pmcr_write(val); | ||
1062 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1063 | } | ||
1064 | |||
1065 | void | ||
1066 | armv6pmu_stop(void) | ||
1067 | { | ||
1068 | unsigned long flags, val; | ||
1069 | |||
1070 | spin_lock_irqsave(&pmu_lock, flags); | ||
1071 | val = armv6_pmcr_read(); | ||
1072 | val &= ~ARMV6_PMCR_ENABLE; | ||
1073 | armv6_pmcr_write(val); | ||
1074 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1075 | } | ||
1076 | |||
1077 | static inline int | ||
1078 | armv6pmu_event_map(int config) | ||
1079 | { | ||
1080 | int mapping = armv6_perf_map[config]; | ||
1081 | if (HW_OP_UNSUPPORTED == mapping) | ||
1082 | mapping = -EOPNOTSUPP; | ||
1083 | return mapping; | ||
1084 | } | ||
1085 | |||
1086 | static inline int | ||
1087 | armv6mpcore_pmu_event_map(int config) | ||
1088 | { | ||
1089 | int mapping = armv6mpcore_perf_map[config]; | ||
1090 | if (HW_OP_UNSUPPORTED == mapping) | ||
1091 | mapping = -EOPNOTSUPP; | ||
1092 | return mapping; | ||
1093 | } | ||
1094 | |||
1095 | static u64 | ||
1096 | armv6pmu_raw_event(u64 config) | ||
1097 | { | ||
1098 | return config & 0xff; | ||
1099 | } | ||
1100 | |||
1101 | static int | ||
1102 | armv6pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
1103 | struct hw_perf_event *event) | ||
1104 | { | ||
1105 | /* Always place a cycle counter into the cycle counter. */ | ||
1106 | if (ARMV6_PERFCTR_CPU_CYCLES == event->config_base) { | ||
1107 | if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask)) | ||
1108 | return -EAGAIN; | ||
1109 | |||
1110 | return ARMV6_CYCLE_COUNTER; | ||
1111 | } else { | ||
1112 | /* | ||
1113 | * For anything other than a cycle counter, try and use | ||
1114 | * counter0 and counter1. | ||
1115 | */ | ||
1116 | if (!test_and_set_bit(ARMV6_COUNTER1, cpuc->used_mask)) { | ||
1117 | return ARMV6_COUNTER1; | ||
1118 | } | ||
1119 | |||
1120 | if (!test_and_set_bit(ARMV6_COUNTER0, cpuc->used_mask)) { | ||
1121 | return ARMV6_COUNTER0; | ||
1122 | } | ||
1123 | |||
1124 | /* The counters are all in use. */ | ||
1125 | return -EAGAIN; | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | static void | ||
1130 | armv6pmu_disable_event(struct hw_perf_event *hwc, | ||
1131 | int idx) | ||
1132 | { | ||
1133 | unsigned long val, mask, evt, flags; | ||
1134 | |||
1135 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
1136 | mask = ARMV6_PMCR_CCOUNT_IEN; | ||
1137 | evt = 0; | ||
1138 | } else if (ARMV6_COUNTER0 == idx) { | ||
1139 | mask = ARMV6_PMCR_COUNT0_IEN | ARMV6_PMCR_EVT_COUNT0_MASK; | ||
1140 | evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT0_SHIFT; | ||
1141 | } else if (ARMV6_COUNTER1 == idx) { | ||
1142 | mask = ARMV6_PMCR_COUNT1_IEN | ARMV6_PMCR_EVT_COUNT1_MASK; | ||
1143 | evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT1_SHIFT; | ||
1144 | } else { | ||
1145 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
1146 | return; | ||
1147 | } | ||
1148 | |||
1149 | /* | ||
1150 | * Mask out the current event and set the counter to count the number | ||
1151 | * of ETM bus signal assertion cycles. The external reporting should | ||
1152 | * be disabled and so this should never increment. | ||
1153 | */ | ||
1154 | spin_lock_irqsave(&pmu_lock, flags); | ||
1155 | val = armv6_pmcr_read(); | ||
1156 | val &= ~mask; | ||
1157 | val |= evt; | ||
1158 | armv6_pmcr_write(val); | ||
1159 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1160 | } | ||
1161 | |||
1162 | static void | ||
1163 | armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc, | ||
1164 | int idx) | ||
1165 | { | ||
1166 | unsigned long val, mask, flags, evt = 0; | ||
1167 | |||
1168 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
1169 | mask = ARMV6_PMCR_CCOUNT_IEN; | ||
1170 | } else if (ARMV6_COUNTER0 == idx) { | ||
1171 | mask = ARMV6_PMCR_COUNT0_IEN; | ||
1172 | } else if (ARMV6_COUNTER1 == idx) { | ||
1173 | mask = ARMV6_PMCR_COUNT1_IEN; | ||
1174 | } else { | ||
1175 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
1176 | return; | ||
1177 | } | ||
1178 | |||
1179 | /* | ||
1180 | * Unlike UP ARMv6, we don't have a way of stopping the counters. We | ||
1181 | * simply disable the interrupt reporting. | ||
1182 | */ | ||
1183 | spin_lock_irqsave(&pmu_lock, flags); | ||
1184 | val = armv6_pmcr_read(); | ||
1185 | val &= ~mask; | ||
1186 | val |= evt; | ||
1187 | armv6_pmcr_write(val); | ||
1188 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1189 | } | ||
1190 | |||
1191 | static const struct arm_pmu armv6pmu = { | ||
1192 | .id = ARM_PERF_PMU_ID_V6, | ||
1193 | .handle_irq = armv6pmu_handle_irq, | ||
1194 | .enable = armv6pmu_enable_event, | ||
1195 | .disable = armv6pmu_disable_event, | ||
1196 | .event_map = armv6pmu_event_map, | ||
1197 | .raw_event = armv6pmu_raw_event, | ||
1198 | .read_counter = armv6pmu_read_counter, | ||
1199 | .write_counter = armv6pmu_write_counter, | ||
1200 | .get_event_idx = armv6pmu_get_event_idx, | ||
1201 | .start = armv6pmu_start, | ||
1202 | .stop = armv6pmu_stop, | ||
1203 | .num_events = 3, | ||
1204 | .max_period = (1LLU << 32) - 1, | ||
1205 | }; | ||
1206 | |||
1207 | /* | ||
1208 | * ARMv6mpcore is almost identical to single core ARMv6 with the exception | ||
1209 | * that some of the events have different enumerations and that there is no | ||
1210 | * *hack* to stop the programmable counters. To stop the counters we simply | ||
1211 | * disable the interrupt reporting and update the event. When unthrottling we | ||
1212 | * reset the period and enable the interrupt reporting. | ||
1213 | */ | ||
1214 | static const struct arm_pmu armv6mpcore_pmu = { | ||
1215 | .id = ARM_PERF_PMU_ID_V6MP, | ||
1216 | .handle_irq = armv6pmu_handle_irq, | ||
1217 | .enable = armv6pmu_enable_event, | ||
1218 | .disable = armv6mpcore_pmu_disable_event, | ||
1219 | .event_map = armv6mpcore_pmu_event_map, | ||
1220 | .raw_event = armv6pmu_raw_event, | ||
1221 | .read_counter = armv6pmu_read_counter, | ||
1222 | .write_counter = armv6pmu_write_counter, | ||
1223 | .get_event_idx = armv6pmu_get_event_idx, | ||
1224 | .start = armv6pmu_start, | ||
1225 | .stop = armv6pmu_stop, | ||
1226 | .num_events = 3, | ||
1227 | .max_period = (1LLU << 32) - 1, | ||
1228 | }; | ||
1229 | |||
1230 | /* | ||
1231 | * ARMv7 Cortex-A8 and Cortex-A9 Performance Events handling code. | ||
1232 | * | ||
1233 | * Copied from ARMv6 code, with the low level code inspired | ||
1234 | * by the ARMv7 Oprofile code. | ||
1235 | * | ||
1236 | * Cortex-A8 has up to 4 configurable performance counters and | ||
1237 | * a single cycle counter. | ||
1238 | * Cortex-A9 has up to 31 configurable performance counters and | ||
1239 | * a single cycle counter. | ||
1240 | * | ||
1241 | * All counters can be enabled/disabled and IRQ masked separately. The cycle | ||
1242 | * counter and all 4 performance counters together can be reset separately. | ||
1243 | */ | ||
1244 | |||
1245 | /* Common ARMv7 event types */ | ||
1246 | enum armv7_perf_types { | ||
1247 | ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, | ||
1248 | ARMV7_PERFCTR_IFETCH_MISS = 0x01, | ||
1249 | ARMV7_PERFCTR_ITLB_MISS = 0x02, | ||
1250 | ARMV7_PERFCTR_DCACHE_REFILL = 0x03, | ||
1251 | ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, | ||
1252 | ARMV7_PERFCTR_DTLB_REFILL = 0x05, | ||
1253 | ARMV7_PERFCTR_DREAD = 0x06, | ||
1254 | ARMV7_PERFCTR_DWRITE = 0x07, | ||
1255 | |||
1256 | ARMV7_PERFCTR_EXC_TAKEN = 0x09, | ||
1257 | ARMV7_PERFCTR_EXC_EXECUTED = 0x0A, | ||
1258 | ARMV7_PERFCTR_CID_WRITE = 0x0B, | ||
1259 | /* ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS. | ||
1260 | * It counts: | ||
1261 | * - all branch instructions, | ||
1262 | * - instructions that explicitly write the PC, | ||
1263 | * - exception generating instructions. | ||
1264 | */ | ||
1265 | ARMV7_PERFCTR_PC_WRITE = 0x0C, | ||
1266 | ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D, | ||
1267 | ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F, | ||
1268 | ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, | ||
1269 | ARMV7_PERFCTR_CLOCK_CYCLES = 0x11, | ||
1270 | |||
1271 | ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12, | ||
1272 | |||
1273 | ARMV7_PERFCTR_CPU_CYCLES = 0xFF | ||
1274 | }; | ||
1275 | |||
1276 | /* ARMv7 Cortex-A8 specific event types */ | ||
1277 | enum armv7_a8_perf_types { | ||
1278 | ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, | ||
1279 | |||
1280 | ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, | ||
1281 | |||
1282 | ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40, | ||
1283 | ARMV7_PERFCTR_L2_STORE_MERGED = 0x41, | ||
1284 | ARMV7_PERFCTR_L2_STORE_BUFF = 0x42, | ||
1285 | ARMV7_PERFCTR_L2_ACCESS = 0x43, | ||
1286 | ARMV7_PERFCTR_L2_CACH_MISS = 0x44, | ||
1287 | ARMV7_PERFCTR_AXI_READ_CYCLES = 0x45, | ||
1288 | ARMV7_PERFCTR_AXI_WRITE_CYCLES = 0x46, | ||
1289 | ARMV7_PERFCTR_MEMORY_REPLAY = 0x47, | ||
1290 | ARMV7_PERFCTR_UNALIGNED_ACCESS_REPLAY = 0x48, | ||
1291 | ARMV7_PERFCTR_L1_DATA_MISS = 0x49, | ||
1292 | ARMV7_PERFCTR_L1_INST_MISS = 0x4A, | ||
1293 | ARMV7_PERFCTR_L1_DATA_COLORING = 0x4B, | ||
1294 | ARMV7_PERFCTR_L1_NEON_DATA = 0x4C, | ||
1295 | ARMV7_PERFCTR_L1_NEON_CACH_DATA = 0x4D, | ||
1296 | ARMV7_PERFCTR_L2_NEON = 0x4E, | ||
1297 | ARMV7_PERFCTR_L2_NEON_HIT = 0x4F, | ||
1298 | ARMV7_PERFCTR_L1_INST = 0x50, | ||
1299 | ARMV7_PERFCTR_PC_RETURN_MIS_PRED = 0x51, | ||
1300 | ARMV7_PERFCTR_PC_BRANCH_FAILED = 0x52, | ||
1301 | ARMV7_PERFCTR_PC_BRANCH_TAKEN = 0x53, | ||
1302 | ARMV7_PERFCTR_PC_BRANCH_EXECUTED = 0x54, | ||
1303 | ARMV7_PERFCTR_OP_EXECUTED = 0x55, | ||
1304 | ARMV7_PERFCTR_CYCLES_INST_STALL = 0x56, | ||
1305 | ARMV7_PERFCTR_CYCLES_INST = 0x57, | ||
1306 | ARMV7_PERFCTR_CYCLES_NEON_DATA_STALL = 0x58, | ||
1307 | ARMV7_PERFCTR_CYCLES_NEON_INST_STALL = 0x59, | ||
1308 | ARMV7_PERFCTR_NEON_CYCLES = 0x5A, | ||
1309 | |||
1310 | ARMV7_PERFCTR_PMU0_EVENTS = 0x70, | ||
1311 | ARMV7_PERFCTR_PMU1_EVENTS = 0x71, | ||
1312 | ARMV7_PERFCTR_PMU_EVENTS = 0x72, | ||
1313 | }; | ||
1314 | |||
1315 | /* ARMv7 Cortex-A9 specific event types */ | ||
1316 | enum armv7_a9_perf_types { | ||
1317 | ARMV7_PERFCTR_JAVA_HW_BYTECODE_EXEC = 0x40, | ||
1318 | ARMV7_PERFCTR_JAVA_SW_BYTECODE_EXEC = 0x41, | ||
1319 | ARMV7_PERFCTR_JAZELLE_BRANCH_EXEC = 0x42, | ||
1320 | |||
1321 | ARMV7_PERFCTR_COHERENT_LINE_MISS = 0x50, | ||
1322 | ARMV7_PERFCTR_COHERENT_LINE_HIT = 0x51, | ||
1323 | |||
1324 | ARMV7_PERFCTR_ICACHE_DEP_STALL_CYCLES = 0x60, | ||
1325 | ARMV7_PERFCTR_DCACHE_DEP_STALL_CYCLES = 0x61, | ||
1326 | ARMV7_PERFCTR_TLB_MISS_DEP_STALL_CYCLES = 0x62, | ||
1327 | ARMV7_PERFCTR_STREX_EXECUTED_PASSED = 0x63, | ||
1328 | ARMV7_PERFCTR_STREX_EXECUTED_FAILED = 0x64, | ||
1329 | ARMV7_PERFCTR_DATA_EVICTION = 0x65, | ||
1330 | ARMV7_PERFCTR_ISSUE_STAGE_NO_INST = 0x66, | ||
1331 | ARMV7_PERFCTR_ISSUE_STAGE_EMPTY = 0x67, | ||
1332 | ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE = 0x68, | ||
1333 | |||
1334 | ARMV7_PERFCTR_PREDICTABLE_FUNCT_RETURNS = 0x6E, | ||
1335 | |||
1336 | ARMV7_PERFCTR_MAIN_UNIT_EXECUTED_INST = 0x70, | ||
1337 | ARMV7_PERFCTR_SECOND_UNIT_EXECUTED_INST = 0x71, | ||
1338 | ARMV7_PERFCTR_LD_ST_UNIT_EXECUTED_INST = 0x72, | ||
1339 | ARMV7_PERFCTR_FP_EXECUTED_INST = 0x73, | ||
1340 | ARMV7_PERFCTR_NEON_EXECUTED_INST = 0x74, | ||
1341 | |||
1342 | ARMV7_PERFCTR_PLD_FULL_DEP_STALL_CYCLES = 0x80, | ||
1343 | ARMV7_PERFCTR_DATA_WR_DEP_STALL_CYCLES = 0x81, | ||
1344 | ARMV7_PERFCTR_ITLB_MISS_DEP_STALL_CYCLES = 0x82, | ||
1345 | ARMV7_PERFCTR_DTLB_MISS_DEP_STALL_CYCLES = 0x83, | ||
1346 | ARMV7_PERFCTR_MICRO_ITLB_MISS_DEP_STALL_CYCLES = 0x84, | ||
1347 | ARMV7_PERFCTR_MICRO_DTLB_MISS_DEP_STALL_CYCLES = 0x85, | ||
1348 | ARMV7_PERFCTR_DMB_DEP_STALL_CYCLES = 0x86, | ||
1349 | |||
1350 | ARMV7_PERFCTR_INTGR_CLK_ENABLED_CYCLES = 0x8A, | ||
1351 | ARMV7_PERFCTR_DATA_ENGINE_CLK_EN_CYCLES = 0x8B, | ||
1352 | |||
1353 | ARMV7_PERFCTR_ISB_INST = 0x90, | ||
1354 | ARMV7_PERFCTR_DSB_INST = 0x91, | ||
1355 | ARMV7_PERFCTR_DMB_INST = 0x92, | ||
1356 | ARMV7_PERFCTR_EXT_INTERRUPTS = 0x93, | ||
1357 | |||
1358 | ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_COMPLETED = 0xA0, | ||
1359 | ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_SKIPPED = 0xA1, | ||
1360 | ARMV7_PERFCTR_PLE_FIFO_FLUSH = 0xA2, | ||
1361 | ARMV7_PERFCTR_PLE_RQST_COMPLETED = 0xA3, | ||
1362 | ARMV7_PERFCTR_PLE_FIFO_OVERFLOW = 0xA4, | ||
1363 | ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5 | ||
1364 | }; | ||
1365 | |||
1366 | /* | ||
1367 | * Cortex-A8 HW events mapping | ||
1368 | * | ||
1369 | * The hardware events that we support. We do support cache operations but | ||
1370 | * we have harvard caches and no way to combine instruction and data | ||
1371 | * accesses/misses in hardware. | ||
1372 | */ | ||
1373 | static const unsigned armv7_a8_perf_map[PERF_COUNT_HW_MAX] = { | ||
1374 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, | ||
1375 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, | ||
1376 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
1377 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
1378 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, | ||
1379 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1380 | [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, | ||
1381 | }; | ||
1382 | |||
1383 | static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
1384 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
1385 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
1386 | [C(L1D)] = { | ||
1387 | /* | ||
1388 | * The performance counters don't differentiate between read | ||
1389 | * and write accesses/misses so this isn't strictly correct, | ||
1390 | * but it's the best we can do. Writes and reads get | ||
1391 | * combined. | ||
1392 | */ | ||
1393 | [C(OP_READ)] = { | ||
1394 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
1395 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
1396 | }, | ||
1397 | [C(OP_WRITE)] = { | ||
1398 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
1399 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
1400 | }, | ||
1401 | [C(OP_PREFETCH)] = { | ||
1402 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1403 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1404 | }, | ||
1405 | }, | ||
1406 | [C(L1I)] = { | ||
1407 | [C(OP_READ)] = { | ||
1408 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, | ||
1409 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, | ||
1410 | }, | ||
1411 | [C(OP_WRITE)] = { | ||
1412 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, | ||
1413 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, | ||
1414 | }, | ||
1415 | [C(OP_PREFETCH)] = { | ||
1416 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1417 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1418 | }, | ||
1419 | }, | ||
1420 | [C(LL)] = { | ||
1421 | [C(OP_READ)] = { | ||
1422 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, | ||
1423 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, | ||
1424 | }, | ||
1425 | [C(OP_WRITE)] = { | ||
1426 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, | ||
1427 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, | ||
1428 | }, | ||
1429 | [C(OP_PREFETCH)] = { | ||
1430 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1431 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1432 | }, | ||
1433 | }, | ||
1434 | [C(DTLB)] = { | ||
1435 | /* | ||
1436 | * Only ITLB misses and DTLB refills are supported. | ||
1437 | * If users want the DTLB refills misses a raw counter | ||
1438 | * must be used. | ||
1439 | */ | ||
1440 | [C(OP_READ)] = { | ||
1441 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1442 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
1443 | }, | ||
1444 | [C(OP_WRITE)] = { | ||
1445 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1446 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
1447 | }, | ||
1448 | [C(OP_PREFETCH)] = { | ||
1449 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1450 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1451 | }, | ||
1452 | }, | ||
1453 | [C(ITLB)] = { | ||
1454 | [C(OP_READ)] = { | ||
1455 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1456 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
1457 | }, | ||
1458 | [C(OP_WRITE)] = { | ||
1459 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1460 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
1461 | }, | ||
1462 | [C(OP_PREFETCH)] = { | ||
1463 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1464 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1465 | }, | ||
1466 | }, | ||
1467 | [C(BPU)] = { | ||
1468 | [C(OP_READ)] = { | ||
1469 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
1470 | [C(RESULT_MISS)] | ||
1471 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1472 | }, | ||
1473 | [C(OP_WRITE)] = { | ||
1474 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
1475 | [C(RESULT_MISS)] | ||
1476 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1477 | }, | ||
1478 | [C(OP_PREFETCH)] = { | ||
1479 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1480 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1481 | }, | ||
1482 | }, | ||
1483 | }; | ||
1484 | |||
1485 | /* | ||
1486 | * Cortex-A9 HW events mapping | ||
1487 | */ | ||
1488 | static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = { | ||
1489 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, | ||
1490 | [PERF_COUNT_HW_INSTRUCTIONS] = | ||
1491 | ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE, | ||
1492 | [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT, | ||
1493 | [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS, | ||
1494 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, | ||
1495 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1496 | [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, | ||
1497 | }; | ||
1498 | |||
1499 | static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
1500 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
1501 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
1502 | [C(L1D)] = { | ||
1503 | /* | ||
1504 | * The performance counters don't differentiate between read | ||
1505 | * and write accesses/misses so this isn't strictly correct, | ||
1506 | * but it's the best we can do. Writes and reads get | ||
1507 | * combined. | ||
1508 | */ | ||
1509 | [C(OP_READ)] = { | ||
1510 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
1511 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
1512 | }, | ||
1513 | [C(OP_WRITE)] = { | ||
1514 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
1515 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
1516 | }, | ||
1517 | [C(OP_PREFETCH)] = { | ||
1518 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1519 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1520 | }, | ||
1521 | }, | ||
1522 | [C(L1I)] = { | ||
1523 | [C(OP_READ)] = { | ||
1524 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1525 | [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, | ||
1526 | }, | ||
1527 | [C(OP_WRITE)] = { | ||
1528 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1529 | [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, | ||
1530 | }, | ||
1531 | [C(OP_PREFETCH)] = { | ||
1532 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1533 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1534 | }, | ||
1535 | }, | ||
1536 | [C(LL)] = { | ||
1537 | [C(OP_READ)] = { | ||
1538 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1539 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1540 | }, | ||
1541 | [C(OP_WRITE)] = { | ||
1542 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1543 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1544 | }, | ||
1545 | [C(OP_PREFETCH)] = { | ||
1546 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1547 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1548 | }, | ||
1549 | }, | ||
1550 | [C(DTLB)] = { | ||
1551 | /* | ||
1552 | * Only ITLB misses and DTLB refills are supported. | ||
1553 | * If users want the DTLB refills misses a raw counter | ||
1554 | * must be used. | ||
1555 | */ | ||
1556 | [C(OP_READ)] = { | ||
1557 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1558 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
1559 | }, | ||
1560 | [C(OP_WRITE)] = { | ||
1561 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1562 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
1563 | }, | ||
1564 | [C(OP_PREFETCH)] = { | ||
1565 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1566 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1567 | }, | ||
1568 | }, | ||
1569 | [C(ITLB)] = { | ||
1570 | [C(OP_READ)] = { | ||
1571 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1572 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
1573 | }, | ||
1574 | [C(OP_WRITE)] = { | ||
1575 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1576 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
1577 | }, | ||
1578 | [C(OP_PREFETCH)] = { | ||
1579 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1580 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1581 | }, | ||
1582 | }, | ||
1583 | [C(BPU)] = { | ||
1584 | [C(OP_READ)] = { | ||
1585 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
1586 | [C(RESULT_MISS)] | ||
1587 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1588 | }, | ||
1589 | [C(OP_WRITE)] = { | ||
1590 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
1591 | [C(RESULT_MISS)] | ||
1592 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
1593 | }, | ||
1594 | [C(OP_PREFETCH)] = { | ||
1595 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
1596 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
1597 | }, | ||
1598 | }, | ||
1599 | }; | ||
1600 | |||
1601 | /* | ||
1602 | * Perf Events counters | ||
1603 | */ | ||
1604 | enum armv7_counters { | ||
1605 | ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */ | ||
1606 | ARMV7_COUNTER0 = 2, /* First event counter */ | ||
1607 | }; | ||
1608 | |||
1609 | /* | ||
1610 | * The cycle counter is ARMV7_CYCLE_COUNTER. | ||
1611 | * The first event counter is ARMV7_COUNTER0. | ||
1612 | * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1). | ||
1613 | */ | ||
1614 | #define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1) | ||
1615 | |||
1616 | /* | ||
1617 | * ARMv7 low level PMNC access | ||
1618 | */ | ||
1619 | |||
1620 | /* | ||
1621 | * Per-CPU PMNC: config reg | ||
1622 | */ | ||
1623 | #define ARMV7_PMNC_E (1 << 0) /* Enable all counters */ | ||
1624 | #define ARMV7_PMNC_P (1 << 1) /* Reset all counters */ | ||
1625 | #define ARMV7_PMNC_C (1 << 2) /* Cycle counter reset */ | ||
1626 | #define ARMV7_PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */ | ||
1627 | #define ARMV7_PMNC_X (1 << 4) /* Export to ETM */ | ||
1628 | #define ARMV7_PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ | ||
1629 | #define ARMV7_PMNC_N_SHIFT 11 /* Number of counters supported */ | ||
1630 | #define ARMV7_PMNC_N_MASK 0x1f | ||
1631 | #define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */ | ||
1632 | |||
1633 | /* | ||
1634 | * Available counters | ||
1635 | */ | ||
1636 | #define ARMV7_CNT0 0 /* First event counter */ | ||
1637 | #define ARMV7_CCNT 31 /* Cycle counter */ | ||
1638 | |||
1639 | /* Perf Event to low level counters mapping */ | ||
1640 | #define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0) | ||
1641 | |||
1642 | /* | ||
1643 | * CNTENS: counters enable reg | ||
1644 | */ | ||
1645 | #define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
1646 | #define ARMV7_CNTENS_C (1 << ARMV7_CCNT) | ||
1647 | |||
1648 | /* | ||
1649 | * CNTENC: counters disable reg | ||
1650 | */ | ||
1651 | #define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
1652 | #define ARMV7_CNTENC_C (1 << ARMV7_CCNT) | ||
1653 | |||
1654 | /* | ||
1655 | * INTENS: counters overflow interrupt enable reg | ||
1656 | */ | ||
1657 | #define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
1658 | #define ARMV7_INTENS_C (1 << ARMV7_CCNT) | ||
1659 | |||
1660 | /* | ||
1661 | * INTENC: counters overflow interrupt disable reg | ||
1662 | */ | ||
1663 | #define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
1664 | #define ARMV7_INTENC_C (1 << ARMV7_CCNT) | ||
1665 | |||
1666 | /* | ||
1667 | * EVTSEL: Event selection reg | ||
1668 | */ | ||
1669 | #define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */ | ||
1670 | |||
1671 | /* | ||
1672 | * SELECT: Counter selection reg | ||
1673 | */ | ||
1674 | #define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */ | ||
1675 | |||
1676 | /* | ||
1677 | * FLAG: counters overflow flag status reg | ||
1678 | */ | ||
1679 | #define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
1680 | #define ARMV7_FLAG_C (1 << ARMV7_CCNT) | ||
1681 | #define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */ | ||
1682 | #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK | ||
1683 | |||
1684 | static inline unsigned long armv7_pmnc_read(void) | ||
1685 | { | ||
1686 | u32 val; | ||
1687 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); | ||
1688 | return val; | ||
1689 | } | ||
1690 | |||
1691 | static inline void armv7_pmnc_write(unsigned long val) | ||
1692 | { | ||
1693 | val &= ARMV7_PMNC_MASK; | ||
1694 | asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); | ||
1695 | } | ||
1696 | |||
1697 | static inline int armv7_pmnc_has_overflowed(unsigned long pmnc) | ||
1698 | { | ||
1699 | return pmnc & ARMV7_OVERFLOWED_MASK; | ||
1700 | } | ||
1701 | |||
1702 | static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc, | ||
1703 | enum armv7_counters counter) | ||
1704 | { | ||
1705 | int ret; | ||
1706 | |||
1707 | if (counter == ARMV7_CYCLE_COUNTER) | ||
1708 | ret = pmnc & ARMV7_FLAG_C; | ||
1709 | else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST)) | ||
1710 | ret = pmnc & ARMV7_FLAG_P(counter); | ||
1711 | else | ||
1712 | pr_err("CPU%u checking wrong counter %d overflow status\n", | ||
1713 | smp_processor_id(), counter); | ||
1714 | |||
1715 | return ret; | ||
1716 | } | ||
1717 | |||
1718 | static inline int armv7_pmnc_select_counter(unsigned int idx) | ||
1719 | { | ||
1720 | u32 val; | ||
1721 | |||
1722 | if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) { | ||
1723 | pr_err("CPU%u selecting wrong PMNC counter" | ||
1724 | " %d\n", smp_processor_id(), idx); | ||
1725 | return -1; | ||
1726 | } | ||
1727 | |||
1728 | val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK; | ||
1729 | asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); | ||
1730 | |||
1731 | return idx; | ||
1732 | } | ||
1733 | |||
1734 | static inline u32 armv7pmu_read_counter(int idx) | ||
1735 | { | ||
1736 | unsigned long value = 0; | ||
1737 | |||
1738 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1739 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value)); | ||
1740 | else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { | ||
1741 | if (armv7_pmnc_select_counter(idx) == idx) | ||
1742 | asm volatile("mrc p15, 0, %0, c9, c13, 2" | ||
1743 | : "=r" (value)); | ||
1744 | } else | ||
1745 | pr_err("CPU%u reading wrong counter %d\n", | ||
1746 | smp_processor_id(), idx); | ||
1747 | |||
1748 | return value; | ||
1749 | } | ||
1750 | |||
1751 | static inline void armv7pmu_write_counter(int idx, u32 value) | ||
1752 | { | ||
1753 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1754 | asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value)); | ||
1755 | else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { | ||
1756 | if (armv7_pmnc_select_counter(idx) == idx) | ||
1757 | asm volatile("mcr p15, 0, %0, c9, c13, 2" | ||
1758 | : : "r" (value)); | ||
1759 | } else | ||
1760 | pr_err("CPU%u writing wrong counter %d\n", | ||
1761 | smp_processor_id(), idx); | ||
1762 | } | ||
1763 | |||
1764 | static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val) | ||
1765 | { | ||
1766 | if (armv7_pmnc_select_counter(idx) == idx) { | ||
1767 | val &= ARMV7_EVTSEL_MASK; | ||
1768 | asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); | ||
1769 | } | ||
1770 | } | ||
1771 | |||
1772 | static inline u32 armv7_pmnc_enable_counter(unsigned int idx) | ||
1773 | { | ||
1774 | u32 val; | ||
1775 | |||
1776 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
1777 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
1778 | pr_err("CPU%u enabling wrong PMNC counter" | ||
1779 | " %d\n", smp_processor_id(), idx); | ||
1780 | return -1; | ||
1781 | } | ||
1782 | |||
1783 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1784 | val = ARMV7_CNTENS_C; | ||
1785 | else | ||
1786 | val = ARMV7_CNTENS_P(idx); | ||
1787 | |||
1788 | asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); | ||
1789 | |||
1790 | return idx; | ||
1791 | } | ||
1792 | |||
1793 | static inline u32 armv7_pmnc_disable_counter(unsigned int idx) | ||
1794 | { | ||
1795 | u32 val; | ||
1796 | |||
1797 | |||
1798 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
1799 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
1800 | pr_err("CPU%u disabling wrong PMNC counter" | ||
1801 | " %d\n", smp_processor_id(), idx); | ||
1802 | return -1; | ||
1803 | } | ||
1804 | |||
1805 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1806 | val = ARMV7_CNTENC_C; | ||
1807 | else | ||
1808 | val = ARMV7_CNTENC_P(idx); | ||
1809 | |||
1810 | asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); | ||
1811 | |||
1812 | return idx; | ||
1813 | } | ||
1814 | |||
1815 | static inline u32 armv7_pmnc_enable_intens(unsigned int idx) | ||
1816 | { | ||
1817 | u32 val; | ||
1818 | |||
1819 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
1820 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
1821 | pr_err("CPU%u enabling wrong PMNC counter" | ||
1822 | " interrupt enable %d\n", smp_processor_id(), idx); | ||
1823 | return -1; | ||
1824 | } | ||
1825 | |||
1826 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1827 | val = ARMV7_INTENS_C; | ||
1828 | else | ||
1829 | val = ARMV7_INTENS_P(idx); | ||
1830 | |||
1831 | asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); | ||
1832 | |||
1833 | return idx; | ||
1834 | } | ||
1835 | |||
1836 | static inline u32 armv7_pmnc_disable_intens(unsigned int idx) | ||
1837 | { | ||
1838 | u32 val; | ||
1839 | |||
1840 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
1841 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
1842 | pr_err("CPU%u disabling wrong PMNC counter" | ||
1843 | " interrupt enable %d\n", smp_processor_id(), idx); | ||
1844 | return -1; | ||
1845 | } | ||
1846 | |||
1847 | if (idx == ARMV7_CYCLE_COUNTER) | ||
1848 | val = ARMV7_INTENC_C; | ||
1849 | else | ||
1850 | val = ARMV7_INTENC_P(idx); | ||
1851 | |||
1852 | asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); | ||
1853 | |||
1854 | return idx; | ||
1855 | } | ||
1856 | |||
1857 | static inline u32 armv7_pmnc_getreset_flags(void) | ||
1858 | { | ||
1859 | u32 val; | ||
1860 | |||
1861 | /* Read */ | ||
1862 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
1863 | |||
1864 | /* Write to clear flags */ | ||
1865 | val &= ARMV7_FLAG_MASK; | ||
1866 | asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val)); | ||
1867 | |||
1868 | return val; | ||
1869 | } | ||
1870 | |||
1871 | #ifdef DEBUG | ||
1872 | static void armv7_pmnc_dump_regs(void) | ||
1873 | { | ||
1874 | u32 val; | ||
1875 | unsigned int cnt; | ||
1876 | |||
1877 | printk(KERN_INFO "PMNC registers dump:\n"); | ||
1878 | |||
1879 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); | ||
1880 | printk(KERN_INFO "PMNC =0x%08x\n", val); | ||
1881 | |||
1882 | asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val)); | ||
1883 | printk(KERN_INFO "CNTENS=0x%08x\n", val); | ||
1884 | |||
1885 | asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val)); | ||
1886 | printk(KERN_INFO "INTENS=0x%08x\n", val); | ||
1887 | |||
1888 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
1889 | printk(KERN_INFO "FLAGS =0x%08x\n", val); | ||
1890 | |||
1891 | asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val)); | ||
1892 | printk(KERN_INFO "SELECT=0x%08x\n", val); | ||
1893 | |||
1894 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); | ||
1895 | printk(KERN_INFO "CCNT =0x%08x\n", val); | ||
1896 | |||
1897 | for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) { | ||
1898 | armv7_pmnc_select_counter(cnt); | ||
1899 | asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); | ||
1900 | printk(KERN_INFO "CNT[%d] count =0x%08x\n", | ||
1901 | cnt-ARMV7_EVENT_CNT_TO_CNTx, val); | ||
1902 | asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val)); | ||
1903 | printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", | ||
1904 | cnt-ARMV7_EVENT_CNT_TO_CNTx, val); | ||
1905 | } | ||
1906 | } | ||
1907 | #endif | ||
1908 | |||
1909 | void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
1910 | { | ||
1911 | unsigned long flags; | ||
1912 | |||
1913 | /* | ||
1914 | * Enable counter and interrupt, and set the counter to count | ||
1915 | * the event that we're interested in. | ||
1916 | */ | ||
1917 | spin_lock_irqsave(&pmu_lock, flags); | ||
1918 | |||
1919 | /* | ||
1920 | * Disable counter | ||
1921 | */ | ||
1922 | armv7_pmnc_disable_counter(idx); | ||
1923 | |||
1924 | /* | ||
1925 | * Set event (if destined for PMNx counters) | ||
1926 | * We don't need to set the event if it's a cycle count | ||
1927 | */ | ||
1928 | if (idx != ARMV7_CYCLE_COUNTER) | ||
1929 | armv7_pmnc_write_evtsel(idx, hwc->config_base); | ||
1930 | |||
1931 | /* | ||
1932 | * Enable interrupt for this counter | ||
1933 | */ | ||
1934 | armv7_pmnc_enable_intens(idx); | ||
1935 | |||
1936 | /* | ||
1937 | * Enable counter | ||
1938 | */ | ||
1939 | armv7_pmnc_enable_counter(idx); | ||
1940 | |||
1941 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1942 | } | ||
1943 | |||
1944 | static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
1945 | { | ||
1946 | unsigned long flags; | ||
1947 | |||
1948 | /* | ||
1949 | * Disable counter and interrupt | ||
1950 | */ | ||
1951 | spin_lock_irqsave(&pmu_lock, flags); | ||
1952 | |||
1953 | /* | ||
1954 | * Disable counter | ||
1955 | */ | ||
1956 | armv7_pmnc_disable_counter(idx); | ||
1957 | |||
1958 | /* | ||
1959 | * Disable interrupt for this counter | ||
1960 | */ | ||
1961 | armv7_pmnc_disable_intens(idx); | ||
1962 | |||
1963 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
1964 | } | ||
1965 | |||
1966 | static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) | ||
1967 | { | ||
1968 | unsigned long pmnc; | ||
1969 | struct perf_sample_data data; | ||
1970 | struct cpu_hw_events *cpuc; | ||
1971 | struct pt_regs *regs; | ||
1972 | int idx; | ||
1973 | |||
1974 | /* | ||
1975 | * Get and reset the IRQ flags | ||
1976 | */ | ||
1977 | pmnc = armv7_pmnc_getreset_flags(); | ||
1978 | |||
1979 | /* | ||
1980 | * Did an overflow occur? | ||
1981 | */ | ||
1982 | if (!armv7_pmnc_has_overflowed(pmnc)) | ||
1983 | return IRQ_NONE; | ||
1984 | |||
1985 | /* | ||
1986 | * Handle the counter(s) overflow(s) | ||
1987 | */ | ||
1988 | regs = get_irq_regs(); | ||
1989 | |||
1990 | perf_sample_data_init(&data, 0); | ||
1991 | |||
1992 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
1993 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
1994 | struct perf_event *event = cpuc->events[idx]; | ||
1995 | struct hw_perf_event *hwc; | ||
1996 | |||
1997 | if (!test_bit(idx, cpuc->active_mask)) | ||
1998 | continue; | ||
1999 | |||
2000 | /* | ||
2001 | * We have a single interrupt for all counters. Check that | ||
2002 | * each counter has overflowed before we process it. | ||
2003 | */ | ||
2004 | if (!armv7_pmnc_counter_has_overflowed(pmnc, idx)) | ||
2005 | continue; | ||
2006 | |||
2007 | hwc = &event->hw; | ||
2008 | armpmu_event_update(event, hwc, idx); | ||
2009 | data.period = event->hw.last_period; | ||
2010 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
2011 | continue; | ||
2012 | |||
2013 | if (perf_event_overflow(event, 0, &data, regs)) | ||
2014 | armpmu->disable(hwc, idx); | ||
2015 | } | ||
2016 | |||
2017 | /* | ||
2018 | * Handle the pending perf events. | ||
2019 | * | ||
2020 | * Note: this call *must* be run with interrupts disabled. For | ||
2021 | * platforms that can have the PMU interrupts raised as an NMI, this | ||
2022 | * will not work. | ||
2023 | */ | ||
2024 | perf_event_do_pending(); | ||
2025 | |||
2026 | return IRQ_HANDLED; | ||
2027 | } | ||
2028 | |||
2029 | static void armv7pmu_start(void) | ||
2030 | { | ||
2031 | unsigned long flags; | ||
2032 | |||
2033 | spin_lock_irqsave(&pmu_lock, flags); | ||
2034 | /* Enable all counters */ | ||
2035 | armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E); | ||
2036 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2037 | } | ||
2038 | |||
2039 | static void armv7pmu_stop(void) | ||
2040 | { | ||
2041 | unsigned long flags; | ||
2042 | |||
2043 | spin_lock_irqsave(&pmu_lock, flags); | ||
2044 | /* Disable all counters */ | ||
2045 | armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E); | ||
2046 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2047 | } | ||
2048 | |||
2049 | static inline int armv7_a8_pmu_event_map(int config) | ||
2050 | { | ||
2051 | int mapping = armv7_a8_perf_map[config]; | ||
2052 | if (HW_OP_UNSUPPORTED == mapping) | ||
2053 | mapping = -EOPNOTSUPP; | ||
2054 | return mapping; | ||
2055 | } | ||
2056 | |||
2057 | static inline int armv7_a9_pmu_event_map(int config) | ||
2058 | { | ||
2059 | int mapping = armv7_a9_perf_map[config]; | ||
2060 | if (HW_OP_UNSUPPORTED == mapping) | ||
2061 | mapping = -EOPNOTSUPP; | ||
2062 | return mapping; | ||
2063 | } | ||
2064 | |||
2065 | static u64 armv7pmu_raw_event(u64 config) | ||
2066 | { | ||
2067 | return config & 0xff; | ||
2068 | } | ||
2069 | |||
2070 | static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
2071 | struct hw_perf_event *event) | ||
2072 | { | ||
2073 | int idx; | ||
2074 | |||
2075 | /* Always place a cycle counter into the cycle counter. */ | ||
2076 | if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) { | ||
2077 | if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask)) | ||
2078 | return -EAGAIN; | ||
2079 | |||
2080 | return ARMV7_CYCLE_COUNTER; | ||
2081 | } else { | ||
2082 | /* | ||
2083 | * For anything other than a cycle counter, try and use | ||
2084 | * the events counters | ||
2085 | */ | ||
2086 | for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) { | ||
2087 | if (!test_and_set_bit(idx, cpuc->used_mask)) | ||
2088 | return idx; | ||
2089 | } | ||
2090 | |||
2091 | /* The counters are all in use. */ | ||
2092 | return -EAGAIN; | ||
2093 | } | ||
2094 | } | ||
2095 | |||
2096 | static struct arm_pmu armv7pmu = { | ||
2097 | .handle_irq = armv7pmu_handle_irq, | ||
2098 | .enable = armv7pmu_enable_event, | ||
2099 | .disable = armv7pmu_disable_event, | ||
2100 | .raw_event = armv7pmu_raw_event, | ||
2101 | .read_counter = armv7pmu_read_counter, | ||
2102 | .write_counter = armv7pmu_write_counter, | ||
2103 | .get_event_idx = armv7pmu_get_event_idx, | ||
2104 | .start = armv7pmu_start, | ||
2105 | .stop = armv7pmu_stop, | ||
2106 | .max_period = (1LLU << 32) - 1, | ||
2107 | }; | 621 | }; |
2108 | 622 | ||
2109 | static u32 __init armv7_reset_read_pmnc(void) | 623 | /* Include the PMU-specific implementations. */ |
2110 | { | 624 | #include "perf_event_xscale.c" |
2111 | u32 nb_cnt; | 625 | #include "perf_event_v6.c" |
2112 | 626 | #include "perf_event_v7.c" | |
2113 | /* Initialize & Reset PMNC: C and P bits */ | ||
2114 | armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); | ||
2115 | |||
2116 | /* Read the nb of CNTx counters supported from PMNC */ | ||
2117 | nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK; | ||
2118 | |||
2119 | /* Add the CPU cycles counter and return */ | ||
2120 | return nb_cnt + 1; | ||
2121 | } | ||
2122 | 627 | ||
2123 | /* | 628 | /* |
2124 | * ARMv5 [xscale] Performance counter handling code. | 629 | * Ensure the PMU has sane values out of reset. |
2125 | * | 630 | * This requires SMP to be available, so exists as a separate initcall. |
2126 | * Based on xscale OProfile code. | ||
2127 | * | ||
2128 | * There are two variants of the xscale PMU that we support: | ||
2129 | * - xscale1pmu: 2 event counters and a cycle counter | ||
2130 | * - xscale2pmu: 4 event counters and a cycle counter | ||
2131 | * The two variants share event definitions, but have different | ||
2132 | * PMU structures. | ||
2133 | */ | 631 | */ |
2134 | 632 | static int __init | |
2135 | enum xscale_perf_types { | 633 | armpmu_reset(void) |
2136 | XSCALE_PERFCTR_ICACHE_MISS = 0x00, | ||
2137 | XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01, | ||
2138 | XSCALE_PERFCTR_DATA_STALL = 0x02, | ||
2139 | XSCALE_PERFCTR_ITLB_MISS = 0x03, | ||
2140 | XSCALE_PERFCTR_DTLB_MISS = 0x04, | ||
2141 | XSCALE_PERFCTR_BRANCH = 0x05, | ||
2142 | XSCALE_PERFCTR_BRANCH_MISS = 0x06, | ||
2143 | XSCALE_PERFCTR_INSTRUCTION = 0x07, | ||
2144 | XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08, | ||
2145 | XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09, | ||
2146 | XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A, | ||
2147 | XSCALE_PERFCTR_DCACHE_MISS = 0x0B, | ||
2148 | XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C, | ||
2149 | XSCALE_PERFCTR_PC_CHANGED = 0x0D, | ||
2150 | XSCALE_PERFCTR_BCU_REQUEST = 0x10, | ||
2151 | XSCALE_PERFCTR_BCU_FULL = 0x11, | ||
2152 | XSCALE_PERFCTR_BCU_DRAIN = 0x12, | ||
2153 | XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14, | ||
2154 | XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15, | ||
2155 | XSCALE_PERFCTR_RMW = 0x16, | ||
2156 | /* XSCALE_PERFCTR_CCNT is not hardware defined */ | ||
2157 | XSCALE_PERFCTR_CCNT = 0xFE, | ||
2158 | XSCALE_PERFCTR_UNUSED = 0xFF, | ||
2159 | }; | ||
2160 | |||
2161 | enum xscale_counters { | ||
2162 | XSCALE_CYCLE_COUNTER = 1, | ||
2163 | XSCALE_COUNTER0, | ||
2164 | XSCALE_COUNTER1, | ||
2165 | XSCALE_COUNTER2, | ||
2166 | XSCALE_COUNTER3, | ||
2167 | }; | ||
2168 | |||
2169 | static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = { | ||
2170 | [PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT, | ||
2171 | [PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION, | ||
2172 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
2173 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
2174 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH, | ||
2175 | [PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS, | ||
2176 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
2177 | }; | ||
2178 | |||
2179 | static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
2180 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
2181 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
2182 | [C(L1D)] = { | ||
2183 | [C(OP_READ)] = { | ||
2184 | [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS, | ||
2185 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS, | ||
2186 | }, | ||
2187 | [C(OP_WRITE)] = { | ||
2188 | [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS, | ||
2189 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS, | ||
2190 | }, | ||
2191 | [C(OP_PREFETCH)] = { | ||
2192 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2193 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2194 | }, | ||
2195 | }, | ||
2196 | [C(L1I)] = { | ||
2197 | [C(OP_READ)] = { | ||
2198 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2199 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS, | ||
2200 | }, | ||
2201 | [C(OP_WRITE)] = { | ||
2202 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2203 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS, | ||
2204 | }, | ||
2205 | [C(OP_PREFETCH)] = { | ||
2206 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2207 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2208 | }, | ||
2209 | }, | ||
2210 | [C(LL)] = { | ||
2211 | [C(OP_READ)] = { | ||
2212 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2213 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2214 | }, | ||
2215 | [C(OP_WRITE)] = { | ||
2216 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2217 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2218 | }, | ||
2219 | [C(OP_PREFETCH)] = { | ||
2220 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2221 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2222 | }, | ||
2223 | }, | ||
2224 | [C(DTLB)] = { | ||
2225 | [C(OP_READ)] = { | ||
2226 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2227 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS, | ||
2228 | }, | ||
2229 | [C(OP_WRITE)] = { | ||
2230 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2231 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS, | ||
2232 | }, | ||
2233 | [C(OP_PREFETCH)] = { | ||
2234 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2235 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2236 | }, | ||
2237 | }, | ||
2238 | [C(ITLB)] = { | ||
2239 | [C(OP_READ)] = { | ||
2240 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2241 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS, | ||
2242 | }, | ||
2243 | [C(OP_WRITE)] = { | ||
2244 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2245 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS, | ||
2246 | }, | ||
2247 | [C(OP_PREFETCH)] = { | ||
2248 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2249 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2250 | }, | ||
2251 | }, | ||
2252 | [C(BPU)] = { | ||
2253 | [C(OP_READ)] = { | ||
2254 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2255 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2256 | }, | ||
2257 | [C(OP_WRITE)] = { | ||
2258 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2259 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2260 | }, | ||
2261 | [C(OP_PREFETCH)] = { | ||
2262 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
2263 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
2264 | }, | ||
2265 | }, | ||
2266 | }; | ||
2267 | |||
2268 | #define XSCALE_PMU_ENABLE 0x001 | ||
2269 | #define XSCALE_PMN_RESET 0x002 | ||
2270 | #define XSCALE_CCNT_RESET 0x004 | ||
2271 | #define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET) | ||
2272 | #define XSCALE_PMU_CNT64 0x008 | ||
2273 | |||
2274 | static inline int | ||
2275 | xscalepmu_event_map(int config) | ||
2276 | { | ||
2277 | int mapping = xscale_perf_map[config]; | ||
2278 | if (HW_OP_UNSUPPORTED == mapping) | ||
2279 | mapping = -EOPNOTSUPP; | ||
2280 | return mapping; | ||
2281 | } | ||
2282 | |||
2283 | static u64 | ||
2284 | xscalepmu_raw_event(u64 config) | ||
2285 | { | ||
2286 | return config & 0xff; | ||
2287 | } | ||
2288 | |||
2289 | #define XSCALE1_OVERFLOWED_MASK 0x700 | ||
2290 | #define XSCALE1_CCOUNT_OVERFLOW 0x400 | ||
2291 | #define XSCALE1_COUNT0_OVERFLOW 0x100 | ||
2292 | #define XSCALE1_COUNT1_OVERFLOW 0x200 | ||
2293 | #define XSCALE1_CCOUNT_INT_EN 0x040 | ||
2294 | #define XSCALE1_COUNT0_INT_EN 0x010 | ||
2295 | #define XSCALE1_COUNT1_INT_EN 0x020 | ||
2296 | #define XSCALE1_COUNT0_EVT_SHFT 12 | ||
2297 | #define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT) | ||
2298 | #define XSCALE1_COUNT1_EVT_SHFT 20 | ||
2299 | #define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT) | ||
2300 | |||
2301 | static inline u32 | ||
2302 | xscale1pmu_read_pmnc(void) | ||
2303 | { | ||
2304 | u32 val; | ||
2305 | asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val)); | ||
2306 | return val; | ||
2307 | } | ||
2308 | |||
2309 | static inline void | ||
2310 | xscale1pmu_write_pmnc(u32 val) | ||
2311 | { | ||
2312 | /* upper 4bits and 7, 11 are write-as-0 */ | ||
2313 | val &= 0xffff77f; | ||
2314 | asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val)); | ||
2315 | } | ||
2316 | |||
2317 | static inline int | ||
2318 | xscale1_pmnc_counter_has_overflowed(unsigned long pmnc, | ||
2319 | enum xscale_counters counter) | ||
2320 | { | ||
2321 | int ret = 0; | ||
2322 | |||
2323 | switch (counter) { | ||
2324 | case XSCALE_CYCLE_COUNTER: | ||
2325 | ret = pmnc & XSCALE1_CCOUNT_OVERFLOW; | ||
2326 | break; | ||
2327 | case XSCALE_COUNTER0: | ||
2328 | ret = pmnc & XSCALE1_COUNT0_OVERFLOW; | ||
2329 | break; | ||
2330 | case XSCALE_COUNTER1: | ||
2331 | ret = pmnc & XSCALE1_COUNT1_OVERFLOW; | ||
2332 | break; | ||
2333 | default: | ||
2334 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
2335 | } | ||
2336 | |||
2337 | return ret; | ||
2338 | } | ||
2339 | |||
2340 | static irqreturn_t | ||
2341 | xscale1pmu_handle_irq(int irq_num, void *dev) | ||
2342 | { | ||
2343 | unsigned long pmnc; | ||
2344 | struct perf_sample_data data; | ||
2345 | struct cpu_hw_events *cpuc; | ||
2346 | struct pt_regs *regs; | ||
2347 | int idx; | ||
2348 | |||
2349 | /* | ||
2350 | * NOTE: there's an A stepping erratum that states if an overflow | ||
2351 | * bit already exists and another occurs, the previous | ||
2352 | * Overflow bit gets cleared. There's no workaround. | ||
2353 | * Fixed in B stepping or later. | ||
2354 | */ | ||
2355 | pmnc = xscale1pmu_read_pmnc(); | ||
2356 | |||
2357 | /* | ||
2358 | * Write the value back to clear the overflow flags. Overflow | ||
2359 | * flags remain in pmnc for use below. We also disable the PMU | ||
2360 | * while we process the interrupt. | ||
2361 | */ | ||
2362 | xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE); | ||
2363 | |||
2364 | if (!(pmnc & XSCALE1_OVERFLOWED_MASK)) | ||
2365 | return IRQ_NONE; | ||
2366 | |||
2367 | regs = get_irq_regs(); | ||
2368 | |||
2369 | perf_sample_data_init(&data, 0); | ||
2370 | |||
2371 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
2372 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
2373 | struct perf_event *event = cpuc->events[idx]; | ||
2374 | struct hw_perf_event *hwc; | ||
2375 | |||
2376 | if (!test_bit(idx, cpuc->active_mask)) | ||
2377 | continue; | ||
2378 | |||
2379 | if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx)) | ||
2380 | continue; | ||
2381 | |||
2382 | hwc = &event->hw; | ||
2383 | armpmu_event_update(event, hwc, idx); | ||
2384 | data.period = event->hw.last_period; | ||
2385 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
2386 | continue; | ||
2387 | |||
2388 | if (perf_event_overflow(event, 0, &data, regs)) | ||
2389 | armpmu->disable(hwc, idx); | ||
2390 | } | ||
2391 | |||
2392 | perf_event_do_pending(); | ||
2393 | |||
2394 | /* | ||
2395 | * Re-enable the PMU. | ||
2396 | */ | ||
2397 | pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE; | ||
2398 | xscale1pmu_write_pmnc(pmnc); | ||
2399 | |||
2400 | return IRQ_HANDLED; | ||
2401 | } | ||
2402 | |||
2403 | static void | ||
2404 | xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
2405 | { | ||
2406 | unsigned long val, mask, evt, flags; | ||
2407 | |||
2408 | switch (idx) { | ||
2409 | case XSCALE_CYCLE_COUNTER: | ||
2410 | mask = 0; | ||
2411 | evt = XSCALE1_CCOUNT_INT_EN; | ||
2412 | break; | ||
2413 | case XSCALE_COUNTER0: | ||
2414 | mask = XSCALE1_COUNT0_EVT_MASK; | ||
2415 | evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) | | ||
2416 | XSCALE1_COUNT0_INT_EN; | ||
2417 | break; | ||
2418 | case XSCALE_COUNTER1: | ||
2419 | mask = XSCALE1_COUNT1_EVT_MASK; | ||
2420 | evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) | | ||
2421 | XSCALE1_COUNT1_INT_EN; | ||
2422 | break; | ||
2423 | default: | ||
2424 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
2425 | return; | ||
2426 | } | ||
2427 | |||
2428 | spin_lock_irqsave(&pmu_lock, flags); | ||
2429 | val = xscale1pmu_read_pmnc(); | ||
2430 | val &= ~mask; | ||
2431 | val |= evt; | ||
2432 | xscale1pmu_write_pmnc(val); | ||
2433 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2434 | } | ||
2435 | |||
2436 | static void | ||
2437 | xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
2438 | { | ||
2439 | unsigned long val, mask, evt, flags; | ||
2440 | |||
2441 | switch (idx) { | ||
2442 | case XSCALE_CYCLE_COUNTER: | ||
2443 | mask = XSCALE1_CCOUNT_INT_EN; | ||
2444 | evt = 0; | ||
2445 | break; | ||
2446 | case XSCALE_COUNTER0: | ||
2447 | mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK; | ||
2448 | evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT; | ||
2449 | break; | ||
2450 | case XSCALE_COUNTER1: | ||
2451 | mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK; | ||
2452 | evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT; | ||
2453 | break; | ||
2454 | default: | ||
2455 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
2456 | return; | ||
2457 | } | ||
2458 | |||
2459 | spin_lock_irqsave(&pmu_lock, flags); | ||
2460 | val = xscale1pmu_read_pmnc(); | ||
2461 | val &= ~mask; | ||
2462 | val |= evt; | ||
2463 | xscale1pmu_write_pmnc(val); | ||
2464 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2465 | } | ||
2466 | |||
2467 | static int | ||
2468 | xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
2469 | struct hw_perf_event *event) | ||
2470 | { | ||
2471 | if (XSCALE_PERFCTR_CCNT == event->config_base) { | ||
2472 | if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask)) | ||
2473 | return -EAGAIN; | ||
2474 | |||
2475 | return XSCALE_CYCLE_COUNTER; | ||
2476 | } else { | ||
2477 | if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask)) { | ||
2478 | return XSCALE_COUNTER1; | ||
2479 | } | ||
2480 | |||
2481 | if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask)) { | ||
2482 | return XSCALE_COUNTER0; | ||
2483 | } | ||
2484 | |||
2485 | return -EAGAIN; | ||
2486 | } | ||
2487 | } | ||
2488 | |||
2489 | static void | ||
2490 | xscale1pmu_start(void) | ||
2491 | { | ||
2492 | unsigned long flags, val; | ||
2493 | |||
2494 | spin_lock_irqsave(&pmu_lock, flags); | ||
2495 | val = xscale1pmu_read_pmnc(); | ||
2496 | val |= XSCALE_PMU_ENABLE; | ||
2497 | xscale1pmu_write_pmnc(val); | ||
2498 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2499 | } | ||
2500 | |||
2501 | static void | ||
2502 | xscale1pmu_stop(void) | ||
2503 | { | ||
2504 | unsigned long flags, val; | ||
2505 | |||
2506 | spin_lock_irqsave(&pmu_lock, flags); | ||
2507 | val = xscale1pmu_read_pmnc(); | ||
2508 | val &= ~XSCALE_PMU_ENABLE; | ||
2509 | xscale1pmu_write_pmnc(val); | ||
2510 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2511 | } | ||
2512 | |||
2513 | static inline u32 | ||
2514 | xscale1pmu_read_counter(int counter) | ||
2515 | { | ||
2516 | u32 val = 0; | ||
2517 | |||
2518 | switch (counter) { | ||
2519 | case XSCALE_CYCLE_COUNTER: | ||
2520 | asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val)); | ||
2521 | break; | ||
2522 | case XSCALE_COUNTER0: | ||
2523 | asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val)); | ||
2524 | break; | ||
2525 | case XSCALE_COUNTER1: | ||
2526 | asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val)); | ||
2527 | break; | ||
2528 | } | ||
2529 | |||
2530 | return val; | ||
2531 | } | ||
2532 | |||
2533 | static inline void | ||
2534 | xscale1pmu_write_counter(int counter, u32 val) | ||
2535 | { | ||
2536 | switch (counter) { | ||
2537 | case XSCALE_CYCLE_COUNTER: | ||
2538 | asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val)); | ||
2539 | break; | ||
2540 | case XSCALE_COUNTER0: | ||
2541 | asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val)); | ||
2542 | break; | ||
2543 | case XSCALE_COUNTER1: | ||
2544 | asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val)); | ||
2545 | break; | ||
2546 | } | ||
2547 | } | ||
2548 | |||
2549 | static const struct arm_pmu xscale1pmu = { | ||
2550 | .id = ARM_PERF_PMU_ID_XSCALE1, | ||
2551 | .handle_irq = xscale1pmu_handle_irq, | ||
2552 | .enable = xscale1pmu_enable_event, | ||
2553 | .disable = xscale1pmu_disable_event, | ||
2554 | .event_map = xscalepmu_event_map, | ||
2555 | .raw_event = xscalepmu_raw_event, | ||
2556 | .read_counter = xscale1pmu_read_counter, | ||
2557 | .write_counter = xscale1pmu_write_counter, | ||
2558 | .get_event_idx = xscale1pmu_get_event_idx, | ||
2559 | .start = xscale1pmu_start, | ||
2560 | .stop = xscale1pmu_stop, | ||
2561 | .num_events = 3, | ||
2562 | .max_period = (1LLU << 32) - 1, | ||
2563 | }; | ||
2564 | |||
2565 | #define XSCALE2_OVERFLOWED_MASK 0x01f | ||
2566 | #define XSCALE2_CCOUNT_OVERFLOW 0x001 | ||
2567 | #define XSCALE2_COUNT0_OVERFLOW 0x002 | ||
2568 | #define XSCALE2_COUNT1_OVERFLOW 0x004 | ||
2569 | #define XSCALE2_COUNT2_OVERFLOW 0x008 | ||
2570 | #define XSCALE2_COUNT3_OVERFLOW 0x010 | ||
2571 | #define XSCALE2_CCOUNT_INT_EN 0x001 | ||
2572 | #define XSCALE2_COUNT0_INT_EN 0x002 | ||
2573 | #define XSCALE2_COUNT1_INT_EN 0x004 | ||
2574 | #define XSCALE2_COUNT2_INT_EN 0x008 | ||
2575 | #define XSCALE2_COUNT3_INT_EN 0x010 | ||
2576 | #define XSCALE2_COUNT0_EVT_SHFT 0 | ||
2577 | #define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT) | ||
2578 | #define XSCALE2_COUNT1_EVT_SHFT 8 | ||
2579 | #define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT) | ||
2580 | #define XSCALE2_COUNT2_EVT_SHFT 16 | ||
2581 | #define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT) | ||
2582 | #define XSCALE2_COUNT3_EVT_SHFT 24 | ||
2583 | #define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT) | ||
2584 | |||
2585 | static inline u32 | ||
2586 | xscale2pmu_read_pmnc(void) | ||
2587 | { | ||
2588 | u32 val; | ||
2589 | asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val)); | ||
2590 | /* bits 1-2 and 4-23 are read-unpredictable */ | ||
2591 | return val & 0xff000009; | ||
2592 | } | ||
2593 | |||
2594 | static inline void | ||
2595 | xscale2pmu_write_pmnc(u32 val) | ||
2596 | { | ||
2597 | /* bits 4-23 are write-as-0, 24-31 are write ignored */ | ||
2598 | val &= 0xf; | ||
2599 | asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val)); | ||
2600 | } | ||
2601 | |||
2602 | static inline u32 | ||
2603 | xscale2pmu_read_overflow_flags(void) | ||
2604 | { | ||
2605 | u32 val; | ||
2606 | asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val)); | ||
2607 | return val; | ||
2608 | } | ||
2609 | |||
2610 | static inline void | ||
2611 | xscale2pmu_write_overflow_flags(u32 val) | ||
2612 | { | ||
2613 | asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val)); | ||
2614 | } | ||
2615 | |||
2616 | static inline u32 | ||
2617 | xscale2pmu_read_event_select(void) | ||
2618 | { | ||
2619 | u32 val; | ||
2620 | asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val)); | ||
2621 | return val; | ||
2622 | } | ||
2623 | |||
2624 | static inline void | ||
2625 | xscale2pmu_write_event_select(u32 val) | ||
2626 | { | ||
2627 | asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val)); | ||
2628 | } | ||
2629 | |||
2630 | static inline u32 | ||
2631 | xscale2pmu_read_int_enable(void) | ||
2632 | { | ||
2633 | u32 val; | ||
2634 | asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val)); | ||
2635 | return val; | ||
2636 | } | ||
2637 | |||
2638 | static void | ||
2639 | xscale2pmu_write_int_enable(u32 val) | ||
2640 | { | ||
2641 | asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val)); | ||
2642 | } | ||
2643 | |||
2644 | static inline int | ||
2645 | xscale2_pmnc_counter_has_overflowed(unsigned long of_flags, | ||
2646 | enum xscale_counters counter) | ||
2647 | { | ||
2648 | int ret = 0; | ||
2649 | |||
2650 | switch (counter) { | ||
2651 | case XSCALE_CYCLE_COUNTER: | ||
2652 | ret = of_flags & XSCALE2_CCOUNT_OVERFLOW; | ||
2653 | break; | ||
2654 | case XSCALE_COUNTER0: | ||
2655 | ret = of_flags & XSCALE2_COUNT0_OVERFLOW; | ||
2656 | break; | ||
2657 | case XSCALE_COUNTER1: | ||
2658 | ret = of_flags & XSCALE2_COUNT1_OVERFLOW; | ||
2659 | break; | ||
2660 | case XSCALE_COUNTER2: | ||
2661 | ret = of_flags & XSCALE2_COUNT2_OVERFLOW; | ||
2662 | break; | ||
2663 | case XSCALE_COUNTER3: | ||
2664 | ret = of_flags & XSCALE2_COUNT3_OVERFLOW; | ||
2665 | break; | ||
2666 | default: | ||
2667 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
2668 | } | ||
2669 | |||
2670 | return ret; | ||
2671 | } | ||
2672 | |||
2673 | static irqreturn_t | ||
2674 | xscale2pmu_handle_irq(int irq_num, void *dev) | ||
2675 | { | ||
2676 | unsigned long pmnc, of_flags; | ||
2677 | struct perf_sample_data data; | ||
2678 | struct cpu_hw_events *cpuc; | ||
2679 | struct pt_regs *regs; | ||
2680 | int idx; | ||
2681 | |||
2682 | /* Disable the PMU. */ | ||
2683 | pmnc = xscale2pmu_read_pmnc(); | ||
2684 | xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE); | ||
2685 | |||
2686 | /* Check the overflow flag register. */ | ||
2687 | of_flags = xscale2pmu_read_overflow_flags(); | ||
2688 | if (!(of_flags & XSCALE2_OVERFLOWED_MASK)) | ||
2689 | return IRQ_NONE; | ||
2690 | |||
2691 | /* Clear the overflow bits. */ | ||
2692 | xscale2pmu_write_overflow_flags(of_flags); | ||
2693 | |||
2694 | regs = get_irq_regs(); | ||
2695 | |||
2696 | perf_sample_data_init(&data, 0); | ||
2697 | |||
2698 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
2699 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
2700 | struct perf_event *event = cpuc->events[idx]; | ||
2701 | struct hw_perf_event *hwc; | ||
2702 | |||
2703 | if (!test_bit(idx, cpuc->active_mask)) | ||
2704 | continue; | ||
2705 | |||
2706 | if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx)) | ||
2707 | continue; | ||
2708 | |||
2709 | hwc = &event->hw; | ||
2710 | armpmu_event_update(event, hwc, idx); | ||
2711 | data.period = event->hw.last_period; | ||
2712 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
2713 | continue; | ||
2714 | |||
2715 | if (perf_event_overflow(event, 0, &data, regs)) | ||
2716 | armpmu->disable(hwc, idx); | ||
2717 | } | ||
2718 | |||
2719 | perf_event_do_pending(); | ||
2720 | |||
2721 | /* | ||
2722 | * Re-enable the PMU. | ||
2723 | */ | ||
2724 | pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE; | ||
2725 | xscale2pmu_write_pmnc(pmnc); | ||
2726 | |||
2727 | return IRQ_HANDLED; | ||
2728 | } | ||
2729 | |||
2730 | static void | ||
2731 | xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
2732 | { | ||
2733 | unsigned long flags, ien, evtsel; | ||
2734 | |||
2735 | ien = xscale2pmu_read_int_enable(); | ||
2736 | evtsel = xscale2pmu_read_event_select(); | ||
2737 | |||
2738 | switch (idx) { | ||
2739 | case XSCALE_CYCLE_COUNTER: | ||
2740 | ien |= XSCALE2_CCOUNT_INT_EN; | ||
2741 | break; | ||
2742 | case XSCALE_COUNTER0: | ||
2743 | ien |= XSCALE2_COUNT0_INT_EN; | ||
2744 | evtsel &= ~XSCALE2_COUNT0_EVT_MASK; | ||
2745 | evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT; | ||
2746 | break; | ||
2747 | case XSCALE_COUNTER1: | ||
2748 | ien |= XSCALE2_COUNT1_INT_EN; | ||
2749 | evtsel &= ~XSCALE2_COUNT1_EVT_MASK; | ||
2750 | evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT; | ||
2751 | break; | ||
2752 | case XSCALE_COUNTER2: | ||
2753 | ien |= XSCALE2_COUNT2_INT_EN; | ||
2754 | evtsel &= ~XSCALE2_COUNT2_EVT_MASK; | ||
2755 | evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT; | ||
2756 | break; | ||
2757 | case XSCALE_COUNTER3: | ||
2758 | ien |= XSCALE2_COUNT3_INT_EN; | ||
2759 | evtsel &= ~XSCALE2_COUNT3_EVT_MASK; | ||
2760 | evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT; | ||
2761 | break; | ||
2762 | default: | ||
2763 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
2764 | return; | ||
2765 | } | ||
2766 | |||
2767 | spin_lock_irqsave(&pmu_lock, flags); | ||
2768 | xscale2pmu_write_event_select(evtsel); | ||
2769 | xscale2pmu_write_int_enable(ien); | ||
2770 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2771 | } | ||
2772 | |||
2773 | static void | ||
2774 | xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
2775 | { | ||
2776 | unsigned long flags, ien, evtsel; | ||
2777 | |||
2778 | ien = xscale2pmu_read_int_enable(); | ||
2779 | evtsel = xscale2pmu_read_event_select(); | ||
2780 | |||
2781 | switch (idx) { | ||
2782 | case XSCALE_CYCLE_COUNTER: | ||
2783 | ien &= ~XSCALE2_CCOUNT_INT_EN; | ||
2784 | break; | ||
2785 | case XSCALE_COUNTER0: | ||
2786 | ien &= ~XSCALE2_COUNT0_INT_EN; | ||
2787 | evtsel &= ~XSCALE2_COUNT0_EVT_MASK; | ||
2788 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT; | ||
2789 | break; | ||
2790 | case XSCALE_COUNTER1: | ||
2791 | ien &= ~XSCALE2_COUNT1_INT_EN; | ||
2792 | evtsel &= ~XSCALE2_COUNT1_EVT_MASK; | ||
2793 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT; | ||
2794 | break; | ||
2795 | case XSCALE_COUNTER2: | ||
2796 | ien &= ~XSCALE2_COUNT2_INT_EN; | ||
2797 | evtsel &= ~XSCALE2_COUNT2_EVT_MASK; | ||
2798 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT; | ||
2799 | break; | ||
2800 | case XSCALE_COUNTER3: | ||
2801 | ien &= ~XSCALE2_COUNT3_INT_EN; | ||
2802 | evtsel &= ~XSCALE2_COUNT3_EVT_MASK; | ||
2803 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT; | ||
2804 | break; | ||
2805 | default: | ||
2806 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
2807 | return; | ||
2808 | } | ||
2809 | |||
2810 | spin_lock_irqsave(&pmu_lock, flags); | ||
2811 | xscale2pmu_write_event_select(evtsel); | ||
2812 | xscale2pmu_write_int_enable(ien); | ||
2813 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2814 | } | ||
2815 | |||
2816 | static int | ||
2817 | xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
2818 | struct hw_perf_event *event) | ||
2819 | { | ||
2820 | int idx = xscale1pmu_get_event_idx(cpuc, event); | ||
2821 | if (idx >= 0) | ||
2822 | goto out; | ||
2823 | |||
2824 | if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask)) | ||
2825 | idx = XSCALE_COUNTER3; | ||
2826 | else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask)) | ||
2827 | idx = XSCALE_COUNTER2; | ||
2828 | out: | ||
2829 | return idx; | ||
2830 | } | ||
2831 | |||
2832 | static void | ||
2833 | xscale2pmu_start(void) | ||
2834 | { | ||
2835 | unsigned long flags, val; | ||
2836 | |||
2837 | spin_lock_irqsave(&pmu_lock, flags); | ||
2838 | val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64; | ||
2839 | val |= XSCALE_PMU_ENABLE; | ||
2840 | xscale2pmu_write_pmnc(val); | ||
2841 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2842 | } | ||
2843 | |||
2844 | static void | ||
2845 | xscale2pmu_stop(void) | ||
2846 | { | ||
2847 | unsigned long flags, val; | ||
2848 | |||
2849 | spin_lock_irqsave(&pmu_lock, flags); | ||
2850 | val = xscale2pmu_read_pmnc(); | ||
2851 | val &= ~XSCALE_PMU_ENABLE; | ||
2852 | xscale2pmu_write_pmnc(val); | ||
2853 | spin_unlock_irqrestore(&pmu_lock, flags); | ||
2854 | } | ||
2855 | |||
2856 | static inline u32 | ||
2857 | xscale2pmu_read_counter(int counter) | ||
2858 | { | ||
2859 | u32 val = 0; | ||
2860 | |||
2861 | switch (counter) { | ||
2862 | case XSCALE_CYCLE_COUNTER: | ||
2863 | asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val)); | ||
2864 | break; | ||
2865 | case XSCALE_COUNTER0: | ||
2866 | asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val)); | ||
2867 | break; | ||
2868 | case XSCALE_COUNTER1: | ||
2869 | asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val)); | ||
2870 | break; | ||
2871 | case XSCALE_COUNTER2: | ||
2872 | asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val)); | ||
2873 | break; | ||
2874 | case XSCALE_COUNTER3: | ||
2875 | asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val)); | ||
2876 | break; | ||
2877 | } | ||
2878 | |||
2879 | return val; | ||
2880 | } | ||
2881 | |||
2882 | static inline void | ||
2883 | xscale2pmu_write_counter(int counter, u32 val) | ||
2884 | { | 634 | { |
2885 | switch (counter) { | 635 | if (armpmu && armpmu->reset) |
2886 | case XSCALE_CYCLE_COUNTER: | 636 | return on_each_cpu(armpmu->reset, NULL, 1); |
2887 | asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val)); | 637 | return 0; |
2888 | break; | ||
2889 | case XSCALE_COUNTER0: | ||
2890 | asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val)); | ||
2891 | break; | ||
2892 | case XSCALE_COUNTER1: | ||
2893 | asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val)); | ||
2894 | break; | ||
2895 | case XSCALE_COUNTER2: | ||
2896 | asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val)); | ||
2897 | break; | ||
2898 | case XSCALE_COUNTER3: | ||
2899 | asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val)); | ||
2900 | break; | ||
2901 | } | ||
2902 | } | 638 | } |
2903 | 639 | arch_initcall(armpmu_reset); | |
2904 | static const struct arm_pmu xscale2pmu = { | ||
2905 | .id = ARM_PERF_PMU_ID_XSCALE2, | ||
2906 | .handle_irq = xscale2pmu_handle_irq, | ||
2907 | .enable = xscale2pmu_enable_event, | ||
2908 | .disable = xscale2pmu_disable_event, | ||
2909 | .event_map = xscalepmu_event_map, | ||
2910 | .raw_event = xscalepmu_raw_event, | ||
2911 | .read_counter = xscale2pmu_read_counter, | ||
2912 | .write_counter = xscale2pmu_write_counter, | ||
2913 | .get_event_idx = xscale2pmu_get_event_idx, | ||
2914 | .start = xscale2pmu_start, | ||
2915 | .stop = xscale2pmu_stop, | ||
2916 | .num_events = 5, | ||
2917 | .max_period = (1LLU << 32) - 1, | ||
2918 | }; | ||
2919 | 640 | ||
2920 | static int __init | 641 | static int __init |
2921 | init_hw_perf_events(void) | 642 | init_hw_perf_events(void) |
@@ -2930,41 +651,16 @@ init_hw_perf_events(void) | |||
2930 | case 0xB360: /* ARM1136 */ | 651 | case 0xB360: /* ARM1136 */ |
2931 | case 0xB560: /* ARM1156 */ | 652 | case 0xB560: /* ARM1156 */ |
2932 | case 0xB760: /* ARM1176 */ | 653 | case 0xB760: /* ARM1176 */ |
2933 | armpmu = &armv6pmu; | 654 | armpmu = armv6pmu_init(); |
2934 | memcpy(armpmu_perf_cache_map, armv6_perf_cache_map, | ||
2935 | sizeof(armv6_perf_cache_map)); | ||
2936 | perf_max_events = armv6pmu.num_events; | ||
2937 | break; | 655 | break; |
2938 | case 0xB020: /* ARM11mpcore */ | 656 | case 0xB020: /* ARM11mpcore */ |
2939 | armpmu = &armv6mpcore_pmu; | 657 | armpmu = armv6mpcore_pmu_init(); |
2940 | memcpy(armpmu_perf_cache_map, | ||
2941 | armv6mpcore_perf_cache_map, | ||
2942 | sizeof(armv6mpcore_perf_cache_map)); | ||
2943 | perf_max_events = armv6mpcore_pmu.num_events; | ||
2944 | break; | 658 | break; |
2945 | case 0xC080: /* Cortex-A8 */ | 659 | case 0xC080: /* Cortex-A8 */ |
2946 | armv7pmu.id = ARM_PERF_PMU_ID_CA8; | 660 | armpmu = armv7_a8_pmu_init(); |
2947 | memcpy(armpmu_perf_cache_map, armv7_a8_perf_cache_map, | ||
2948 | sizeof(armv7_a8_perf_cache_map)); | ||
2949 | armv7pmu.event_map = armv7_a8_pmu_event_map; | ||
2950 | armpmu = &armv7pmu; | ||
2951 | |||
2952 | /* Reset PMNC and read the nb of CNTx counters | ||
2953 | supported */ | ||
2954 | armv7pmu.num_events = armv7_reset_read_pmnc(); | ||
2955 | perf_max_events = armv7pmu.num_events; | ||
2956 | break; | 661 | break; |
2957 | case 0xC090: /* Cortex-A9 */ | 662 | case 0xC090: /* Cortex-A9 */ |
2958 | armv7pmu.id = ARM_PERF_PMU_ID_CA9; | 663 | armpmu = armv7_a9_pmu_init(); |
2959 | memcpy(armpmu_perf_cache_map, armv7_a9_perf_cache_map, | ||
2960 | sizeof(armv7_a9_perf_cache_map)); | ||
2961 | armv7pmu.event_map = armv7_a9_pmu_event_map; | ||
2962 | armpmu = &armv7pmu; | ||
2963 | |||
2964 | /* Reset PMNC and read the nb of CNTx counters | ||
2965 | supported */ | ||
2966 | armv7pmu.num_events = armv7_reset_read_pmnc(); | ||
2967 | perf_max_events = armv7pmu.num_events; | ||
2968 | break; | 664 | break; |
2969 | } | 665 | } |
2970 | /* Intel CPUs [xscale]. */ | 666 | /* Intel CPUs [xscale]. */ |
@@ -2972,42 +668,30 @@ init_hw_perf_events(void) | |||
2972 | part_number = (cpuid >> 13) & 0x7; | 668 | part_number = (cpuid >> 13) & 0x7; |
2973 | switch (part_number) { | 669 | switch (part_number) { |
2974 | case 1: | 670 | case 1: |
2975 | armpmu = &xscale1pmu; | 671 | armpmu = xscale1pmu_init(); |
2976 | memcpy(armpmu_perf_cache_map, xscale_perf_cache_map, | ||
2977 | sizeof(xscale_perf_cache_map)); | ||
2978 | perf_max_events = xscale1pmu.num_events; | ||
2979 | break; | 672 | break; |
2980 | case 2: | 673 | case 2: |
2981 | armpmu = &xscale2pmu; | 674 | armpmu = xscale2pmu_init(); |
2982 | memcpy(armpmu_perf_cache_map, xscale_perf_cache_map, | ||
2983 | sizeof(xscale_perf_cache_map)); | ||
2984 | perf_max_events = xscale2pmu.num_events; | ||
2985 | break; | 675 | break; |
2986 | } | 676 | } |
2987 | } | 677 | } |
2988 | 678 | ||
2989 | if (armpmu) { | 679 | if (armpmu) { |
2990 | pr_info("enabled with %s PMU driver, %d counters available\n", | 680 | pr_info("enabled with %s PMU driver, %d counters available\n", |
2991 | arm_pmu_names[armpmu->id], armpmu->num_events); | 681 | armpmu->name, armpmu->num_events); |
2992 | } else { | 682 | } else { |
2993 | pr_info("no hardware support available\n"); | 683 | pr_info("no hardware support available\n"); |
2994 | perf_max_events = -1; | ||
2995 | } | 684 | } |
2996 | 685 | ||
686 | perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); | ||
687 | |||
2997 | return 0; | 688 | return 0; |
2998 | } | 689 | } |
2999 | arch_initcall(init_hw_perf_events); | 690 | early_initcall(init_hw_perf_events); |
3000 | 691 | ||
3001 | /* | 692 | /* |
3002 | * Callchain handling code. | 693 | * Callchain handling code. |
3003 | */ | 694 | */ |
3004 | static inline void | ||
3005 | callchain_store(struct perf_callchain_entry *entry, | ||
3006 | u64 ip) | ||
3007 | { | ||
3008 | if (entry->nr < PERF_MAX_STACK_DEPTH) | ||
3009 | entry->ip[entry->nr++] = ip; | ||
3010 | } | ||
3011 | 695 | ||
3012 | /* | 696 | /* |
3013 | * The registers we're interested in are at the end of the variable | 697 | * The registers we're interested in are at the end of the variable |
@@ -3018,17 +702,17 @@ callchain_store(struct perf_callchain_entry *entry, | |||
3018 | * This code has been adapted from the ARM OProfile support. | 702 | * This code has been adapted from the ARM OProfile support. |
3019 | */ | 703 | */ |
3020 | struct frame_tail { | 704 | struct frame_tail { |
3021 | struct frame_tail *fp; | 705 | struct frame_tail __user *fp; |
3022 | unsigned long sp; | 706 | unsigned long sp; |
3023 | unsigned long lr; | 707 | unsigned long lr; |
3024 | } __attribute__((packed)); | 708 | } __attribute__((packed)); |
3025 | 709 | ||
3026 | /* | 710 | /* |
3027 | * Get the return address for a single stackframe and return a pointer to the | 711 | * Get the return address for a single stackframe and return a pointer to the |
3028 | * next frame tail. | 712 | * next frame tail. |
3029 | */ | 713 | */ |
3030 | static struct frame_tail * | 714 | static struct frame_tail __user * |
3031 | user_backtrace(struct frame_tail *tail, | 715 | user_backtrace(struct frame_tail __user *tail, |
3032 | struct perf_callchain_entry *entry) | 716 | struct perf_callchain_entry *entry) |
3033 | { | 717 | { |
3034 | struct frame_tail buftail; | 718 | struct frame_tail buftail; |
@@ -3039,32 +723,28 @@ user_backtrace(struct frame_tail *tail, | |||
3039 | if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail))) | 723 | if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail))) |
3040 | return NULL; | 724 | return NULL; |
3041 | 725 | ||
3042 | callchain_store(entry, buftail.lr); | 726 | perf_callchain_store(entry, buftail.lr); |
3043 | 727 | ||
3044 | /* | 728 | /* |
3045 | * Frame pointers should strictly progress back up the stack | 729 | * Frame pointers should strictly progress back up the stack |
3046 | * (towards higher addresses). | 730 | * (towards higher addresses). |
3047 | */ | 731 | */ |
3048 | if (tail >= buftail.fp) | 732 | if (tail + 1 >= buftail.fp) |
3049 | return NULL; | 733 | return NULL; |
3050 | 734 | ||
3051 | return buftail.fp - 1; | 735 | return buftail.fp - 1; |
3052 | } | 736 | } |
3053 | 737 | ||
3054 | static void | 738 | void |
3055 | perf_callchain_user(struct pt_regs *regs, | 739 | perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) |
3056 | struct perf_callchain_entry *entry) | ||
3057 | { | 740 | { |
3058 | struct frame_tail *tail; | 741 | struct frame_tail __user *tail; |
3059 | |||
3060 | callchain_store(entry, PERF_CONTEXT_USER); | ||
3061 | 742 | ||
3062 | if (!user_mode(regs)) | ||
3063 | regs = task_pt_regs(current); | ||
3064 | 743 | ||
3065 | tail = (struct frame_tail *)regs->ARM_fp - 1; | 744 | tail = (struct frame_tail __user *)regs->ARM_fp - 1; |
3066 | 745 | ||
3067 | while (tail && !((unsigned long)tail & 0x3)) | 746 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && |
747 | tail && !((unsigned long)tail & 0x3)) | ||
3068 | tail = user_backtrace(tail, entry); | 748 | tail = user_backtrace(tail, entry); |
3069 | } | 749 | } |
3070 | 750 | ||
@@ -3078,56 +758,18 @@ callchain_trace(struct stackframe *fr, | |||
3078 | void *data) | 758 | void *data) |
3079 | { | 759 | { |
3080 | struct perf_callchain_entry *entry = data; | 760 | struct perf_callchain_entry *entry = data; |
3081 | callchain_store(entry, fr->pc); | 761 | perf_callchain_store(entry, fr->pc); |
3082 | return 0; | 762 | return 0; |
3083 | } | 763 | } |
3084 | 764 | ||
3085 | static void | 765 | void |
3086 | perf_callchain_kernel(struct pt_regs *regs, | 766 | perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) |
3087 | struct perf_callchain_entry *entry) | ||
3088 | { | 767 | { |
3089 | struct stackframe fr; | 768 | struct stackframe fr; |
3090 | 769 | ||
3091 | callchain_store(entry, PERF_CONTEXT_KERNEL); | ||
3092 | fr.fp = regs->ARM_fp; | 770 | fr.fp = regs->ARM_fp; |
3093 | fr.sp = regs->ARM_sp; | 771 | fr.sp = regs->ARM_sp; |
3094 | fr.lr = regs->ARM_lr; | 772 | fr.lr = regs->ARM_lr; |
3095 | fr.pc = regs->ARM_pc; | 773 | fr.pc = regs->ARM_pc; |
3096 | walk_stackframe(&fr, callchain_trace, entry); | 774 | walk_stackframe(&fr, callchain_trace, entry); |
3097 | } | 775 | } |
3098 | |||
3099 | static void | ||
3100 | perf_do_callchain(struct pt_regs *regs, | ||
3101 | struct perf_callchain_entry *entry) | ||
3102 | { | ||
3103 | int is_user; | ||
3104 | |||
3105 | if (!regs) | ||
3106 | return; | ||
3107 | |||
3108 | is_user = user_mode(regs); | ||
3109 | |||
3110 | if (!current || !current->pid) | ||
3111 | return; | ||
3112 | |||
3113 | if (is_user && current->state != TASK_RUNNING) | ||
3114 | return; | ||
3115 | |||
3116 | if (!is_user) | ||
3117 | perf_callchain_kernel(regs, entry); | ||
3118 | |||
3119 | if (current->mm) | ||
3120 | perf_callchain_user(regs, entry); | ||
3121 | } | ||
3122 | |||
3123 | static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry); | ||
3124 | |||
3125 | struct perf_callchain_entry * | ||
3126 | perf_callchain(struct pt_regs *regs) | ||
3127 | { | ||
3128 | struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry); | ||
3129 | |||
3130 | entry->nr = 0; | ||
3131 | perf_do_callchain(regs, entry); | ||
3132 | return entry; | ||
3133 | } | ||
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c new file mode 100644 index 000000000000..f1e8dd94afe8 --- /dev/null +++ b/arch/arm/kernel/perf_event_v6.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * ARMv6 Performance counter handling code. | ||
3 | * | ||
4 | * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles | ||
5 | * | ||
6 | * ARMv6 has 2 configurable performance counters and a single cycle counter. | ||
7 | * They all share a single reset bit but can be written to zero so we can use | ||
8 | * that for a reset. | ||
9 | * | ||
10 | * The counters can't be individually enabled or disabled so when we remove | ||
11 | * one event and replace it with another we could get spurious counts from the | ||
12 | * wrong event. However, we can take advantage of the fact that the | ||
13 | * performance counters can export events to the event bus, and the event bus | ||
14 | * itself can be monitored. This requires that we *don't* export the events to | ||
15 | * the event bus. The procedure for disabling a configurable counter is: | ||
16 | * - change the counter to count the ETMEXTOUT[0] signal (0x20). This | ||
17 | * effectively stops the counter from counting. | ||
18 | * - disable the counter's interrupt generation (each counter has it's | ||
19 | * own interrupt enable bit). | ||
20 | * Once stopped, the counter value can be written as 0 to reset. | ||
21 | * | ||
22 | * To enable a counter: | ||
23 | * - enable the counter's interrupt generation. | ||
24 | * - set the new event type. | ||
25 | * | ||
26 | * Note: the dedicated cycle counter only counts cycles and can't be | ||
27 | * enabled/disabled independently of the others. When we want to disable the | ||
28 | * cycle counter, we have to just disable the interrupt reporting and start | ||
29 | * ignoring that counter. When re-enabling, we have to reset the value and | ||
30 | * enable the interrupt. | ||
31 | */ | ||
32 | |||
33 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) | ||
34 | enum armv6_perf_types { | ||
35 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, | ||
36 | ARMV6_PERFCTR_IBUF_STALL = 0x1, | ||
37 | ARMV6_PERFCTR_DDEP_STALL = 0x2, | ||
38 | ARMV6_PERFCTR_ITLB_MISS = 0x3, | ||
39 | ARMV6_PERFCTR_DTLB_MISS = 0x4, | ||
40 | ARMV6_PERFCTR_BR_EXEC = 0x5, | ||
41 | ARMV6_PERFCTR_BR_MISPREDICT = 0x6, | ||
42 | ARMV6_PERFCTR_INSTR_EXEC = 0x7, | ||
43 | ARMV6_PERFCTR_DCACHE_HIT = 0x9, | ||
44 | ARMV6_PERFCTR_DCACHE_ACCESS = 0xA, | ||
45 | ARMV6_PERFCTR_DCACHE_MISS = 0xB, | ||
46 | ARMV6_PERFCTR_DCACHE_WBACK = 0xC, | ||
47 | ARMV6_PERFCTR_SW_PC_CHANGE = 0xD, | ||
48 | ARMV6_PERFCTR_MAIN_TLB_MISS = 0xF, | ||
49 | ARMV6_PERFCTR_EXPL_D_ACCESS = 0x10, | ||
50 | ARMV6_PERFCTR_LSU_FULL_STALL = 0x11, | ||
51 | ARMV6_PERFCTR_WBUF_DRAINED = 0x12, | ||
52 | ARMV6_PERFCTR_CPU_CYCLES = 0xFF, | ||
53 | ARMV6_PERFCTR_NOP = 0x20, | ||
54 | }; | ||
55 | |||
56 | enum armv6_counters { | ||
57 | ARMV6_CYCLE_COUNTER = 1, | ||
58 | ARMV6_COUNTER0, | ||
59 | ARMV6_COUNTER1, | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * The hardware events that we support. We do support cache operations but | ||
64 | * we have harvard caches and no way to combine instruction and data | ||
65 | * accesses/misses in hardware. | ||
66 | */ | ||
67 | static const unsigned armv6_perf_map[PERF_COUNT_HW_MAX] = { | ||
68 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV6_PERFCTR_CPU_CYCLES, | ||
69 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6_PERFCTR_INSTR_EXEC, | ||
70 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
71 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
72 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6_PERFCTR_BR_EXEC, | ||
73 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6_PERFCTR_BR_MISPREDICT, | ||
74 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
75 | }; | ||
76 | |||
77 | static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
78 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
79 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
80 | [C(L1D)] = { | ||
81 | /* | ||
82 | * The performance counters don't differentiate between read | ||
83 | * and write accesses/misses so this isn't strictly correct, | ||
84 | * but it's the best we can do. Writes and reads get | ||
85 | * combined. | ||
86 | */ | ||
87 | [C(OP_READ)] = { | ||
88 | [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, | ||
89 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, | ||
90 | }, | ||
91 | [C(OP_WRITE)] = { | ||
92 | [C(RESULT_ACCESS)] = ARMV6_PERFCTR_DCACHE_ACCESS, | ||
93 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DCACHE_MISS, | ||
94 | }, | ||
95 | [C(OP_PREFETCH)] = { | ||
96 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
97 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
98 | }, | ||
99 | }, | ||
100 | [C(L1I)] = { | ||
101 | [C(OP_READ)] = { | ||
102 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
103 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, | ||
104 | }, | ||
105 | [C(OP_WRITE)] = { | ||
106 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
107 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ICACHE_MISS, | ||
108 | }, | ||
109 | [C(OP_PREFETCH)] = { | ||
110 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
111 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
112 | }, | ||
113 | }, | ||
114 | [C(LL)] = { | ||
115 | [C(OP_READ)] = { | ||
116 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
117 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
118 | }, | ||
119 | [C(OP_WRITE)] = { | ||
120 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
121 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
122 | }, | ||
123 | [C(OP_PREFETCH)] = { | ||
124 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
125 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
126 | }, | ||
127 | }, | ||
128 | [C(DTLB)] = { | ||
129 | /* | ||
130 | * The ARM performance counters can count micro DTLB misses, | ||
131 | * micro ITLB misses and main TLB misses. There isn't an event | ||
132 | * for TLB misses, so use the micro misses here and if users | ||
133 | * want the main TLB misses they can use a raw counter. | ||
134 | */ | ||
135 | [C(OP_READ)] = { | ||
136 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
137 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, | ||
138 | }, | ||
139 | [C(OP_WRITE)] = { | ||
140 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
141 | [C(RESULT_MISS)] = ARMV6_PERFCTR_DTLB_MISS, | ||
142 | }, | ||
143 | [C(OP_PREFETCH)] = { | ||
144 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
145 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
146 | }, | ||
147 | }, | ||
148 | [C(ITLB)] = { | ||
149 | [C(OP_READ)] = { | ||
150 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
151 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, | ||
152 | }, | ||
153 | [C(OP_WRITE)] = { | ||
154 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
155 | [C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, | ||
156 | }, | ||
157 | [C(OP_PREFETCH)] = { | ||
158 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
159 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
160 | }, | ||
161 | }, | ||
162 | [C(BPU)] = { | ||
163 | [C(OP_READ)] = { | ||
164 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
165 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
166 | }, | ||
167 | [C(OP_WRITE)] = { | ||
168 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
169 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
170 | }, | ||
171 | [C(OP_PREFETCH)] = { | ||
172 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
173 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
174 | }, | ||
175 | }, | ||
176 | }; | ||
177 | |||
178 | enum armv6mpcore_perf_types { | ||
179 | ARMV6MPCORE_PERFCTR_ICACHE_MISS = 0x0, | ||
180 | ARMV6MPCORE_PERFCTR_IBUF_STALL = 0x1, | ||
181 | ARMV6MPCORE_PERFCTR_DDEP_STALL = 0x2, | ||
182 | ARMV6MPCORE_PERFCTR_ITLB_MISS = 0x3, | ||
183 | ARMV6MPCORE_PERFCTR_DTLB_MISS = 0x4, | ||
184 | ARMV6MPCORE_PERFCTR_BR_EXEC = 0x5, | ||
185 | ARMV6MPCORE_PERFCTR_BR_NOTPREDICT = 0x6, | ||
186 | ARMV6MPCORE_PERFCTR_BR_MISPREDICT = 0x7, | ||
187 | ARMV6MPCORE_PERFCTR_INSTR_EXEC = 0x8, | ||
188 | ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS = 0xA, | ||
189 | ARMV6MPCORE_PERFCTR_DCACHE_RDMISS = 0xB, | ||
190 | ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS = 0xC, | ||
191 | ARMV6MPCORE_PERFCTR_DCACHE_WRMISS = 0xD, | ||
192 | ARMV6MPCORE_PERFCTR_DCACHE_EVICTION = 0xE, | ||
193 | ARMV6MPCORE_PERFCTR_SW_PC_CHANGE = 0xF, | ||
194 | ARMV6MPCORE_PERFCTR_MAIN_TLB_MISS = 0x10, | ||
195 | ARMV6MPCORE_PERFCTR_EXPL_MEM_ACCESS = 0x11, | ||
196 | ARMV6MPCORE_PERFCTR_LSU_FULL_STALL = 0x12, | ||
197 | ARMV6MPCORE_PERFCTR_WBUF_DRAINED = 0x13, | ||
198 | ARMV6MPCORE_PERFCTR_CPU_CYCLES = 0xFF, | ||
199 | }; | ||
200 | |||
201 | /* | ||
202 | * The hardware events that we support. We do support cache operations but | ||
203 | * we have harvard caches and no way to combine instruction and data | ||
204 | * accesses/misses in hardware. | ||
205 | */ | ||
206 | static const unsigned armv6mpcore_perf_map[PERF_COUNT_HW_MAX] = { | ||
207 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV6MPCORE_PERFCTR_CPU_CYCLES, | ||
208 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_INSTR_EXEC, | ||
209 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
210 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
211 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_BR_EXEC, | ||
212 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6MPCORE_PERFCTR_BR_MISPREDICT, | ||
213 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
214 | }; | ||
215 | |||
216 | static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
217 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
218 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
219 | [C(L1D)] = { | ||
220 | [C(OP_READ)] = { | ||
221 | [C(RESULT_ACCESS)] = | ||
222 | ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS, | ||
223 | [C(RESULT_MISS)] = | ||
224 | ARMV6MPCORE_PERFCTR_DCACHE_RDMISS, | ||
225 | }, | ||
226 | [C(OP_WRITE)] = { | ||
227 | [C(RESULT_ACCESS)] = | ||
228 | ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS, | ||
229 | [C(RESULT_MISS)] = | ||
230 | ARMV6MPCORE_PERFCTR_DCACHE_WRMISS, | ||
231 | }, | ||
232 | [C(OP_PREFETCH)] = { | ||
233 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
234 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
235 | }, | ||
236 | }, | ||
237 | [C(L1I)] = { | ||
238 | [C(OP_READ)] = { | ||
239 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
240 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, | ||
241 | }, | ||
242 | [C(OP_WRITE)] = { | ||
243 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
244 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, | ||
245 | }, | ||
246 | [C(OP_PREFETCH)] = { | ||
247 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
248 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
249 | }, | ||
250 | }, | ||
251 | [C(LL)] = { | ||
252 | [C(OP_READ)] = { | ||
253 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
254 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
255 | }, | ||
256 | [C(OP_WRITE)] = { | ||
257 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
258 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
259 | }, | ||
260 | [C(OP_PREFETCH)] = { | ||
261 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
262 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
263 | }, | ||
264 | }, | ||
265 | [C(DTLB)] = { | ||
266 | /* | ||
267 | * The ARM performance counters can count micro DTLB misses, | ||
268 | * micro ITLB misses and main TLB misses. There isn't an event | ||
269 | * for TLB misses, so use the micro misses here and if users | ||
270 | * want the main TLB misses they can use a raw counter. | ||
271 | */ | ||
272 | [C(OP_READ)] = { | ||
273 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
274 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, | ||
275 | }, | ||
276 | [C(OP_WRITE)] = { | ||
277 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
278 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, | ||
279 | }, | ||
280 | [C(OP_PREFETCH)] = { | ||
281 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
282 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
283 | }, | ||
284 | }, | ||
285 | [C(ITLB)] = { | ||
286 | [C(OP_READ)] = { | ||
287 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
288 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, | ||
289 | }, | ||
290 | [C(OP_WRITE)] = { | ||
291 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
292 | [C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, | ||
293 | }, | ||
294 | [C(OP_PREFETCH)] = { | ||
295 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
296 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
297 | }, | ||
298 | }, | ||
299 | [C(BPU)] = { | ||
300 | [C(OP_READ)] = { | ||
301 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
302 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
303 | }, | ||
304 | [C(OP_WRITE)] = { | ||
305 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
306 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
307 | }, | ||
308 | [C(OP_PREFETCH)] = { | ||
309 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
310 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
311 | }, | ||
312 | }, | ||
313 | }; | ||
314 | |||
315 | static inline unsigned long | ||
316 | armv6_pmcr_read(void) | ||
317 | { | ||
318 | u32 val; | ||
319 | asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r"(val)); | ||
320 | return val; | ||
321 | } | ||
322 | |||
323 | static inline void | ||
324 | armv6_pmcr_write(unsigned long val) | ||
325 | { | ||
326 | asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r"(val)); | ||
327 | } | ||
328 | |||
329 | #define ARMV6_PMCR_ENABLE (1 << 0) | ||
330 | #define ARMV6_PMCR_CTR01_RESET (1 << 1) | ||
331 | #define ARMV6_PMCR_CCOUNT_RESET (1 << 2) | ||
332 | #define ARMV6_PMCR_CCOUNT_DIV (1 << 3) | ||
333 | #define ARMV6_PMCR_COUNT0_IEN (1 << 4) | ||
334 | #define ARMV6_PMCR_COUNT1_IEN (1 << 5) | ||
335 | #define ARMV6_PMCR_CCOUNT_IEN (1 << 6) | ||
336 | #define ARMV6_PMCR_COUNT0_OVERFLOW (1 << 8) | ||
337 | #define ARMV6_PMCR_COUNT1_OVERFLOW (1 << 9) | ||
338 | #define ARMV6_PMCR_CCOUNT_OVERFLOW (1 << 10) | ||
339 | #define ARMV6_PMCR_EVT_COUNT0_SHIFT 20 | ||
340 | #define ARMV6_PMCR_EVT_COUNT0_MASK (0xFF << ARMV6_PMCR_EVT_COUNT0_SHIFT) | ||
341 | #define ARMV6_PMCR_EVT_COUNT1_SHIFT 12 | ||
342 | #define ARMV6_PMCR_EVT_COUNT1_MASK (0xFF << ARMV6_PMCR_EVT_COUNT1_SHIFT) | ||
343 | |||
344 | #define ARMV6_PMCR_OVERFLOWED_MASK \ | ||
345 | (ARMV6_PMCR_COUNT0_OVERFLOW | ARMV6_PMCR_COUNT1_OVERFLOW | \ | ||
346 | ARMV6_PMCR_CCOUNT_OVERFLOW) | ||
347 | |||
348 | static inline int | ||
349 | armv6_pmcr_has_overflowed(unsigned long pmcr) | ||
350 | { | ||
351 | return pmcr & ARMV6_PMCR_OVERFLOWED_MASK; | ||
352 | } | ||
353 | |||
354 | static inline int | ||
355 | armv6_pmcr_counter_has_overflowed(unsigned long pmcr, | ||
356 | enum armv6_counters counter) | ||
357 | { | ||
358 | int ret = 0; | ||
359 | |||
360 | if (ARMV6_CYCLE_COUNTER == counter) | ||
361 | ret = pmcr & ARMV6_PMCR_CCOUNT_OVERFLOW; | ||
362 | else if (ARMV6_COUNTER0 == counter) | ||
363 | ret = pmcr & ARMV6_PMCR_COUNT0_OVERFLOW; | ||
364 | else if (ARMV6_COUNTER1 == counter) | ||
365 | ret = pmcr & ARMV6_PMCR_COUNT1_OVERFLOW; | ||
366 | else | ||
367 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static inline u32 | ||
373 | armv6pmu_read_counter(int counter) | ||
374 | { | ||
375 | unsigned long value = 0; | ||
376 | |||
377 | if (ARMV6_CYCLE_COUNTER == counter) | ||
378 | asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r"(value)); | ||
379 | else if (ARMV6_COUNTER0 == counter) | ||
380 | asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r"(value)); | ||
381 | else if (ARMV6_COUNTER1 == counter) | ||
382 | asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r"(value)); | ||
383 | else | ||
384 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
385 | |||
386 | return value; | ||
387 | } | ||
388 | |||
389 | static inline void | ||
390 | armv6pmu_write_counter(int counter, | ||
391 | u32 value) | ||
392 | { | ||
393 | if (ARMV6_CYCLE_COUNTER == counter) | ||
394 | asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r"(value)); | ||
395 | else if (ARMV6_COUNTER0 == counter) | ||
396 | asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r"(value)); | ||
397 | else if (ARMV6_COUNTER1 == counter) | ||
398 | asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r"(value)); | ||
399 | else | ||
400 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
401 | } | ||
402 | |||
403 | static void | ||
404 | armv6pmu_enable_event(struct hw_perf_event *hwc, | ||
405 | int idx) | ||
406 | { | ||
407 | unsigned long val, mask, evt, flags; | ||
408 | |||
409 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
410 | mask = 0; | ||
411 | evt = ARMV6_PMCR_CCOUNT_IEN; | ||
412 | } else if (ARMV6_COUNTER0 == idx) { | ||
413 | mask = ARMV6_PMCR_EVT_COUNT0_MASK; | ||
414 | evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT0_SHIFT) | | ||
415 | ARMV6_PMCR_COUNT0_IEN; | ||
416 | } else if (ARMV6_COUNTER1 == idx) { | ||
417 | mask = ARMV6_PMCR_EVT_COUNT1_MASK; | ||
418 | evt = (hwc->config_base << ARMV6_PMCR_EVT_COUNT1_SHIFT) | | ||
419 | ARMV6_PMCR_COUNT1_IEN; | ||
420 | } else { | ||
421 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Mask out the current event and set the counter to count the event | ||
427 | * that we're interested in. | ||
428 | */ | ||
429 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
430 | val = armv6_pmcr_read(); | ||
431 | val &= ~mask; | ||
432 | val |= evt; | ||
433 | armv6_pmcr_write(val); | ||
434 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
435 | } | ||
436 | |||
437 | static irqreturn_t | ||
438 | armv6pmu_handle_irq(int irq_num, | ||
439 | void *dev) | ||
440 | { | ||
441 | unsigned long pmcr = armv6_pmcr_read(); | ||
442 | struct perf_sample_data data; | ||
443 | struct cpu_hw_events *cpuc; | ||
444 | struct pt_regs *regs; | ||
445 | int idx; | ||
446 | |||
447 | if (!armv6_pmcr_has_overflowed(pmcr)) | ||
448 | return IRQ_NONE; | ||
449 | |||
450 | regs = get_irq_regs(); | ||
451 | |||
452 | /* | ||
453 | * The interrupts are cleared by writing the overflow flags back to | ||
454 | * the control register. All of the other bits don't have any effect | ||
455 | * if they are rewritten, so write the whole value back. | ||
456 | */ | ||
457 | armv6_pmcr_write(pmcr); | ||
458 | |||
459 | perf_sample_data_init(&data, 0); | ||
460 | |||
461 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
462 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
463 | struct perf_event *event = cpuc->events[idx]; | ||
464 | struct hw_perf_event *hwc; | ||
465 | |||
466 | if (!test_bit(idx, cpuc->active_mask)) | ||
467 | continue; | ||
468 | |||
469 | /* | ||
470 | * We have a single interrupt for all counters. Check that | ||
471 | * each counter has overflowed before we process it. | ||
472 | */ | ||
473 | if (!armv6_pmcr_counter_has_overflowed(pmcr, idx)) | ||
474 | continue; | ||
475 | |||
476 | hwc = &event->hw; | ||
477 | armpmu_event_update(event, hwc, idx, 1); | ||
478 | data.period = event->hw.last_period; | ||
479 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
480 | continue; | ||
481 | |||
482 | if (perf_event_overflow(event, 0, &data, regs)) | ||
483 | armpmu->disable(hwc, idx); | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * Handle the pending perf events. | ||
488 | * | ||
489 | * Note: this call *must* be run with interrupts disabled. For | ||
490 | * platforms that can have the PMU interrupts raised as an NMI, this | ||
491 | * will not work. | ||
492 | */ | ||
493 | irq_work_run(); | ||
494 | |||
495 | return IRQ_HANDLED; | ||
496 | } | ||
497 | |||
498 | static void | ||
499 | armv6pmu_start(void) | ||
500 | { | ||
501 | unsigned long flags, val; | ||
502 | |||
503 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
504 | val = armv6_pmcr_read(); | ||
505 | val |= ARMV6_PMCR_ENABLE; | ||
506 | armv6_pmcr_write(val); | ||
507 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
508 | } | ||
509 | |||
510 | static void | ||
511 | armv6pmu_stop(void) | ||
512 | { | ||
513 | unsigned long flags, val; | ||
514 | |||
515 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
516 | val = armv6_pmcr_read(); | ||
517 | val &= ~ARMV6_PMCR_ENABLE; | ||
518 | armv6_pmcr_write(val); | ||
519 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
520 | } | ||
521 | |||
522 | static int | ||
523 | armv6pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
524 | struct hw_perf_event *event) | ||
525 | { | ||
526 | /* Always place a cycle counter into the cycle counter. */ | ||
527 | if (ARMV6_PERFCTR_CPU_CYCLES == event->config_base) { | ||
528 | if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask)) | ||
529 | return -EAGAIN; | ||
530 | |||
531 | return ARMV6_CYCLE_COUNTER; | ||
532 | } else { | ||
533 | /* | ||
534 | * For anything other than a cycle counter, try and use | ||
535 | * counter0 and counter1. | ||
536 | */ | ||
537 | if (!test_and_set_bit(ARMV6_COUNTER1, cpuc->used_mask)) | ||
538 | return ARMV6_COUNTER1; | ||
539 | |||
540 | if (!test_and_set_bit(ARMV6_COUNTER0, cpuc->used_mask)) | ||
541 | return ARMV6_COUNTER0; | ||
542 | |||
543 | /* The counters are all in use. */ | ||
544 | return -EAGAIN; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | static void | ||
549 | armv6pmu_disable_event(struct hw_perf_event *hwc, | ||
550 | int idx) | ||
551 | { | ||
552 | unsigned long val, mask, evt, flags; | ||
553 | |||
554 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
555 | mask = ARMV6_PMCR_CCOUNT_IEN; | ||
556 | evt = 0; | ||
557 | } else if (ARMV6_COUNTER0 == idx) { | ||
558 | mask = ARMV6_PMCR_COUNT0_IEN | ARMV6_PMCR_EVT_COUNT0_MASK; | ||
559 | evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT0_SHIFT; | ||
560 | } else if (ARMV6_COUNTER1 == idx) { | ||
561 | mask = ARMV6_PMCR_COUNT1_IEN | ARMV6_PMCR_EVT_COUNT1_MASK; | ||
562 | evt = ARMV6_PERFCTR_NOP << ARMV6_PMCR_EVT_COUNT1_SHIFT; | ||
563 | } else { | ||
564 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
565 | return; | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * Mask out the current event and set the counter to count the number | ||
570 | * of ETM bus signal assertion cycles. The external reporting should | ||
571 | * be disabled and so this should never increment. | ||
572 | */ | ||
573 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
574 | val = armv6_pmcr_read(); | ||
575 | val &= ~mask; | ||
576 | val |= evt; | ||
577 | armv6_pmcr_write(val); | ||
578 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
579 | } | ||
580 | |||
581 | static void | ||
582 | armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc, | ||
583 | int idx) | ||
584 | { | ||
585 | unsigned long val, mask, flags, evt = 0; | ||
586 | |||
587 | if (ARMV6_CYCLE_COUNTER == idx) { | ||
588 | mask = ARMV6_PMCR_CCOUNT_IEN; | ||
589 | } else if (ARMV6_COUNTER0 == idx) { | ||
590 | mask = ARMV6_PMCR_COUNT0_IEN; | ||
591 | } else if (ARMV6_COUNTER1 == idx) { | ||
592 | mask = ARMV6_PMCR_COUNT1_IEN; | ||
593 | } else { | ||
594 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * Unlike UP ARMv6, we don't have a way of stopping the counters. We | ||
600 | * simply disable the interrupt reporting. | ||
601 | */ | ||
602 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
603 | val = armv6_pmcr_read(); | ||
604 | val &= ~mask; | ||
605 | val |= evt; | ||
606 | armv6_pmcr_write(val); | ||
607 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
608 | } | ||
609 | |||
610 | static const struct arm_pmu armv6pmu = { | ||
611 | .id = ARM_PERF_PMU_ID_V6, | ||
612 | .name = "v6", | ||
613 | .handle_irq = armv6pmu_handle_irq, | ||
614 | .enable = armv6pmu_enable_event, | ||
615 | .disable = armv6pmu_disable_event, | ||
616 | .read_counter = armv6pmu_read_counter, | ||
617 | .write_counter = armv6pmu_write_counter, | ||
618 | .get_event_idx = armv6pmu_get_event_idx, | ||
619 | .start = armv6pmu_start, | ||
620 | .stop = armv6pmu_stop, | ||
621 | .cache_map = &armv6_perf_cache_map, | ||
622 | .event_map = &armv6_perf_map, | ||
623 | .raw_event_mask = 0xFF, | ||
624 | .num_events = 3, | ||
625 | .max_period = (1LLU << 32) - 1, | ||
626 | }; | ||
627 | |||
628 | static const struct arm_pmu *__init armv6pmu_init(void) | ||
629 | { | ||
630 | return &armv6pmu; | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * ARMv6mpcore is almost identical to single core ARMv6 with the exception | ||
635 | * that some of the events have different enumerations and that there is no | ||
636 | * *hack* to stop the programmable counters. To stop the counters we simply | ||
637 | * disable the interrupt reporting and update the event. When unthrottling we | ||
638 | * reset the period and enable the interrupt reporting. | ||
639 | */ | ||
640 | static const struct arm_pmu armv6mpcore_pmu = { | ||
641 | .id = ARM_PERF_PMU_ID_V6MP, | ||
642 | .name = "v6mpcore", | ||
643 | .handle_irq = armv6pmu_handle_irq, | ||
644 | .enable = armv6pmu_enable_event, | ||
645 | .disable = armv6mpcore_pmu_disable_event, | ||
646 | .read_counter = armv6pmu_read_counter, | ||
647 | .write_counter = armv6pmu_write_counter, | ||
648 | .get_event_idx = armv6pmu_get_event_idx, | ||
649 | .start = armv6pmu_start, | ||
650 | .stop = armv6pmu_stop, | ||
651 | .cache_map = &armv6mpcore_perf_cache_map, | ||
652 | .event_map = &armv6mpcore_perf_map, | ||
653 | .raw_event_mask = 0xFF, | ||
654 | .num_events = 3, | ||
655 | .max_period = (1LLU << 32) - 1, | ||
656 | }; | ||
657 | |||
658 | static const struct arm_pmu *__init armv6mpcore_pmu_init(void) | ||
659 | { | ||
660 | return &armv6mpcore_pmu; | ||
661 | } | ||
662 | #else | ||
663 | static const struct arm_pmu *__init armv6pmu_init(void) | ||
664 | { | ||
665 | return NULL; | ||
666 | } | ||
667 | |||
668 | static const struct arm_pmu *__init armv6mpcore_pmu_init(void) | ||
669 | { | ||
670 | return NULL; | ||
671 | } | ||
672 | #endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */ | ||
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c new file mode 100644 index 000000000000..4960686afb58 --- /dev/null +++ b/arch/arm/kernel/perf_event_v7.c | |||
@@ -0,0 +1,918 @@ | |||
1 | /* | ||
2 | * ARMv7 Cortex-A8 and Cortex-A9 Performance Events handling code. | ||
3 | * | ||
4 | * ARMv7 support: Jean Pihet <jpihet@mvista.com> | ||
5 | * 2010 (c) MontaVista Software, LLC. | ||
6 | * | ||
7 | * Copied from ARMv6 code, with the low level code inspired | ||
8 | * by the ARMv7 Oprofile code. | ||
9 | * | ||
10 | * Cortex-A8 has up to 4 configurable performance counters and | ||
11 | * a single cycle counter. | ||
12 | * Cortex-A9 has up to 31 configurable performance counters and | ||
13 | * a single cycle counter. | ||
14 | * | ||
15 | * All counters can be enabled/disabled and IRQ masked separately. The cycle | ||
16 | * counter and all 4 performance counters together can be reset separately. | ||
17 | */ | ||
18 | |||
19 | #ifdef CONFIG_CPU_V7 | ||
20 | /* Common ARMv7 event types */ | ||
21 | enum armv7_perf_types { | ||
22 | ARMV7_PERFCTR_PMNC_SW_INCR = 0x00, | ||
23 | ARMV7_PERFCTR_IFETCH_MISS = 0x01, | ||
24 | ARMV7_PERFCTR_ITLB_MISS = 0x02, | ||
25 | ARMV7_PERFCTR_DCACHE_REFILL = 0x03, | ||
26 | ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, | ||
27 | ARMV7_PERFCTR_DTLB_REFILL = 0x05, | ||
28 | ARMV7_PERFCTR_DREAD = 0x06, | ||
29 | ARMV7_PERFCTR_DWRITE = 0x07, | ||
30 | |||
31 | ARMV7_PERFCTR_EXC_TAKEN = 0x09, | ||
32 | ARMV7_PERFCTR_EXC_EXECUTED = 0x0A, | ||
33 | ARMV7_PERFCTR_CID_WRITE = 0x0B, | ||
34 | /* ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS. | ||
35 | * It counts: | ||
36 | * - all branch instructions, | ||
37 | * - instructions that explicitly write the PC, | ||
38 | * - exception generating instructions. | ||
39 | */ | ||
40 | ARMV7_PERFCTR_PC_WRITE = 0x0C, | ||
41 | ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D, | ||
42 | ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F, | ||
43 | ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, | ||
44 | ARMV7_PERFCTR_CLOCK_CYCLES = 0x11, | ||
45 | |||
46 | ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12, | ||
47 | |||
48 | ARMV7_PERFCTR_CPU_CYCLES = 0xFF | ||
49 | }; | ||
50 | |||
51 | /* ARMv7 Cortex-A8 specific event types */ | ||
52 | enum armv7_a8_perf_types { | ||
53 | ARMV7_PERFCTR_INSTR_EXECUTED = 0x08, | ||
54 | |||
55 | ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E, | ||
56 | |||
57 | ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40, | ||
58 | ARMV7_PERFCTR_L2_STORE_MERGED = 0x41, | ||
59 | ARMV7_PERFCTR_L2_STORE_BUFF = 0x42, | ||
60 | ARMV7_PERFCTR_L2_ACCESS = 0x43, | ||
61 | ARMV7_PERFCTR_L2_CACH_MISS = 0x44, | ||
62 | ARMV7_PERFCTR_AXI_READ_CYCLES = 0x45, | ||
63 | ARMV7_PERFCTR_AXI_WRITE_CYCLES = 0x46, | ||
64 | ARMV7_PERFCTR_MEMORY_REPLAY = 0x47, | ||
65 | ARMV7_PERFCTR_UNALIGNED_ACCESS_REPLAY = 0x48, | ||
66 | ARMV7_PERFCTR_L1_DATA_MISS = 0x49, | ||
67 | ARMV7_PERFCTR_L1_INST_MISS = 0x4A, | ||
68 | ARMV7_PERFCTR_L1_DATA_COLORING = 0x4B, | ||
69 | ARMV7_PERFCTR_L1_NEON_DATA = 0x4C, | ||
70 | ARMV7_PERFCTR_L1_NEON_CACH_DATA = 0x4D, | ||
71 | ARMV7_PERFCTR_L2_NEON = 0x4E, | ||
72 | ARMV7_PERFCTR_L2_NEON_HIT = 0x4F, | ||
73 | ARMV7_PERFCTR_L1_INST = 0x50, | ||
74 | ARMV7_PERFCTR_PC_RETURN_MIS_PRED = 0x51, | ||
75 | ARMV7_PERFCTR_PC_BRANCH_FAILED = 0x52, | ||
76 | ARMV7_PERFCTR_PC_BRANCH_TAKEN = 0x53, | ||
77 | ARMV7_PERFCTR_PC_BRANCH_EXECUTED = 0x54, | ||
78 | ARMV7_PERFCTR_OP_EXECUTED = 0x55, | ||
79 | ARMV7_PERFCTR_CYCLES_INST_STALL = 0x56, | ||
80 | ARMV7_PERFCTR_CYCLES_INST = 0x57, | ||
81 | ARMV7_PERFCTR_CYCLES_NEON_DATA_STALL = 0x58, | ||
82 | ARMV7_PERFCTR_CYCLES_NEON_INST_STALL = 0x59, | ||
83 | ARMV7_PERFCTR_NEON_CYCLES = 0x5A, | ||
84 | |||
85 | ARMV7_PERFCTR_PMU0_EVENTS = 0x70, | ||
86 | ARMV7_PERFCTR_PMU1_EVENTS = 0x71, | ||
87 | ARMV7_PERFCTR_PMU_EVENTS = 0x72, | ||
88 | }; | ||
89 | |||
90 | /* ARMv7 Cortex-A9 specific event types */ | ||
91 | enum armv7_a9_perf_types { | ||
92 | ARMV7_PERFCTR_JAVA_HW_BYTECODE_EXEC = 0x40, | ||
93 | ARMV7_PERFCTR_JAVA_SW_BYTECODE_EXEC = 0x41, | ||
94 | ARMV7_PERFCTR_JAZELLE_BRANCH_EXEC = 0x42, | ||
95 | |||
96 | ARMV7_PERFCTR_COHERENT_LINE_MISS = 0x50, | ||
97 | ARMV7_PERFCTR_COHERENT_LINE_HIT = 0x51, | ||
98 | |||
99 | ARMV7_PERFCTR_ICACHE_DEP_STALL_CYCLES = 0x60, | ||
100 | ARMV7_PERFCTR_DCACHE_DEP_STALL_CYCLES = 0x61, | ||
101 | ARMV7_PERFCTR_TLB_MISS_DEP_STALL_CYCLES = 0x62, | ||
102 | ARMV7_PERFCTR_STREX_EXECUTED_PASSED = 0x63, | ||
103 | ARMV7_PERFCTR_STREX_EXECUTED_FAILED = 0x64, | ||
104 | ARMV7_PERFCTR_DATA_EVICTION = 0x65, | ||
105 | ARMV7_PERFCTR_ISSUE_STAGE_NO_INST = 0x66, | ||
106 | ARMV7_PERFCTR_ISSUE_STAGE_EMPTY = 0x67, | ||
107 | ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE = 0x68, | ||
108 | |||
109 | ARMV7_PERFCTR_PREDICTABLE_FUNCT_RETURNS = 0x6E, | ||
110 | |||
111 | ARMV7_PERFCTR_MAIN_UNIT_EXECUTED_INST = 0x70, | ||
112 | ARMV7_PERFCTR_SECOND_UNIT_EXECUTED_INST = 0x71, | ||
113 | ARMV7_PERFCTR_LD_ST_UNIT_EXECUTED_INST = 0x72, | ||
114 | ARMV7_PERFCTR_FP_EXECUTED_INST = 0x73, | ||
115 | ARMV7_PERFCTR_NEON_EXECUTED_INST = 0x74, | ||
116 | |||
117 | ARMV7_PERFCTR_PLD_FULL_DEP_STALL_CYCLES = 0x80, | ||
118 | ARMV7_PERFCTR_DATA_WR_DEP_STALL_CYCLES = 0x81, | ||
119 | ARMV7_PERFCTR_ITLB_MISS_DEP_STALL_CYCLES = 0x82, | ||
120 | ARMV7_PERFCTR_DTLB_MISS_DEP_STALL_CYCLES = 0x83, | ||
121 | ARMV7_PERFCTR_MICRO_ITLB_MISS_DEP_STALL_CYCLES = 0x84, | ||
122 | ARMV7_PERFCTR_MICRO_DTLB_MISS_DEP_STALL_CYCLES = 0x85, | ||
123 | ARMV7_PERFCTR_DMB_DEP_STALL_CYCLES = 0x86, | ||
124 | |||
125 | ARMV7_PERFCTR_INTGR_CLK_ENABLED_CYCLES = 0x8A, | ||
126 | ARMV7_PERFCTR_DATA_ENGINE_CLK_EN_CYCLES = 0x8B, | ||
127 | |||
128 | ARMV7_PERFCTR_ISB_INST = 0x90, | ||
129 | ARMV7_PERFCTR_DSB_INST = 0x91, | ||
130 | ARMV7_PERFCTR_DMB_INST = 0x92, | ||
131 | ARMV7_PERFCTR_EXT_INTERRUPTS = 0x93, | ||
132 | |||
133 | ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_COMPLETED = 0xA0, | ||
134 | ARMV7_PERFCTR_PLE_CACHE_LINE_RQST_SKIPPED = 0xA1, | ||
135 | ARMV7_PERFCTR_PLE_FIFO_FLUSH = 0xA2, | ||
136 | ARMV7_PERFCTR_PLE_RQST_COMPLETED = 0xA3, | ||
137 | ARMV7_PERFCTR_PLE_FIFO_OVERFLOW = 0xA4, | ||
138 | ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5 | ||
139 | }; | ||
140 | |||
141 | /* | ||
142 | * Cortex-A8 HW events mapping | ||
143 | * | ||
144 | * The hardware events that we support. We do support cache operations but | ||
145 | * we have harvard caches and no way to combine instruction and data | ||
146 | * accesses/misses in hardware. | ||
147 | */ | ||
148 | static const unsigned armv7_a8_perf_map[PERF_COUNT_HW_MAX] = { | ||
149 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, | ||
150 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, | ||
151 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
152 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
153 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, | ||
154 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
155 | [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, | ||
156 | }; | ||
157 | |||
158 | static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
159 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
160 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
161 | [C(L1D)] = { | ||
162 | /* | ||
163 | * The performance counters don't differentiate between read | ||
164 | * and write accesses/misses so this isn't strictly correct, | ||
165 | * but it's the best we can do. Writes and reads get | ||
166 | * combined. | ||
167 | */ | ||
168 | [C(OP_READ)] = { | ||
169 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
170 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
171 | }, | ||
172 | [C(OP_WRITE)] = { | ||
173 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
174 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
175 | }, | ||
176 | [C(OP_PREFETCH)] = { | ||
177 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
178 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
179 | }, | ||
180 | }, | ||
181 | [C(L1I)] = { | ||
182 | [C(OP_READ)] = { | ||
183 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, | ||
184 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, | ||
185 | }, | ||
186 | [C(OP_WRITE)] = { | ||
187 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_INST, | ||
188 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_INST_MISS, | ||
189 | }, | ||
190 | [C(OP_PREFETCH)] = { | ||
191 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
192 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
193 | }, | ||
194 | }, | ||
195 | [C(LL)] = { | ||
196 | [C(OP_READ)] = { | ||
197 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, | ||
198 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, | ||
199 | }, | ||
200 | [C(OP_WRITE)] = { | ||
201 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_ACCESS, | ||
202 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACH_MISS, | ||
203 | }, | ||
204 | [C(OP_PREFETCH)] = { | ||
205 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
206 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
207 | }, | ||
208 | }, | ||
209 | [C(DTLB)] = { | ||
210 | /* | ||
211 | * Only ITLB misses and DTLB refills are supported. | ||
212 | * If users want the DTLB refills misses a raw counter | ||
213 | * must be used. | ||
214 | */ | ||
215 | [C(OP_READ)] = { | ||
216 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
217 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
218 | }, | ||
219 | [C(OP_WRITE)] = { | ||
220 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
221 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
222 | }, | ||
223 | [C(OP_PREFETCH)] = { | ||
224 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
225 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
226 | }, | ||
227 | }, | ||
228 | [C(ITLB)] = { | ||
229 | [C(OP_READ)] = { | ||
230 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
231 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
232 | }, | ||
233 | [C(OP_WRITE)] = { | ||
234 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
235 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
236 | }, | ||
237 | [C(OP_PREFETCH)] = { | ||
238 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
239 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
240 | }, | ||
241 | }, | ||
242 | [C(BPU)] = { | ||
243 | [C(OP_READ)] = { | ||
244 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
245 | [C(RESULT_MISS)] | ||
246 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
247 | }, | ||
248 | [C(OP_WRITE)] = { | ||
249 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
250 | [C(RESULT_MISS)] | ||
251 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
252 | }, | ||
253 | [C(OP_PREFETCH)] = { | ||
254 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
255 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
256 | }, | ||
257 | }, | ||
258 | }; | ||
259 | |||
260 | /* | ||
261 | * Cortex-A9 HW events mapping | ||
262 | */ | ||
263 | static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = { | ||
264 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, | ||
265 | [PERF_COUNT_HW_INSTRUCTIONS] = | ||
266 | ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE, | ||
267 | [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT, | ||
268 | [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS, | ||
269 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, | ||
270 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
271 | [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, | ||
272 | }; | ||
273 | |||
274 | static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
275 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
276 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
277 | [C(L1D)] = { | ||
278 | /* | ||
279 | * The performance counters don't differentiate between read | ||
280 | * and write accesses/misses so this isn't strictly correct, | ||
281 | * but it's the best we can do. Writes and reads get | ||
282 | * combined. | ||
283 | */ | ||
284 | [C(OP_READ)] = { | ||
285 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
286 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
287 | }, | ||
288 | [C(OP_WRITE)] = { | ||
289 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS, | ||
290 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL, | ||
291 | }, | ||
292 | [C(OP_PREFETCH)] = { | ||
293 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
294 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
295 | }, | ||
296 | }, | ||
297 | [C(L1I)] = { | ||
298 | [C(OP_READ)] = { | ||
299 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
300 | [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, | ||
301 | }, | ||
302 | [C(OP_WRITE)] = { | ||
303 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
304 | [C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS, | ||
305 | }, | ||
306 | [C(OP_PREFETCH)] = { | ||
307 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
308 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
309 | }, | ||
310 | }, | ||
311 | [C(LL)] = { | ||
312 | [C(OP_READ)] = { | ||
313 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
314 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
315 | }, | ||
316 | [C(OP_WRITE)] = { | ||
317 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
318 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
319 | }, | ||
320 | [C(OP_PREFETCH)] = { | ||
321 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
322 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
323 | }, | ||
324 | }, | ||
325 | [C(DTLB)] = { | ||
326 | /* | ||
327 | * Only ITLB misses and DTLB refills are supported. | ||
328 | * If users want the DTLB refills misses a raw counter | ||
329 | * must be used. | ||
330 | */ | ||
331 | [C(OP_READ)] = { | ||
332 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
333 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
334 | }, | ||
335 | [C(OP_WRITE)] = { | ||
336 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
337 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
338 | }, | ||
339 | [C(OP_PREFETCH)] = { | ||
340 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
341 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
342 | }, | ||
343 | }, | ||
344 | [C(ITLB)] = { | ||
345 | [C(OP_READ)] = { | ||
346 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
347 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
348 | }, | ||
349 | [C(OP_WRITE)] = { | ||
350 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
351 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS, | ||
352 | }, | ||
353 | [C(OP_PREFETCH)] = { | ||
354 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
355 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
356 | }, | ||
357 | }, | ||
358 | [C(BPU)] = { | ||
359 | [C(OP_READ)] = { | ||
360 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
361 | [C(RESULT_MISS)] | ||
362 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
363 | }, | ||
364 | [C(OP_WRITE)] = { | ||
365 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_WRITE, | ||
366 | [C(RESULT_MISS)] | ||
367 | = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
368 | }, | ||
369 | [C(OP_PREFETCH)] = { | ||
370 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
371 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
372 | }, | ||
373 | }, | ||
374 | }; | ||
375 | |||
376 | /* | ||
377 | * Perf Events counters | ||
378 | */ | ||
379 | enum armv7_counters { | ||
380 | ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */ | ||
381 | ARMV7_COUNTER0 = 2, /* First event counter */ | ||
382 | }; | ||
383 | |||
384 | /* | ||
385 | * The cycle counter is ARMV7_CYCLE_COUNTER. | ||
386 | * The first event counter is ARMV7_COUNTER0. | ||
387 | * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1). | ||
388 | */ | ||
389 | #define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1) | ||
390 | |||
391 | /* | ||
392 | * ARMv7 low level PMNC access | ||
393 | */ | ||
394 | |||
395 | /* | ||
396 | * Per-CPU PMNC: config reg | ||
397 | */ | ||
398 | #define ARMV7_PMNC_E (1 << 0) /* Enable all counters */ | ||
399 | #define ARMV7_PMNC_P (1 << 1) /* Reset all counters */ | ||
400 | #define ARMV7_PMNC_C (1 << 2) /* Cycle counter reset */ | ||
401 | #define ARMV7_PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */ | ||
402 | #define ARMV7_PMNC_X (1 << 4) /* Export to ETM */ | ||
403 | #define ARMV7_PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ | ||
404 | #define ARMV7_PMNC_N_SHIFT 11 /* Number of counters supported */ | ||
405 | #define ARMV7_PMNC_N_MASK 0x1f | ||
406 | #define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */ | ||
407 | |||
408 | /* | ||
409 | * Available counters | ||
410 | */ | ||
411 | #define ARMV7_CNT0 0 /* First event counter */ | ||
412 | #define ARMV7_CCNT 31 /* Cycle counter */ | ||
413 | |||
414 | /* Perf Event to low level counters mapping */ | ||
415 | #define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0) | ||
416 | |||
417 | /* | ||
418 | * CNTENS: counters enable reg | ||
419 | */ | ||
420 | #define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
421 | #define ARMV7_CNTENS_C (1 << ARMV7_CCNT) | ||
422 | |||
423 | /* | ||
424 | * CNTENC: counters disable reg | ||
425 | */ | ||
426 | #define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
427 | #define ARMV7_CNTENC_C (1 << ARMV7_CCNT) | ||
428 | |||
429 | /* | ||
430 | * INTENS: counters overflow interrupt enable reg | ||
431 | */ | ||
432 | #define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
433 | #define ARMV7_INTENS_C (1 << ARMV7_CCNT) | ||
434 | |||
435 | /* | ||
436 | * INTENC: counters overflow interrupt disable reg | ||
437 | */ | ||
438 | #define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
439 | #define ARMV7_INTENC_C (1 << ARMV7_CCNT) | ||
440 | |||
441 | /* | ||
442 | * EVTSEL: Event selection reg | ||
443 | */ | ||
444 | #define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */ | ||
445 | |||
446 | /* | ||
447 | * SELECT: Counter selection reg | ||
448 | */ | ||
449 | #define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */ | ||
450 | |||
451 | /* | ||
452 | * FLAG: counters overflow flag status reg | ||
453 | */ | ||
454 | #define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) | ||
455 | #define ARMV7_FLAG_C (1 << ARMV7_CCNT) | ||
456 | #define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */ | ||
457 | #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK | ||
458 | |||
459 | static inline unsigned long armv7_pmnc_read(void) | ||
460 | { | ||
461 | u32 val; | ||
462 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); | ||
463 | return val; | ||
464 | } | ||
465 | |||
466 | static inline void armv7_pmnc_write(unsigned long val) | ||
467 | { | ||
468 | val &= ARMV7_PMNC_MASK; | ||
469 | isb(); | ||
470 | asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); | ||
471 | } | ||
472 | |||
473 | static inline int armv7_pmnc_has_overflowed(unsigned long pmnc) | ||
474 | { | ||
475 | return pmnc & ARMV7_OVERFLOWED_MASK; | ||
476 | } | ||
477 | |||
478 | static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc, | ||
479 | enum armv7_counters counter) | ||
480 | { | ||
481 | int ret = 0; | ||
482 | |||
483 | if (counter == ARMV7_CYCLE_COUNTER) | ||
484 | ret = pmnc & ARMV7_FLAG_C; | ||
485 | else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST)) | ||
486 | ret = pmnc & ARMV7_FLAG_P(counter); | ||
487 | else | ||
488 | pr_err("CPU%u checking wrong counter %d overflow status\n", | ||
489 | smp_processor_id(), counter); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | static inline int armv7_pmnc_select_counter(unsigned int idx) | ||
495 | { | ||
496 | u32 val; | ||
497 | |||
498 | if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) { | ||
499 | pr_err("CPU%u selecting wrong PMNC counter" | ||
500 | " %d\n", smp_processor_id(), idx); | ||
501 | return -1; | ||
502 | } | ||
503 | |||
504 | val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK; | ||
505 | asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); | ||
506 | isb(); | ||
507 | |||
508 | return idx; | ||
509 | } | ||
510 | |||
511 | static inline u32 armv7pmu_read_counter(int idx) | ||
512 | { | ||
513 | unsigned long value = 0; | ||
514 | |||
515 | if (idx == ARMV7_CYCLE_COUNTER) | ||
516 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value)); | ||
517 | else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { | ||
518 | if (armv7_pmnc_select_counter(idx) == idx) | ||
519 | asm volatile("mrc p15, 0, %0, c9, c13, 2" | ||
520 | : "=r" (value)); | ||
521 | } else | ||
522 | pr_err("CPU%u reading wrong counter %d\n", | ||
523 | smp_processor_id(), idx); | ||
524 | |||
525 | return value; | ||
526 | } | ||
527 | |||
528 | static inline void armv7pmu_write_counter(int idx, u32 value) | ||
529 | { | ||
530 | if (idx == ARMV7_CYCLE_COUNTER) | ||
531 | asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value)); | ||
532 | else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) { | ||
533 | if (armv7_pmnc_select_counter(idx) == idx) | ||
534 | asm volatile("mcr p15, 0, %0, c9, c13, 2" | ||
535 | : : "r" (value)); | ||
536 | } else | ||
537 | pr_err("CPU%u writing wrong counter %d\n", | ||
538 | smp_processor_id(), idx); | ||
539 | } | ||
540 | |||
541 | static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val) | ||
542 | { | ||
543 | if (armv7_pmnc_select_counter(idx) == idx) { | ||
544 | val &= ARMV7_EVTSEL_MASK; | ||
545 | asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | static inline u32 armv7_pmnc_enable_counter(unsigned int idx) | ||
550 | { | ||
551 | u32 val; | ||
552 | |||
553 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
554 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
555 | pr_err("CPU%u enabling wrong PMNC counter" | ||
556 | " %d\n", smp_processor_id(), idx); | ||
557 | return -1; | ||
558 | } | ||
559 | |||
560 | if (idx == ARMV7_CYCLE_COUNTER) | ||
561 | val = ARMV7_CNTENS_C; | ||
562 | else | ||
563 | val = ARMV7_CNTENS_P(idx); | ||
564 | |||
565 | asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); | ||
566 | |||
567 | return idx; | ||
568 | } | ||
569 | |||
570 | static inline u32 armv7_pmnc_disable_counter(unsigned int idx) | ||
571 | { | ||
572 | u32 val; | ||
573 | |||
574 | |||
575 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
576 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
577 | pr_err("CPU%u disabling wrong PMNC counter" | ||
578 | " %d\n", smp_processor_id(), idx); | ||
579 | return -1; | ||
580 | } | ||
581 | |||
582 | if (idx == ARMV7_CYCLE_COUNTER) | ||
583 | val = ARMV7_CNTENC_C; | ||
584 | else | ||
585 | val = ARMV7_CNTENC_P(idx); | ||
586 | |||
587 | asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); | ||
588 | |||
589 | return idx; | ||
590 | } | ||
591 | |||
592 | static inline u32 armv7_pmnc_enable_intens(unsigned int idx) | ||
593 | { | ||
594 | u32 val; | ||
595 | |||
596 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
597 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
598 | pr_err("CPU%u enabling wrong PMNC counter" | ||
599 | " interrupt enable %d\n", smp_processor_id(), idx); | ||
600 | return -1; | ||
601 | } | ||
602 | |||
603 | if (idx == ARMV7_CYCLE_COUNTER) | ||
604 | val = ARMV7_INTENS_C; | ||
605 | else | ||
606 | val = ARMV7_INTENS_P(idx); | ||
607 | |||
608 | asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); | ||
609 | |||
610 | return idx; | ||
611 | } | ||
612 | |||
613 | static inline u32 armv7_pmnc_disable_intens(unsigned int idx) | ||
614 | { | ||
615 | u32 val; | ||
616 | |||
617 | if ((idx != ARMV7_CYCLE_COUNTER) && | ||
618 | ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) { | ||
619 | pr_err("CPU%u disabling wrong PMNC counter" | ||
620 | " interrupt enable %d\n", smp_processor_id(), idx); | ||
621 | return -1; | ||
622 | } | ||
623 | |||
624 | if (idx == ARMV7_CYCLE_COUNTER) | ||
625 | val = ARMV7_INTENC_C; | ||
626 | else | ||
627 | val = ARMV7_INTENC_P(idx); | ||
628 | |||
629 | asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); | ||
630 | |||
631 | return idx; | ||
632 | } | ||
633 | |||
634 | static inline u32 armv7_pmnc_getreset_flags(void) | ||
635 | { | ||
636 | u32 val; | ||
637 | |||
638 | /* Read */ | ||
639 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
640 | |||
641 | /* Write to clear flags */ | ||
642 | val &= ARMV7_FLAG_MASK; | ||
643 | asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val)); | ||
644 | |||
645 | return val; | ||
646 | } | ||
647 | |||
648 | #ifdef DEBUG | ||
649 | static void armv7_pmnc_dump_regs(void) | ||
650 | { | ||
651 | u32 val; | ||
652 | unsigned int cnt; | ||
653 | |||
654 | printk(KERN_INFO "PMNC registers dump:\n"); | ||
655 | |||
656 | asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); | ||
657 | printk(KERN_INFO "PMNC =0x%08x\n", val); | ||
658 | |||
659 | asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val)); | ||
660 | printk(KERN_INFO "CNTENS=0x%08x\n", val); | ||
661 | |||
662 | asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val)); | ||
663 | printk(KERN_INFO "INTENS=0x%08x\n", val); | ||
664 | |||
665 | asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); | ||
666 | printk(KERN_INFO "FLAGS =0x%08x\n", val); | ||
667 | |||
668 | asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val)); | ||
669 | printk(KERN_INFO "SELECT=0x%08x\n", val); | ||
670 | |||
671 | asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); | ||
672 | printk(KERN_INFO "CCNT =0x%08x\n", val); | ||
673 | |||
674 | for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) { | ||
675 | armv7_pmnc_select_counter(cnt); | ||
676 | asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); | ||
677 | printk(KERN_INFO "CNT[%d] count =0x%08x\n", | ||
678 | cnt-ARMV7_EVENT_CNT_TO_CNTx, val); | ||
679 | asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val)); | ||
680 | printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", | ||
681 | cnt-ARMV7_EVENT_CNT_TO_CNTx, val); | ||
682 | } | ||
683 | } | ||
684 | #endif | ||
685 | |||
686 | static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
687 | { | ||
688 | unsigned long flags; | ||
689 | |||
690 | /* | ||
691 | * Enable counter and interrupt, and set the counter to count | ||
692 | * the event that we're interested in. | ||
693 | */ | ||
694 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
695 | |||
696 | /* | ||
697 | * Disable counter | ||
698 | */ | ||
699 | armv7_pmnc_disable_counter(idx); | ||
700 | |||
701 | /* | ||
702 | * Set event (if destined for PMNx counters) | ||
703 | * We don't need to set the event if it's a cycle count | ||
704 | */ | ||
705 | if (idx != ARMV7_CYCLE_COUNTER) | ||
706 | armv7_pmnc_write_evtsel(idx, hwc->config_base); | ||
707 | |||
708 | /* | ||
709 | * Enable interrupt for this counter | ||
710 | */ | ||
711 | armv7_pmnc_enable_intens(idx); | ||
712 | |||
713 | /* | ||
714 | * Enable counter | ||
715 | */ | ||
716 | armv7_pmnc_enable_counter(idx); | ||
717 | |||
718 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
719 | } | ||
720 | |||
721 | static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
722 | { | ||
723 | unsigned long flags; | ||
724 | |||
725 | /* | ||
726 | * Disable counter and interrupt | ||
727 | */ | ||
728 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
729 | |||
730 | /* | ||
731 | * Disable counter | ||
732 | */ | ||
733 | armv7_pmnc_disable_counter(idx); | ||
734 | |||
735 | /* | ||
736 | * Disable interrupt for this counter | ||
737 | */ | ||
738 | armv7_pmnc_disable_intens(idx); | ||
739 | |||
740 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
741 | } | ||
742 | |||
743 | static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) | ||
744 | { | ||
745 | unsigned long pmnc; | ||
746 | struct perf_sample_data data; | ||
747 | struct cpu_hw_events *cpuc; | ||
748 | struct pt_regs *regs; | ||
749 | int idx; | ||
750 | |||
751 | /* | ||
752 | * Get and reset the IRQ flags | ||
753 | */ | ||
754 | pmnc = armv7_pmnc_getreset_flags(); | ||
755 | |||
756 | /* | ||
757 | * Did an overflow occur? | ||
758 | */ | ||
759 | if (!armv7_pmnc_has_overflowed(pmnc)) | ||
760 | return IRQ_NONE; | ||
761 | |||
762 | /* | ||
763 | * Handle the counter(s) overflow(s) | ||
764 | */ | ||
765 | regs = get_irq_regs(); | ||
766 | |||
767 | perf_sample_data_init(&data, 0); | ||
768 | |||
769 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
770 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
771 | struct perf_event *event = cpuc->events[idx]; | ||
772 | struct hw_perf_event *hwc; | ||
773 | |||
774 | if (!test_bit(idx, cpuc->active_mask)) | ||
775 | continue; | ||
776 | |||
777 | /* | ||
778 | * We have a single interrupt for all counters. Check that | ||
779 | * each counter has overflowed before we process it. | ||
780 | */ | ||
781 | if (!armv7_pmnc_counter_has_overflowed(pmnc, idx)) | ||
782 | continue; | ||
783 | |||
784 | hwc = &event->hw; | ||
785 | armpmu_event_update(event, hwc, idx, 1); | ||
786 | data.period = event->hw.last_period; | ||
787 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
788 | continue; | ||
789 | |||
790 | if (perf_event_overflow(event, 0, &data, regs)) | ||
791 | armpmu->disable(hwc, idx); | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * Handle the pending perf events. | ||
796 | * | ||
797 | * Note: this call *must* be run with interrupts disabled. For | ||
798 | * platforms that can have the PMU interrupts raised as an NMI, this | ||
799 | * will not work. | ||
800 | */ | ||
801 | irq_work_run(); | ||
802 | |||
803 | return IRQ_HANDLED; | ||
804 | } | ||
805 | |||
806 | static void armv7pmu_start(void) | ||
807 | { | ||
808 | unsigned long flags; | ||
809 | |||
810 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
811 | /* Enable all counters */ | ||
812 | armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E); | ||
813 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
814 | } | ||
815 | |||
816 | static void armv7pmu_stop(void) | ||
817 | { | ||
818 | unsigned long flags; | ||
819 | |||
820 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
821 | /* Disable all counters */ | ||
822 | armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E); | ||
823 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
824 | } | ||
825 | |||
826 | static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
827 | struct hw_perf_event *event) | ||
828 | { | ||
829 | int idx; | ||
830 | |||
831 | /* Always place a cycle counter into the cycle counter. */ | ||
832 | if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) { | ||
833 | if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask)) | ||
834 | return -EAGAIN; | ||
835 | |||
836 | return ARMV7_CYCLE_COUNTER; | ||
837 | } else { | ||
838 | /* | ||
839 | * For anything other than a cycle counter, try and use | ||
840 | * the events counters | ||
841 | */ | ||
842 | for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) { | ||
843 | if (!test_and_set_bit(idx, cpuc->used_mask)) | ||
844 | return idx; | ||
845 | } | ||
846 | |||
847 | /* The counters are all in use. */ | ||
848 | return -EAGAIN; | ||
849 | } | ||
850 | } | ||
851 | |||
852 | static void armv7pmu_reset(void *info) | ||
853 | { | ||
854 | u32 idx, nb_cnt = armpmu->num_events; | ||
855 | |||
856 | /* The counter and interrupt enable registers are unknown at reset. */ | ||
857 | for (idx = 1; idx < nb_cnt; ++idx) | ||
858 | armv7pmu_disable_event(NULL, idx); | ||
859 | |||
860 | /* Initialize & Reset PMNC: C and P bits */ | ||
861 | armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); | ||
862 | } | ||
863 | |||
864 | static struct arm_pmu armv7pmu = { | ||
865 | .handle_irq = armv7pmu_handle_irq, | ||
866 | .enable = armv7pmu_enable_event, | ||
867 | .disable = armv7pmu_disable_event, | ||
868 | .read_counter = armv7pmu_read_counter, | ||
869 | .write_counter = armv7pmu_write_counter, | ||
870 | .get_event_idx = armv7pmu_get_event_idx, | ||
871 | .start = armv7pmu_start, | ||
872 | .stop = armv7pmu_stop, | ||
873 | .reset = armv7pmu_reset, | ||
874 | .raw_event_mask = 0xFF, | ||
875 | .max_period = (1LLU << 32) - 1, | ||
876 | }; | ||
877 | |||
878 | static u32 __init armv7_read_num_pmnc_events(void) | ||
879 | { | ||
880 | u32 nb_cnt; | ||
881 | |||
882 | /* Read the nb of CNTx counters supported from PMNC */ | ||
883 | nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK; | ||
884 | |||
885 | /* Add the CPU cycles counter and return */ | ||
886 | return nb_cnt + 1; | ||
887 | } | ||
888 | |||
889 | static const struct arm_pmu *__init armv7_a8_pmu_init(void) | ||
890 | { | ||
891 | armv7pmu.id = ARM_PERF_PMU_ID_CA8; | ||
892 | armv7pmu.name = "ARMv7 Cortex-A8"; | ||
893 | armv7pmu.cache_map = &armv7_a8_perf_cache_map; | ||
894 | armv7pmu.event_map = &armv7_a8_perf_map; | ||
895 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | ||
896 | return &armv7pmu; | ||
897 | } | ||
898 | |||
899 | static const struct arm_pmu *__init armv7_a9_pmu_init(void) | ||
900 | { | ||
901 | armv7pmu.id = ARM_PERF_PMU_ID_CA9; | ||
902 | armv7pmu.name = "ARMv7 Cortex-A9"; | ||
903 | armv7pmu.cache_map = &armv7_a9_perf_cache_map; | ||
904 | armv7pmu.event_map = &armv7_a9_perf_map; | ||
905 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | ||
906 | return &armv7pmu; | ||
907 | } | ||
908 | #else | ||
909 | static const struct arm_pmu *__init armv7_a8_pmu_init(void) | ||
910 | { | ||
911 | return NULL; | ||
912 | } | ||
913 | |||
914 | static const struct arm_pmu *__init armv7_a9_pmu_init(void) | ||
915 | { | ||
916 | return NULL; | ||
917 | } | ||
918 | #endif /* CONFIG_CPU_V7 */ | ||
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c new file mode 100644 index 000000000000..39affbe4fdb2 --- /dev/null +++ b/arch/arm/kernel/perf_event_xscale.c | |||
@@ -0,0 +1,807 @@ | |||
1 | /* | ||
2 | * ARMv5 [xscale] Performance counter handling code. | ||
3 | * | ||
4 | * Copyright (C) 2010, ARM Ltd., Will Deacon <will.deacon@arm.com> | ||
5 | * | ||
6 | * Based on the previous xscale OProfile code. | ||
7 | * | ||
8 | * There are two variants of the xscale PMU that we support: | ||
9 | * - xscale1pmu: 2 event counters and a cycle counter | ||
10 | * - xscale2pmu: 4 event counters and a cycle counter | ||
11 | * The two variants share event definitions, but have different | ||
12 | * PMU structures. | ||
13 | */ | ||
14 | |||
15 | #ifdef CONFIG_CPU_XSCALE | ||
16 | enum xscale_perf_types { | ||
17 | XSCALE_PERFCTR_ICACHE_MISS = 0x00, | ||
18 | XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01, | ||
19 | XSCALE_PERFCTR_DATA_STALL = 0x02, | ||
20 | XSCALE_PERFCTR_ITLB_MISS = 0x03, | ||
21 | XSCALE_PERFCTR_DTLB_MISS = 0x04, | ||
22 | XSCALE_PERFCTR_BRANCH = 0x05, | ||
23 | XSCALE_PERFCTR_BRANCH_MISS = 0x06, | ||
24 | XSCALE_PERFCTR_INSTRUCTION = 0x07, | ||
25 | XSCALE_PERFCTR_DCACHE_FULL_STALL = 0x08, | ||
26 | XSCALE_PERFCTR_DCACHE_FULL_STALL_CONTIG = 0x09, | ||
27 | XSCALE_PERFCTR_DCACHE_ACCESS = 0x0A, | ||
28 | XSCALE_PERFCTR_DCACHE_MISS = 0x0B, | ||
29 | XSCALE_PERFCTR_DCACHE_WRITE_BACK = 0x0C, | ||
30 | XSCALE_PERFCTR_PC_CHANGED = 0x0D, | ||
31 | XSCALE_PERFCTR_BCU_REQUEST = 0x10, | ||
32 | XSCALE_PERFCTR_BCU_FULL = 0x11, | ||
33 | XSCALE_PERFCTR_BCU_DRAIN = 0x12, | ||
34 | XSCALE_PERFCTR_BCU_ECC_NO_ELOG = 0x14, | ||
35 | XSCALE_PERFCTR_BCU_1_BIT_ERR = 0x15, | ||
36 | XSCALE_PERFCTR_RMW = 0x16, | ||
37 | /* XSCALE_PERFCTR_CCNT is not hardware defined */ | ||
38 | XSCALE_PERFCTR_CCNT = 0xFE, | ||
39 | XSCALE_PERFCTR_UNUSED = 0xFF, | ||
40 | }; | ||
41 | |||
42 | enum xscale_counters { | ||
43 | XSCALE_CYCLE_COUNTER = 1, | ||
44 | XSCALE_COUNTER0, | ||
45 | XSCALE_COUNTER1, | ||
46 | XSCALE_COUNTER2, | ||
47 | XSCALE_COUNTER3, | ||
48 | }; | ||
49 | |||
50 | static const unsigned xscale_perf_map[PERF_COUNT_HW_MAX] = { | ||
51 | [PERF_COUNT_HW_CPU_CYCLES] = XSCALE_PERFCTR_CCNT, | ||
52 | [PERF_COUNT_HW_INSTRUCTIONS] = XSCALE_PERFCTR_INSTRUCTION, | ||
53 | [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, | ||
54 | [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, | ||
55 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = XSCALE_PERFCTR_BRANCH, | ||
56 | [PERF_COUNT_HW_BRANCH_MISSES] = XSCALE_PERFCTR_BRANCH_MISS, | ||
57 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
58 | }; | ||
59 | |||
60 | static const unsigned xscale_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
61 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
62 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
63 | [C(L1D)] = { | ||
64 | [C(OP_READ)] = { | ||
65 | [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS, | ||
66 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS, | ||
67 | }, | ||
68 | [C(OP_WRITE)] = { | ||
69 | [C(RESULT_ACCESS)] = XSCALE_PERFCTR_DCACHE_ACCESS, | ||
70 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DCACHE_MISS, | ||
71 | }, | ||
72 | [C(OP_PREFETCH)] = { | ||
73 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
74 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
75 | }, | ||
76 | }, | ||
77 | [C(L1I)] = { | ||
78 | [C(OP_READ)] = { | ||
79 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
80 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS, | ||
81 | }, | ||
82 | [C(OP_WRITE)] = { | ||
83 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
84 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ICACHE_MISS, | ||
85 | }, | ||
86 | [C(OP_PREFETCH)] = { | ||
87 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
88 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
89 | }, | ||
90 | }, | ||
91 | [C(LL)] = { | ||
92 | [C(OP_READ)] = { | ||
93 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
94 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
95 | }, | ||
96 | [C(OP_WRITE)] = { | ||
97 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
98 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
99 | }, | ||
100 | [C(OP_PREFETCH)] = { | ||
101 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
102 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
103 | }, | ||
104 | }, | ||
105 | [C(DTLB)] = { | ||
106 | [C(OP_READ)] = { | ||
107 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
108 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS, | ||
109 | }, | ||
110 | [C(OP_WRITE)] = { | ||
111 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
112 | [C(RESULT_MISS)] = XSCALE_PERFCTR_DTLB_MISS, | ||
113 | }, | ||
114 | [C(OP_PREFETCH)] = { | ||
115 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
116 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
117 | }, | ||
118 | }, | ||
119 | [C(ITLB)] = { | ||
120 | [C(OP_READ)] = { | ||
121 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
122 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS, | ||
123 | }, | ||
124 | [C(OP_WRITE)] = { | ||
125 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
126 | [C(RESULT_MISS)] = XSCALE_PERFCTR_ITLB_MISS, | ||
127 | }, | ||
128 | [C(OP_PREFETCH)] = { | ||
129 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
130 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
131 | }, | ||
132 | }, | ||
133 | [C(BPU)] = { | ||
134 | [C(OP_READ)] = { | ||
135 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
136 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
137 | }, | ||
138 | [C(OP_WRITE)] = { | ||
139 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
140 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
141 | }, | ||
142 | [C(OP_PREFETCH)] = { | ||
143 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
144 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
145 | }, | ||
146 | }, | ||
147 | }; | ||
148 | |||
149 | #define XSCALE_PMU_ENABLE 0x001 | ||
150 | #define XSCALE_PMN_RESET 0x002 | ||
151 | #define XSCALE_CCNT_RESET 0x004 | ||
152 | #define XSCALE_PMU_RESET (CCNT_RESET | PMN_RESET) | ||
153 | #define XSCALE_PMU_CNT64 0x008 | ||
154 | |||
155 | #define XSCALE1_OVERFLOWED_MASK 0x700 | ||
156 | #define XSCALE1_CCOUNT_OVERFLOW 0x400 | ||
157 | #define XSCALE1_COUNT0_OVERFLOW 0x100 | ||
158 | #define XSCALE1_COUNT1_OVERFLOW 0x200 | ||
159 | #define XSCALE1_CCOUNT_INT_EN 0x040 | ||
160 | #define XSCALE1_COUNT0_INT_EN 0x010 | ||
161 | #define XSCALE1_COUNT1_INT_EN 0x020 | ||
162 | #define XSCALE1_COUNT0_EVT_SHFT 12 | ||
163 | #define XSCALE1_COUNT0_EVT_MASK (0xff << XSCALE1_COUNT0_EVT_SHFT) | ||
164 | #define XSCALE1_COUNT1_EVT_SHFT 20 | ||
165 | #define XSCALE1_COUNT1_EVT_MASK (0xff << XSCALE1_COUNT1_EVT_SHFT) | ||
166 | |||
167 | static inline u32 | ||
168 | xscale1pmu_read_pmnc(void) | ||
169 | { | ||
170 | u32 val; | ||
171 | asm volatile("mrc p14, 0, %0, c0, c0, 0" : "=r" (val)); | ||
172 | return val; | ||
173 | } | ||
174 | |||
175 | static inline void | ||
176 | xscale1pmu_write_pmnc(u32 val) | ||
177 | { | ||
178 | /* upper 4bits and 7, 11 are write-as-0 */ | ||
179 | val &= 0xffff77f; | ||
180 | asm volatile("mcr p14, 0, %0, c0, c0, 0" : : "r" (val)); | ||
181 | } | ||
182 | |||
183 | static inline int | ||
184 | xscale1_pmnc_counter_has_overflowed(unsigned long pmnc, | ||
185 | enum xscale_counters counter) | ||
186 | { | ||
187 | int ret = 0; | ||
188 | |||
189 | switch (counter) { | ||
190 | case XSCALE_CYCLE_COUNTER: | ||
191 | ret = pmnc & XSCALE1_CCOUNT_OVERFLOW; | ||
192 | break; | ||
193 | case XSCALE_COUNTER0: | ||
194 | ret = pmnc & XSCALE1_COUNT0_OVERFLOW; | ||
195 | break; | ||
196 | case XSCALE_COUNTER1: | ||
197 | ret = pmnc & XSCALE1_COUNT1_OVERFLOW; | ||
198 | break; | ||
199 | default: | ||
200 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
201 | } | ||
202 | |||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | static irqreturn_t | ||
207 | xscale1pmu_handle_irq(int irq_num, void *dev) | ||
208 | { | ||
209 | unsigned long pmnc; | ||
210 | struct perf_sample_data data; | ||
211 | struct cpu_hw_events *cpuc; | ||
212 | struct pt_regs *regs; | ||
213 | int idx; | ||
214 | |||
215 | /* | ||
216 | * NOTE: there's an A stepping erratum that states if an overflow | ||
217 | * bit already exists and another occurs, the previous | ||
218 | * Overflow bit gets cleared. There's no workaround. | ||
219 | * Fixed in B stepping or later. | ||
220 | */ | ||
221 | pmnc = xscale1pmu_read_pmnc(); | ||
222 | |||
223 | /* | ||
224 | * Write the value back to clear the overflow flags. Overflow | ||
225 | * flags remain in pmnc for use below. We also disable the PMU | ||
226 | * while we process the interrupt. | ||
227 | */ | ||
228 | xscale1pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE); | ||
229 | |||
230 | if (!(pmnc & XSCALE1_OVERFLOWED_MASK)) | ||
231 | return IRQ_NONE; | ||
232 | |||
233 | regs = get_irq_regs(); | ||
234 | |||
235 | perf_sample_data_init(&data, 0); | ||
236 | |||
237 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
238 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
239 | struct perf_event *event = cpuc->events[idx]; | ||
240 | struct hw_perf_event *hwc; | ||
241 | |||
242 | if (!test_bit(idx, cpuc->active_mask)) | ||
243 | continue; | ||
244 | |||
245 | if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx)) | ||
246 | continue; | ||
247 | |||
248 | hwc = &event->hw; | ||
249 | armpmu_event_update(event, hwc, idx, 1); | ||
250 | data.period = event->hw.last_period; | ||
251 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
252 | continue; | ||
253 | |||
254 | if (perf_event_overflow(event, 0, &data, regs)) | ||
255 | armpmu->disable(hwc, idx); | ||
256 | } | ||
257 | |||
258 | irq_work_run(); | ||
259 | |||
260 | /* | ||
261 | * Re-enable the PMU. | ||
262 | */ | ||
263 | pmnc = xscale1pmu_read_pmnc() | XSCALE_PMU_ENABLE; | ||
264 | xscale1pmu_write_pmnc(pmnc); | ||
265 | |||
266 | return IRQ_HANDLED; | ||
267 | } | ||
268 | |||
269 | static void | ||
270 | xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
271 | { | ||
272 | unsigned long val, mask, evt, flags; | ||
273 | |||
274 | switch (idx) { | ||
275 | case XSCALE_CYCLE_COUNTER: | ||
276 | mask = 0; | ||
277 | evt = XSCALE1_CCOUNT_INT_EN; | ||
278 | break; | ||
279 | case XSCALE_COUNTER0: | ||
280 | mask = XSCALE1_COUNT0_EVT_MASK; | ||
281 | evt = (hwc->config_base << XSCALE1_COUNT0_EVT_SHFT) | | ||
282 | XSCALE1_COUNT0_INT_EN; | ||
283 | break; | ||
284 | case XSCALE_COUNTER1: | ||
285 | mask = XSCALE1_COUNT1_EVT_MASK; | ||
286 | evt = (hwc->config_base << XSCALE1_COUNT1_EVT_SHFT) | | ||
287 | XSCALE1_COUNT1_INT_EN; | ||
288 | break; | ||
289 | default: | ||
290 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
295 | val = xscale1pmu_read_pmnc(); | ||
296 | val &= ~mask; | ||
297 | val |= evt; | ||
298 | xscale1pmu_write_pmnc(val); | ||
299 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
300 | } | ||
301 | |||
302 | static void | ||
303 | xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
304 | { | ||
305 | unsigned long val, mask, evt, flags; | ||
306 | |||
307 | switch (idx) { | ||
308 | case XSCALE_CYCLE_COUNTER: | ||
309 | mask = XSCALE1_CCOUNT_INT_EN; | ||
310 | evt = 0; | ||
311 | break; | ||
312 | case XSCALE_COUNTER0: | ||
313 | mask = XSCALE1_COUNT0_INT_EN | XSCALE1_COUNT0_EVT_MASK; | ||
314 | evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT0_EVT_SHFT; | ||
315 | break; | ||
316 | case XSCALE_COUNTER1: | ||
317 | mask = XSCALE1_COUNT1_INT_EN | XSCALE1_COUNT1_EVT_MASK; | ||
318 | evt = XSCALE_PERFCTR_UNUSED << XSCALE1_COUNT1_EVT_SHFT; | ||
319 | break; | ||
320 | default: | ||
321 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
326 | val = xscale1pmu_read_pmnc(); | ||
327 | val &= ~mask; | ||
328 | val |= evt; | ||
329 | xscale1pmu_write_pmnc(val); | ||
330 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
331 | } | ||
332 | |||
333 | static int | ||
334 | xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
335 | struct hw_perf_event *event) | ||
336 | { | ||
337 | if (XSCALE_PERFCTR_CCNT == event->config_base) { | ||
338 | if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask)) | ||
339 | return -EAGAIN; | ||
340 | |||
341 | return XSCALE_CYCLE_COUNTER; | ||
342 | } else { | ||
343 | if (!test_and_set_bit(XSCALE_COUNTER1, cpuc->used_mask)) | ||
344 | return XSCALE_COUNTER1; | ||
345 | |||
346 | if (!test_and_set_bit(XSCALE_COUNTER0, cpuc->used_mask)) | ||
347 | return XSCALE_COUNTER0; | ||
348 | |||
349 | return -EAGAIN; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static void | ||
354 | xscale1pmu_start(void) | ||
355 | { | ||
356 | unsigned long flags, val; | ||
357 | |||
358 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
359 | val = xscale1pmu_read_pmnc(); | ||
360 | val |= XSCALE_PMU_ENABLE; | ||
361 | xscale1pmu_write_pmnc(val); | ||
362 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | xscale1pmu_stop(void) | ||
367 | { | ||
368 | unsigned long flags, val; | ||
369 | |||
370 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
371 | val = xscale1pmu_read_pmnc(); | ||
372 | val &= ~XSCALE_PMU_ENABLE; | ||
373 | xscale1pmu_write_pmnc(val); | ||
374 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
375 | } | ||
376 | |||
377 | static inline u32 | ||
378 | xscale1pmu_read_counter(int counter) | ||
379 | { | ||
380 | u32 val = 0; | ||
381 | |||
382 | switch (counter) { | ||
383 | case XSCALE_CYCLE_COUNTER: | ||
384 | asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (val)); | ||
385 | break; | ||
386 | case XSCALE_COUNTER0: | ||
387 | asm volatile("mrc p14, 0, %0, c2, c0, 0" : "=r" (val)); | ||
388 | break; | ||
389 | case XSCALE_COUNTER1: | ||
390 | asm volatile("mrc p14, 0, %0, c3, c0, 0" : "=r" (val)); | ||
391 | break; | ||
392 | } | ||
393 | |||
394 | return val; | ||
395 | } | ||
396 | |||
397 | static inline void | ||
398 | xscale1pmu_write_counter(int counter, u32 val) | ||
399 | { | ||
400 | switch (counter) { | ||
401 | case XSCALE_CYCLE_COUNTER: | ||
402 | asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val)); | ||
403 | break; | ||
404 | case XSCALE_COUNTER0: | ||
405 | asm volatile("mcr p14, 0, %0, c2, c0, 0" : : "r" (val)); | ||
406 | break; | ||
407 | case XSCALE_COUNTER1: | ||
408 | asm volatile("mcr p14, 0, %0, c3, c0, 0" : : "r" (val)); | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static const struct arm_pmu xscale1pmu = { | ||
414 | .id = ARM_PERF_PMU_ID_XSCALE1, | ||
415 | .name = "xscale1", | ||
416 | .handle_irq = xscale1pmu_handle_irq, | ||
417 | .enable = xscale1pmu_enable_event, | ||
418 | .disable = xscale1pmu_disable_event, | ||
419 | .read_counter = xscale1pmu_read_counter, | ||
420 | .write_counter = xscale1pmu_write_counter, | ||
421 | .get_event_idx = xscale1pmu_get_event_idx, | ||
422 | .start = xscale1pmu_start, | ||
423 | .stop = xscale1pmu_stop, | ||
424 | .cache_map = &xscale_perf_cache_map, | ||
425 | .event_map = &xscale_perf_map, | ||
426 | .raw_event_mask = 0xFF, | ||
427 | .num_events = 3, | ||
428 | .max_period = (1LLU << 32) - 1, | ||
429 | }; | ||
430 | |||
431 | static const struct arm_pmu *__init xscale1pmu_init(void) | ||
432 | { | ||
433 | return &xscale1pmu; | ||
434 | } | ||
435 | |||
436 | #define XSCALE2_OVERFLOWED_MASK 0x01f | ||
437 | #define XSCALE2_CCOUNT_OVERFLOW 0x001 | ||
438 | #define XSCALE2_COUNT0_OVERFLOW 0x002 | ||
439 | #define XSCALE2_COUNT1_OVERFLOW 0x004 | ||
440 | #define XSCALE2_COUNT2_OVERFLOW 0x008 | ||
441 | #define XSCALE2_COUNT3_OVERFLOW 0x010 | ||
442 | #define XSCALE2_CCOUNT_INT_EN 0x001 | ||
443 | #define XSCALE2_COUNT0_INT_EN 0x002 | ||
444 | #define XSCALE2_COUNT1_INT_EN 0x004 | ||
445 | #define XSCALE2_COUNT2_INT_EN 0x008 | ||
446 | #define XSCALE2_COUNT3_INT_EN 0x010 | ||
447 | #define XSCALE2_COUNT0_EVT_SHFT 0 | ||
448 | #define XSCALE2_COUNT0_EVT_MASK (0xff << XSCALE2_COUNT0_EVT_SHFT) | ||
449 | #define XSCALE2_COUNT1_EVT_SHFT 8 | ||
450 | #define XSCALE2_COUNT1_EVT_MASK (0xff << XSCALE2_COUNT1_EVT_SHFT) | ||
451 | #define XSCALE2_COUNT2_EVT_SHFT 16 | ||
452 | #define XSCALE2_COUNT2_EVT_MASK (0xff << XSCALE2_COUNT2_EVT_SHFT) | ||
453 | #define XSCALE2_COUNT3_EVT_SHFT 24 | ||
454 | #define XSCALE2_COUNT3_EVT_MASK (0xff << XSCALE2_COUNT3_EVT_SHFT) | ||
455 | |||
456 | static inline u32 | ||
457 | xscale2pmu_read_pmnc(void) | ||
458 | { | ||
459 | u32 val; | ||
460 | asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (val)); | ||
461 | /* bits 1-2 and 4-23 are read-unpredictable */ | ||
462 | return val & 0xff000009; | ||
463 | } | ||
464 | |||
465 | static inline void | ||
466 | xscale2pmu_write_pmnc(u32 val) | ||
467 | { | ||
468 | /* bits 4-23 are write-as-0, 24-31 are write ignored */ | ||
469 | val &= 0xf; | ||
470 | asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (val)); | ||
471 | } | ||
472 | |||
473 | static inline u32 | ||
474 | xscale2pmu_read_overflow_flags(void) | ||
475 | { | ||
476 | u32 val; | ||
477 | asm volatile("mrc p14, 0, %0, c5, c1, 0" : "=r" (val)); | ||
478 | return val; | ||
479 | } | ||
480 | |||
481 | static inline void | ||
482 | xscale2pmu_write_overflow_flags(u32 val) | ||
483 | { | ||
484 | asm volatile("mcr p14, 0, %0, c5, c1, 0" : : "r" (val)); | ||
485 | } | ||
486 | |||
487 | static inline u32 | ||
488 | xscale2pmu_read_event_select(void) | ||
489 | { | ||
490 | u32 val; | ||
491 | asm volatile("mrc p14, 0, %0, c8, c1, 0" : "=r" (val)); | ||
492 | return val; | ||
493 | } | ||
494 | |||
495 | static inline void | ||
496 | xscale2pmu_write_event_select(u32 val) | ||
497 | { | ||
498 | asm volatile("mcr p14, 0, %0, c8, c1, 0" : : "r"(val)); | ||
499 | } | ||
500 | |||
501 | static inline u32 | ||
502 | xscale2pmu_read_int_enable(void) | ||
503 | { | ||
504 | u32 val; | ||
505 | asm volatile("mrc p14, 0, %0, c4, c1, 0" : "=r" (val)); | ||
506 | return val; | ||
507 | } | ||
508 | |||
509 | static void | ||
510 | xscale2pmu_write_int_enable(u32 val) | ||
511 | { | ||
512 | asm volatile("mcr p14, 0, %0, c4, c1, 0" : : "r" (val)); | ||
513 | } | ||
514 | |||
515 | static inline int | ||
516 | xscale2_pmnc_counter_has_overflowed(unsigned long of_flags, | ||
517 | enum xscale_counters counter) | ||
518 | { | ||
519 | int ret = 0; | ||
520 | |||
521 | switch (counter) { | ||
522 | case XSCALE_CYCLE_COUNTER: | ||
523 | ret = of_flags & XSCALE2_CCOUNT_OVERFLOW; | ||
524 | break; | ||
525 | case XSCALE_COUNTER0: | ||
526 | ret = of_flags & XSCALE2_COUNT0_OVERFLOW; | ||
527 | break; | ||
528 | case XSCALE_COUNTER1: | ||
529 | ret = of_flags & XSCALE2_COUNT1_OVERFLOW; | ||
530 | break; | ||
531 | case XSCALE_COUNTER2: | ||
532 | ret = of_flags & XSCALE2_COUNT2_OVERFLOW; | ||
533 | break; | ||
534 | case XSCALE_COUNTER3: | ||
535 | ret = of_flags & XSCALE2_COUNT3_OVERFLOW; | ||
536 | break; | ||
537 | default: | ||
538 | WARN_ONCE(1, "invalid counter number (%d)\n", counter); | ||
539 | } | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | static irqreturn_t | ||
545 | xscale2pmu_handle_irq(int irq_num, void *dev) | ||
546 | { | ||
547 | unsigned long pmnc, of_flags; | ||
548 | struct perf_sample_data data; | ||
549 | struct cpu_hw_events *cpuc; | ||
550 | struct pt_regs *regs; | ||
551 | int idx; | ||
552 | |||
553 | /* Disable the PMU. */ | ||
554 | pmnc = xscale2pmu_read_pmnc(); | ||
555 | xscale2pmu_write_pmnc(pmnc & ~XSCALE_PMU_ENABLE); | ||
556 | |||
557 | /* Check the overflow flag register. */ | ||
558 | of_flags = xscale2pmu_read_overflow_flags(); | ||
559 | if (!(of_flags & XSCALE2_OVERFLOWED_MASK)) | ||
560 | return IRQ_NONE; | ||
561 | |||
562 | /* Clear the overflow bits. */ | ||
563 | xscale2pmu_write_overflow_flags(of_flags); | ||
564 | |||
565 | regs = get_irq_regs(); | ||
566 | |||
567 | perf_sample_data_init(&data, 0); | ||
568 | |||
569 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
570 | for (idx = 0; idx <= armpmu->num_events; ++idx) { | ||
571 | struct perf_event *event = cpuc->events[idx]; | ||
572 | struct hw_perf_event *hwc; | ||
573 | |||
574 | if (!test_bit(idx, cpuc->active_mask)) | ||
575 | continue; | ||
576 | |||
577 | if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx)) | ||
578 | continue; | ||
579 | |||
580 | hwc = &event->hw; | ||
581 | armpmu_event_update(event, hwc, idx, 1); | ||
582 | data.period = event->hw.last_period; | ||
583 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
584 | continue; | ||
585 | |||
586 | if (perf_event_overflow(event, 0, &data, regs)) | ||
587 | armpmu->disable(hwc, idx); | ||
588 | } | ||
589 | |||
590 | irq_work_run(); | ||
591 | |||
592 | /* | ||
593 | * Re-enable the PMU. | ||
594 | */ | ||
595 | pmnc = xscale2pmu_read_pmnc() | XSCALE_PMU_ENABLE; | ||
596 | xscale2pmu_write_pmnc(pmnc); | ||
597 | |||
598 | return IRQ_HANDLED; | ||
599 | } | ||
600 | |||
601 | static void | ||
602 | xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
603 | { | ||
604 | unsigned long flags, ien, evtsel; | ||
605 | |||
606 | ien = xscale2pmu_read_int_enable(); | ||
607 | evtsel = xscale2pmu_read_event_select(); | ||
608 | |||
609 | switch (idx) { | ||
610 | case XSCALE_CYCLE_COUNTER: | ||
611 | ien |= XSCALE2_CCOUNT_INT_EN; | ||
612 | break; | ||
613 | case XSCALE_COUNTER0: | ||
614 | ien |= XSCALE2_COUNT0_INT_EN; | ||
615 | evtsel &= ~XSCALE2_COUNT0_EVT_MASK; | ||
616 | evtsel |= hwc->config_base << XSCALE2_COUNT0_EVT_SHFT; | ||
617 | break; | ||
618 | case XSCALE_COUNTER1: | ||
619 | ien |= XSCALE2_COUNT1_INT_EN; | ||
620 | evtsel &= ~XSCALE2_COUNT1_EVT_MASK; | ||
621 | evtsel |= hwc->config_base << XSCALE2_COUNT1_EVT_SHFT; | ||
622 | break; | ||
623 | case XSCALE_COUNTER2: | ||
624 | ien |= XSCALE2_COUNT2_INT_EN; | ||
625 | evtsel &= ~XSCALE2_COUNT2_EVT_MASK; | ||
626 | evtsel |= hwc->config_base << XSCALE2_COUNT2_EVT_SHFT; | ||
627 | break; | ||
628 | case XSCALE_COUNTER3: | ||
629 | ien |= XSCALE2_COUNT3_INT_EN; | ||
630 | evtsel &= ~XSCALE2_COUNT3_EVT_MASK; | ||
631 | evtsel |= hwc->config_base << XSCALE2_COUNT3_EVT_SHFT; | ||
632 | break; | ||
633 | default: | ||
634 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
635 | return; | ||
636 | } | ||
637 | |||
638 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
639 | xscale2pmu_write_event_select(evtsel); | ||
640 | xscale2pmu_write_int_enable(ien); | ||
641 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
642 | } | ||
643 | |||
644 | static void | ||
645 | xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
646 | { | ||
647 | unsigned long flags, ien, evtsel; | ||
648 | |||
649 | ien = xscale2pmu_read_int_enable(); | ||
650 | evtsel = xscale2pmu_read_event_select(); | ||
651 | |||
652 | switch (idx) { | ||
653 | case XSCALE_CYCLE_COUNTER: | ||
654 | ien &= ~XSCALE2_CCOUNT_INT_EN; | ||
655 | break; | ||
656 | case XSCALE_COUNTER0: | ||
657 | ien &= ~XSCALE2_COUNT0_INT_EN; | ||
658 | evtsel &= ~XSCALE2_COUNT0_EVT_MASK; | ||
659 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT0_EVT_SHFT; | ||
660 | break; | ||
661 | case XSCALE_COUNTER1: | ||
662 | ien &= ~XSCALE2_COUNT1_INT_EN; | ||
663 | evtsel &= ~XSCALE2_COUNT1_EVT_MASK; | ||
664 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT1_EVT_SHFT; | ||
665 | break; | ||
666 | case XSCALE_COUNTER2: | ||
667 | ien &= ~XSCALE2_COUNT2_INT_EN; | ||
668 | evtsel &= ~XSCALE2_COUNT2_EVT_MASK; | ||
669 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT2_EVT_SHFT; | ||
670 | break; | ||
671 | case XSCALE_COUNTER3: | ||
672 | ien &= ~XSCALE2_COUNT3_INT_EN; | ||
673 | evtsel &= ~XSCALE2_COUNT3_EVT_MASK; | ||
674 | evtsel |= XSCALE_PERFCTR_UNUSED << XSCALE2_COUNT3_EVT_SHFT; | ||
675 | break; | ||
676 | default: | ||
677 | WARN_ONCE(1, "invalid counter number (%d)\n", idx); | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
682 | xscale2pmu_write_event_select(evtsel); | ||
683 | xscale2pmu_write_int_enable(ien); | ||
684 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
685 | } | ||
686 | |||
687 | static int | ||
688 | xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc, | ||
689 | struct hw_perf_event *event) | ||
690 | { | ||
691 | int idx = xscale1pmu_get_event_idx(cpuc, event); | ||
692 | if (idx >= 0) | ||
693 | goto out; | ||
694 | |||
695 | if (!test_and_set_bit(XSCALE_COUNTER3, cpuc->used_mask)) | ||
696 | idx = XSCALE_COUNTER3; | ||
697 | else if (!test_and_set_bit(XSCALE_COUNTER2, cpuc->used_mask)) | ||
698 | idx = XSCALE_COUNTER2; | ||
699 | out: | ||
700 | return idx; | ||
701 | } | ||
702 | |||
703 | static void | ||
704 | xscale2pmu_start(void) | ||
705 | { | ||
706 | unsigned long flags, val; | ||
707 | |||
708 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
709 | val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64; | ||
710 | val |= XSCALE_PMU_ENABLE; | ||
711 | xscale2pmu_write_pmnc(val); | ||
712 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
713 | } | ||
714 | |||
715 | static void | ||
716 | xscale2pmu_stop(void) | ||
717 | { | ||
718 | unsigned long flags, val; | ||
719 | |||
720 | raw_spin_lock_irqsave(&pmu_lock, flags); | ||
721 | val = xscale2pmu_read_pmnc(); | ||
722 | val &= ~XSCALE_PMU_ENABLE; | ||
723 | xscale2pmu_write_pmnc(val); | ||
724 | raw_spin_unlock_irqrestore(&pmu_lock, flags); | ||
725 | } | ||
726 | |||
727 | static inline u32 | ||
728 | xscale2pmu_read_counter(int counter) | ||
729 | { | ||
730 | u32 val = 0; | ||
731 | |||
732 | switch (counter) { | ||
733 | case XSCALE_CYCLE_COUNTER: | ||
734 | asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (val)); | ||
735 | break; | ||
736 | case XSCALE_COUNTER0: | ||
737 | asm volatile("mrc p14, 0, %0, c0, c2, 0" : "=r" (val)); | ||
738 | break; | ||
739 | case XSCALE_COUNTER1: | ||
740 | asm volatile("mrc p14, 0, %0, c1, c2, 0" : "=r" (val)); | ||
741 | break; | ||
742 | case XSCALE_COUNTER2: | ||
743 | asm volatile("mrc p14, 0, %0, c2, c2, 0" : "=r" (val)); | ||
744 | break; | ||
745 | case XSCALE_COUNTER3: | ||
746 | asm volatile("mrc p14, 0, %0, c3, c2, 0" : "=r" (val)); | ||
747 | break; | ||
748 | } | ||
749 | |||
750 | return val; | ||
751 | } | ||
752 | |||
753 | static inline void | ||
754 | xscale2pmu_write_counter(int counter, u32 val) | ||
755 | { | ||
756 | switch (counter) { | ||
757 | case XSCALE_CYCLE_COUNTER: | ||
758 | asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val)); | ||
759 | break; | ||
760 | case XSCALE_COUNTER0: | ||
761 | asm volatile("mcr p14, 0, %0, c0, c2, 0" : : "r" (val)); | ||
762 | break; | ||
763 | case XSCALE_COUNTER1: | ||
764 | asm volatile("mcr p14, 0, %0, c1, c2, 0" : : "r" (val)); | ||
765 | break; | ||
766 | case XSCALE_COUNTER2: | ||
767 | asm volatile("mcr p14, 0, %0, c2, c2, 0" : : "r" (val)); | ||
768 | break; | ||
769 | case XSCALE_COUNTER3: | ||
770 | asm volatile("mcr p14, 0, %0, c3, c2, 0" : : "r" (val)); | ||
771 | break; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | static const struct arm_pmu xscale2pmu = { | ||
776 | .id = ARM_PERF_PMU_ID_XSCALE2, | ||
777 | .name = "xscale2", | ||
778 | .handle_irq = xscale2pmu_handle_irq, | ||
779 | .enable = xscale2pmu_enable_event, | ||
780 | .disable = xscale2pmu_disable_event, | ||
781 | .read_counter = xscale2pmu_read_counter, | ||
782 | .write_counter = xscale2pmu_write_counter, | ||
783 | .get_event_idx = xscale2pmu_get_event_idx, | ||
784 | .start = xscale2pmu_start, | ||
785 | .stop = xscale2pmu_stop, | ||
786 | .cache_map = &xscale_perf_cache_map, | ||
787 | .event_map = &xscale_perf_map, | ||
788 | .raw_event_mask = 0xFF, | ||
789 | .num_events = 5, | ||
790 | .max_period = (1LLU << 32) - 1, | ||
791 | }; | ||
792 | |||
793 | static const struct arm_pmu *__init xscale2pmu_init(void) | ||
794 | { | ||
795 | return &xscale2pmu; | ||
796 | } | ||
797 | #else | ||
798 | static const struct arm_pmu *__init xscale1pmu_init(void) | ||
799 | { | ||
800 | return NULL; | ||
801 | } | ||
802 | |||
803 | static const struct arm_pmu *__init xscale2pmu_init(void) | ||
804 | { | ||
805 | return NULL; | ||
806 | } | ||
807 | #endif /* CONFIG_CPU_XSCALE */ | ||
diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c new file mode 100644 index 000000000000..a4b1b0748fd3 --- /dev/null +++ b/arch/arm/kernel/pj4-cp0.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/pj4-cp0.c | ||
3 | * | ||
4 | * PJ4 iWMMXt coprocessor context switching and handling | ||
5 | * | ||
6 | * Copyright (c) 2010 Marvell International Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/signal.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <asm/thread_notify.h> | ||
21 | |||
22 | static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t) | ||
23 | { | ||
24 | struct thread_info *thread = t; | ||
25 | |||
26 | switch (cmd) { | ||
27 | case THREAD_NOTIFY_FLUSH: | ||
28 | /* | ||
29 | * flush_thread() zeroes thread->fpstate, so no need | ||
30 | * to do anything here. | ||
31 | * | ||
32 | * FALLTHROUGH: Ensure we don't try to overwrite our newly | ||
33 | * initialised state information on the first fault. | ||
34 | */ | ||
35 | |||
36 | case THREAD_NOTIFY_EXIT: | ||
37 | iwmmxt_task_release(thread); | ||
38 | break; | ||
39 | |||
40 | case THREAD_NOTIFY_SWITCH: | ||
41 | iwmmxt_task_switch(thread); | ||
42 | break; | ||
43 | } | ||
44 | |||
45 | return NOTIFY_DONE; | ||
46 | } | ||
47 | |||
48 | static struct notifier_block iwmmxt_notifier_block = { | ||
49 | .notifier_call = iwmmxt_do, | ||
50 | }; | ||
51 | |||
52 | |||
53 | static u32 __init pj4_cp_access_read(void) | ||
54 | { | ||
55 | u32 value; | ||
56 | |||
57 | __asm__ __volatile__ ( | ||
58 | "mrc p15, 0, %0, c1, c0, 2\n\t" | ||
59 | : "=r" (value)); | ||
60 | return value; | ||
61 | } | ||
62 | |||
63 | static void __init pj4_cp_access_write(u32 value) | ||
64 | { | ||
65 | u32 temp; | ||
66 | |||
67 | __asm__ __volatile__ ( | ||
68 | "mcr p15, 0, %1, c1, c0, 2\n\t" | ||
69 | "mrc p15, 0, %0, c1, c0, 2\n\t" | ||
70 | "mov %0, %0\n\t" | ||
71 | "sub pc, pc, #4\n\t" | ||
72 | : "=r" (temp) : "r" (value)); | ||
73 | } | ||
74 | |||
75 | |||
76 | /* | ||
77 | * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy | ||
78 | * switch code handle iWMMXt context switching. | ||
79 | */ | ||
80 | static int __init pj4_cp0_init(void) | ||
81 | { | ||
82 | u32 cp_access; | ||
83 | |||
84 | cp_access = pj4_cp_access_read() & ~0xf; | ||
85 | pj4_cp_access_write(cp_access); | ||
86 | |||
87 | printk(KERN_INFO "PJ4 iWMMXt coprocessor enabled.\n"); | ||
88 | elf_hwcap |= HWCAP_IWMMXT; | ||
89 | thread_register_notifier(&iwmmxt_notifier_block); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | late_initcall(pj4_cp0_init); | ||
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index b8af96ea62e6..2c79eec19262 100644 --- a/arch/arm/kernel/pmu.c +++ b/arch/arm/kernel/pmu.c | |||
@@ -97,28 +97,34 @@ set_irq_affinity(int irq, | |||
97 | irq, cpu); | 97 | irq, cpu); |
98 | return err; | 98 | return err; |
99 | #else | 99 | #else |
100 | return 0; | 100 | return -EINVAL; |
101 | #endif | 101 | #endif |
102 | } | 102 | } |
103 | 103 | ||
104 | static int | 104 | static int |
105 | init_cpu_pmu(void) | 105 | init_cpu_pmu(void) |
106 | { | 106 | { |
107 | int i, err = 0; | 107 | int i, irqs, err = 0; |
108 | struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; | 108 | struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; |
109 | 109 | ||
110 | if (!pdev) { | 110 | if (!pdev) |
111 | err = -ENODEV; | 111 | return -ENODEV; |
112 | goto out; | 112 | |
113 | } | 113 | irqs = pdev->num_resources; |
114 | |||
115 | /* | ||
116 | * If we have a single PMU interrupt that we can't shift, assume that | ||
117 | * we're running on a uniprocessor machine and continue. | ||
118 | */ | ||
119 | if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0))) | ||
120 | return 0; | ||
114 | 121 | ||
115 | for (i = 0; i < pdev->num_resources; ++i) { | 122 | for (i = 0; i < irqs; ++i) { |
116 | err = set_irq_affinity(platform_get_irq(pdev, i), i); | 123 | err = set_irq_affinity(platform_get_irq(pdev, i), i); |
117 | if (err) | 124 | if (err) |
118 | break; | 125 | break; |
119 | } | 126 | } |
120 | 127 | ||
121 | out: | ||
122 | return err; | 128 | return err; |
123 | } | 129 | } |
124 | 130 | ||
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 401e38be1f78..5e1e54197227 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/random.h> | 31 | #include <linux/random.h> |
32 | #include <linux/hw_breakpoint.h> | ||
32 | 33 | ||
33 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
34 | #include <asm/leds.h> | 35 | #include <asm/leds.h> |
@@ -135,6 +136,25 @@ EXPORT_SYMBOL(pm_power_off); | |||
135 | void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart; | 136 | void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart; |
136 | EXPORT_SYMBOL_GPL(arm_pm_restart); | 137 | EXPORT_SYMBOL_GPL(arm_pm_restart); |
137 | 138 | ||
139 | static void do_nothing(void *unused) | ||
140 | { | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of | ||
145 | * pm_idle and update to new pm_idle value. Required while changing pm_idle | ||
146 | * handler on SMP systems. | ||
147 | * | ||
148 | * Caller must have changed pm_idle to the new value before the call. Old | ||
149 | * pm_idle value will not be used by any CPU after the return of this function. | ||
150 | */ | ||
151 | void cpu_idle_wait(void) | ||
152 | { | ||
153 | smp_mb(); | ||
154 | /* kick all the CPUs so that they exit out of pm_idle */ | ||
155 | smp_call_function(do_nothing, NULL, 1); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | ||
138 | 158 | ||
139 | /* | 159 | /* |
140 | * This is our default idle handler. We need to disable | 160 | * This is our default idle handler. We need to disable |
@@ -317,6 +337,8 @@ void flush_thread(void) | |||
317 | struct thread_info *thread = current_thread_info(); | 337 | struct thread_info *thread = current_thread_info(); |
318 | struct task_struct *tsk = current; | 338 | struct task_struct *tsk = current; |
319 | 339 | ||
340 | flush_ptrace_hw_breakpoint(tsk); | ||
341 | |||
320 | memset(thread->used_cp, 0, sizeof(thread->used_cp)); | 342 | memset(thread->used_cp, 0, sizeof(thread->used_cp)); |
321 | memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); | 343 | memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); |
322 | memset(&thread->fpstate, 0, sizeof(union fp_state)); | 344 | memset(&thread->fpstate, 0, sizeof(union fp_state)); |
@@ -345,9 +367,13 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
345 | thread->cpu_context.sp = (unsigned long)childregs; | 367 | thread->cpu_context.sp = (unsigned long)childregs; |
346 | thread->cpu_context.pc = (unsigned long)ret_from_fork; | 368 | thread->cpu_context.pc = (unsigned long)ret_from_fork; |
347 | 369 | ||
370 | clear_ptrace_hw_breakpoint(p); | ||
371 | |||
348 | if (clone_flags & CLONE_SETTLS) | 372 | if (clone_flags & CLONE_SETTLS) |
349 | thread->tp_value = regs->ARM_r3; | 373 | thread->tp_value = regs->ARM_r3; |
350 | 374 | ||
375 | thread_notify(THREAD_NOTIFY_COPY, thread); | ||
376 | |||
351 | return 0; | 377 | return 0; |
352 | } | 378 | } |
353 | 379 | ||
@@ -458,3 +484,26 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) | |||
458 | unsigned long range_end = mm->brk + 0x02000000; | 484 | unsigned long range_end = mm->brk + 0x02000000; |
459 | return randomize_range(mm->brk, range_end, 0) ? : mm->brk; | 485 | return randomize_range(mm->brk, range_end, 0) ? : mm->brk; |
460 | } | 486 | } |
487 | |||
488 | #ifdef CONFIG_MMU | ||
489 | /* | ||
490 | * The vectors page is always readable from user space for the | ||
491 | * atomic helpers and the signal restart code. Let's declare a mapping | ||
492 | * for it so it is visible through ptrace and /proc/<pid>/mem. | ||
493 | */ | ||
494 | |||
495 | int vectors_user_mapping(void) | ||
496 | { | ||
497 | struct mm_struct *mm = current->mm; | ||
498 | return install_special_mapping(mm, 0xffff0000, PAGE_SIZE, | ||
499 | VM_READ | VM_EXEC | | ||
500 | VM_MAYREAD | VM_MAYEXEC | | ||
501 | VM_ALWAYSDUMP | VM_RESERVED, | ||
502 | NULL); | ||
503 | } | ||
504 | |||
505 | const char *arch_vma_name(struct vm_area_struct *vma) | ||
506 | { | ||
507 | return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL; | ||
508 | } | ||
509 | #endif | ||
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index f99d489822d5..97260060bf26 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -19,13 +19,14 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/signal.h> | 20 | #include <linux/signal.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/perf_event.h> | ||
23 | #include <linux/hw_breakpoint.h> | ||
24 | #include <linux/regset.h> | ||
22 | 25 | ||
23 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
24 | #include <asm/system.h> | 27 | #include <asm/system.h> |
25 | #include <asm/traps.h> | 28 | #include <asm/traps.h> |
26 | 29 | ||
27 | #include "ptrace.h" | ||
28 | |||
29 | #define REG_PC 15 | 30 | #define REG_PC 15 |
30 | #define REG_PSR 16 | 31 | #define REG_PSR 16 |
31 | /* | 32 | /* |
@@ -182,389 +183,12 @@ put_user_reg(struct task_struct *task, int offset, long data) | |||
182 | return ret; | 183 | return ret; |
183 | } | 184 | } |
184 | 185 | ||
185 | static inline int | ||
186 | read_u32(struct task_struct *task, unsigned long addr, u32 *res) | ||
187 | { | ||
188 | int ret; | ||
189 | |||
190 | ret = access_process_vm(task, addr, res, sizeof(*res), 0); | ||
191 | |||
192 | return ret == sizeof(*res) ? 0 : -EIO; | ||
193 | } | ||
194 | |||
195 | static inline int | ||
196 | read_instr(struct task_struct *task, unsigned long addr, u32 *res) | ||
197 | { | ||
198 | int ret; | ||
199 | |||
200 | if (addr & 1) { | ||
201 | u16 val; | ||
202 | ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); | ||
203 | ret = ret == sizeof(val) ? 0 : -EIO; | ||
204 | *res = val; | ||
205 | } else { | ||
206 | u32 val; | ||
207 | ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); | ||
208 | ret = ret == sizeof(val) ? 0 : -EIO; | ||
209 | *res = val; | ||
210 | } | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Get value of register `rn' (in the instruction) | ||
216 | */ | ||
217 | static unsigned long | ||
218 | ptrace_getrn(struct task_struct *child, unsigned long insn) | ||
219 | { | ||
220 | unsigned int reg = (insn >> 16) & 15; | ||
221 | unsigned long val; | ||
222 | |||
223 | val = get_user_reg(child, reg); | ||
224 | if (reg == 15) | ||
225 | val += 8; | ||
226 | |||
227 | return val; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Get value of operand 2 (in an ALU instruction) | ||
232 | */ | ||
233 | static unsigned long | ||
234 | ptrace_getaluop2(struct task_struct *child, unsigned long insn) | ||
235 | { | ||
236 | unsigned long val; | ||
237 | int shift; | ||
238 | int type; | ||
239 | |||
240 | if (insn & 1 << 25) { | ||
241 | val = insn & 255; | ||
242 | shift = (insn >> 8) & 15; | ||
243 | type = 3; | ||
244 | } else { | ||
245 | val = get_user_reg (child, insn & 15); | ||
246 | |||
247 | if (insn & (1 << 4)) | ||
248 | shift = (int)get_user_reg (child, (insn >> 8) & 15); | ||
249 | else | ||
250 | shift = (insn >> 7) & 31; | ||
251 | |||
252 | type = (insn >> 5) & 3; | ||
253 | } | ||
254 | |||
255 | switch (type) { | ||
256 | case 0: val <<= shift; break; | ||
257 | case 1: val >>= shift; break; | ||
258 | case 2: | ||
259 | val = (((signed long)val) >> shift); | ||
260 | break; | ||
261 | case 3: | ||
262 | val = (val >> shift) | (val << (32 - shift)); | ||
263 | break; | ||
264 | } | ||
265 | return val; | ||
266 | } | ||
267 | |||
268 | /* | ||
269 | * Get value of operand 2 (in a LDR instruction) | ||
270 | */ | ||
271 | static unsigned long | ||
272 | ptrace_getldrop2(struct task_struct *child, unsigned long insn) | ||
273 | { | ||
274 | unsigned long val; | ||
275 | int shift; | ||
276 | int type; | ||
277 | |||
278 | val = get_user_reg(child, insn & 15); | ||
279 | shift = (insn >> 7) & 31; | ||
280 | type = (insn >> 5) & 3; | ||
281 | |||
282 | switch (type) { | ||
283 | case 0: val <<= shift; break; | ||
284 | case 1: val >>= shift; break; | ||
285 | case 2: | ||
286 | val = (((signed long)val) >> shift); | ||
287 | break; | ||
288 | case 3: | ||
289 | val = (val >> shift) | (val << (32 - shift)); | ||
290 | break; | ||
291 | } | ||
292 | return val; | ||
293 | } | ||
294 | |||
295 | #define OP_MASK 0x01e00000 | ||
296 | #define OP_AND 0x00000000 | ||
297 | #define OP_EOR 0x00200000 | ||
298 | #define OP_SUB 0x00400000 | ||
299 | #define OP_RSB 0x00600000 | ||
300 | #define OP_ADD 0x00800000 | ||
301 | #define OP_ADC 0x00a00000 | ||
302 | #define OP_SBC 0x00c00000 | ||
303 | #define OP_RSC 0x00e00000 | ||
304 | #define OP_ORR 0x01800000 | ||
305 | #define OP_MOV 0x01a00000 | ||
306 | #define OP_BIC 0x01c00000 | ||
307 | #define OP_MVN 0x01e00000 | ||
308 | |||
309 | static unsigned long | ||
310 | get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) | ||
311 | { | ||
312 | u32 alt = 0; | ||
313 | |||
314 | switch (insn & 0x0e000000) { | ||
315 | case 0x00000000: | ||
316 | case 0x02000000: { | ||
317 | /* | ||
318 | * data processing | ||
319 | */ | ||
320 | long aluop1, aluop2, ccbit; | ||
321 | |||
322 | if ((insn & 0x0fffffd0) == 0x012fff10) { | ||
323 | /* | ||
324 | * bx or blx | ||
325 | */ | ||
326 | alt = get_user_reg(child, insn & 15); | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | |||
331 | if ((insn & 0xf000) != 0xf000) | ||
332 | break; | ||
333 | |||
334 | aluop1 = ptrace_getrn(child, insn); | ||
335 | aluop2 = ptrace_getaluop2(child, insn); | ||
336 | ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; | ||
337 | |||
338 | switch (insn & OP_MASK) { | ||
339 | case OP_AND: alt = aluop1 & aluop2; break; | ||
340 | case OP_EOR: alt = aluop1 ^ aluop2; break; | ||
341 | case OP_SUB: alt = aluop1 - aluop2; break; | ||
342 | case OP_RSB: alt = aluop2 - aluop1; break; | ||
343 | case OP_ADD: alt = aluop1 + aluop2; break; | ||
344 | case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; | ||
345 | case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; | ||
346 | case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; | ||
347 | case OP_ORR: alt = aluop1 | aluop2; break; | ||
348 | case OP_MOV: alt = aluop2; break; | ||
349 | case OP_BIC: alt = aluop1 & ~aluop2; break; | ||
350 | case OP_MVN: alt = ~aluop2; break; | ||
351 | } | ||
352 | break; | ||
353 | } | ||
354 | |||
355 | case 0x04000000: | ||
356 | case 0x06000000: | ||
357 | /* | ||
358 | * ldr | ||
359 | */ | ||
360 | if ((insn & 0x0010f000) == 0x0010f000) { | ||
361 | unsigned long base; | ||
362 | |||
363 | base = ptrace_getrn(child, insn); | ||
364 | if (insn & 1 << 24) { | ||
365 | long aluop2; | ||
366 | |||
367 | if (insn & 0x02000000) | ||
368 | aluop2 = ptrace_getldrop2(child, insn); | ||
369 | else | ||
370 | aluop2 = insn & 0xfff; | ||
371 | |||
372 | if (insn & 1 << 23) | ||
373 | base += aluop2; | ||
374 | else | ||
375 | base -= aluop2; | ||
376 | } | ||
377 | read_u32(child, base, &alt); | ||
378 | } | ||
379 | break; | ||
380 | |||
381 | case 0x08000000: | ||
382 | /* | ||
383 | * ldm | ||
384 | */ | ||
385 | if ((insn & 0x00108000) == 0x00108000) { | ||
386 | unsigned long base; | ||
387 | unsigned int nr_regs; | ||
388 | |||
389 | if (insn & (1 << 23)) { | ||
390 | nr_regs = hweight16(insn & 65535) << 2; | ||
391 | |||
392 | if (!(insn & (1 << 24))) | ||
393 | nr_regs -= 4; | ||
394 | } else { | ||
395 | if (insn & (1 << 24)) | ||
396 | nr_regs = -4; | ||
397 | else | ||
398 | nr_regs = 0; | ||
399 | } | ||
400 | |||
401 | base = ptrace_getrn(child, insn); | ||
402 | |||
403 | read_u32(child, base + nr_regs, &alt); | ||
404 | break; | ||
405 | } | ||
406 | break; | ||
407 | |||
408 | case 0x0a000000: { | ||
409 | /* | ||
410 | * bl or b | ||
411 | */ | ||
412 | signed long displ; | ||
413 | /* It's a branch/branch link: instead of trying to | ||
414 | * figure out whether the branch will be taken or not, | ||
415 | * we'll put a breakpoint at both locations. This is | ||
416 | * simpler, more reliable, and probably not a whole lot | ||
417 | * slower than the alternative approach of emulating the | ||
418 | * branch. | ||
419 | */ | ||
420 | displ = (insn & 0x00ffffff) << 8; | ||
421 | displ = (displ >> 6) + 8; | ||
422 | if (displ != 0 && displ != 4) | ||
423 | alt = pc + displ; | ||
424 | } | ||
425 | break; | ||
426 | } | ||
427 | |||
428 | return alt; | ||
429 | } | ||
430 | |||
431 | static int | ||
432 | swap_insn(struct task_struct *task, unsigned long addr, | ||
433 | void *old_insn, void *new_insn, int size) | ||
434 | { | ||
435 | int ret; | ||
436 | |||
437 | ret = access_process_vm(task, addr, old_insn, size, 0); | ||
438 | if (ret == size) | ||
439 | ret = access_process_vm(task, addr, new_insn, size, 1); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) | ||
445 | { | ||
446 | int nr = dbg->nsaved; | ||
447 | |||
448 | if (nr < 2) { | ||
449 | u32 new_insn = BREAKINST_ARM; | ||
450 | int res; | ||
451 | |||
452 | res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); | ||
453 | |||
454 | if (res == 4) { | ||
455 | dbg->bp[nr].address = addr; | ||
456 | dbg->nsaved += 1; | ||
457 | } | ||
458 | } else | ||
459 | printk(KERN_ERR "ptrace: too many breakpoints\n"); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Clear one breakpoint in the user program. We copy what the hardware | ||
464 | * does and use bit 0 of the address to indicate whether this is a Thumb | ||
465 | * breakpoint or an ARM breakpoint. | ||
466 | */ | ||
467 | static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) | ||
468 | { | ||
469 | unsigned long addr = bp->address; | ||
470 | union debug_insn old_insn; | ||
471 | int ret; | ||
472 | |||
473 | if (addr & 1) { | ||
474 | ret = swap_insn(task, addr & ~1, &old_insn.thumb, | ||
475 | &bp->insn.thumb, 2); | ||
476 | |||
477 | if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) | ||
478 | printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " | ||
479 | "0x%08lx (0x%04x)\n", task->comm, | ||
480 | task_pid_nr(task), addr, old_insn.thumb); | ||
481 | } else { | ||
482 | ret = swap_insn(task, addr & ~3, &old_insn.arm, | ||
483 | &bp->insn.arm, 4); | ||
484 | |||
485 | if (ret != 4 || old_insn.arm != BREAKINST_ARM) | ||
486 | printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " | ||
487 | "0x%08lx (0x%08x)\n", task->comm, | ||
488 | task_pid_nr(task), addr, old_insn.arm); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | void ptrace_set_bpt(struct task_struct *child) | ||
493 | { | ||
494 | struct pt_regs *regs; | ||
495 | unsigned long pc; | ||
496 | u32 insn; | ||
497 | int res; | ||
498 | |||
499 | regs = task_pt_regs(child); | ||
500 | pc = instruction_pointer(regs); | ||
501 | |||
502 | if (thumb_mode(regs)) { | ||
503 | printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | res = read_instr(child, pc, &insn); | ||
508 | if (!res) { | ||
509 | struct debug_info *dbg = &child->thread.debug; | ||
510 | unsigned long alt; | ||
511 | |||
512 | dbg->nsaved = 0; | ||
513 | |||
514 | alt = get_branch_address(child, pc, insn); | ||
515 | if (alt) | ||
516 | add_breakpoint(child, dbg, alt); | ||
517 | |||
518 | /* | ||
519 | * Note that we ignore the result of setting the above | ||
520 | * breakpoint since it may fail. When it does, this is | ||
521 | * not so much an error, but a forewarning that we may | ||
522 | * be receiving a prefetch abort shortly. | ||
523 | * | ||
524 | * If we don't set this breakpoint here, then we can | ||
525 | * lose control of the thread during single stepping. | ||
526 | */ | ||
527 | if (!alt || predicate(insn) != PREDICATE_ALWAYS) | ||
528 | add_breakpoint(child, dbg, pc + 4); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Ensure no single-step breakpoint is pending. Returns non-zero | ||
534 | * value if child was being single-stepped. | ||
535 | */ | ||
536 | void ptrace_cancel_bpt(struct task_struct *child) | ||
537 | { | ||
538 | int i, nsaved = child->thread.debug.nsaved; | ||
539 | |||
540 | child->thread.debug.nsaved = 0; | ||
541 | |||
542 | if (nsaved > 2) { | ||
543 | printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); | ||
544 | nsaved = 2; | ||
545 | } | ||
546 | |||
547 | for (i = 0; i < nsaved; i++) | ||
548 | clear_breakpoint(child, &child->thread.debug.bp[i]); | ||
549 | } | ||
550 | |||
551 | void user_disable_single_step(struct task_struct *task) | ||
552 | { | ||
553 | task->ptrace &= ~PT_SINGLESTEP; | ||
554 | ptrace_cancel_bpt(task); | ||
555 | } | ||
556 | |||
557 | void user_enable_single_step(struct task_struct *task) | ||
558 | { | ||
559 | task->ptrace |= PT_SINGLESTEP; | ||
560 | } | ||
561 | |||
562 | /* | 186 | /* |
563 | * Called by kernel/ptrace.c when detaching.. | 187 | * Called by kernel/ptrace.c when detaching.. |
564 | */ | 188 | */ |
565 | void ptrace_disable(struct task_struct *child) | 189 | void ptrace_disable(struct task_struct *child) |
566 | { | 190 | { |
567 | user_disable_single_step(child); | 191 | /* Nothing to do. */ |
568 | } | 192 | } |
569 | 193 | ||
570 | /* | 194 | /* |
@@ -574,8 +198,6 @@ void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) | |||
574 | { | 198 | { |
575 | siginfo_t info; | 199 | siginfo_t info; |
576 | 200 | ||
577 | ptrace_cancel_bpt(tsk); | ||
578 | |||
579 | info.si_signo = SIGTRAP; | 201 | info.si_signo = SIGTRAP; |
580 | info.si_errno = 0; | 202 | info.si_errno = 0; |
581 | info.si_code = TRAP_BRKPT; | 203 | info.si_code = TRAP_BRKPT; |
@@ -687,58 +309,6 @@ static int ptrace_write_user(struct task_struct *tsk, unsigned long off, | |||
687 | return put_user_reg(tsk, off >> 2, val); | 309 | return put_user_reg(tsk, off >> 2, val); |
688 | } | 310 | } |
689 | 311 | ||
690 | /* | ||
691 | * Get all user integer registers. | ||
692 | */ | ||
693 | static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | ||
694 | { | ||
695 | struct pt_regs *regs = task_pt_regs(tsk); | ||
696 | |||
697 | return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | * Set all user integer registers. | ||
702 | */ | ||
703 | static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) | ||
704 | { | ||
705 | struct pt_regs newregs; | ||
706 | int ret; | ||
707 | |||
708 | ret = -EFAULT; | ||
709 | if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { | ||
710 | struct pt_regs *regs = task_pt_regs(tsk); | ||
711 | |||
712 | ret = -EINVAL; | ||
713 | if (valid_user_regs(&newregs)) { | ||
714 | *regs = newregs; | ||
715 | ret = 0; | ||
716 | } | ||
717 | } | ||
718 | |||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | /* | ||
723 | * Get the child FPU state. | ||
724 | */ | ||
725 | static int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) | ||
726 | { | ||
727 | return copy_to_user(ufp, &task_thread_info(tsk)->fpstate, | ||
728 | sizeof(struct user_fp)) ? -EFAULT : 0; | ||
729 | } | ||
730 | |||
731 | /* | ||
732 | * Set the child FPU state. | ||
733 | */ | ||
734 | static int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) | ||
735 | { | ||
736 | struct thread_info *thread = task_thread_info(tsk); | ||
737 | thread->used_cp[1] = thread->used_cp[2] = 1; | ||
738 | return copy_from_user(&thread->fpstate, ufp, | ||
739 | sizeof(struct user_fp)) ? -EFAULT : 0; | ||
740 | } | ||
741 | |||
742 | #ifdef CONFIG_IWMMXT | 312 | #ifdef CONFIG_IWMMXT |
743 | 313 | ||
744 | /* | 314 | /* |
@@ -797,63 +367,454 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) | |||
797 | } | 367 | } |
798 | #endif | 368 | #endif |
799 | 369 | ||
800 | #ifdef CONFIG_VFP | 370 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
801 | /* | 371 | /* |
802 | * Get the child VFP state. | 372 | * Convert a virtual register number into an index for a thread_info |
373 | * breakpoint array. Breakpoints are identified using positive numbers | ||
374 | * whilst watchpoints are negative. The registers are laid out as pairs | ||
375 | * of (address, control), each pair mapping to a unique hw_breakpoint struct. | ||
376 | * Register 0 is reserved for describing resource information. | ||
803 | */ | 377 | */ |
804 | static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data) | 378 | static int ptrace_hbp_num_to_idx(long num) |
805 | { | 379 | { |
806 | struct thread_info *thread = task_thread_info(tsk); | 380 | if (num < 0) |
807 | union vfp_state *vfp = &thread->vfpstate; | 381 | num = (ARM_MAX_BRP << 1) - num; |
808 | struct user_vfp __user *ufp = data; | 382 | return (num - 1) >> 1; |
383 | } | ||
809 | 384 | ||
810 | vfp_sync_hwstate(thread); | 385 | /* |
386 | * Returns the virtual register number for the address of the | ||
387 | * breakpoint at index idx. | ||
388 | */ | ||
389 | static long ptrace_hbp_idx_to_num(int idx) | ||
390 | { | ||
391 | long mid = ARM_MAX_BRP << 1; | ||
392 | long num = (idx << 1) + 1; | ||
393 | return num > mid ? mid - num : num; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * Handle hitting a HW-breakpoint. | ||
398 | */ | ||
399 | static void ptrace_hbptriggered(struct perf_event *bp, int unused, | ||
400 | struct perf_sample_data *data, | ||
401 | struct pt_regs *regs) | ||
402 | { | ||
403 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); | ||
404 | long num; | ||
405 | int i; | ||
406 | siginfo_t info; | ||
407 | |||
408 | for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i) | ||
409 | if (current->thread.debug.hbp[i] == bp) | ||
410 | break; | ||
811 | 411 | ||
812 | /* copy the floating point registers */ | 412 | num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i); |
813 | if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs, | ||
814 | sizeof(vfp->hard.fpregs))) | ||
815 | return -EFAULT; | ||
816 | 413 | ||
817 | /* copy the status and control register */ | 414 | info.si_signo = SIGTRAP; |
818 | if (put_user(vfp->hard.fpscr, &ufp->fpscr)) | 415 | info.si_errno = (int)num; |
819 | return -EFAULT; | 416 | info.si_code = TRAP_HWBKPT; |
417 | info.si_addr = (void __user *)(bkpt->trigger); | ||
820 | 418 | ||
419 | force_sig_info(SIGTRAP, &info, current); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Set ptrace breakpoint pointers to zero for this task. | ||
424 | * This is required in order to prevent child processes from unregistering | ||
425 | * breakpoints held by their parent. | ||
426 | */ | ||
427 | void clear_ptrace_hw_breakpoint(struct task_struct *tsk) | ||
428 | { | ||
429 | memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp)); | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Unregister breakpoints from this task and reset the pointers in | ||
434 | * the thread_struct. | ||
435 | */ | ||
436 | void flush_ptrace_hw_breakpoint(struct task_struct *tsk) | ||
437 | { | ||
438 | int i; | ||
439 | struct thread_struct *t = &tsk->thread; | ||
440 | |||
441 | for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) { | ||
442 | if (t->debug.hbp[i]) { | ||
443 | unregister_hw_breakpoint(t->debug.hbp[i]); | ||
444 | t->debug.hbp[i] = NULL; | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
449 | static u32 ptrace_get_hbp_resource_info(void) | ||
450 | { | ||
451 | u8 num_brps, num_wrps, debug_arch, wp_len; | ||
452 | u32 reg = 0; | ||
453 | |||
454 | num_brps = hw_breakpoint_slots(TYPE_INST); | ||
455 | num_wrps = hw_breakpoint_slots(TYPE_DATA); | ||
456 | debug_arch = arch_get_debug_arch(); | ||
457 | wp_len = arch_get_max_wp_len(); | ||
458 | |||
459 | reg |= debug_arch; | ||
460 | reg <<= 8; | ||
461 | reg |= wp_len; | ||
462 | reg <<= 8; | ||
463 | reg |= num_wrps; | ||
464 | reg <<= 8; | ||
465 | reg |= num_brps; | ||
466 | |||
467 | return reg; | ||
468 | } | ||
469 | |||
470 | static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type) | ||
471 | { | ||
472 | struct perf_event_attr attr; | ||
473 | |||
474 | ptrace_breakpoint_init(&attr); | ||
475 | |||
476 | /* Initialise fields to sane defaults. */ | ||
477 | attr.bp_addr = 0; | ||
478 | attr.bp_len = HW_BREAKPOINT_LEN_4; | ||
479 | attr.bp_type = type; | ||
480 | attr.disabled = 1; | ||
481 | |||
482 | return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk); | ||
483 | } | ||
484 | |||
485 | static int ptrace_gethbpregs(struct task_struct *tsk, long num, | ||
486 | unsigned long __user *data) | ||
487 | { | ||
488 | u32 reg; | ||
489 | int idx, ret = 0; | ||
490 | struct perf_event *bp; | ||
491 | struct arch_hw_breakpoint_ctrl arch_ctrl; | ||
492 | |||
493 | if (num == 0) { | ||
494 | reg = ptrace_get_hbp_resource_info(); | ||
495 | } else { | ||
496 | idx = ptrace_hbp_num_to_idx(num); | ||
497 | if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { | ||
498 | ret = -EINVAL; | ||
499 | goto out; | ||
500 | } | ||
501 | |||
502 | bp = tsk->thread.debug.hbp[idx]; | ||
503 | if (!bp) { | ||
504 | reg = 0; | ||
505 | goto put; | ||
506 | } | ||
507 | |||
508 | arch_ctrl = counter_arch_bp(bp)->ctrl; | ||
509 | |||
510 | /* | ||
511 | * Fix up the len because we may have adjusted it | ||
512 | * to compensate for an unaligned address. | ||
513 | */ | ||
514 | while (!(arch_ctrl.len & 0x1)) | ||
515 | arch_ctrl.len >>= 1; | ||
516 | |||
517 | if (num & 0x1) | ||
518 | reg = bp->attr.bp_addr; | ||
519 | else | ||
520 | reg = encode_ctrl_reg(arch_ctrl); | ||
521 | } | ||
522 | |||
523 | put: | ||
524 | if (put_user(reg, data)) | ||
525 | ret = -EFAULT; | ||
526 | |||
527 | out: | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | static int ptrace_sethbpregs(struct task_struct *tsk, long num, | ||
532 | unsigned long __user *data) | ||
533 | { | ||
534 | int idx, gen_len, gen_type, implied_type, ret = 0; | ||
535 | u32 user_val; | ||
536 | struct perf_event *bp; | ||
537 | struct arch_hw_breakpoint_ctrl ctrl; | ||
538 | struct perf_event_attr attr; | ||
539 | |||
540 | if (num == 0) | ||
541 | goto out; | ||
542 | else if (num < 0) | ||
543 | implied_type = HW_BREAKPOINT_RW; | ||
544 | else | ||
545 | implied_type = HW_BREAKPOINT_X; | ||
546 | |||
547 | idx = ptrace_hbp_num_to_idx(num); | ||
548 | if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { | ||
549 | ret = -EINVAL; | ||
550 | goto out; | ||
551 | } | ||
552 | |||
553 | if (get_user(user_val, data)) { | ||
554 | ret = -EFAULT; | ||
555 | goto out; | ||
556 | } | ||
557 | |||
558 | bp = tsk->thread.debug.hbp[idx]; | ||
559 | if (!bp) { | ||
560 | bp = ptrace_hbp_create(tsk, implied_type); | ||
561 | if (IS_ERR(bp)) { | ||
562 | ret = PTR_ERR(bp); | ||
563 | goto out; | ||
564 | } | ||
565 | tsk->thread.debug.hbp[idx] = bp; | ||
566 | } | ||
567 | |||
568 | attr = bp->attr; | ||
569 | |||
570 | if (num & 0x1) { | ||
571 | /* Address */ | ||
572 | attr.bp_addr = user_val; | ||
573 | } else { | ||
574 | /* Control */ | ||
575 | decode_ctrl_reg(user_val, &ctrl); | ||
576 | ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type); | ||
577 | if (ret) | ||
578 | goto out; | ||
579 | |||
580 | if ((gen_type & implied_type) != gen_type) { | ||
581 | ret = -EINVAL; | ||
582 | goto out; | ||
583 | } | ||
584 | |||
585 | attr.bp_len = gen_len; | ||
586 | attr.bp_type = gen_type; | ||
587 | attr.disabled = !ctrl.enabled; | ||
588 | } | ||
589 | |||
590 | ret = modify_user_hw_breakpoint(bp, &attr); | ||
591 | out: | ||
592 | return ret; | ||
593 | } | ||
594 | #endif | ||
595 | |||
596 | /* regset get/set implementations */ | ||
597 | |||
598 | static int gpr_get(struct task_struct *target, | ||
599 | const struct user_regset *regset, | ||
600 | unsigned int pos, unsigned int count, | ||
601 | void *kbuf, void __user *ubuf) | ||
602 | { | ||
603 | struct pt_regs *regs = task_pt_regs(target); | ||
604 | |||
605 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
606 | regs, | ||
607 | 0, sizeof(*regs)); | ||
608 | } | ||
609 | |||
610 | static int gpr_set(struct task_struct *target, | ||
611 | const struct user_regset *regset, | ||
612 | unsigned int pos, unsigned int count, | ||
613 | const void *kbuf, const void __user *ubuf) | ||
614 | { | ||
615 | int ret; | ||
616 | struct pt_regs newregs; | ||
617 | |||
618 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
619 | &newregs, | ||
620 | 0, sizeof(newregs)); | ||
621 | if (ret) | ||
622 | return ret; | ||
623 | |||
624 | if (!valid_user_regs(&newregs)) | ||
625 | return -EINVAL; | ||
626 | |||
627 | *task_pt_regs(target) = newregs; | ||
821 | return 0; | 628 | return 0; |
822 | } | 629 | } |
823 | 630 | ||
631 | static int fpa_get(struct task_struct *target, | ||
632 | const struct user_regset *regset, | ||
633 | unsigned int pos, unsigned int count, | ||
634 | void *kbuf, void __user *ubuf) | ||
635 | { | ||
636 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
637 | &task_thread_info(target)->fpstate, | ||
638 | 0, sizeof(struct user_fp)); | ||
639 | } | ||
640 | |||
641 | static int fpa_set(struct task_struct *target, | ||
642 | const struct user_regset *regset, | ||
643 | unsigned int pos, unsigned int count, | ||
644 | const void *kbuf, const void __user *ubuf) | ||
645 | { | ||
646 | struct thread_info *thread = task_thread_info(target); | ||
647 | |||
648 | thread->used_cp[1] = thread->used_cp[2] = 1; | ||
649 | |||
650 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
651 | &thread->fpstate, | ||
652 | 0, sizeof(struct user_fp)); | ||
653 | } | ||
654 | |||
655 | #ifdef CONFIG_VFP | ||
824 | /* | 656 | /* |
825 | * Set the child VFP state. | 657 | * VFP register get/set implementations. |
658 | * | ||
659 | * With respect to the kernel, struct user_fp is divided into three chunks: | ||
660 | * 16 or 32 real VFP registers (d0-d15 or d0-31) | ||
661 | * These are transferred to/from the real registers in the task's | ||
662 | * vfp_hard_struct. The number of registers depends on the kernel | ||
663 | * configuration. | ||
664 | * | ||
665 | * 16 or 0 fake VFP registers (d16-d31 or empty) | ||
666 | * i.e., the user_vfp structure has space for 32 registers even if | ||
667 | * the kernel doesn't have them all. | ||
668 | * | ||
669 | * vfp_get() reads this chunk as zero where applicable | ||
670 | * vfp_set() ignores this chunk | ||
671 | * | ||
672 | * 1 word for the FPSCR | ||
673 | * | ||
674 | * The bounds-checking logic built into user_regset_copyout and friends | ||
675 | * means that we can make a simple sequence of calls to map the relevant data | ||
676 | * to/from the specified slice of the user regset structure. | ||
826 | */ | 677 | */ |
827 | static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data) | 678 | static int vfp_get(struct task_struct *target, |
679 | const struct user_regset *regset, | ||
680 | unsigned int pos, unsigned int count, | ||
681 | void *kbuf, void __user *ubuf) | ||
828 | { | 682 | { |
829 | struct thread_info *thread = task_thread_info(tsk); | 683 | int ret; |
830 | union vfp_state *vfp = &thread->vfpstate; | 684 | struct thread_info *thread = task_thread_info(target); |
831 | struct user_vfp __user *ufp = data; | 685 | struct vfp_hard_struct const *vfp = &thread->vfpstate.hard; |
686 | const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); | ||
687 | const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); | ||
832 | 688 | ||
833 | vfp_sync_hwstate(thread); | 689 | vfp_sync_hwstate(thread); |
834 | 690 | ||
835 | /* copy the floating point registers */ | 691 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
836 | if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs, | 692 | &vfp->fpregs, |
837 | sizeof(vfp->hard.fpregs))) | 693 | user_fpregs_offset, |
838 | return -EFAULT; | 694 | user_fpregs_offset + sizeof(vfp->fpregs)); |
695 | if (ret) | ||
696 | return ret; | ||
839 | 697 | ||
840 | /* copy the status and control register */ | 698 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, |
841 | if (get_user(vfp->hard.fpscr, &ufp->fpscr)) | 699 | user_fpregs_offset + sizeof(vfp->fpregs), |
842 | return -EFAULT; | 700 | user_fpscr_offset); |
701 | if (ret) | ||
702 | return ret; | ||
843 | 703 | ||
704 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
705 | &vfp->fpscr, | ||
706 | user_fpscr_offset, | ||
707 | user_fpscr_offset + sizeof(vfp->fpscr)); | ||
708 | } | ||
709 | |||
710 | /* | ||
711 | * For vfp_set() a read-modify-write is done on the VFP registers, | ||
712 | * in order to avoid writing back a half-modified set of registers on | ||
713 | * failure. | ||
714 | */ | ||
715 | static int vfp_set(struct task_struct *target, | ||
716 | const struct user_regset *regset, | ||
717 | unsigned int pos, unsigned int count, | ||
718 | const void *kbuf, const void __user *ubuf) | ||
719 | { | ||
720 | int ret; | ||
721 | struct thread_info *thread = task_thread_info(target); | ||
722 | struct vfp_hard_struct new_vfp = thread->vfpstate.hard; | ||
723 | const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); | ||
724 | const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); | ||
725 | |||
726 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
727 | &new_vfp.fpregs, | ||
728 | user_fpregs_offset, | ||
729 | user_fpregs_offset + sizeof(new_vfp.fpregs)); | ||
730 | if (ret) | ||
731 | return ret; | ||
732 | |||
733 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
734 | user_fpregs_offset + sizeof(new_vfp.fpregs), | ||
735 | user_fpscr_offset); | ||
736 | if (ret) | ||
737 | return ret; | ||
738 | |||
739 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
740 | &new_vfp.fpscr, | ||
741 | user_fpscr_offset, | ||
742 | user_fpscr_offset + sizeof(new_vfp.fpscr)); | ||
743 | if (ret) | ||
744 | return ret; | ||
745 | |||
746 | vfp_sync_hwstate(thread); | ||
747 | thread->vfpstate.hard = new_vfp; | ||
844 | vfp_flush_hwstate(thread); | 748 | vfp_flush_hwstate(thread); |
845 | 749 | ||
846 | return 0; | 750 | return 0; |
847 | } | 751 | } |
752 | #endif /* CONFIG_VFP */ | ||
753 | |||
754 | enum arm_regset { | ||
755 | REGSET_GPR, | ||
756 | REGSET_FPR, | ||
757 | #ifdef CONFIG_VFP | ||
758 | REGSET_VFP, | ||
848 | #endif | 759 | #endif |
760 | }; | ||
849 | 761 | ||
850 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 762 | static const struct user_regset arm_regsets[] = { |
763 | [REGSET_GPR] = { | ||
764 | .core_note_type = NT_PRSTATUS, | ||
765 | .n = ELF_NGREG, | ||
766 | .size = sizeof(u32), | ||
767 | .align = sizeof(u32), | ||
768 | .get = gpr_get, | ||
769 | .set = gpr_set | ||
770 | }, | ||
771 | [REGSET_FPR] = { | ||
772 | /* | ||
773 | * For the FPA regs in fpstate, the real fields are a mixture | ||
774 | * of sizes, so pretend that the registers are word-sized: | ||
775 | */ | ||
776 | .core_note_type = NT_PRFPREG, | ||
777 | .n = sizeof(struct user_fp) / sizeof(u32), | ||
778 | .size = sizeof(u32), | ||
779 | .align = sizeof(u32), | ||
780 | .get = fpa_get, | ||
781 | .set = fpa_set | ||
782 | }, | ||
783 | #ifdef CONFIG_VFP | ||
784 | [REGSET_VFP] = { | ||
785 | /* | ||
786 | * Pretend that the VFP regs are word-sized, since the FPSCR is | ||
787 | * a single word dangling at the end of struct user_vfp: | ||
788 | */ | ||
789 | .core_note_type = NT_ARM_VFP, | ||
790 | .n = ARM_VFPREGS_SIZE / sizeof(u32), | ||
791 | .size = sizeof(u32), | ||
792 | .align = sizeof(u32), | ||
793 | .get = vfp_get, | ||
794 | .set = vfp_set | ||
795 | }, | ||
796 | #endif /* CONFIG_VFP */ | ||
797 | }; | ||
798 | |||
799 | static const struct user_regset_view user_arm_view = { | ||
800 | .name = "arm", .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, | ||
801 | .regsets = arm_regsets, .n = ARRAY_SIZE(arm_regsets) | ||
802 | }; | ||
803 | |||
804 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
805 | { | ||
806 | return &user_arm_view; | ||
807 | } | ||
808 | |||
809 | long arch_ptrace(struct task_struct *child, long request, | ||
810 | unsigned long addr, unsigned long data) | ||
851 | { | 811 | { |
852 | int ret; | 812 | int ret; |
813 | unsigned long __user *datap = (unsigned long __user *) data; | ||
853 | 814 | ||
854 | switch (request) { | 815 | switch (request) { |
855 | case PTRACE_PEEKUSR: | 816 | case PTRACE_PEEKUSR: |
856 | ret = ptrace_read_user(child, addr, (unsigned long __user *)data); | 817 | ret = ptrace_read_user(child, addr, datap); |
857 | break; | 818 | break; |
858 | 819 | ||
859 | case PTRACE_POKEUSR: | 820 | case PTRACE_POKEUSR: |
@@ -861,34 +822,46 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
861 | break; | 822 | break; |
862 | 823 | ||
863 | case PTRACE_GETREGS: | 824 | case PTRACE_GETREGS: |
864 | ret = ptrace_getregs(child, (void __user *)data); | 825 | ret = copy_regset_to_user(child, |
826 | &user_arm_view, REGSET_GPR, | ||
827 | 0, sizeof(struct pt_regs), | ||
828 | datap); | ||
865 | break; | 829 | break; |
866 | 830 | ||
867 | case PTRACE_SETREGS: | 831 | case PTRACE_SETREGS: |
868 | ret = ptrace_setregs(child, (void __user *)data); | 832 | ret = copy_regset_from_user(child, |
833 | &user_arm_view, REGSET_GPR, | ||
834 | 0, sizeof(struct pt_regs), | ||
835 | datap); | ||
869 | break; | 836 | break; |
870 | 837 | ||
871 | case PTRACE_GETFPREGS: | 838 | case PTRACE_GETFPREGS: |
872 | ret = ptrace_getfpregs(child, (void __user *)data); | 839 | ret = copy_regset_to_user(child, |
840 | &user_arm_view, REGSET_FPR, | ||
841 | 0, sizeof(union fp_state), | ||
842 | datap); | ||
873 | break; | 843 | break; |
874 | 844 | ||
875 | case PTRACE_SETFPREGS: | 845 | case PTRACE_SETFPREGS: |
876 | ret = ptrace_setfpregs(child, (void __user *)data); | 846 | ret = copy_regset_from_user(child, |
847 | &user_arm_view, REGSET_FPR, | ||
848 | 0, sizeof(union fp_state), | ||
849 | datap); | ||
877 | break; | 850 | break; |
878 | 851 | ||
879 | #ifdef CONFIG_IWMMXT | 852 | #ifdef CONFIG_IWMMXT |
880 | case PTRACE_GETWMMXREGS: | 853 | case PTRACE_GETWMMXREGS: |
881 | ret = ptrace_getwmmxregs(child, (void __user *)data); | 854 | ret = ptrace_getwmmxregs(child, datap); |
882 | break; | 855 | break; |
883 | 856 | ||
884 | case PTRACE_SETWMMXREGS: | 857 | case PTRACE_SETWMMXREGS: |
885 | ret = ptrace_setwmmxregs(child, (void __user *)data); | 858 | ret = ptrace_setwmmxregs(child, datap); |
886 | break; | 859 | break; |
887 | #endif | 860 | #endif |
888 | 861 | ||
889 | case PTRACE_GET_THREAD_AREA: | 862 | case PTRACE_GET_THREAD_AREA: |
890 | ret = put_user(task_thread_info(child)->tp_value, | 863 | ret = put_user(task_thread_info(child)->tp_value, |
891 | (unsigned long __user *) data); | 864 | datap); |
892 | break; | 865 | break; |
893 | 866 | ||
894 | case PTRACE_SET_SYSCALL: | 867 | case PTRACE_SET_SYSCALL: |
@@ -898,21 +871,46 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
898 | 871 | ||
899 | #ifdef CONFIG_CRUNCH | 872 | #ifdef CONFIG_CRUNCH |
900 | case PTRACE_GETCRUNCHREGS: | 873 | case PTRACE_GETCRUNCHREGS: |
901 | ret = ptrace_getcrunchregs(child, (void __user *)data); | 874 | ret = ptrace_getcrunchregs(child, datap); |
902 | break; | 875 | break; |
903 | 876 | ||
904 | case PTRACE_SETCRUNCHREGS: | 877 | case PTRACE_SETCRUNCHREGS: |
905 | ret = ptrace_setcrunchregs(child, (void __user *)data); | 878 | ret = ptrace_setcrunchregs(child, datap); |
906 | break; | 879 | break; |
907 | #endif | 880 | #endif |
908 | 881 | ||
909 | #ifdef CONFIG_VFP | 882 | #ifdef CONFIG_VFP |
910 | case PTRACE_GETVFPREGS: | 883 | case PTRACE_GETVFPREGS: |
911 | ret = ptrace_getvfpregs(child, (void __user *)data); | 884 | ret = copy_regset_to_user(child, |
885 | &user_arm_view, REGSET_VFP, | ||
886 | 0, ARM_VFPREGS_SIZE, | ||
887 | datap); | ||
912 | break; | 888 | break; |
913 | 889 | ||
914 | case PTRACE_SETVFPREGS: | 890 | case PTRACE_SETVFPREGS: |
915 | ret = ptrace_setvfpregs(child, (void __user *)data); | 891 | ret = copy_regset_from_user(child, |
892 | &user_arm_view, REGSET_VFP, | ||
893 | 0, ARM_VFPREGS_SIZE, | ||
894 | datap); | ||
895 | break; | ||
896 | #endif | ||
897 | |||
898 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
899 | case PTRACE_GETHBPREGS: | ||
900 | if (ptrace_get_breakpoints(child) < 0) | ||
901 | return -ESRCH; | ||
902 | |||
903 | ret = ptrace_gethbpregs(child, addr, | ||
904 | (unsigned long __user *)data); | ||
905 | ptrace_put_breakpoints(child); | ||
906 | break; | ||
907 | case PTRACE_SETHBPREGS: | ||
908 | if (ptrace_get_breakpoints(child) < 0) | ||
909 | return -ESRCH; | ||
910 | |||
911 | ret = ptrace_sethbpregs(child, addr, | ||
912 | (unsigned long __user *)data); | ||
913 | ptrace_put_breakpoints(child); | ||
916 | break; | 914 | break; |
917 | #endif | 915 | #endif |
918 | 916 | ||
diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h deleted file mode 100644 index 3926605b82ea..000000000000 --- a/arch/arm/kernel/ptrace.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/ptrace.h | ||
3 | * | ||
4 | * Copyright (C) 2000-2003 Russell King | ||
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 | #include <linux/ptrace.h> | ||
11 | |||
12 | extern void ptrace_cancel_bpt(struct task_struct *); | ||
13 | extern void ptrace_set_bpt(struct task_struct *); | ||
14 | extern void ptrace_break(struct task_struct *, struct pt_regs *); | ||
15 | |||
16 | /* | ||
17 | * Send SIGTRAP if we're single-stepping | ||
18 | */ | ||
19 | static inline void single_step_trap(struct task_struct *task) | ||
20 | { | ||
21 | if (task->ptrace & PT_SINGLESTEP) { | ||
22 | ptrace_cancel_bpt(task); | ||
23 | send_sig(SIGTRAP, task, 1); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | static inline void single_step_clear(struct task_struct *task) | ||
28 | { | ||
29 | if (task->ptrace & PT_SINGLESTEP) | ||
30 | ptrace_cancel_bpt(task); | ||
31 | } | ||
32 | |||
33 | static inline void single_step_set(struct task_struct *task) | ||
34 | { | ||
35 | if (task->ptrace & PT_SINGLESTEP) | ||
36 | ptrace_set_bpt(task); | ||
37 | } | ||
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index fd26f8d65151..9cf4cbf8f95b 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S | |||
@@ -59,6 +59,8 @@ relocate_new_kernel: | |||
59 | ldr r2,kexec_boot_atags | 59 | ldr r2,kexec_boot_atags |
60 | mov pc,lr | 60 | mov pc,lr |
61 | 61 | ||
62 | .align | ||
63 | |||
62 | .globl kexec_start_address | 64 | .globl kexec_start_address |
63 | kexec_start_address: | 65 | kexec_start_address: |
64 | .long 0x0 | 66 | .long 0x0 |
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c index df246da4ceca..0b13a72f855d 100644 --- a/arch/arm/kernel/return_address.c +++ b/arch/arm/kernel/return_address.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * the Free Software Foundation. | 9 | * the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/ftrace.h> | ||
12 | 13 | ||
13 | #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) | 14 | #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) |
14 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c new file mode 100644 index 000000000000..9a46370fe9da --- /dev/null +++ b/arch/arm/kernel/sched_clock.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * sched_clock.c: support for extending counters to full 64-bit ns counter | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/clocksource.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/jiffies.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/timer.h> | ||
14 | |||
15 | #include <asm/sched_clock.h> | ||
16 | |||
17 | static void sched_clock_poll(unsigned long wrap_ticks); | ||
18 | static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0); | ||
19 | static void (*sched_clock_update_fn)(void); | ||
20 | |||
21 | static void sched_clock_poll(unsigned long wrap_ticks) | ||
22 | { | ||
23 | mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks)); | ||
24 | sched_clock_update_fn(); | ||
25 | } | ||
26 | |||
27 | void __init init_sched_clock(struct clock_data *cd, void (*update)(void), | ||
28 | unsigned int clock_bits, unsigned long rate) | ||
29 | { | ||
30 | unsigned long r, w; | ||
31 | u64 res, wrap; | ||
32 | char r_unit; | ||
33 | |||
34 | sched_clock_update_fn = update; | ||
35 | |||
36 | /* calculate the mult/shift to convert counter ticks to ns. */ | ||
37 | clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 0); | ||
38 | |||
39 | r = rate; | ||
40 | if (r >= 4000000) { | ||
41 | r /= 1000000; | ||
42 | r_unit = 'M'; | ||
43 | } else { | ||
44 | r /= 1000; | ||
45 | r_unit = 'k'; | ||
46 | } | ||
47 | |||
48 | /* calculate how many ns until we wrap */ | ||
49 | wrap = cyc_to_ns((1ULL << clock_bits) - 1, cd->mult, cd->shift); | ||
50 | do_div(wrap, NSEC_PER_MSEC); | ||
51 | w = wrap; | ||
52 | |||
53 | /* calculate the ns resolution of this counter */ | ||
54 | res = cyc_to_ns(1ULL, cd->mult, cd->shift); | ||
55 | pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n", | ||
56 | clock_bits, r, r_unit, res, w); | ||
57 | |||
58 | /* | ||
59 | * Start the timer to keep sched_clock() properly updated and | ||
60 | * sets the initial epoch. | ||
61 | */ | ||
62 | sched_clock_timer.data = msecs_to_jiffies(w - (w / 10)); | ||
63 | update(); | ||
64 | |||
65 | /* | ||
66 | * Ensure that sched_clock() starts off at 0ns | ||
67 | */ | ||
68 | cd->epoch_ns = 0; | ||
69 | } | ||
70 | |||
71 | void __init sched_clock_postinit(void) | ||
72 | { | ||
73 | sched_clock_poll(sched_clock_timer.data); | ||
74 | } | ||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index d5231ae7355a..acbb447ac6b5 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/screen_info.h> | 20 | #include <linux/screen_info.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/kexec.h> | 22 | #include <linux/kexec.h> |
23 | #include <linux/of_fdt.h> | ||
23 | #include <linux/crash_dump.h> | 24 | #include <linux/crash_dump.h> |
24 | #include <linux/root_dev.h> | 25 | #include <linux/root_dev.h> |
25 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
@@ -36,11 +37,13 @@ | |||
36 | #include <asm/procinfo.h> | 37 | #include <asm/procinfo.h> |
37 | #include <asm/sections.h> | 38 | #include <asm/sections.h> |
38 | #include <asm/setup.h> | 39 | #include <asm/setup.h> |
40 | #include <asm/smp_plat.h> | ||
39 | #include <asm/mach-types.h> | 41 | #include <asm/mach-types.h> |
40 | #include <asm/cacheflush.h> | 42 | #include <asm/cacheflush.h> |
41 | #include <asm/cachetype.h> | 43 | #include <asm/cachetype.h> |
42 | #include <asm/tlbflush.h> | 44 | #include <asm/tlbflush.h> |
43 | 45 | ||
46 | #include <asm/prom.h> | ||
44 | #include <asm/mach/arch.h> | 47 | #include <asm/mach/arch.h> |
45 | #include <asm/mach/irq.h> | 48 | #include <asm/mach/irq.h> |
46 | #include <asm/mach/time.h> | 49 | #include <asm/mach/time.h> |
@@ -70,13 +73,14 @@ __setup("fpe=", fpe_setup); | |||
70 | #endif | 73 | #endif |
71 | 74 | ||
72 | extern void paging_init(struct machine_desc *desc); | 75 | extern void paging_init(struct machine_desc *desc); |
76 | extern void sanity_check_meminfo(void); | ||
73 | extern void reboot_setup(char *str); | 77 | extern void reboot_setup(char *str); |
74 | 78 | ||
75 | unsigned int processor_id; | 79 | unsigned int processor_id; |
76 | EXPORT_SYMBOL(processor_id); | 80 | EXPORT_SYMBOL(processor_id); |
77 | unsigned int __machine_arch_type; | 81 | unsigned int __machine_arch_type __read_mostly; |
78 | EXPORT_SYMBOL(__machine_arch_type); | 82 | EXPORT_SYMBOL(__machine_arch_type); |
79 | unsigned int cacheid; | 83 | unsigned int cacheid __read_mostly; |
80 | EXPORT_SYMBOL(cacheid); | 84 | EXPORT_SYMBOL(cacheid); |
81 | 85 | ||
82 | unsigned int __atags_pointer __initdata; | 86 | unsigned int __atags_pointer __initdata; |
@@ -90,24 +94,24 @@ EXPORT_SYMBOL(system_serial_low); | |||
90 | unsigned int system_serial_high; | 94 | unsigned int system_serial_high; |
91 | EXPORT_SYMBOL(system_serial_high); | 95 | EXPORT_SYMBOL(system_serial_high); |
92 | 96 | ||
93 | unsigned int elf_hwcap; | 97 | unsigned int elf_hwcap __read_mostly; |
94 | EXPORT_SYMBOL(elf_hwcap); | 98 | EXPORT_SYMBOL(elf_hwcap); |
95 | 99 | ||
96 | 100 | ||
97 | #ifdef MULTI_CPU | 101 | #ifdef MULTI_CPU |
98 | struct processor processor; | 102 | struct processor processor __read_mostly; |
99 | #endif | 103 | #endif |
100 | #ifdef MULTI_TLB | 104 | #ifdef MULTI_TLB |
101 | struct cpu_tlb_fns cpu_tlb; | 105 | struct cpu_tlb_fns cpu_tlb __read_mostly; |
102 | #endif | 106 | #endif |
103 | #ifdef MULTI_USER | 107 | #ifdef MULTI_USER |
104 | struct cpu_user_fns cpu_user; | 108 | struct cpu_user_fns cpu_user __read_mostly; |
105 | #endif | 109 | #endif |
106 | #ifdef MULTI_CACHE | 110 | #ifdef MULTI_CACHE |
107 | struct cpu_cache_fns cpu_cache; | 111 | struct cpu_cache_fns cpu_cache __read_mostly; |
108 | #endif | 112 | #endif |
109 | #ifdef CONFIG_OUTER_CACHE | 113 | #ifdef CONFIG_OUTER_CACHE |
110 | struct outer_cache_fns outer_cache; | 114 | struct outer_cache_fns outer_cache __read_mostly; |
111 | EXPORT_SYMBOL(outer_cache); | 115 | EXPORT_SYMBOL(outer_cache); |
112 | #endif | 116 | #endif |
113 | 117 | ||
@@ -125,6 +129,7 @@ EXPORT_SYMBOL(elf_platform); | |||
125 | static const char *cpu_name; | 129 | static const char *cpu_name; |
126 | static const char *machine_name; | 130 | static const char *machine_name; |
127 | static char __initdata cmd_line[COMMAND_LINE_SIZE]; | 131 | static char __initdata cmd_line[COMMAND_LINE_SIZE]; |
132 | struct machine_desc *machine_desc __initdata; | ||
128 | 133 | ||
129 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | 134 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; |
130 | static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; | 135 | static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; |
@@ -224,8 +229,8 @@ int cpu_architecture(void) | |||
224 | * Register 0 and check for VMSAv7 or PMSAv7 */ | 229 | * Register 0 and check for VMSAv7 or PMSAv7 */ |
225 | asm("mrc p15, 0, %0, c0, c1, 4" | 230 | asm("mrc p15, 0, %0, c0, c1, 4" |
226 | : "=r" (mmfr0)); | 231 | : "=r" (mmfr0)); |
227 | if ((mmfr0 & 0x0000000f) == 0x00000003 || | 232 | if ((mmfr0 & 0x0000000f) >= 0x00000003 || |
228 | (mmfr0 & 0x000000f0) == 0x00000030) | 233 | (mmfr0 & 0x000000f0) >= 0x00000030) |
229 | cpu_arch = CPU_ARCH_ARMv7; | 234 | cpu_arch = CPU_ARCH_ARMv7; |
230 | else if ((mmfr0 & 0x0000000f) == 0x00000002 || | 235 | else if ((mmfr0 & 0x0000000f) == 0x00000002 || |
231 | (mmfr0 & 0x000000f0) == 0x00000020) | 236 | (mmfr0 & 0x000000f0) == 0x00000020) |
@@ -238,6 +243,35 @@ int cpu_architecture(void) | |||
238 | return cpu_arch; | 243 | return cpu_arch; |
239 | } | 244 | } |
240 | 245 | ||
246 | static int cpu_has_aliasing_icache(unsigned int arch) | ||
247 | { | ||
248 | int aliasing_icache; | ||
249 | unsigned int id_reg, num_sets, line_size; | ||
250 | |||
251 | /* arch specifies the register format */ | ||
252 | switch (arch) { | ||
253 | case CPU_ARCH_ARMv7: | ||
254 | asm("mcr p15, 2, %0, c0, c0, 0 @ set CSSELR" | ||
255 | : /* No output operands */ | ||
256 | : "r" (1)); | ||
257 | isb(); | ||
258 | asm("mrc p15, 1, %0, c0, c0, 0 @ read CCSIDR" | ||
259 | : "=r" (id_reg)); | ||
260 | line_size = 4 << ((id_reg & 0x7) + 2); | ||
261 | num_sets = ((id_reg >> 13) & 0x7fff) + 1; | ||
262 | aliasing_icache = (line_size * num_sets) > PAGE_SIZE; | ||
263 | break; | ||
264 | case CPU_ARCH_ARMv6: | ||
265 | aliasing_icache = read_cpuid_cachetype() & (1 << 11); | ||
266 | break; | ||
267 | default: | ||
268 | /* I-cache aliases will be handled by D-cache aliasing code */ | ||
269 | aliasing_icache = 0; | ||
270 | } | ||
271 | |||
272 | return aliasing_icache; | ||
273 | } | ||
274 | |||
241 | static void __init cacheid_init(void) | 275 | static void __init cacheid_init(void) |
242 | { | 276 | { |
243 | unsigned int cachetype = read_cpuid_cachetype(); | 277 | unsigned int cachetype = read_cpuid_cachetype(); |
@@ -249,10 +283,15 @@ static void __init cacheid_init(void) | |||
249 | cacheid = CACHEID_VIPT_NONALIASING; | 283 | cacheid = CACHEID_VIPT_NONALIASING; |
250 | if ((cachetype & (3 << 14)) == 1 << 14) | 284 | if ((cachetype & (3 << 14)) == 1 << 14) |
251 | cacheid |= CACHEID_ASID_TAGGED; | 285 | cacheid |= CACHEID_ASID_TAGGED; |
252 | } else if (cachetype & (1 << 23)) | 286 | else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7)) |
287 | cacheid |= CACHEID_VIPT_I_ALIASING; | ||
288 | } else if (cachetype & (1 << 23)) { | ||
253 | cacheid = CACHEID_VIPT_ALIASING; | 289 | cacheid = CACHEID_VIPT_ALIASING; |
254 | else | 290 | } else { |
255 | cacheid = CACHEID_VIPT_NONALIASING; | 291 | cacheid = CACHEID_VIPT_NONALIASING; |
292 | if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6)) | ||
293 | cacheid |= CACHEID_VIPT_I_ALIASING; | ||
294 | } | ||
256 | } else { | 295 | } else { |
257 | cacheid = CACHEID_VIVT; | 296 | cacheid = CACHEID_VIVT; |
258 | } | 297 | } |
@@ -263,7 +302,7 @@ static void __init cacheid_init(void) | |||
263 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", | 302 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown", |
264 | cache_is_vivt() ? "VIVT" : | 303 | cache_is_vivt() ? "VIVT" : |
265 | icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : | 304 | icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" : |
266 | cache_is_vipt_aliasing() ? "VIPT aliasing" : | 305 | icache_is_vipt_aliasing() ? "VIPT aliasing" : |
267 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); | 306 | cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown"); |
268 | } | 307 | } |
269 | 308 | ||
@@ -272,7 +311,22 @@ static void __init cacheid_init(void) | |||
272 | * already provide the required functionality. | 311 | * already provide the required functionality. |
273 | */ | 312 | */ |
274 | extern struct proc_info_list *lookup_processor_type(unsigned int); | 313 | extern struct proc_info_list *lookup_processor_type(unsigned int); |
275 | extern struct machine_desc *lookup_machine_type(unsigned int); | 314 | |
315 | void __init early_print(const char *str, ...) | ||
316 | { | ||
317 | extern void printascii(const char *); | ||
318 | char buf[256]; | ||
319 | va_list ap; | ||
320 | |||
321 | va_start(ap, str); | ||
322 | vsnprintf(buf, sizeof(buf), str, ap); | ||
323 | va_end(ap); | ||
324 | |||
325 | #ifdef CONFIG_DEBUG_LL | ||
326 | printascii(buf); | ||
327 | #endif | ||
328 | printk("%s", buf); | ||
329 | } | ||
276 | 330 | ||
277 | static void __init feat_v6_fixup(void) | 331 | static void __init feat_v6_fixup(void) |
278 | { | 332 | { |
@@ -388,32 +442,27 @@ void cpu_init(void) | |||
388 | : "r14"); | 442 | : "r14"); |
389 | } | 443 | } |
390 | 444 | ||
391 | static struct machine_desc * __init setup_machine(unsigned int nr) | 445 | void __init dump_machine_table(void) |
392 | { | 446 | { |
393 | struct machine_desc *list; | 447 | struct machine_desc *p; |
394 | 448 | ||
395 | /* | 449 | early_print("Available machine support:\n\nID (hex)\tNAME\n"); |
396 | * locate machine in the list of supported machines. | 450 | for_each_machine_desc(p) |
397 | */ | 451 | early_print("%08x\t%s\n", p->nr, p->name); |
398 | list = lookup_machine_type(nr); | ||
399 | if (!list) { | ||
400 | printk("Machine configuration botched (nr %d), unable " | ||
401 | "to continue.\n", nr); | ||
402 | while (1); | ||
403 | } | ||
404 | 452 | ||
405 | printk("Machine: %s\n", list->name); | 453 | early_print("\nPlease check your kernel config and/or bootloader.\n"); |
406 | 454 | ||
407 | return list; | 455 | while (true) |
456 | /* can't use cpu_relax() here as it may require MMU setup */; | ||
408 | } | 457 | } |
409 | 458 | ||
410 | static int __init arm_add_memory(unsigned long start, unsigned long size) | 459 | int __init arm_add_memory(phys_addr_t start, unsigned long size) |
411 | { | 460 | { |
412 | struct membank *bank = &meminfo.bank[meminfo.nr_banks]; | 461 | struct membank *bank = &meminfo.bank[meminfo.nr_banks]; |
413 | 462 | ||
414 | if (meminfo.nr_banks >= NR_BANKS) { | 463 | if (meminfo.nr_banks >= NR_BANKS) { |
415 | printk(KERN_CRIT "NR_BANKS too low, " | 464 | printk(KERN_CRIT "NR_BANKS too low, " |
416 | "ignoring memory at %#lx\n", start); | 465 | "ignoring memory at 0x%08llx\n", (long long)start); |
417 | return -EINVAL; | 466 | return -EINVAL; |
418 | } | 467 | } |
419 | 468 | ||
@@ -443,7 +492,8 @@ static int __init arm_add_memory(unsigned long start, unsigned long size) | |||
443 | static int __init early_mem(char *p) | 492 | static int __init early_mem(char *p) |
444 | { | 493 | { |
445 | static int usermem __initdata = 0; | 494 | static int usermem __initdata = 0; |
446 | unsigned long size, start; | 495 | unsigned long size; |
496 | phys_addr_t start; | ||
447 | char *endp; | 497 | char *endp; |
448 | 498 | ||
449 | /* | 499 | /* |
@@ -482,25 +532,21 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) | |||
482 | #endif | 532 | #endif |
483 | } | 533 | } |
484 | 534 | ||
485 | static void __init | 535 | static void __init request_standard_resources(struct machine_desc *mdesc) |
486 | request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) | ||
487 | { | 536 | { |
537 | struct memblock_region *region; | ||
488 | struct resource *res; | 538 | struct resource *res; |
489 | int i; | ||
490 | 539 | ||
491 | kernel_code.start = virt_to_phys(_text); | 540 | kernel_code.start = virt_to_phys(_text); |
492 | kernel_code.end = virt_to_phys(_etext - 1); | 541 | kernel_code.end = virt_to_phys(_etext - 1); |
493 | kernel_data.start = virt_to_phys(_data); | 542 | kernel_data.start = virt_to_phys(_sdata); |
494 | kernel_data.end = virt_to_phys(_end - 1); | 543 | kernel_data.end = virt_to_phys(_end - 1); |
495 | 544 | ||
496 | for (i = 0; i < mi->nr_banks; i++) { | 545 | for_each_memblock(memory, region) { |
497 | if (mi->bank[i].size == 0) | ||
498 | continue; | ||
499 | |||
500 | res = alloc_bootmem_low(sizeof(*res)); | 546 | res = alloc_bootmem_low(sizeof(*res)); |
501 | res->name = "System RAM"; | 547 | res->name = "System RAM"; |
502 | res->start = mi->bank[i].start; | 548 | res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); |
503 | res->end = mi->bank[i].start + mi->bank[i].size - 1; | 549 | res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; |
504 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 550 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
505 | 551 | ||
506 | request_resource(&iomem_resource, res); | 552 | request_resource(&iomem_resource, res); |
@@ -614,15 +660,22 @@ static int __init parse_tag_revision(const struct tag *tag) | |||
614 | 660 | ||
615 | __tagtable(ATAG_REVISION, parse_tag_revision); | 661 | __tagtable(ATAG_REVISION, parse_tag_revision); |
616 | 662 | ||
617 | #ifndef CONFIG_CMDLINE_FORCE | ||
618 | static int __init parse_tag_cmdline(const struct tag *tag) | 663 | static int __init parse_tag_cmdline(const struct tag *tag) |
619 | { | 664 | { |
620 | strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); | 665 | #if defined(CONFIG_CMDLINE_EXTEND) |
666 | strlcat(default_command_line, " ", COMMAND_LINE_SIZE); | ||
667 | strlcat(default_command_line, tag->u.cmdline.cmdline, | ||
668 | COMMAND_LINE_SIZE); | ||
669 | #elif defined(CONFIG_CMDLINE_FORCE) | ||
670 | pr_warning("Ignoring tag cmdline (using the default kernel command line)\n"); | ||
671 | #else | ||
672 | strlcpy(default_command_line, tag->u.cmdline.cmdline, | ||
673 | COMMAND_LINE_SIZE); | ||
674 | #endif | ||
621 | return 0; | 675 | return 0; |
622 | } | 676 | } |
623 | 677 | ||
624 | __tagtable(ATAG_CMDLINE, parse_tag_cmdline); | 678 | __tagtable(ATAG_CMDLINE, parse_tag_cmdline); |
625 | #endif /* CONFIG_CMDLINE_FORCE */ | ||
626 | 679 | ||
627 | /* | 680 | /* |
628 | * Scan the tag table for this tag, and call its parse function. | 681 | * Scan the tag table for this tag, and call its parse function. |
@@ -669,17 +722,15 @@ static struct init_tags { | |||
669 | { tag_size(tag_core), ATAG_CORE }, | 722 | { tag_size(tag_core), ATAG_CORE }, |
670 | { 1, PAGE_SIZE, 0xff }, | 723 | { 1, PAGE_SIZE, 0xff }, |
671 | { tag_size(tag_mem32), ATAG_MEM }, | 724 | { tag_size(tag_mem32), ATAG_MEM }, |
672 | { MEM_SIZE, PHYS_OFFSET }, | 725 | { MEM_SIZE }, |
673 | { 0, ATAG_NONE } | 726 | { 0, ATAG_NONE } |
674 | }; | 727 | }; |
675 | 728 | ||
676 | static void (*init_machine)(void) __initdata; | ||
677 | |||
678 | static int __init customize_machine(void) | 729 | static int __init customize_machine(void) |
679 | { | 730 | { |
680 | /* customizes platform devices, or adds new ones */ | 731 | /* customizes platform devices, or adds new ones */ |
681 | if (init_machine) | 732 | if (machine_desc->init_machine) |
682 | init_machine(); | 733 | machine_desc->init_machine(); |
683 | return 0; | 734 | return 0; |
684 | } | 735 | } |
685 | arch_initcall(customize_machine); | 736 | arch_initcall(customize_machine); |
@@ -733,30 +784,6 @@ static void __init reserve_crashkernel(void) | |||
733 | static inline void reserve_crashkernel(void) {} | 784 | static inline void reserve_crashkernel(void) {} |
734 | #endif /* CONFIG_KEXEC */ | 785 | #endif /* CONFIG_KEXEC */ |
735 | 786 | ||
736 | /* | ||
737 | * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by | ||
738 | * is_kdump_kernel() to determine if we are booting after a panic. Hence | ||
739 | * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE. | ||
740 | */ | ||
741 | |||
742 | #ifdef CONFIG_CRASH_DUMP | ||
743 | /* | ||
744 | * elfcorehdr= specifies the location of elf core header stored by the crashed | ||
745 | * kernel. This option will be passed by kexec loader to the capture kernel. | ||
746 | */ | ||
747 | static int __init setup_elfcorehdr(char *arg) | ||
748 | { | ||
749 | char *end; | ||
750 | |||
751 | if (!arg) | ||
752 | return -EINVAL; | ||
753 | |||
754 | elfcorehdr_addr = memparse(arg, &end); | ||
755 | return end > arg ? 0 : -EINVAL; | ||
756 | } | ||
757 | early_param("elfcorehdr", setup_elfcorehdr); | ||
758 | #endif /* CONFIG_CRASH_DUMP */ | ||
759 | |||
760 | static void __init squash_mem_tags(struct tag *tag) | 787 | static void __init squash_mem_tags(struct tag *tag) |
761 | { | 788 | { |
762 | for (; tag->hdr.size; tag = tag_next(tag)) | 789 | for (; tag->hdr.size; tag = tag_next(tag)) |
@@ -764,25 +791,51 @@ static void __init squash_mem_tags(struct tag *tag) | |||
764 | tag->hdr.tag = ATAG_NONE; | 791 | tag->hdr.tag = ATAG_NONE; |
765 | } | 792 | } |
766 | 793 | ||
767 | void __init setup_arch(char **cmdline_p) | 794 | static struct machine_desc * __init setup_machine_tags(unsigned int nr) |
768 | { | 795 | { |
769 | struct tag *tags = (struct tag *)&init_tags; | 796 | struct tag *tags = (struct tag *)&init_tags; |
770 | struct machine_desc *mdesc; | 797 | struct machine_desc *mdesc = NULL, *p; |
771 | char *from = default_command_line; | 798 | char *from = default_command_line; |
772 | 799 | ||
773 | unwind_init(); | 800 | init_tags.mem.start = PHYS_OFFSET; |
774 | 801 | ||
775 | setup_processor(); | 802 | /* |
776 | mdesc = setup_machine(machine_arch_type); | 803 | * locate machine in the list of supported machines. |
777 | machine_name = mdesc->name; | 804 | */ |
805 | for_each_machine_desc(p) | ||
806 | if (nr == p->nr) { | ||
807 | printk("Machine: %s\n", p->name); | ||
808 | mdesc = p; | ||
809 | break; | ||
810 | } | ||
778 | 811 | ||
779 | if (mdesc->soft_reboot) | 812 | if (!mdesc) { |
780 | reboot_setup("s"); | 813 | early_print("\nError: unrecognized/unsupported machine ID" |
814 | " (r1 = 0x%08x).\n\n", nr); | ||
815 | dump_machine_table(); /* does not return */ | ||
816 | } | ||
781 | 817 | ||
782 | if (__atags_pointer) | 818 | if (__atags_pointer) |
783 | tags = phys_to_virt(__atags_pointer); | 819 | tags = phys_to_virt(__atags_pointer); |
784 | else if (mdesc->boot_params) | 820 | else if (mdesc->boot_params) { |
785 | tags = phys_to_virt(mdesc->boot_params); | 821 | #ifdef CONFIG_MMU |
822 | /* | ||
823 | * We still are executing with a minimal MMU mapping created | ||
824 | * with the presumption that the machine default for this | ||
825 | * is located in the first MB of RAM. Anything else will | ||
826 | * fault and silently hang the kernel at this point. | ||
827 | */ | ||
828 | if (mdesc->boot_params < PHYS_OFFSET || | ||
829 | mdesc->boot_params >= PHYS_OFFSET + SZ_1M) { | ||
830 | printk(KERN_WARNING | ||
831 | "Default boot params at physical 0x%08lx out of reach\n", | ||
832 | mdesc->boot_params); | ||
833 | } else | ||
834 | #endif | ||
835 | { | ||
836 | tags = phys_to_virt(mdesc->boot_params); | ||
837 | } | ||
838 | } | ||
786 | 839 | ||
787 | #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) | 840 | #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) |
788 | /* | 841 | /* |
@@ -792,8 +845,17 @@ void __init setup_arch(char **cmdline_p) | |||
792 | if (tags->hdr.tag != ATAG_CORE) | 845 | if (tags->hdr.tag != ATAG_CORE) |
793 | convert_to_tag_list(tags); | 846 | convert_to_tag_list(tags); |
794 | #endif | 847 | #endif |
795 | if (tags->hdr.tag != ATAG_CORE) | 848 | |
849 | if (tags->hdr.tag != ATAG_CORE) { | ||
850 | #if defined(CONFIG_OF) | ||
851 | /* | ||
852 | * If CONFIG_OF is set, then assume this is a reasonably | ||
853 | * modern system that should pass boot parameters | ||
854 | */ | ||
855 | early_print("Warning: Neither atags nor dtb found\n"); | ||
856 | #endif | ||
796 | tags = (struct tag *)&init_tags; | 857 | tags = (struct tag *)&init_tags; |
858 | } | ||
797 | 859 | ||
798 | if (mdesc->fixup) | 860 | if (mdesc->fixup) |
799 | mdesc->fixup(mdesc, tags, &from, &meminfo); | 861 | mdesc->fixup(mdesc, tags, &from, &meminfo); |
@@ -805,40 +867,60 @@ void __init setup_arch(char **cmdline_p) | |||
805 | parse_tags(tags); | 867 | parse_tags(tags); |
806 | } | 868 | } |
807 | 869 | ||
870 | /* parse_early_param needs a boot_command_line */ | ||
871 | strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); | ||
872 | |||
873 | return mdesc; | ||
874 | } | ||
875 | |||
876 | |||
877 | void __init setup_arch(char **cmdline_p) | ||
878 | { | ||
879 | struct machine_desc *mdesc; | ||
880 | |||
881 | unwind_init(); | ||
882 | |||
883 | setup_processor(); | ||
884 | mdesc = setup_machine_fdt(__atags_pointer); | ||
885 | if (!mdesc) | ||
886 | mdesc = setup_machine_tags(machine_arch_type); | ||
887 | machine_desc = mdesc; | ||
888 | machine_name = mdesc->name; | ||
889 | |||
890 | if (mdesc->soft_reboot) | ||
891 | reboot_setup("s"); | ||
892 | |||
808 | init_mm.start_code = (unsigned long) _text; | 893 | init_mm.start_code = (unsigned long) _text; |
809 | init_mm.end_code = (unsigned long) _etext; | 894 | init_mm.end_code = (unsigned long) _etext; |
810 | init_mm.end_data = (unsigned long) _edata; | 895 | init_mm.end_data = (unsigned long) _edata; |
811 | init_mm.brk = (unsigned long) _end; | 896 | init_mm.brk = (unsigned long) _end; |
812 | 897 | ||
813 | /* parse_early_param needs a boot_command_line */ | ||
814 | strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); | ||
815 | |||
816 | /* populate cmd_line too for later use, preserving boot_command_line */ | 898 | /* populate cmd_line too for later use, preserving boot_command_line */ |
817 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | 899 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); |
818 | *cmdline_p = cmd_line; | 900 | *cmdline_p = cmd_line; |
819 | 901 | ||
820 | parse_early_param(); | 902 | parse_early_param(); |
821 | 903 | ||
904 | sanity_check_meminfo(); | ||
822 | arm_memblock_init(&meminfo, mdesc); | 905 | arm_memblock_init(&meminfo, mdesc); |
823 | 906 | ||
824 | paging_init(mdesc); | 907 | paging_init(mdesc); |
825 | request_standard_resources(&meminfo, mdesc); | 908 | request_standard_resources(mdesc); |
909 | |||
910 | unflatten_device_tree(); | ||
826 | 911 | ||
827 | #ifdef CONFIG_SMP | 912 | #ifdef CONFIG_SMP |
828 | smp_init_cpus(); | 913 | if (is_smp()) |
914 | smp_init_cpus(); | ||
829 | #endif | 915 | #endif |
830 | reserve_crashkernel(); | 916 | reserve_crashkernel(); |
831 | 917 | ||
832 | cpu_init(); | 918 | cpu_init(); |
833 | tcm_init(); | 919 | tcm_init(); |
834 | 920 | ||
835 | /* | 921 | #ifdef CONFIG_MULTI_IRQ_HANDLER |
836 | * Set up various architecture-specific pointers | 922 | handle_arch_irq = mdesc->handle_irq; |
837 | */ | 923 | #endif |
838 | arch_nr_irqs = mdesc->nr_irqs; | ||
839 | init_arch_irq = mdesc->init_irq; | ||
840 | system_timer = mdesc->timer; | ||
841 | init_machine = mdesc->init_machine; | ||
842 | 924 | ||
843 | #ifdef CONFIG_VT | 925 | #ifdef CONFIG_VT |
844 | #if defined(CONFIG_VGA_CONSOLE) | 926 | #if defined(CONFIG_VGA_CONSOLE) |
@@ -848,6 +930,9 @@ void __init setup_arch(char **cmdline_p) | |||
848 | #endif | 930 | #endif |
849 | #endif | 931 | #endif |
850 | early_trap_init(); | 932 | early_trap_init(); |
933 | |||
934 | if (mdesc->init_early) | ||
935 | mdesc->init_early(); | ||
851 | } | 936 | } |
852 | 937 | ||
853 | 938 | ||
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 907d5a620bca..0340224cf73c 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
21 | #include <asm/vfp.h> | 21 | #include <asm/vfp.h> |
22 | 22 | ||
23 | #include "ptrace.h" | ||
24 | #include "signal.h" | 23 | #include "signal.h" |
25 | 24 | ||
26 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 25 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -348,8 +347,6 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) | |||
348 | if (restore_sigframe(regs, frame)) | 347 | if (restore_sigframe(regs, frame)) |
349 | goto badframe; | 348 | goto badframe; |
350 | 349 | ||
351 | single_step_trap(current); | ||
352 | |||
353 | return regs->ARM_r0; | 350 | return regs->ARM_r0; |
354 | 351 | ||
355 | badframe: | 352 | badframe: |
@@ -383,8 +380,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
383 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) | 380 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) |
384 | goto badframe; | 381 | goto badframe; |
385 | 382 | ||
386 | single_step_trap(current); | ||
387 | |||
388 | return regs->ARM_r0; | 383 | return regs->ARM_r0; |
389 | 384 | ||
390 | badframe: | 385 | badframe: |
@@ -474,7 +469,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, | |||
474 | unsigned long handler = (unsigned long)ka->sa.sa_handler; | 469 | unsigned long handler = (unsigned long)ka->sa.sa_handler; |
475 | unsigned long retcode; | 470 | unsigned long retcode; |
476 | int thumb = 0; | 471 | int thumb = 0; |
477 | unsigned long cpsr = regs->ARM_cpsr & ~PSR_f; | 472 | unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); |
473 | |||
474 | cpsr |= PSR_ENDSTATE; | ||
478 | 475 | ||
479 | /* | 476 | /* |
480 | * Maybe we need to deliver a 32-bit signal to a 26-bit task. | 477 | * Maybe we need to deliver a 32-bit signal to a 26-bit task. |
@@ -600,19 +597,13 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | |||
600 | return err; | 597 | return err; |
601 | } | 598 | } |
602 | 599 | ||
603 | static inline void setup_syscall_restart(struct pt_regs *regs) | ||
604 | { | ||
605 | regs->ARM_r0 = regs->ARM_ORIG_r0; | ||
606 | regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; | ||
607 | } | ||
608 | |||
609 | /* | 600 | /* |
610 | * OK, we're invoking a handler | 601 | * OK, we're invoking a handler |
611 | */ | 602 | */ |
612 | static int | 603 | static int |
613 | handle_signal(unsigned long sig, struct k_sigaction *ka, | 604 | handle_signal(unsigned long sig, struct k_sigaction *ka, |
614 | siginfo_t *info, sigset_t *oldset, | 605 | siginfo_t *info, sigset_t *oldset, |
615 | struct pt_regs * regs, int syscall) | 606 | struct pt_regs * regs) |
616 | { | 607 | { |
617 | struct thread_info *thread = current_thread_info(); | 608 | struct thread_info *thread = current_thread_info(); |
618 | struct task_struct *tsk = current; | 609 | struct task_struct *tsk = current; |
@@ -620,26 +611,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
620 | int ret; | 611 | int ret; |
621 | 612 | ||
622 | /* | 613 | /* |
623 | * If we were from a system call, check for system call restarting... | ||
624 | */ | ||
625 | if (syscall) { | ||
626 | switch (regs->ARM_r0) { | ||
627 | case -ERESTART_RESTARTBLOCK: | ||
628 | case -ERESTARTNOHAND: | ||
629 | regs->ARM_r0 = -EINTR; | ||
630 | break; | ||
631 | case -ERESTARTSYS: | ||
632 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
633 | regs->ARM_r0 = -EINTR; | ||
634 | break; | ||
635 | } | ||
636 | /* fallthrough */ | ||
637 | case -ERESTARTNOINTR: | ||
638 | setup_syscall_restart(regs); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * translate the signal | 614 | * translate the signal |
644 | */ | 615 | */ |
645 | if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) | 616 | if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) |
@@ -688,6 +659,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
688 | */ | 659 | */ |
689 | static void do_signal(struct pt_regs *regs, int syscall) | 660 | static void do_signal(struct pt_regs *regs, int syscall) |
690 | { | 661 | { |
662 | unsigned int retval = 0, continue_addr = 0, restart_addr = 0; | ||
691 | struct k_sigaction ka; | 663 | struct k_sigaction ka; |
692 | siginfo_t info; | 664 | siginfo_t info; |
693 | int signr; | 665 | int signr; |
@@ -701,20 +673,61 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
701 | if (!user_mode(regs)) | 673 | if (!user_mode(regs)) |
702 | return; | 674 | return; |
703 | 675 | ||
676 | /* | ||
677 | * If we were from a system call, check for system call restarting... | ||
678 | */ | ||
679 | if (syscall) { | ||
680 | continue_addr = regs->ARM_pc; | ||
681 | restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4); | ||
682 | retval = regs->ARM_r0; | ||
683 | |||
684 | /* | ||
685 | * Prepare for system call restart. We do this here so that a | ||
686 | * debugger will see the already changed PSW. | ||
687 | */ | ||
688 | switch (retval) { | ||
689 | case -ERESTARTNOHAND: | ||
690 | case -ERESTARTSYS: | ||
691 | case -ERESTARTNOINTR: | ||
692 | regs->ARM_r0 = regs->ARM_ORIG_r0; | ||
693 | regs->ARM_pc = restart_addr; | ||
694 | break; | ||
695 | case -ERESTART_RESTARTBLOCK: | ||
696 | regs->ARM_r0 = -EINTR; | ||
697 | break; | ||
698 | } | ||
699 | } | ||
700 | |||
704 | if (try_to_freeze()) | 701 | if (try_to_freeze()) |
705 | goto no_signal; | 702 | goto no_signal; |
706 | 703 | ||
707 | single_step_clear(current); | 704 | /* |
708 | 705 | * Get the signal to deliver. When running under ptrace, at this | |
706 | * point the debugger may change all our registers ... | ||
707 | */ | ||
709 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 708 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
710 | if (signr > 0) { | 709 | if (signr > 0) { |
711 | sigset_t *oldset; | 710 | sigset_t *oldset; |
712 | 711 | ||
712 | /* | ||
713 | * Depending on the signal settings we may need to revert the | ||
714 | * decision to restart the system call. But skip this if a | ||
715 | * debugger has chosen to restart at a different PC. | ||
716 | */ | ||
717 | if (regs->ARM_pc == restart_addr) { | ||
718 | if (retval == -ERESTARTNOHAND | ||
719 | || (retval == -ERESTARTSYS | ||
720 | && !(ka.sa.sa_flags & SA_RESTART))) { | ||
721 | regs->ARM_r0 = -EINTR; | ||
722 | regs->ARM_pc = continue_addr; | ||
723 | } | ||
724 | } | ||
725 | |||
713 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 726 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
714 | oldset = ¤t->saved_sigmask; | 727 | oldset = ¤t->saved_sigmask; |
715 | else | 728 | else |
716 | oldset = ¤t->blocked; | 729 | oldset = ¤t->blocked; |
717 | if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { | 730 | if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { |
718 | /* | 731 | /* |
719 | * A signal was successfully delivered; the saved | 732 | * A signal was successfully delivered; the saved |
720 | * sigmask will have been stored in the signal frame, | 733 | * sigmask will have been stored in the signal frame, |
@@ -724,16 +737,18 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
724 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 737 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
725 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 738 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
726 | } | 739 | } |
727 | single_step_set(current); | ||
728 | return; | 740 | return; |
729 | } | 741 | } |
730 | 742 | ||
731 | no_signal: | 743 | no_signal: |
732 | /* | ||
733 | * No signal to deliver to the process - restart the syscall. | ||
734 | */ | ||
735 | if (syscall) { | 744 | if (syscall) { |
736 | if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { | 745 | /* |
746 | * Handle restarting a different system call. As above, | ||
747 | * if a debugger has chosen to restart at a different PC, | ||
748 | * ignore the restart. | ||
749 | */ | ||
750 | if (retval == -ERESTART_RESTARTBLOCK | ||
751 | && regs->ARM_pc == continue_addr) { | ||
737 | if (thumb_mode(regs)) { | 752 | if (thumb_mode(regs)) { |
738 | regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; | 753 | regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; |
739 | regs->ARM_pc -= 2; | 754 | regs->ARM_pc -= 2; |
@@ -756,11 +771,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
756 | #endif | 771 | #endif |
757 | } | 772 | } |
758 | } | 773 | } |
759 | if (regs->ARM_r0 == -ERESTARTNOHAND || | ||
760 | regs->ARM_r0 == -ERESTARTSYS || | ||
761 | regs->ARM_r0 == -ERESTARTNOINTR) { | ||
762 | setup_syscall_restart(regs); | ||
763 | } | ||
764 | 774 | ||
765 | /* If there's no signal to deliver, we just put the saved sigmask | 775 | /* If there's no signal to deliver, we just put the saved sigmask |
766 | * back. | 776 | * back. |
@@ -770,7 +780,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
770 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 780 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
771 | } | 781 | } |
772 | } | 782 | } |
773 | single_step_set(current); | ||
774 | } | 783 | } |
775 | 784 | ||
776 | asmlinkage void | 785 | asmlinkage void |
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S new file mode 100644 index 000000000000..6398ead9d1c0 --- /dev/null +++ b/arch/arm/kernel/sleep.S | |||
@@ -0,0 +1,142 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <linux/threads.h> | ||
3 | #include <asm/asm-offsets.h> | ||
4 | #include <asm/assembler.h> | ||
5 | #include <asm/glue-cache.h> | ||
6 | #include <asm/glue-proc.h> | ||
7 | #include <asm/system.h> | ||
8 | .text | ||
9 | |||
10 | /* | ||
11 | * Save CPU state for a suspend | ||
12 | * r1 = v:p offset | ||
13 | * r3 = virtual return function | ||
14 | * Note: sp is decremented to allocate space for CPU state on stack | ||
15 | * r0-r3,r9,r10,lr corrupted | ||
16 | */ | ||
17 | ENTRY(cpu_suspend) | ||
18 | mov r9, lr | ||
19 | #ifdef MULTI_CPU | ||
20 | ldr r10, =processor | ||
21 | mov r2, sp @ current virtual SP | ||
22 | ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state | ||
23 | ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function | ||
24 | sub sp, sp, r0 @ allocate CPU state on stack | ||
25 | mov r0, sp @ save pointer | ||
26 | add ip, ip, r1 @ convert resume fn to phys | ||
27 | stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn | ||
28 | ldr r3, =sleep_save_sp | ||
29 | add r2, sp, r1 @ convert SP to phys | ||
30 | #ifdef CONFIG_SMP | ||
31 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | ||
32 | ALT_UP(mov lr, #0) | ||
33 | and lr, lr, #15 | ||
34 | str r2, [r3, lr, lsl #2] @ save phys SP | ||
35 | #else | ||
36 | str r2, [r3] @ save phys SP | ||
37 | #endif | ||
38 | mov lr, pc | ||
39 | ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state | ||
40 | #else | ||
41 | mov r2, sp @ current virtual SP | ||
42 | ldr r0, =cpu_suspend_size | ||
43 | sub sp, sp, r0 @ allocate CPU state on stack | ||
44 | mov r0, sp @ save pointer | ||
45 | stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn | ||
46 | ldr r3, =sleep_save_sp | ||
47 | add r2, sp, r1 @ convert SP to phys | ||
48 | #ifdef CONFIG_SMP | ||
49 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | ||
50 | ALT_UP(mov lr, #0) | ||
51 | and lr, lr, #15 | ||
52 | str r2, [r3, lr, lsl #2] @ save phys SP | ||
53 | #else | ||
54 | str r2, [r3] @ save phys SP | ||
55 | #endif | ||
56 | bl cpu_do_suspend | ||
57 | #endif | ||
58 | |||
59 | @ flush data cache | ||
60 | #ifdef MULTI_CACHE | ||
61 | ldr r10, =cpu_cache | ||
62 | mov lr, r9 | ||
63 | ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] | ||
64 | #else | ||
65 | mov lr, r9 | ||
66 | b __cpuc_flush_kern_all | ||
67 | #endif | ||
68 | ENDPROC(cpu_suspend) | ||
69 | .ltorg | ||
70 | |||
71 | /* | ||
72 | * r0 = control register value | ||
73 | * r1 = v:p offset (preserved by cpu_do_resume) | ||
74 | * r2 = phys page table base | ||
75 | * r3 = L1 section flags | ||
76 | */ | ||
77 | ENTRY(cpu_resume_mmu) | ||
78 | adr r4, cpu_resume_turn_mmu_on | ||
79 | mov r4, r4, lsr #20 | ||
80 | orr r3, r3, r4, lsl #20 | ||
81 | ldr r5, [r2, r4, lsl #2] @ save old mapping | ||
82 | str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code | ||
83 | sub r2, r2, r1 | ||
84 | ldr r3, =cpu_resume_after_mmu | ||
85 | bic r1, r0, #CR_C @ ensure D-cache is disabled | ||
86 | b cpu_resume_turn_mmu_on | ||
87 | ENDPROC(cpu_resume_mmu) | ||
88 | .ltorg | ||
89 | .align 5 | ||
90 | cpu_resume_turn_mmu_on: | ||
91 | mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc | ||
92 | mrc p15, 0, r1, c0, c0, 0 @ read id reg | ||
93 | mov r1, r1 | ||
94 | mov r1, r1 | ||
95 | mov pc, r3 @ jump to virtual address | ||
96 | ENDPROC(cpu_resume_turn_mmu_on) | ||
97 | cpu_resume_after_mmu: | ||
98 | str r5, [r2, r4, lsl #2] @ restore old mapping | ||
99 | mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache | ||
100 | mov pc, lr | ||
101 | ENDPROC(cpu_resume_after_mmu) | ||
102 | |||
103 | /* | ||
104 | * Note: Yes, part of the following code is located into the .data section. | ||
105 | * This is to allow sleep_save_sp to be accessed with a relative load | ||
106 | * while we can't rely on any MMU translation. We could have put | ||
107 | * sleep_save_sp in the .text section as well, but some setups might | ||
108 | * insist on it to be truly read-only. | ||
109 | */ | ||
110 | .data | ||
111 | .align | ||
112 | ENTRY(cpu_resume) | ||
113 | #ifdef CONFIG_SMP | ||
114 | adr r0, sleep_save_sp | ||
115 | ALT_SMP(mrc p15, 0, r1, c0, c0, 5) | ||
116 | ALT_UP(mov r1, #0) | ||
117 | and r1, r1, #15 | ||
118 | ldr r0, [r0, r1, lsl #2] @ stack phys addr | ||
119 | #else | ||
120 | ldr r0, sleep_save_sp @ stack phys addr | ||
121 | #endif | ||
122 | setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off | ||
123 | #ifdef MULTI_CPU | ||
124 | @ load v:p, stack, return fn, resume fn | ||
125 | ARM( ldmia r0!, {r1, sp, lr, pc} ) | ||
126 | THUMB( ldmia r0!, {r1, r2, r3, r4} ) | ||
127 | THUMB( mov sp, r2 ) | ||
128 | THUMB( mov lr, r3 ) | ||
129 | THUMB( bx r4 ) | ||
130 | #else | ||
131 | @ load v:p, stack, return fn | ||
132 | ARM( ldmia r0!, {r1, sp, lr} ) | ||
133 | THUMB( ldmia r0!, {r1, r2, lr} ) | ||
134 | THUMB( mov sp, r2 ) | ||
135 | b cpu_do_resume | ||
136 | #endif | ||
137 | ENDPROC(cpu_resume) | ||
138 | |||
139 | sleep_save_sp: | ||
140 | .rept CONFIG_NR_CPUS | ||
141 | .long 0 @ preserve stack phys ptr here | ||
142 | .endr | ||
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index b72fbf3d043c..5a574296ace0 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/cache.h> | 16 | #include <linux/cache.h> |
17 | #include <linux/profile.h> | 17 | #include <linux/profile.h> |
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/ftrace.h> | ||
19 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
20 | #include <linux/err.h> | 21 | #include <linux/err.h> |
21 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
@@ -24,6 +25,7 @@ | |||
24 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
25 | #include <linux/percpu.h> | 26 | #include <linux/percpu.h> |
26 | #include <linux/clockchips.h> | 27 | #include <linux/clockchips.h> |
28 | #include <linux/completion.h> | ||
27 | 29 | ||
28 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
29 | #include <asm/cacheflush.h> | 31 | #include <asm/cacheflush.h> |
@@ -33,10 +35,10 @@ | |||
33 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
34 | #include <asm/pgalloc.h> | 36 | #include <asm/pgalloc.h> |
35 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
38 | #include <asm/sections.h> | ||
36 | #include <asm/tlbflush.h> | 39 | #include <asm/tlbflush.h> |
37 | #include <asm/ptrace.h> | 40 | #include <asm/ptrace.h> |
38 | #include <asm/localtimer.h> | 41 | #include <asm/localtimer.h> |
39 | #include <asm/smp_plat.h> | ||
40 | 42 | ||
41 | #include <litmus/preempt.h> | 43 | #include <litmus/preempt.h> |
42 | 44 | ||
@@ -47,22 +49,8 @@ | |||
47 | */ | 49 | */ |
48 | struct secondary_data secondary_data; | 50 | struct secondary_data secondary_data; |
49 | 51 | ||
50 | /* | ||
51 | * structures for inter-processor calls | ||
52 | * - A collection of single bit ipi messages. | ||
53 | */ | ||
54 | struct ipi_data { | ||
55 | spinlock_t lock; | ||
56 | unsigned long ipi_count; | ||
57 | unsigned long bits; | ||
58 | }; | ||
59 | |||
60 | static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { | ||
61 | .lock = SPIN_LOCK_UNLOCKED, | ||
62 | }; | ||
63 | |||
64 | enum ipi_msg_type { | 52 | enum ipi_msg_type { |
65 | IPI_TIMER, | 53 | IPI_TIMER = 2, |
66 | IPI_RESCHEDULE, | 54 | IPI_RESCHEDULE, |
67 | IPI_CALL_FUNC, | 55 | IPI_CALL_FUNC, |
68 | IPI_CALL_FUNC_SINGLE, | 56 | IPI_CALL_FUNC_SINGLE, |
@@ -74,7 +62,6 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
74 | struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); | 62 | struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); |
75 | struct task_struct *idle = ci->idle; | 63 | struct task_struct *idle = ci->idle; |
76 | pgd_t *pgd; | 64 | pgd_t *pgd; |
77 | pmd_t *pmd; | ||
78 | int ret; | 65 | int ret; |
79 | 66 | ||
80 | /* | 67 | /* |
@@ -103,11 +90,16 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
103 | * a 1:1 mapping for the physical address of the kernel. | 90 | * a 1:1 mapping for the physical address of the kernel. |
104 | */ | 91 | */ |
105 | pgd = pgd_alloc(&init_mm); | 92 | pgd = pgd_alloc(&init_mm); |
106 | pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET); | 93 | if (!pgd) |
107 | *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) | | 94 | return -ENOMEM; |
108 | PMD_TYPE_SECT | PMD_SECT_AP_WRITE); | 95 | |
109 | flush_pmd_entry(pmd); | 96 | if (PHYS_OFFSET != PAGE_OFFSET) { |
110 | outer_clean_range(__pa(pmd), __pa(pmd + 1)); | 97 | #ifndef CONFIG_HOTPLUG_CPU |
98 | identity_mapping_add(pgd, __pa(__init_begin), __pa(__init_end)); | ||
99 | #endif | ||
100 | identity_mapping_add(pgd, __pa(_stext), __pa(_etext)); | ||
101 | identity_mapping_add(pgd, __pa(_sdata), __pa(_edata)); | ||
102 | } | ||
111 | 103 | ||
112 | /* | 104 | /* |
113 | * We need to tell the secondary core where to find | 105 | * We need to tell the secondary core where to find |
@@ -115,6 +107,7 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
115 | */ | 107 | */ |
116 | secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; | 108 | secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; |
117 | secondary_data.pgdir = virt_to_phys(pgd); | 109 | secondary_data.pgdir = virt_to_phys(pgd); |
110 | secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir); | ||
118 | __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data)); | 111 | __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data)); |
119 | outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); | 112 | outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); |
120 | 113 | ||
@@ -138,29 +131,33 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
138 | barrier(); | 131 | barrier(); |
139 | } | 132 | } |
140 | 133 | ||
141 | if (!cpu_online(cpu)) | 134 | if (!cpu_online(cpu)) { |
135 | pr_crit("CPU%u: failed to come online\n", cpu); | ||
142 | ret = -EIO; | 136 | ret = -EIO; |
137 | } | ||
138 | } else { | ||
139 | pr_err("CPU%u: failed to boot: %d\n", cpu, ret); | ||
143 | } | 140 | } |
144 | 141 | ||
145 | secondary_data.stack = NULL; | 142 | secondary_data.stack = NULL; |
146 | secondary_data.pgdir = 0; | 143 | secondary_data.pgdir = 0; |
147 | 144 | ||
148 | *pmd = __pmd(0); | 145 | if (PHYS_OFFSET != PAGE_OFFSET) { |
149 | clean_pmd_entry(pmd); | 146 | #ifndef CONFIG_HOTPLUG_CPU |
150 | pgd_free(&init_mm, pgd); | 147 | identity_mapping_del(pgd, __pa(__init_begin), __pa(__init_end)); |
151 | 148 | #endif | |
152 | if (ret) { | 149 | identity_mapping_del(pgd, __pa(_stext), __pa(_etext)); |
153 | printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); | 150 | identity_mapping_del(pgd, __pa(_sdata), __pa(_edata)); |
154 | |||
155 | /* | ||
156 | * FIXME: We need to clean up the new idle thread. --rmk | ||
157 | */ | ||
158 | } | 151 | } |
159 | 152 | ||
153 | pgd_free(&init_mm, pgd); | ||
154 | |||
160 | return ret; | 155 | return ret; |
161 | } | 156 | } |
162 | 157 | ||
163 | #ifdef CONFIG_HOTPLUG_CPU | 158 | #ifdef CONFIG_HOTPLUG_CPU |
159 | static void percpu_timer_stop(void); | ||
160 | |||
164 | /* | 161 | /* |
165 | * __cpu_disable runs on the processor to be shutdown. | 162 | * __cpu_disable runs on the processor to be shutdown. |
166 | */ | 163 | */ |
@@ -188,7 +185,7 @@ int __cpu_disable(void) | |||
188 | /* | 185 | /* |
189 | * Stop the local timer for this CPU. | 186 | * Stop the local timer for this CPU. |
190 | */ | 187 | */ |
191 | local_timer_stop(); | 188 | percpu_timer_stop(); |
192 | 189 | ||
193 | /* | 190 | /* |
194 | * Flush user cache and TLB mappings, and then remove this CPU | 191 | * Flush user cache and TLB mappings, and then remove this CPU |
@@ -207,12 +204,20 @@ int __cpu_disable(void) | |||
207 | return 0; | 204 | return 0; |
208 | } | 205 | } |
209 | 206 | ||
207 | static DECLARE_COMPLETION(cpu_died); | ||
208 | |||
210 | /* | 209 | /* |
211 | * called on the thread which is asking for a CPU to be shutdown - | 210 | * called on the thread which is asking for a CPU to be shutdown - |
212 | * waits until shutdown has completed, or it is timed out. | 211 | * waits until shutdown has completed, or it is timed out. |
213 | */ | 212 | */ |
214 | void __cpu_die(unsigned int cpu) | 213 | void __cpu_die(unsigned int cpu) |
215 | { | 214 | { |
215 | if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { | ||
216 | pr_err("CPU%u: cpu didn't die\n", cpu); | ||
217 | return; | ||
218 | } | ||
219 | printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); | ||
220 | |||
216 | if (!platform_cpu_kill(cpu)) | 221 | if (!platform_cpu_kill(cpu)) |
217 | printk("CPU%u: unable to kill\n", cpu); | 222 | printk("CPU%u: unable to kill\n", cpu); |
218 | } | 223 | } |
@@ -229,12 +234,17 @@ void __ref cpu_die(void) | |||
229 | { | 234 | { |
230 | unsigned int cpu = smp_processor_id(); | 235 | unsigned int cpu = smp_processor_id(); |
231 | 236 | ||
232 | local_irq_disable(); | ||
233 | idle_task_exit(); | 237 | idle_task_exit(); |
234 | 238 | ||
239 | local_irq_disable(); | ||
240 | mb(); | ||
241 | |||
242 | /* Tell __cpu_die() that this CPU is now safe to dispose of */ | ||
243 | complete(&cpu_died); | ||
244 | |||
235 | /* | 245 | /* |
236 | * actual CPU shutdown procedure is at least platform (if not | 246 | * actual CPU shutdown procedure is at least platform (if not |
237 | * CPU) specific | 247 | * CPU) specific. |
238 | */ | 248 | */ |
239 | platform_cpu_die(cpu); | 249 | platform_cpu_die(cpu); |
240 | 250 | ||
@@ -244,6 +254,7 @@ void __ref cpu_die(void) | |||
244 | * to be repeated to undo the effects of taking the CPU offline. | 254 | * to be repeated to undo the effects of taking the CPU offline. |
245 | */ | 255 | */ |
246 | __asm__("mov sp, %0\n" | 256 | __asm__("mov sp, %0\n" |
257 | " mov fp, #0\n" | ||
247 | " b secondary_start_kernel" | 258 | " b secondary_start_kernel" |
248 | : | 259 | : |
249 | : "r" (task_stack_page(current) + THREAD_SIZE - 8)); | 260 | : "r" (task_stack_page(current) + THREAD_SIZE - 8)); |
@@ -251,6 +262,17 @@ void __ref cpu_die(void) | |||
251 | #endif /* CONFIG_HOTPLUG_CPU */ | 262 | #endif /* CONFIG_HOTPLUG_CPU */ |
252 | 263 | ||
253 | /* | 264 | /* |
265 | * Called by both boot and secondaries to move global data into | ||
266 | * per-processor storage. | ||
267 | */ | ||
268 | static void __cpuinit smp_store_cpu_info(unsigned int cpuid) | ||
269 | { | ||
270 | struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); | ||
271 | |||
272 | cpu_info->loops_per_jiffy = loops_per_jiffy; | ||
273 | } | ||
274 | |||
275 | /* | ||
254 | * This is the secondary CPU boot entry. We're using this CPUs | 276 | * This is the secondary CPU boot entry. We're using this CPUs |
255 | * idle thread stack, but a set of temporary page tables. | 277 | * idle thread stack, but a set of temporary page tables. |
256 | */ | 278 | */ |
@@ -265,7 +287,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
265 | * All kernel threads share the same mm context; grab a | 287 | * All kernel threads share the same mm context; grab a |
266 | * reference and switch to it. | 288 | * reference and switch to it. |
267 | */ | 289 | */ |
268 | atomic_inc(&mm->mm_users); | ||
269 | atomic_inc(&mm->mm_count); | 290 | atomic_inc(&mm->mm_count); |
270 | current->active_mm = mm; | 291 | current->active_mm = mm; |
271 | cpumask_set_cpu(cpu, mm_cpumask(mm)); | 292 | cpumask_set_cpu(cpu, mm_cpumask(mm)); |
@@ -275,6 +296,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
275 | 296 | ||
276 | cpu_init(); | 297 | cpu_init(); |
277 | preempt_disable(); | 298 | preempt_disable(); |
299 | trace_hardirqs_off(); | ||
278 | 300 | ||
279 | /* | 301 | /* |
280 | * Give the platform a chance to do its own initialisation. | 302 | * Give the platform a chance to do its own initialisation. |
@@ -298,9 +320,13 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
298 | smp_store_cpu_info(cpu); | 320 | smp_store_cpu_info(cpu); |
299 | 321 | ||
300 | /* | 322 | /* |
301 | * OK, now it's safe to let the boot CPU continue | 323 | * OK, now it's safe to let the boot CPU continue. Wait for |
324 | * the CPU migration code to notice that the CPU is online | ||
325 | * before we continue. | ||
302 | */ | 326 | */ |
303 | set_cpu_online(cpu, true); | 327 | set_cpu_online(cpu, true); |
328 | while (!cpu_active(cpu)) | ||
329 | cpu_relax(); | ||
304 | 330 | ||
305 | /* | 331 | /* |
306 | * OK, it's off to the idle thread for us | 332 | * OK, it's off to the idle thread for us |
@@ -308,17 +334,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
308 | cpu_idle(); | 334 | cpu_idle(); |
309 | } | 335 | } |
310 | 336 | ||
311 | /* | ||
312 | * Called by both boot and secondaries to move global data into | ||
313 | * per-processor storage. | ||
314 | */ | ||
315 | void __cpuinit smp_store_cpu_info(unsigned int cpuid) | ||
316 | { | ||
317 | struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); | ||
318 | |||
319 | cpu_info->loops_per_jiffy = loops_per_jiffy; | ||
320 | } | ||
321 | |||
322 | void __init smp_cpus_done(unsigned int max_cpus) | 337 | void __init smp_cpus_done(unsigned int max_cpus) |
323 | { | 338 | { |
324 | int cpu; | 339 | int cpu; |
@@ -341,61 +356,87 @@ void __init smp_prepare_boot_cpu(void) | |||
341 | per_cpu(cpu_data, cpu).idle = current; | 356 | per_cpu(cpu_data, cpu).idle = current; |
342 | } | 357 | } |
343 | 358 | ||
344 | static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) | 359 | void __init smp_prepare_cpus(unsigned int max_cpus) |
345 | { | 360 | { |
346 | unsigned long flags; | 361 | unsigned int ncores = num_possible_cpus(); |
347 | unsigned int cpu; | ||
348 | 362 | ||
349 | local_irq_save(flags); | 363 | smp_store_cpu_info(smp_processor_id()); |
350 | 364 | ||
351 | for_each_cpu(cpu, mask) { | 365 | /* |
352 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); | 366 | * are we trying to boot more cores than exist? |
367 | */ | ||
368 | if (max_cpus > ncores) | ||
369 | max_cpus = ncores; | ||
353 | 370 | ||
354 | spin_lock(&ipi->lock); | 371 | if (max_cpus > 1) { |
355 | ipi->bits |= 1 << msg; | 372 | /* |
356 | spin_unlock(&ipi->lock); | 373 | * Enable the local timer or broadcast device for the |
374 | * boot CPU, but only if we have more than one CPU. | ||
375 | */ | ||
376 | percpu_timer_setup(); | ||
377 | |||
378 | /* | ||
379 | * Initialise the SCU if there are more than one CPU | ||
380 | * and let them know where to start. | ||
381 | */ | ||
382 | platform_smp_prepare_cpus(max_cpus); | ||
357 | } | 383 | } |
384 | } | ||
358 | 385 | ||
359 | /* | 386 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); |
360 | * Call the platform specific cross-CPU call function. | ||
361 | */ | ||
362 | smp_cross_call(mask); | ||
363 | 387 | ||
364 | local_irq_restore(flags); | 388 | void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) |
389 | { | ||
390 | smp_cross_call = fn; | ||
365 | } | 391 | } |
366 | 392 | ||
367 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) | 393 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) |
368 | { | 394 | { |
369 | send_ipi_message(mask, IPI_CALL_FUNC); | 395 | smp_cross_call(mask, IPI_CALL_FUNC); |
370 | } | 396 | } |
371 | 397 | ||
372 | void arch_send_call_function_single_ipi(int cpu) | 398 | void arch_send_call_function_single_ipi(int cpu) |
373 | { | 399 | { |
374 | send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); | 400 | smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); |
375 | } | 401 | } |
376 | 402 | ||
377 | void show_ipi_list(struct seq_file *p) | 403 | static const char *ipi_types[NR_IPI] = { |
404 | #define S(x,s) [x - IPI_TIMER] = s | ||
405 | S(IPI_TIMER, "Timer broadcast interrupts"), | ||
406 | S(IPI_RESCHEDULE, "Rescheduling interrupts"), | ||
407 | S(IPI_CALL_FUNC, "Function call interrupts"), | ||
408 | S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), | ||
409 | S(IPI_CPU_STOP, "CPU stop interrupts"), | ||
410 | }; | ||
411 | |||
412 | void show_ipi_list(struct seq_file *p, int prec) | ||
378 | { | 413 | { |
379 | unsigned int cpu; | 414 | unsigned int cpu, i; |
380 | 415 | ||
381 | seq_puts(p, "IPI:"); | 416 | for (i = 0; i < NR_IPI; i++) { |
417 | seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); | ||
382 | 418 | ||
383 | for_each_present_cpu(cpu) | 419 | for_each_present_cpu(cpu) |
384 | seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count); | 420 | seq_printf(p, "%10u ", |
421 | __get_irq_stat(cpu, ipi_irqs[i])); | ||
385 | 422 | ||
386 | seq_putc(p, '\n'); | 423 | seq_printf(p, " %s\n", ipi_types[i]); |
424 | } | ||
387 | } | 425 | } |
388 | 426 | ||
389 | void show_local_irqs(struct seq_file *p) | 427 | u64 smp_irq_stat_cpu(unsigned int cpu) |
390 | { | 428 | { |
391 | unsigned int cpu; | 429 | u64 sum = 0; |
430 | int i; | ||
392 | 431 | ||
393 | seq_printf(p, "LOC: "); | 432 | for (i = 0; i < NR_IPI; i++) |
433 | sum += __get_irq_stat(cpu, ipi_irqs[i]); | ||
394 | 434 | ||
395 | for_each_present_cpu(cpu) | 435 | #ifdef CONFIG_LOCAL_TIMERS |
396 | seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); | 436 | sum += __get_irq_stat(cpu, local_timer_irqs); |
437 | #endif | ||
397 | 438 | ||
398 | seq_putc(p, '\n'); | 439 | return sum; |
399 | } | 440 | } |
400 | 441 | ||
401 | /* | 442 | /* |
@@ -412,36 +453,47 @@ static void ipi_timer(void) | |||
412 | } | 453 | } |
413 | 454 | ||
414 | #ifdef CONFIG_LOCAL_TIMERS | 455 | #ifdef CONFIG_LOCAL_TIMERS |
415 | asmlinkage void __exception do_local_timer(struct pt_regs *regs) | 456 | asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs) |
416 | { | 457 | { |
417 | struct pt_regs *old_regs = set_irq_regs(regs); | 458 | struct pt_regs *old_regs = set_irq_regs(regs); |
418 | int cpu = smp_processor_id(); | 459 | int cpu = smp_processor_id(); |
419 | 460 | ||
420 | if (local_timer_ack()) { | 461 | if (local_timer_ack()) { |
421 | irq_stat[cpu].local_timer_irqs++; | 462 | __inc_irq_stat(cpu, local_timer_irqs); |
422 | ipi_timer(); | 463 | ipi_timer(); |
423 | } | 464 | } |
424 | 465 | ||
425 | set_irq_regs(old_regs); | 466 | set_irq_regs(old_regs); |
426 | } | 467 | } |
468 | |||
469 | void show_local_irqs(struct seq_file *p, int prec) | ||
470 | { | ||
471 | unsigned int cpu; | ||
472 | |||
473 | seq_printf(p, "%*s: ", prec, "LOC"); | ||
474 | |||
475 | for_each_present_cpu(cpu) | ||
476 | seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); | ||
477 | |||
478 | seq_printf(p, " Local timer interrupts\n"); | ||
479 | } | ||
427 | #endif | 480 | #endif |
428 | 481 | ||
429 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | 482 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST |
430 | static void smp_timer_broadcast(const struct cpumask *mask) | 483 | static void smp_timer_broadcast(const struct cpumask *mask) |
431 | { | 484 | { |
432 | send_ipi_message(mask, IPI_TIMER); | 485 | smp_cross_call(mask, IPI_TIMER); |
433 | } | 486 | } |
434 | #else | 487 | #else |
435 | #define smp_timer_broadcast NULL | 488 | #define smp_timer_broadcast NULL |
436 | #endif | 489 | #endif |
437 | 490 | ||
438 | #ifndef CONFIG_LOCAL_TIMERS | ||
439 | static void broadcast_timer_set_mode(enum clock_event_mode mode, | 491 | static void broadcast_timer_set_mode(enum clock_event_mode mode, |
440 | struct clock_event_device *evt) | 492 | struct clock_event_device *evt) |
441 | { | 493 | { |
442 | } | 494 | } |
443 | 495 | ||
444 | static void local_timer_setup(struct clock_event_device *evt) | 496 | static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt) |
445 | { | 497 | { |
446 | evt->name = "dummy_timer"; | 498 | evt->name = "dummy_timer"; |
447 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | 499 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
@@ -453,7 +505,6 @@ static void local_timer_setup(struct clock_event_device *evt) | |||
453 | 505 | ||
454 | clockevents_register_device(evt); | 506 | clockevents_register_device(evt); |
455 | } | 507 | } |
456 | #endif | ||
457 | 508 | ||
458 | void __cpuinit percpu_timer_setup(void) | 509 | void __cpuinit percpu_timer_setup(void) |
459 | { | 510 | { |
@@ -463,8 +514,24 @@ void __cpuinit percpu_timer_setup(void) | |||
463 | evt->cpumask = cpumask_of(cpu); | 514 | evt->cpumask = cpumask_of(cpu); |
464 | evt->broadcast = smp_timer_broadcast; | 515 | evt->broadcast = smp_timer_broadcast; |
465 | 516 | ||
466 | local_timer_setup(evt); | 517 | if (local_timer_setup(evt)) |
518 | broadcast_timer_setup(evt); | ||
519 | } | ||
520 | |||
521 | #ifdef CONFIG_HOTPLUG_CPU | ||
522 | /* | ||
523 | * The generic clock events code purposely does not stop the local timer | ||
524 | * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it | ||
525 | * manually here. | ||
526 | */ | ||
527 | static void percpu_timer_stop(void) | ||
528 | { | ||
529 | unsigned int cpu = smp_processor_id(); | ||
530 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | ||
531 | |||
532 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | ||
467 | } | 533 | } |
534 | #endif | ||
468 | 535 | ||
469 | static DEFINE_SPINLOCK(stop_lock); | 536 | static DEFINE_SPINLOCK(stop_lock); |
470 | 537 | ||
@@ -492,217 +559,75 @@ static void ipi_cpu_stop(unsigned int cpu) | |||
492 | 559 | ||
493 | /* | 560 | /* |
494 | * Main handler for inter-processor interrupts | 561 | * Main handler for inter-processor interrupts |
495 | * | ||
496 | * For ARM, the ipimask now only identifies a single | ||
497 | * category of IPI (Bit 1 IPIs have been replaced by a | ||
498 | * different mechanism): | ||
499 | * | ||
500 | * Bit 0 - Inter-processor function call | ||
501 | */ | 562 | */ |
502 | asmlinkage void __exception do_IPI(struct pt_regs *regs) | 563 | asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) |
503 | { | 564 | { |
504 | unsigned int cpu = smp_processor_id(); | 565 | unsigned int cpu = smp_processor_id(); |
505 | struct ipi_data *ipi = &per_cpu(ipi_data, cpu); | ||
506 | struct pt_regs *old_regs = set_irq_regs(regs); | 566 | struct pt_regs *old_regs = set_irq_regs(regs); |
507 | 567 | ||
508 | ipi->ipi_count++; | 568 | if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI) |
509 | 569 | __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]); | |
510 | for (;;) { | ||
511 | unsigned long msgs; | ||
512 | |||
513 | spin_lock(&ipi->lock); | ||
514 | msgs = ipi->bits; | ||
515 | ipi->bits = 0; | ||
516 | spin_unlock(&ipi->lock); | ||
517 | |||
518 | if (!msgs) | ||
519 | break; | ||
520 | |||
521 | do { | ||
522 | unsigned nextmsg; | ||
523 | |||
524 | nextmsg = msgs & -msgs; | ||
525 | msgs &= ~nextmsg; | ||
526 | nextmsg = ffz(~nextmsg); | ||
527 | |||
528 | switch (nextmsg) { | ||
529 | case IPI_TIMER: | ||
530 | ipi_timer(); | ||
531 | break; | ||
532 | |||
533 | case IPI_RESCHEDULE: | ||
534 | /* | ||
535 | * nothing more to do - eveything is | ||
536 | * done on the interrupt return path | ||
537 | */ | ||
538 | /* LITMUS^RT: take action based on scheduler state */ | ||
539 | sched_state_ipi(); | ||
540 | break; | ||
541 | |||
542 | case IPI_CALL_FUNC: | ||
543 | generic_smp_call_function_interrupt(); | ||
544 | break; | ||
545 | |||
546 | case IPI_CALL_FUNC_SINGLE: | ||
547 | generic_smp_call_function_single_interrupt(); | ||
548 | break; | ||
549 | 570 | ||
550 | case IPI_CPU_STOP: | 571 | switch (ipinr) { |
551 | ipi_cpu_stop(cpu); | 572 | case IPI_TIMER: |
552 | break; | 573 | ipi_timer(); |
553 | 574 | break; | |
554 | default: | 575 | |
555 | printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", | 576 | case IPI_RESCHEDULE: |
556 | cpu, nextmsg); | 577 | /* LITMUS^RT: take action based on scheduler state */ |
557 | break; | 578 | sched_state_ipi(); |
558 | } | 579 | scheduler_ipi(); |
559 | } while (msgs); | 580 | break; |
581 | |||
582 | case IPI_CALL_FUNC: | ||
583 | generic_smp_call_function_interrupt(); | ||
584 | break; | ||
585 | |||
586 | case IPI_CALL_FUNC_SINGLE: | ||
587 | generic_smp_call_function_single_interrupt(); | ||
588 | break; | ||
589 | |||
590 | case IPI_CPU_STOP: | ||
591 | ipi_cpu_stop(cpu); | ||
592 | break; | ||
593 | |||
594 | default: | ||
595 | printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", | ||
596 | cpu, ipinr); | ||
597 | break; | ||
560 | } | 598 | } |
561 | |||
562 | set_irq_regs(old_regs); | 599 | set_irq_regs(old_regs); |
563 | } | 600 | } |
564 | 601 | ||
565 | void smp_send_reschedule(int cpu) | 602 | void smp_send_reschedule(int cpu) |
566 | { | 603 | { |
567 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); | 604 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); |
568 | } | 605 | } |
569 | 606 | ||
570 | void smp_send_stop(void) | 607 | void smp_send_stop(void) |
571 | { | 608 | { |
572 | cpumask_t mask = cpu_online_map; | 609 | unsigned long timeout; |
573 | cpu_clear(smp_processor_id(), mask); | ||
574 | send_ipi_message(&mask, IPI_CPU_STOP); | ||
575 | } | ||
576 | 610 | ||
577 | /* | 611 | if (num_online_cpus() > 1) { |
578 | * not supported here | 612 | cpumask_t mask = cpu_online_map; |
579 | */ | 613 | cpu_clear(smp_processor_id(), mask); |
580 | int setup_profiling_timer(unsigned int multiplier) | ||
581 | { | ||
582 | return -EINVAL; | ||
583 | } | ||
584 | 614 | ||
585 | static void | 615 | smp_cross_call(&mask, IPI_CPU_STOP); |
586 | on_each_cpu_mask(void (*func)(void *), void *info, int wait, | 616 | } |
587 | const struct cpumask *mask) | ||
588 | { | ||
589 | preempt_disable(); | ||
590 | 617 | ||
591 | smp_call_function_many(mask, func, info, wait); | 618 | /* Wait up to one second for other CPUs to stop */ |
592 | if (cpumask_test_cpu(smp_processor_id(), mask)) | 619 | timeout = USEC_PER_SEC; |
593 | func(info); | 620 | while (num_online_cpus() > 1 && timeout--) |
621 | udelay(1); | ||
594 | 622 | ||
595 | preempt_enable(); | 623 | if (num_online_cpus() > 1) |
624 | pr_warning("SMP: failed to stop secondary CPUs\n"); | ||
596 | } | 625 | } |
597 | 626 | ||
598 | /**********************************************************************/ | ||
599 | |||
600 | /* | 627 | /* |
601 | * TLB operations | 628 | * not supported here |
602 | */ | 629 | */ |
603 | struct tlb_args { | 630 | int setup_profiling_timer(unsigned int multiplier) |
604 | struct vm_area_struct *ta_vma; | ||
605 | unsigned long ta_start; | ||
606 | unsigned long ta_end; | ||
607 | }; | ||
608 | |||
609 | static inline void ipi_flush_tlb_all(void *ignored) | ||
610 | { | ||
611 | local_flush_tlb_all(); | ||
612 | } | ||
613 | |||
614 | static inline void ipi_flush_tlb_mm(void *arg) | ||
615 | { | ||
616 | struct mm_struct *mm = (struct mm_struct *)arg; | ||
617 | |||
618 | local_flush_tlb_mm(mm); | ||
619 | } | ||
620 | |||
621 | static inline void ipi_flush_tlb_page(void *arg) | ||
622 | { | ||
623 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
624 | |||
625 | local_flush_tlb_page(ta->ta_vma, ta->ta_start); | ||
626 | } | ||
627 | |||
628 | static inline void ipi_flush_tlb_kernel_page(void *arg) | ||
629 | { | ||
630 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
631 | |||
632 | local_flush_tlb_kernel_page(ta->ta_start); | ||
633 | } | ||
634 | |||
635 | static inline void ipi_flush_tlb_range(void *arg) | ||
636 | { | ||
637 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
638 | |||
639 | local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); | ||
640 | } | ||
641 | |||
642 | static inline void ipi_flush_tlb_kernel_range(void *arg) | ||
643 | { | ||
644 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
645 | |||
646 | local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); | ||
647 | } | ||
648 | |||
649 | void flush_tlb_all(void) | ||
650 | { | ||
651 | if (tlb_ops_need_broadcast()) | ||
652 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
653 | else | ||
654 | local_flush_tlb_all(); | ||
655 | } | ||
656 | |||
657 | void flush_tlb_mm(struct mm_struct *mm) | ||
658 | { | ||
659 | if (tlb_ops_need_broadcast()) | ||
660 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); | ||
661 | else | ||
662 | local_flush_tlb_mm(mm); | ||
663 | } | ||
664 | |||
665 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | ||
666 | { | ||
667 | if (tlb_ops_need_broadcast()) { | ||
668 | struct tlb_args ta; | ||
669 | ta.ta_vma = vma; | ||
670 | ta.ta_start = uaddr; | ||
671 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
672 | } else | ||
673 | local_flush_tlb_page(vma, uaddr); | ||
674 | } | ||
675 | |||
676 | void flush_tlb_kernel_page(unsigned long kaddr) | ||
677 | { | ||
678 | if (tlb_ops_need_broadcast()) { | ||
679 | struct tlb_args ta; | ||
680 | ta.ta_start = kaddr; | ||
681 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | ||
682 | } else | ||
683 | local_flush_tlb_kernel_page(kaddr); | ||
684 | } | ||
685 | |||
686 | void flush_tlb_range(struct vm_area_struct *vma, | ||
687 | unsigned long start, unsigned long end) | ||
688 | { | ||
689 | if (tlb_ops_need_broadcast()) { | ||
690 | struct tlb_args ta; | ||
691 | ta.ta_vma = vma; | ||
692 | ta.ta_start = start; | ||
693 | ta.ta_end = end; | ||
694 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
695 | } else | ||
696 | local_flush_tlb_range(vma, start, end); | ||
697 | } | ||
698 | |||
699 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
700 | { | 631 | { |
701 | if (tlb_ops_need_broadcast()) { | 632 | return -EINVAL; |
702 | struct tlb_args ta; | ||
703 | ta.ta_start = start; | ||
704 | ta.ta_end = end; | ||
705 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | ||
706 | } else | ||
707 | local_flush_tlb_kernel_range(start, end); | ||
708 | } | 633 | } |
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index 9ab4149bd983..a1e757c3439b 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c | |||
@@ -50,3 +50,26 @@ void __init scu_enable(void __iomem *scu_base) | |||
50 | */ | 50 | */ |
51 | flush_cache_all(); | 51 | flush_cache_all(); |
52 | } | 52 | } |
53 | |||
54 | /* | ||
55 | * Set the executing CPUs power mode as defined. This will be in | ||
56 | * preparation for it executing a WFI instruction. | ||
57 | * | ||
58 | * This function must be called with preemption disabled, and as it | ||
59 | * has the side effect of disabling coherency, caches must have been | ||
60 | * flushed. Interrupts must also have been disabled. | ||
61 | */ | ||
62 | int scu_power_mode(void __iomem *scu_base, unsigned int mode) | ||
63 | { | ||
64 | unsigned int val; | ||
65 | int cpu = smp_processor_id(); | ||
66 | |||
67 | if (mode > 3 || mode == 1 || cpu > 3) | ||
68 | return -EINVAL; | ||
69 | |||
70 | val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03; | ||
71 | val |= mode; | ||
72 | __raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c new file mode 100644 index 000000000000..7dcb35285be7 --- /dev/null +++ b/arch/arm/kernel/smp_tlb.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/smp_tlb.c | ||
3 | * | ||
4 | * Copyright (C) 2002 ARM Limited, All Rights Reserved. | ||
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 | #include <linux/preempt.h> | ||
11 | #include <linux/smp.h> | ||
12 | |||
13 | #include <asm/smp_plat.h> | ||
14 | #include <asm/tlbflush.h> | ||
15 | |||
16 | static void on_each_cpu_mask(void (*func)(void *), void *info, int wait, | ||
17 | const struct cpumask *mask) | ||
18 | { | ||
19 | preempt_disable(); | ||
20 | |||
21 | smp_call_function_many(mask, func, info, wait); | ||
22 | if (cpumask_test_cpu(smp_processor_id(), mask)) | ||
23 | func(info); | ||
24 | |||
25 | preempt_enable(); | ||
26 | } | ||
27 | |||
28 | /**********************************************************************/ | ||
29 | |||
30 | /* | ||
31 | * TLB operations | ||
32 | */ | ||
33 | struct tlb_args { | ||
34 | struct vm_area_struct *ta_vma; | ||
35 | unsigned long ta_start; | ||
36 | unsigned long ta_end; | ||
37 | }; | ||
38 | |||
39 | static inline void ipi_flush_tlb_all(void *ignored) | ||
40 | { | ||
41 | local_flush_tlb_all(); | ||
42 | } | ||
43 | |||
44 | static inline void ipi_flush_tlb_mm(void *arg) | ||
45 | { | ||
46 | struct mm_struct *mm = (struct mm_struct *)arg; | ||
47 | |||
48 | local_flush_tlb_mm(mm); | ||
49 | } | ||
50 | |||
51 | static inline void ipi_flush_tlb_page(void *arg) | ||
52 | { | ||
53 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
54 | |||
55 | local_flush_tlb_page(ta->ta_vma, ta->ta_start); | ||
56 | } | ||
57 | |||
58 | static inline void ipi_flush_tlb_kernel_page(void *arg) | ||
59 | { | ||
60 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
61 | |||
62 | local_flush_tlb_kernel_page(ta->ta_start); | ||
63 | } | ||
64 | |||
65 | static inline void ipi_flush_tlb_range(void *arg) | ||
66 | { | ||
67 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
68 | |||
69 | local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); | ||
70 | } | ||
71 | |||
72 | static inline void ipi_flush_tlb_kernel_range(void *arg) | ||
73 | { | ||
74 | struct tlb_args *ta = (struct tlb_args *)arg; | ||
75 | |||
76 | local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); | ||
77 | } | ||
78 | |||
79 | void flush_tlb_all(void) | ||
80 | { | ||
81 | if (tlb_ops_need_broadcast()) | ||
82 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
83 | else | ||
84 | local_flush_tlb_all(); | ||
85 | } | ||
86 | |||
87 | void flush_tlb_mm(struct mm_struct *mm) | ||
88 | { | ||
89 | if (tlb_ops_need_broadcast()) | ||
90 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); | ||
91 | else | ||
92 | local_flush_tlb_mm(mm); | ||
93 | } | ||
94 | |||
95 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | ||
96 | { | ||
97 | if (tlb_ops_need_broadcast()) { | ||
98 | struct tlb_args ta; | ||
99 | ta.ta_vma = vma; | ||
100 | ta.ta_start = uaddr; | ||
101 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
102 | } else | ||
103 | local_flush_tlb_page(vma, uaddr); | ||
104 | } | ||
105 | |||
106 | void flush_tlb_kernel_page(unsigned long kaddr) | ||
107 | { | ||
108 | if (tlb_ops_need_broadcast()) { | ||
109 | struct tlb_args ta; | ||
110 | ta.ta_start = kaddr; | ||
111 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | ||
112 | } else | ||
113 | local_flush_tlb_kernel_page(kaddr); | ||
114 | } | ||
115 | |||
116 | void flush_tlb_range(struct vm_area_struct *vma, | ||
117 | unsigned long start, unsigned long end) | ||
118 | { | ||
119 | if (tlb_ops_need_broadcast()) { | ||
120 | struct tlb_args ta; | ||
121 | ta.ta_vma = vma; | ||
122 | ta.ta_start = start; | ||
123 | ta.ta_end = end; | ||
124 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); | ||
125 | } else | ||
126 | local_flush_tlb_range(vma, start, end); | ||
127 | } | ||
128 | |||
129 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
130 | { | ||
131 | if (tlb_ops_need_broadcast()) { | ||
132 | struct tlb_args ta; | ||
133 | ta.ta_start = start; | ||
134 | ta.ta_end = end; | ||
135 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | ||
136 | } else | ||
137 | local_flush_tlb_kernel_range(start, end); | ||
138 | } | ||
139 | |||
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 35882fbf37f9..2c277d40cee6 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -36,6 +36,7 @@ static void twd_set_mode(enum clock_event_mode mode, | |||
36 | /* timer load already set up */ | 36 | /* timer load already set up */ |
37 | ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE | 37 | ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE |
38 | | TWD_TIMER_CONTROL_PERIODIC; | 38 | | TWD_TIMER_CONTROL_PERIODIC; |
39 | __raw_writel(twd_timer_rate / HZ, twd_base + TWD_TIMER_LOAD); | ||
39 | break; | 40 | break; |
40 | case CLOCK_EVT_MODE_ONESHOT: | 41 | case CLOCK_EVT_MODE_ONESHOT: |
41 | /* period set, and timer enabled in 'next_event' hook */ | 42 | /* period set, and timer enabled in 'next_event' hook */ |
@@ -81,7 +82,7 @@ int twd_timer_ack(void) | |||
81 | 82 | ||
82 | static void __cpuinit twd_calibrate_rate(void) | 83 | static void __cpuinit twd_calibrate_rate(void) |
83 | { | 84 | { |
84 | unsigned long load, count; | 85 | unsigned long count; |
85 | u64 waitjiffies; | 86 | u64 waitjiffies; |
86 | 87 | ||
87 | /* | 88 | /* |
@@ -114,12 +115,8 @@ static void __cpuinit twd_calibrate_rate(void) | |||
114 | twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); | 115 | twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); |
115 | 116 | ||
116 | printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, | 117 | printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, |
117 | (twd_timer_rate / 100000) % 100); | 118 | (twd_timer_rate / 10000) % 100); |
118 | } | 119 | } |
119 | |||
120 | load = twd_timer_rate / HZ; | ||
121 | |||
122 | __raw_writel(load, twd_base + TWD_TIMER_LOAD); | ||
123 | } | 120 | } |
124 | 121 | ||
125 | /* | 122 | /* |
@@ -127,8 +124,6 @@ static void __cpuinit twd_calibrate_rate(void) | |||
127 | */ | 124 | */ |
128 | void __cpuinit twd_timer_setup(struct clock_event_device *clk) | 125 | void __cpuinit twd_timer_setup(struct clock_event_device *clk) |
129 | { | 126 | { |
130 | unsigned long flags; | ||
131 | |||
132 | twd_calibrate_rate(); | 127 | twd_calibrate_rate(); |
133 | 128 | ||
134 | clk->name = "local_timer"; | 129 | clk->name = "local_timer"; |
@@ -143,20 +138,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) | |||
143 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); | 138 | clk->min_delta_ns = clockevent_delta2ns(0xf, clk); |
144 | 139 | ||
145 | /* Make sure our local interrupt controller has this enabled */ | 140 | /* Make sure our local interrupt controller has this enabled */ |
146 | local_irq_save(flags); | 141 | gic_enable_ppi(clk->irq); |
147 | irq_to_desc(clk->irq)->status |= IRQ_NOPROBE; | ||
148 | get_irq_chip(clk->irq)->unmask(clk->irq); | ||
149 | local_irq_restore(flags); | ||
150 | 142 | ||
151 | clockevents_register_device(clk); | 143 | clockevents_register_device(clk); |
152 | } | 144 | } |
153 | |||
154 | #ifdef CONFIG_HOTPLUG_CPU | ||
155 | /* | ||
156 | * take a local timer down | ||
157 | */ | ||
158 | void twd_timer_stop(void) | ||
159 | { | ||
160 | __raw_writel(0, twd_base + TWD_TIMER_CONTROL); | ||
161 | } | ||
162 | #endif | ||
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 20b7411e47fd..381d23a497c1 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c | |||
@@ -28,7 +28,7 @@ int notrace unwind_frame(struct stackframe *frame) | |||
28 | 28 | ||
29 | /* only go to a higher address on the stack */ | 29 | /* only go to a higher address on the stack */ |
30 | low = frame->sp; | 30 | low = frame->sp; |
31 | high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE; | 31 | high = ALIGN(low, THREAD_SIZE); |
32 | 32 | ||
33 | /* check current frame pointer is within bounds */ | 33 | /* check current frame pointer is within bounds */ |
34 | if (fp < (low + 12) || fp + 4 >= high) | 34 | if (fp < (low + 12) || fp + 4 >= high) |
@@ -94,10 +94,13 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | |||
94 | if (tsk != current) { | 94 | if (tsk != current) { |
95 | #ifdef CONFIG_SMP | 95 | #ifdef CONFIG_SMP |
96 | /* | 96 | /* |
97 | * What guarantees do we have here that 'tsk' | 97 | * What guarantees do we have here that 'tsk' is not |
98 | * is not running on another CPU? | 98 | * running on another CPU? For now, ignore it as we |
99 | * can't guarantee we won't explode. | ||
99 | */ | 100 | */ |
100 | BUG(); | 101 | if (trace->nr_entries < trace->max_entries) |
102 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
103 | return; | ||
101 | #else | 104 | #else |
102 | data.no_sched_functions = 1; | 105 | data.no_sched_functions = 1; |
103 | frame.fp = thread_saved_fp(tsk); | 106 | frame.fp = thread_saved_fp(tsk); |
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c new file mode 100644 index 000000000000..40ee7e5045e4 --- /dev/null +++ b/arch/arm/kernel/swp_emulate.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/swp_emulate.c | ||
3 | * | ||
4 | * Copyright (C) 2009 ARM Limited | ||
5 | * __user_* functions adapted from include/asm/uaccess.h | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Implements emulation of the SWP/SWPB instructions using load-exclusive and | ||
12 | * store-exclusive for processors that have them disabled (or future ones that | ||
13 | * might not implement them). | ||
14 | * | ||
15 | * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] | ||
16 | * Where: Rt = destination | ||
17 | * Rt2 = source | ||
18 | * Rn = address | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/proc_fs.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/syscalls.h> | ||
26 | #include <linux/perf_event.h> | ||
27 | |||
28 | #include <asm/traps.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | |||
31 | /* | ||
32 | * Error-checking SWP macros implemented using ldrex{b}/strex{b} | ||
33 | */ | ||
34 | #define __user_swpX_asm(data, addr, res, temp, B) \ | ||
35 | __asm__ __volatile__( \ | ||
36 | " mov %2, %1\n" \ | ||
37 | "0: ldrex"B" %1, [%3]\n" \ | ||
38 | "1: strex"B" %0, %2, [%3]\n" \ | ||
39 | " cmp %0, #0\n" \ | ||
40 | " movne %0, %4\n" \ | ||
41 | "2:\n" \ | ||
42 | " .section .fixup,\"ax\"\n" \ | ||
43 | " .align 2\n" \ | ||
44 | "3: mov %0, %5\n" \ | ||
45 | " b 2b\n" \ | ||
46 | " .previous\n" \ | ||
47 | " .section __ex_table,\"a\"\n" \ | ||
48 | " .align 3\n" \ | ||
49 | " .long 0b, 3b\n" \ | ||
50 | " .long 1b, 3b\n" \ | ||
51 | " .previous" \ | ||
52 | : "=&r" (res), "+r" (data), "=&r" (temp) \ | ||
53 | : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ | ||
54 | : "cc", "memory") | ||
55 | |||
56 | #define __user_swp_asm(data, addr, res, temp) \ | ||
57 | __user_swpX_asm(data, addr, res, temp, "") | ||
58 | #define __user_swpb_asm(data, addr, res, temp) \ | ||
59 | __user_swpX_asm(data, addr, res, temp, "b") | ||
60 | |||
61 | /* | ||
62 | * Macros/defines for extracting register numbers from instruction. | ||
63 | */ | ||
64 | #define EXTRACT_REG_NUM(instruction, offset) \ | ||
65 | (((instruction) & (0xf << (offset))) >> (offset)) | ||
66 | #define RN_OFFSET 16 | ||
67 | #define RT_OFFSET 12 | ||
68 | #define RT2_OFFSET 0 | ||
69 | /* | ||
70 | * Bit 22 of the instruction encoding distinguishes between | ||
71 | * the SWP and SWPB variants (bit set means SWPB). | ||
72 | */ | ||
73 | #define TYPE_SWPB (1 << 22) | ||
74 | |||
75 | static unsigned long swpcounter; | ||
76 | static unsigned long swpbcounter; | ||
77 | static unsigned long abtcounter; | ||
78 | static pid_t previous_pid; | ||
79 | |||
80 | #ifdef CONFIG_PROC_FS | ||
81 | static int proc_read_status(char *page, char **start, off_t off, int count, | ||
82 | int *eof, void *data) | ||
83 | { | ||
84 | char *p = page; | ||
85 | int len; | ||
86 | |||
87 | p += sprintf(p, "Emulated SWP:\t\t%lu\n", swpcounter); | ||
88 | p += sprintf(p, "Emulated SWPB:\t\t%lu\n", swpbcounter); | ||
89 | p += sprintf(p, "Aborted SWP{B}:\t\t%lu\n", abtcounter); | ||
90 | if (previous_pid != 0) | ||
91 | p += sprintf(p, "Last process:\t\t%d\n", previous_pid); | ||
92 | |||
93 | len = (p - page) - off; | ||
94 | if (len < 0) | ||
95 | len = 0; | ||
96 | |||
97 | *eof = (len <= count) ? 1 : 0; | ||
98 | *start = page + off; | ||
99 | |||
100 | return len; | ||
101 | } | ||
102 | #endif | ||
103 | |||
104 | /* | ||
105 | * Set up process info to signal segmentation fault - called on access error. | ||
106 | */ | ||
107 | static void set_segfault(struct pt_regs *regs, unsigned long addr) | ||
108 | { | ||
109 | siginfo_t info; | ||
110 | |||
111 | if (find_vma(current->mm, addr) == NULL) | ||
112 | info.si_code = SEGV_MAPERR; | ||
113 | else | ||
114 | info.si_code = SEGV_ACCERR; | ||
115 | |||
116 | info.si_signo = SIGSEGV; | ||
117 | info.si_errno = 0; | ||
118 | info.si_addr = (void *) instruction_pointer(regs); | ||
119 | |||
120 | pr_debug("SWP{B} emulation: access caused memory abort!\n"); | ||
121 | arm_notify_die("Illegal memory access", regs, &info, 0, 0); | ||
122 | |||
123 | abtcounter++; | ||
124 | } | ||
125 | |||
126 | static int emulate_swpX(unsigned int address, unsigned int *data, | ||
127 | unsigned int type) | ||
128 | { | ||
129 | unsigned int res = 0; | ||
130 | |||
131 | if ((type != TYPE_SWPB) && (address & 0x3)) { | ||
132 | /* SWP to unaligned address not permitted */ | ||
133 | pr_debug("SWP instruction on unaligned pointer!\n"); | ||
134 | return -EFAULT; | ||
135 | } | ||
136 | |||
137 | while (1) { | ||
138 | unsigned long temp; | ||
139 | |||
140 | /* | ||
141 | * Barrier required between accessing protected resource and | ||
142 | * releasing a lock for it. Legacy code might not have done | ||
143 | * this, and we cannot determine that this is not the case | ||
144 | * being emulated, so insert always. | ||
145 | */ | ||
146 | smp_mb(); | ||
147 | |||
148 | if (type == TYPE_SWPB) | ||
149 | __user_swpb_asm(*data, address, res, temp); | ||
150 | else | ||
151 | __user_swp_asm(*data, address, res, temp); | ||
152 | |||
153 | if (likely(res != -EAGAIN) || signal_pending(current)) | ||
154 | break; | ||
155 | |||
156 | cond_resched(); | ||
157 | } | ||
158 | |||
159 | if (res == 0) { | ||
160 | /* | ||
161 | * Barrier also required between acquiring a lock for a | ||
162 | * protected resource and accessing the resource. Inserted for | ||
163 | * same reason as above. | ||
164 | */ | ||
165 | smp_mb(); | ||
166 | |||
167 | if (type == TYPE_SWPB) | ||
168 | swpbcounter++; | ||
169 | else | ||
170 | swpcounter++; | ||
171 | } | ||
172 | |||
173 | return res; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * swp_handler logs the id of calling process, dissects the instruction, sanity | ||
178 | * checks the memory location, calls emulate_swpX for the actual operation and | ||
179 | * deals with fixup/error handling before returning | ||
180 | */ | ||
181 | static int swp_handler(struct pt_regs *regs, unsigned int instr) | ||
182 | { | ||
183 | unsigned int address, destreg, data, type; | ||
184 | unsigned int res = 0; | ||
185 | |||
186 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, regs->ARM_pc); | ||
187 | |||
188 | if (current->pid != previous_pid) { | ||
189 | pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n", | ||
190 | current->comm, (unsigned long)current->pid); | ||
191 | previous_pid = current->pid; | ||
192 | } | ||
193 | |||
194 | address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)]; | ||
195 | data = regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)]; | ||
196 | destreg = EXTRACT_REG_NUM(instr, RT_OFFSET); | ||
197 | |||
198 | type = instr & TYPE_SWPB; | ||
199 | |||
200 | pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", | ||
201 | EXTRACT_REG_NUM(instr, RN_OFFSET), address, | ||
202 | destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); | ||
203 | |||
204 | /* Check access in reasonable access range for both SWP and SWPB */ | ||
205 | if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { | ||
206 | pr_debug("SWP{B} emulation: access to %p not allowed!\n", | ||
207 | (void *)address); | ||
208 | res = -EFAULT; | ||
209 | } else { | ||
210 | res = emulate_swpX(address, &data, type); | ||
211 | } | ||
212 | |||
213 | if (res == 0) { | ||
214 | /* | ||
215 | * On successful emulation, revert the adjustment to the PC | ||
216 | * made in kernel/traps.c in order to resume execution at the | ||
217 | * instruction following the SWP{B}. | ||
218 | */ | ||
219 | regs->ARM_pc += 4; | ||
220 | regs->uregs[destreg] = data; | ||
221 | } else if (res == -EFAULT) { | ||
222 | /* | ||
223 | * Memory errors do not mean emulation failed. | ||
224 | * Set up signal info to return SEGV, then return OK | ||
225 | */ | ||
226 | set_segfault(regs, address); | ||
227 | } | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Only emulate SWP/SWPB executed in ARM state/User mode. | ||
234 | * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE. | ||
235 | */ | ||
236 | static struct undef_hook swp_hook = { | ||
237 | .instr_mask = 0x0fb00ff0, | ||
238 | .instr_val = 0x01000090, | ||
239 | .cpsr_mask = MODE_MASK | PSR_T_BIT | PSR_J_BIT, | ||
240 | .cpsr_val = USR_MODE, | ||
241 | .fn = swp_handler | ||
242 | }; | ||
243 | |||
244 | /* | ||
245 | * Register handler and create status file in /proc/cpu | ||
246 | * Invoked as late_initcall, since not needed before init spawned. | ||
247 | */ | ||
248 | static int __init swp_emulation_init(void) | ||
249 | { | ||
250 | #ifdef CONFIG_PROC_FS | ||
251 | struct proc_dir_entry *res; | ||
252 | |||
253 | res = create_proc_entry("cpu/swp_emulation", S_IRUGO, NULL); | ||
254 | |||
255 | if (!res) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | res->read_proc = proc_read_status; | ||
259 | #endif /* CONFIG_PROC_FS */ | ||
260 | |||
261 | printk(KERN_NOTICE "Registering SWP/SWPB emulation handler\n"); | ||
262 | register_undef_hook(&swp_hook); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | late_initcall(swp_emulation_init); | ||
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 4ad8da15ef2b..af0aaebf4de6 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c | |||
@@ -311,7 +311,7 @@ asmlinkage long sys_oabi_semtimedop(int semid, | |||
311 | long err; | 311 | long err; |
312 | int i; | 312 | int i; |
313 | 313 | ||
314 | if (nsops < 1) | 314 | if (nsops < 1 || nsops > SEMOPM) |
315 | return -EINVAL; | 315 | return -EINVAL; |
316 | sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); | 316 | sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); |
317 | if (!sops) | 317 | if (!sops) |
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index 26685c2f7a49..f5cf660eefcc 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/string.h> /* memcpy */ | 15 | #include <linux/string.h> /* memcpy */ |
16 | #include <asm/cputype.h> | 16 | #include <asm/cputype.h> |
17 | #include <asm/mach/map.h> | 17 | #include <asm/mach/map.h> |
18 | #include <mach/memory.h> | 18 | #include <asm/memory.h> |
19 | #include "tcm.h" | 19 | #include "tcm.h" |
20 | 20 | ||
21 | static struct gen_pool *tcm_pool; | 21 | static struct gen_pool *tcm_pool; |
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 38c261f9951c..cb634c3e28e9 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/timex.h> | 21 | #include <linux/timex.h> |
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/profile.h> | 23 | #include <linux/profile.h> |
24 | #include <linux/sysdev.h> | 24 | #include <linux/syscore_ops.h> |
25 | #include <linux/timer.h> | 25 | #include <linux/timer.h> |
26 | #include <linux/irq.h> | 26 | #include <linux/irq.h> |
27 | 27 | ||
@@ -29,13 +29,15 @@ | |||
29 | 29 | ||
30 | #include <asm/leds.h> | 30 | #include <asm/leds.h> |
31 | #include <asm/thread_info.h> | 31 | #include <asm/thread_info.h> |
32 | #include <asm/sched_clock.h> | ||
32 | #include <asm/stacktrace.h> | 33 | #include <asm/stacktrace.h> |
34 | #include <asm/mach/arch.h> | ||
33 | #include <asm/mach/time.h> | 35 | #include <asm/mach/time.h> |
34 | 36 | ||
35 | /* | 37 | /* |
36 | * Our system timer. | 38 | * Our system timer. |
37 | */ | 39 | */ |
38 | struct sys_timer *system_timer; | 40 | static struct sys_timer *system_timer; |
39 | 41 | ||
40 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) | 42 | #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) |
41 | /* this needs a better home */ | 43 | /* this needs a better home */ |
@@ -105,9 +107,7 @@ void timer_tick(void) | |||
105 | { | 107 | { |
106 | profile_tick(CPU_PROFILING); | 108 | profile_tick(CPU_PROFILING); |
107 | do_leds(); | 109 | do_leds(); |
108 | write_seqlock(&xtime_lock); | 110 | xtime_update(1); |
109 | do_timer(1); | ||
110 | write_sequnlock(&xtime_lock); | ||
111 | #ifndef CONFIG_SMP | 111 | #ifndef CONFIG_SMP |
112 | update_process_times(user_mode(get_irq_regs())); | 112 | update_process_times(user_mode(get_irq_regs())); |
113 | #endif | 113 | #endif |
@@ -115,51 +115,44 @@ void timer_tick(void) | |||
115 | #endif | 115 | #endif |
116 | 116 | ||
117 | #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) | 117 | #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) |
118 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 118 | static int timer_suspend(void) |
119 | { | 119 | { |
120 | struct sys_timer *timer = container_of(dev, struct sys_timer, dev); | 120 | if (system_timer->suspend) |
121 | 121 | system_timer->suspend(); | |
122 | if (timer->suspend != NULL) | ||
123 | timer->suspend(); | ||
124 | 122 | ||
125 | return 0; | 123 | return 0; |
126 | } | 124 | } |
127 | 125 | ||
128 | static int timer_resume(struct sys_device *dev) | 126 | static void timer_resume(void) |
129 | { | 127 | { |
130 | struct sys_timer *timer = container_of(dev, struct sys_timer, dev); | 128 | if (system_timer->resume) |
131 | 129 | system_timer->resume(); | |
132 | if (timer->resume != NULL) | ||
133 | timer->resume(); | ||
134 | |||
135 | return 0; | ||
136 | } | 130 | } |
137 | #else | 131 | #else |
138 | #define timer_suspend NULL | 132 | #define timer_suspend NULL |
139 | #define timer_resume NULL | 133 | #define timer_resume NULL |
140 | #endif | 134 | #endif |
141 | 135 | ||
142 | static struct sysdev_class timer_sysclass = { | 136 | static struct syscore_ops timer_syscore_ops = { |
143 | .name = "timer", | ||
144 | .suspend = timer_suspend, | 137 | .suspend = timer_suspend, |
145 | .resume = timer_resume, | 138 | .resume = timer_resume, |
146 | }; | 139 | }; |
147 | 140 | ||
148 | static int __init timer_init_sysfs(void) | 141 | static int __init timer_init_syscore_ops(void) |
149 | { | 142 | { |
150 | int ret = sysdev_class_register(&timer_sysclass); | 143 | register_syscore_ops(&timer_syscore_ops); |
151 | if (ret == 0) { | ||
152 | system_timer->dev.cls = &timer_sysclass; | ||
153 | ret = sysdev_register(&system_timer->dev); | ||
154 | } | ||
155 | 144 | ||
156 | return ret; | 145 | return 0; |
157 | } | 146 | } |
158 | 147 | ||
159 | device_initcall(timer_init_sysfs); | 148 | device_initcall(timer_init_syscore_ops); |
160 | 149 | ||
161 | void __init time_init(void) | 150 | void __init time_init(void) |
162 | { | 151 | { |
152 | system_timer = machine_desc->timer; | ||
163 | system_timer->init(); | 153 | system_timer->init(); |
154 | #ifdef CONFIG_HAVE_SCHED_CLOCK | ||
155 | sched_clock_postinit(); | ||
156 | #endif | ||
164 | } | 157 | } |
165 | 158 | ||
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index cda78d59aa31..6807cb1e76dd 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kexec.h> | 23 | #include <linux/kexec.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/sched.h> | ||
26 | 27 | ||
27 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
28 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
@@ -32,11 +33,12 @@ | |||
32 | #include <asm/unwind.h> | 33 | #include <asm/unwind.h> |
33 | #include <asm/tls.h> | 34 | #include <asm/tls.h> |
34 | 35 | ||
35 | #include "ptrace.h" | ||
36 | #include "signal.h" | 36 | #include "signal.h" |
37 | 37 | ||
38 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; | 38 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; |
39 | 39 | ||
40 | void *vectors_page; | ||
41 | |||
40 | #ifdef CONFIG_DEBUG_USER | 42 | #ifdef CONFIG_DEBUG_USER |
41 | unsigned int user_debug; | 43 | unsigned int user_debug; |
42 | 44 | ||
@@ -53,10 +55,7 @@ static void dump_mem(const char *, const char *, unsigned long, unsigned long); | |||
53 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) | 55 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) |
54 | { | 56 | { |
55 | #ifdef CONFIG_KALLSYMS | 57 | #ifdef CONFIG_KALLSYMS |
56 | char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN]; | 58 | printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); |
57 | sprint_symbol(sym1, where); | ||
58 | sprint_symbol(sym2, from); | ||
59 | printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2); | ||
60 | #else | 59 | #else |
61 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); | 60 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); |
62 | #endif | 61 | #endif |
@@ -140,7 +139,7 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) | |||
140 | fs = get_fs(); | 139 | fs = get_fs(); |
141 | set_fs(KERNEL_DS); | 140 | set_fs(KERNEL_DS); |
142 | 141 | ||
143 | for (i = -4; i < 1; i++) { | 142 | for (i = -4; i < 1 + !!thumb; i++) { |
144 | unsigned int val, bad; | 143 | unsigned int val, bad; |
145 | 144 | ||
146 | if (thumb) | 145 | if (thumb) |
@@ -235,7 +234,6 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt | |||
235 | 234 | ||
236 | printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", | 235 | printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", |
237 | str, err, ++die_counter); | 236 | str, err, ++die_counter); |
238 | sysfs_printk_last_file(); | ||
239 | 237 | ||
240 | /* trap and error numbers are mostly meaningless on ARM */ | 238 | /* trap and error numbers are mostly meaningless on ARM */ |
241 | ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); | 239 | ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); |
@@ -257,7 +255,7 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt | |||
257 | return ret; | 255 | return ret; |
258 | } | 256 | } |
259 | 257 | ||
260 | DEFINE_SPINLOCK(die_lock); | 258 | static DEFINE_SPINLOCK(die_lock); |
261 | 259 | ||
262 | /* | 260 | /* |
263 | * This function is protected against re-entrancy. | 261 | * This function is protected against re-entrancy. |
@@ -411,8 +409,7 @@ static int bad_syscall(int n, struct pt_regs *regs) | |||
411 | struct thread_info *thread = current_thread_info(); | 409 | struct thread_info *thread = current_thread_info(); |
412 | siginfo_t info; | 410 | siginfo_t info; |
413 | 411 | ||
414 | if (current->personality != PER_LINUX && | 412 | if ((current->personality & PER_MASK) != PER_LINUX && |
415 | current->personality != PER_LINUX_32BIT && | ||
416 | thread->exec_domain->handler) { | 413 | thread->exec_domain->handler) { |
417 | thread->exec_domain->handler(n, regs); | 414 | thread->exec_domain->handler(n, regs); |
418 | return regs->ARM_r0; | 415 | return regs->ARM_r0; |
@@ -566,7 +563,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
566 | if (!pmd_present(*pmd)) | 563 | if (!pmd_present(*pmd)) |
567 | goto bad_access; | 564 | goto bad_access; |
568 | pte = pte_offset_map_lock(mm, pmd, addr, &ptl); | 565 | pte = pte_offset_map_lock(mm, pmd, addr, &ptl); |
569 | if (!pte_present(*pte) || !pte_dirty(*pte)) { | 566 | if (!pte_present(*pte) || !pte_write(*pte) || !pte_dirty(*pte)) { |
570 | pte_unmap_unlock(pte, ptl); | 567 | pte_unmap_unlock(pte, ptl); |
571 | goto bad_access; | 568 | goto bad_access; |
572 | } | 569 | } |
@@ -711,19 +708,19 @@ void __readwrite_bug(const char *fn) | |||
711 | } | 708 | } |
712 | EXPORT_SYMBOL(__readwrite_bug); | 709 | EXPORT_SYMBOL(__readwrite_bug); |
713 | 710 | ||
714 | void __pte_error(const char *file, int line, unsigned long val) | 711 | void __pte_error(const char *file, int line, pte_t pte) |
715 | { | 712 | { |
716 | printk("%s:%d: bad pte %08lx.\n", file, line, val); | 713 | printk("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte)); |
717 | } | 714 | } |
718 | 715 | ||
719 | void __pmd_error(const char *file, int line, unsigned long val) | 716 | void __pmd_error(const char *file, int line, pmd_t pmd) |
720 | { | 717 | { |
721 | printk("%s:%d: bad pmd %08lx.\n", file, line, val); | 718 | printk("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd)); |
722 | } | 719 | } |
723 | 720 | ||
724 | void __pgd_error(const char *file, int line, unsigned long val) | 721 | void __pgd_error(const char *file, int line, pgd_t pgd) |
725 | { | 722 | { |
726 | printk("%s:%d: bad pgd %08lx.\n", file, line, val); | 723 | printk("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd)); |
727 | } | 724 | } |
728 | 725 | ||
729 | asmlinkage void __div0(void) | 726 | asmlinkage void __div0(void) |
@@ -759,7 +756,11 @@ static void __init kuser_get_tls_init(unsigned long vectors) | |||
759 | 756 | ||
760 | void __init early_trap_init(void) | 757 | void __init early_trap_init(void) |
761 | { | 758 | { |
759 | #if defined(CONFIG_CPU_USE_DOMAINS) | ||
762 | unsigned long vectors = CONFIG_VECTORS_BASE; | 760 | unsigned long vectors = CONFIG_VECTORS_BASE; |
761 | #else | ||
762 | unsigned long vectors = (unsigned long)vectors_page; | ||
763 | #endif | ||
763 | extern char __stubs_start[], __stubs_end[]; | 764 | extern char __stubs_start[], __stubs_end[]; |
764 | extern char __vectors_start[], __vectors_end[]; | 765 | extern char __vectors_start[], __vectors_end[]; |
765 | extern char __kuser_helper_start[], __kuser_helper_end[]; | 766 | extern char __kuser_helper_start[], __kuser_helper_end[]; |
@@ -783,10 +784,10 @@ void __init early_trap_init(void) | |||
783 | * Copy signal return handlers into the vector page, and | 784 | * Copy signal return handlers into the vector page, and |
784 | * set sigreturn to be a pointer to these. | 785 | * set sigreturn to be a pointer to these. |
785 | */ | 786 | */ |
786 | memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, | 787 | memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), |
787 | sizeof(sigreturn_codes)); | 788 | sigreturn_codes, sizeof(sigreturn_codes)); |
788 | memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, | 789 | memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), |
789 | sizeof(syscall_restart_code)); | 790 | syscall_restart_code, sizeof(syscall_restart_code)); |
790 | 791 | ||
791 | flush_icache_range(vectors, vectors + PAGE_SIZE); | 792 | flush_icache_range(vectors, vectors + PAGE_SIZE); |
792 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); | 793 | modify_domain(DOMAIN_USER, DOMAIN_CLIENT); |
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index dd81a918c106..d2cb0b3c9872 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c | |||
@@ -146,6 +146,8 @@ static struct unwind_idx *unwind_find_idx(unsigned long addr) | |||
146 | addr < table->end_addr) { | 146 | addr < table->end_addr) { |
147 | idx = search_index(addr, table->start, | 147 | idx = search_index(addr, table->start, |
148 | table->stop - 1); | 148 | table->stop - 1); |
149 | /* Move-to-front to exploit common traces */ | ||
150 | list_move(&table->list, &unwind_tables); | ||
149 | break; | 151 | break; |
150 | } | 152 | } |
151 | } | 153 | } |
@@ -277,7 +279,7 @@ int unwind_frame(struct stackframe *frame) | |||
277 | 279 | ||
278 | /* only go to a higher address on the stack */ | 280 | /* only go to a higher address on the stack */ |
279 | low = frame->sp; | 281 | low = frame->sp; |
280 | high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE; | 282 | high = ALIGN(low, THREAD_SIZE); |
281 | 283 | ||
282 | pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, | 284 | pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, |
283 | frame->pc, frame->lr, frame->sp); | 285 | frame->pc, frame->lr, frame->sp); |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index b16c07914b55..e5287f21badc 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -8,6 +8,25 @@ | |||
8 | #include <asm/memory.h> | 8 | #include <asm/memory.h> |
9 | #include <asm/page.h> | 9 | #include <asm/page.h> |
10 | 10 | ||
11 | #define PROC_INFO \ | ||
12 | VMLINUX_SYMBOL(__proc_info_begin) = .; \ | ||
13 | *(.proc.info.init) \ | ||
14 | VMLINUX_SYMBOL(__proc_info_end) = .; | ||
15 | |||
16 | #ifdef CONFIG_HOTPLUG_CPU | ||
17 | #define ARM_CPU_DISCARD(x) | ||
18 | #define ARM_CPU_KEEP(x) x | ||
19 | #else | ||
20 | #define ARM_CPU_DISCARD(x) x | ||
21 | #define ARM_CPU_KEEP(x) | ||
22 | #endif | ||
23 | |||
24 | #if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK) | ||
25 | #define ARM_EXIT_KEEP(x) x | ||
26 | #else | ||
27 | #define ARM_EXIT_KEEP(x) | ||
28 | #endif | ||
29 | |||
11 | OUTPUT_ARCH(arm) | 30 | OUTPUT_ARCH(arm) |
12 | ENTRY(stext) | 31 | ENTRY(stext) |
13 | 32 | ||
@@ -30,16 +49,24 @@ SECTIONS | |||
30 | _sinittext = .; | 49 | _sinittext = .; |
31 | HEAD_TEXT | 50 | HEAD_TEXT |
32 | INIT_TEXT | 51 | INIT_TEXT |
52 | ARM_EXIT_KEEP(EXIT_TEXT) | ||
33 | _einittext = .; | 53 | _einittext = .; |
34 | __proc_info_begin = .; | 54 | ARM_CPU_DISCARD(PROC_INFO) |
35 | *(.proc.info.init) | ||
36 | __proc_info_end = .; | ||
37 | __arch_info_begin = .; | 55 | __arch_info_begin = .; |
38 | *(.arch.info.init) | 56 | *(.arch.info.init) |
39 | __arch_info_end = .; | 57 | __arch_info_end = .; |
40 | __tagtable_begin = .; | 58 | __tagtable_begin = .; |
41 | *(.taglist.init) | 59 | *(.taglist.init) |
42 | __tagtable_end = .; | 60 | __tagtable_end = .; |
61 | #ifdef CONFIG_SMP_ON_UP | ||
62 | __smpalt_begin = .; | ||
63 | *(.alt.smp.init) | ||
64 | __smpalt_end = .; | ||
65 | #endif | ||
66 | |||
67 | __pv_table_begin = .; | ||
68 | *(.pv_table) | ||
69 | __pv_table_end = .; | ||
43 | 70 | ||
44 | INIT_SETUP(16) | 71 | INIT_SETUP(16) |
45 | 72 | ||
@@ -51,10 +78,11 @@ SECTIONS | |||
51 | #ifndef CONFIG_XIP_KERNEL | 78 | #ifndef CONFIG_XIP_KERNEL |
52 | __init_begin = _stext; | 79 | __init_begin = _stext; |
53 | INIT_DATA | 80 | INIT_DATA |
81 | ARM_EXIT_KEEP(EXIT_DATA) | ||
54 | #endif | 82 | #endif |
55 | } | 83 | } |
56 | 84 | ||
57 | PERCPU(PAGE_SIZE) | 85 | PERCPU_SECTION(32) |
58 | 86 | ||
59 | #ifndef CONFIG_XIP_KERNEL | 87 | #ifndef CONFIG_XIP_KERNEL |
60 | . = ALIGN(PAGE_SIZE); | 88 | . = ALIGN(PAGE_SIZE); |
@@ -68,10 +96,8 @@ SECTIONS | |||
68 | /DISCARD/ : { | 96 | /DISCARD/ : { |
69 | *(.ARM.exidx.exit.text) | 97 | *(.ARM.exidx.exit.text) |
70 | *(.ARM.extab.exit.text) | 98 | *(.ARM.extab.exit.text) |
71 | #ifndef CONFIG_HOTPLUG_CPU | 99 | ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text)) |
72 | *(.ARM.exidx.cpuexit.text) | 100 | ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text)) |
73 | *(.ARM.extab.cpuexit.text) | ||
74 | #endif | ||
75 | #ifndef CONFIG_HOTPLUG | 101 | #ifndef CONFIG_HOTPLUG |
76 | *(.ARM.exidx.devexit.text) | 102 | *(.ARM.exidx.devexit.text) |
77 | *(.ARM.extab.devexit.text) | 103 | *(.ARM.extab.devexit.text) |
@@ -87,6 +113,7 @@ SECTIONS | |||
87 | __exception_text_start = .; | 113 | __exception_text_start = .; |
88 | *(.exception.text) | 114 | *(.exception.text) |
89 | __exception_text_end = .; | 115 | __exception_text_end = .; |
116 | IRQENTRY_TEXT | ||
90 | TEXT_TEXT | 117 | TEXT_TEXT |
91 | SCHED_TEXT | 118 | SCHED_TEXT |
92 | LOCK_TEXT | 119 | LOCK_TEXT |
@@ -99,13 +126,13 @@ SECTIONS | |||
99 | *(.rodata.*) | 126 | *(.rodata.*) |
100 | *(.glue_7) | 127 | *(.glue_7) |
101 | *(.glue_7t) | 128 | *(.glue_7t) |
129 | . = ALIGN(4); | ||
102 | *(.got) /* Global offset table */ | 130 | *(.got) /* Global offset table */ |
131 | ARM_CPU_KEEP(PROC_INFO) | ||
103 | } | 132 | } |
104 | 133 | ||
105 | RO_DATA(PAGE_SIZE) | 134 | RO_DATA(PAGE_SIZE) |
106 | 135 | ||
107 | _etext = .; /* End of text and rodata section */ | ||
108 | |||
109 | #ifdef CONFIG_ARM_UNWIND | 136 | #ifdef CONFIG_ARM_UNWIND |
110 | /* | 137 | /* |
111 | * Stack unwinding tables | 138 | * Stack unwinding tables |
@@ -123,6 +150,8 @@ SECTIONS | |||
123 | } | 150 | } |
124 | #endif | 151 | #endif |
125 | 152 | ||
153 | _etext = .; /* End of text and rodata section */ | ||
154 | |||
126 | #ifdef CONFIG_XIP_KERNEL | 155 | #ifdef CONFIG_XIP_KERNEL |
127 | __data_loc = ALIGN(4); /* location in binary */ | 156 | __data_loc = ALIGN(4); /* location in binary */ |
128 | . = PAGE_OFFSET + TEXT_OFFSET; | 157 | . = PAGE_OFFSET + TEXT_OFFSET; |
@@ -145,12 +174,14 @@ SECTIONS | |||
145 | . = ALIGN(PAGE_SIZE); | 174 | . = ALIGN(PAGE_SIZE); |
146 | __init_begin = .; | 175 | __init_begin = .; |
147 | INIT_DATA | 176 | INIT_DATA |
177 | ARM_EXIT_KEEP(EXIT_DATA) | ||
148 | . = ALIGN(PAGE_SIZE); | 178 | . = ALIGN(PAGE_SIZE); |
149 | __init_end = .; | 179 | __init_end = .; |
150 | #endif | 180 | #endif |
151 | 181 | ||
152 | NOSAVE_DATA | 182 | NOSAVE_DATA |
153 | CACHELINE_ALIGNED_DATA(32) | 183 | CACHELINE_ALIGNED_DATA(32) |
184 | READ_MOSTLY_DATA(32) | ||
154 | 185 | ||
155 | /* | 186 | /* |
156 | * The exception fixup table (might need resorting at runtime) | 187 | * The exception fixup table (might need resorting at runtime) |
@@ -229,6 +260,8 @@ SECTIONS | |||
229 | } | 260 | } |
230 | #endif | 261 | #endif |
231 | 262 | ||
263 | NOTES | ||
264 | |||
232 | BSS_SECTION(0, 0, 0) | 265 | BSS_SECTION(0, 0, 0) |
233 | _end = .; | 266 | _end = .; |
234 | 267 | ||
@@ -237,6 +270,12 @@ SECTIONS | |||
237 | 270 | ||
238 | /* Default discards */ | 271 | /* Default discards */ |
239 | DISCARDS | 272 | DISCARDS |
273 | |||
274 | #ifndef CONFIG_SMP_ON_UP | ||
275 | /DISCARD/ : { | ||
276 | *(.alt.smp.init) | ||
277 | } | ||
278 | #endif | ||
240 | } | 279 | } |
241 | 280 | ||
242 | /* | 281 | /* |