diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-20 18:40:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-20 18:40:44 -0500 |
commit | 82b51734b4f228c76b6064b6e899d9d3d4c17c1a (patch) | |
tree | 0f8735944ab146713dba402261b4c7cc5629d02f /arch/arm64 | |
parent | 15c81026204da897a05424c79263aea861a782cc (diff) | |
parent | 883c057367014d20a14b5054e4eb0d81ce3bea5c (diff) |
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull ARM64 updates from Catalin Marinas:
- CPU suspend support on top of PSCI (firmware Power State Coordination
Interface)
- jump label support
- CMA can now be enabled on arm64
- HWCAP bits for crypto and CRC32 extensions
- optimised percpu using tpidr_el1 register
- code cleanup
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (42 commits)
arm64: fix typo in entry.S
arm64: kernel: restore HW breakpoint registers in cpu_suspend
jump_label: use defined macros instead of hard-coding for better readability
arm64, jump label: optimize jump label implementation
arm64, jump label: detect %c support for ARM64
arm64: introduce aarch64_insn_gen_{nop|branch_imm}() helper functions
arm64: move encode_insn_immediate() from module.c to insn.c
arm64: introduce interfaces to hotpatch kernel and module code
arm64: introduce basic aarch64 instruction decoding helpers
arm64: dts: Reduce size of virtio block device for foundation model
arm64: Remove unused __data_loc variable
arm64: Enable CMA
arm64: Warn on NULL device structure for dma APIs
arm64: Add hwcaps for crypto and CRC32 extensions.
arm64: drop redundant macros from read_cpuid()
arm64: Remove outdated comment
arm64: cmpxchg: update macros to prevent warnings
arm64: support single-step and breakpoint handler hooks
ARM64: fix framepointer check in unwind_frame
ARM64: check stack pointer in get_wchan
...
Diffstat (limited to 'arch/arm64')
46 files changed, 1808 insertions, 395 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 6d4dd22ee4b7..dd4327f09ba4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -2,6 +2,7 @@ config ARM64 | |||
2 | def_bool y | 2 | def_bool y |
3 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 3 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
4 | select ARCH_USE_CMPXCHG_LOCKREF | 4 | select ARCH_USE_CMPXCHG_LOCKREF |
5 | select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST | ||
5 | select ARCH_WANT_OPTIONAL_GPIOLIB | 6 | select ARCH_WANT_OPTIONAL_GPIOLIB |
6 | select ARCH_WANT_COMPAT_IPC_PARSE_VERSION | 7 | select ARCH_WANT_COMPAT_IPC_PARSE_VERSION |
7 | select ARCH_WANT_FRAME_POINTERS | 8 | select ARCH_WANT_FRAME_POINTERS |
@@ -11,19 +12,27 @@ config ARM64 | |||
11 | select BUILDTIME_EXTABLE_SORT | 12 | select BUILDTIME_EXTABLE_SORT |
12 | select CLONE_BACKWARDS | 13 | select CLONE_BACKWARDS |
13 | select COMMON_CLK | 14 | select COMMON_CLK |
15 | select CPU_PM if (SUSPEND || CPU_IDLE) | ||
16 | select DCACHE_WORD_ACCESS | ||
14 | select GENERIC_CLOCKEVENTS | 17 | select GENERIC_CLOCKEVENTS |
18 | select GENERIC_CLOCKEVENTS_BROADCAST if SMP | ||
15 | select GENERIC_IOMAP | 19 | select GENERIC_IOMAP |
16 | select GENERIC_IRQ_PROBE | 20 | select GENERIC_IRQ_PROBE |
17 | select GENERIC_IRQ_SHOW | 21 | select GENERIC_IRQ_SHOW |
18 | select GENERIC_SCHED_CLOCK | 22 | select GENERIC_SCHED_CLOCK |
19 | select GENERIC_SMP_IDLE_THREAD | 23 | select GENERIC_SMP_IDLE_THREAD |
24 | select GENERIC_STRNCPY_FROM_USER | ||
25 | select GENERIC_STRNLEN_USER | ||
20 | select GENERIC_TIME_VSYSCALL | 26 | select GENERIC_TIME_VSYSCALL |
21 | select HARDIRQS_SW_RESEND | 27 | select HARDIRQS_SW_RESEND |
28 | select HAVE_ARCH_JUMP_LABEL | ||
22 | select HAVE_ARCH_TRACEHOOK | 29 | select HAVE_ARCH_TRACEHOOK |
23 | select HAVE_DEBUG_BUGVERBOSE | 30 | select HAVE_DEBUG_BUGVERBOSE |
24 | select HAVE_DEBUG_KMEMLEAK | 31 | select HAVE_DEBUG_KMEMLEAK |
25 | select HAVE_DMA_API_DEBUG | 32 | select HAVE_DMA_API_DEBUG |
26 | select HAVE_DMA_ATTRS | 33 | select HAVE_DMA_ATTRS |
34 | select HAVE_DMA_CONTIGUOUS | ||
35 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | ||
27 | select HAVE_GENERIC_DMA_COHERENT | 36 | select HAVE_GENERIC_DMA_COHERENT |
28 | select HAVE_HW_BREAKPOINT if PERF_EVENTS | 37 | select HAVE_HW_BREAKPOINT if PERF_EVENTS |
29 | select HAVE_MEMBLOCK | 38 | select HAVE_MEMBLOCK |
@@ -275,6 +284,24 @@ config SYSVIPC_COMPAT | |||
275 | 284 | ||
276 | endmenu | 285 | endmenu |
277 | 286 | ||
287 | menu "Power management options" | ||
288 | |||
289 | source "kernel/power/Kconfig" | ||
290 | |||
291 | config ARCH_SUSPEND_POSSIBLE | ||
292 | def_bool y | ||
293 | |||
294 | config ARM64_CPU_SUSPEND | ||
295 | def_bool PM_SLEEP | ||
296 | |||
297 | endmenu | ||
298 | |||
299 | menu "CPU Power Management" | ||
300 | |||
301 | source "drivers/cpuidle/Kconfig" | ||
302 | |||
303 | endmenu | ||
304 | |||
278 | source "net/Kconfig" | 305 | source "net/Kconfig" |
279 | 306 | ||
280 | source "drivers/Kconfig" | 307 | source "drivers/Kconfig" |
diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts index 519c4b2c0687..4a060906809d 100644 --- a/arch/arm64/boot/dts/foundation-v8.dts +++ b/arch/arm64/boot/dts/foundation-v8.dts | |||
@@ -224,7 +224,7 @@ | |||
224 | 224 | ||
225 | virtio_block@0130000 { | 225 | virtio_block@0130000 { |
226 | compatible = "virtio,mmio"; | 226 | compatible = "virtio,mmio"; |
227 | reg = <0x130000 0x1000>; | 227 | reg = <0x130000 0x200>; |
228 | interrupts = <42>; | 228 | interrupts = <42>; |
229 | }; | 229 | }; |
230 | }; | 230 | }; |
diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi index b45e5f39f577..2f2ecd217363 100644 --- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +++ b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi | |||
@@ -183,6 +183,12 @@ | |||
183 | clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; | 183 | clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; |
184 | clock-names = "clcdclk", "apb_pclk"; | 184 | clock-names = "clcdclk", "apb_pclk"; |
185 | }; | 185 | }; |
186 | |||
187 | virtio_block@0130000 { | ||
188 | compatible = "virtio,mmio"; | ||
189 | reg = <0x130000 0x200>; | ||
190 | interrupts = <42>; | ||
191 | }; | ||
186 | }; | 192 | }; |
187 | 193 | ||
188 | v2m_fixed_3v3: fixedregulator@0 { | 194 | v2m_fixed_3v3: fixedregulator@0 { |
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index 519f89f5b6a3..d0ff25de67ca 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild | |||
@@ -26,7 +26,6 @@ generic-y += mman.h | |||
26 | generic-y += msgbuf.h | 26 | generic-y += msgbuf.h |
27 | generic-y += mutex.h | 27 | generic-y += mutex.h |
28 | generic-y += pci.h | 28 | generic-y += pci.h |
29 | generic-y += percpu.h | ||
30 | generic-y += poll.h | 29 | generic-y += poll.h |
31 | generic-y += posix_types.h | 30 | generic-y += posix_types.h |
32 | generic-y += resource.h | 31 | generic-y += resource.h |
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 3914c0dcd09c..56166d7f4a25 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h | |||
@@ -158,17 +158,23 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, | |||
158 | return ret; | 158 | return ret; |
159 | } | 159 | } |
160 | 160 | ||
161 | #define cmpxchg(ptr,o,n) \ | 161 | #define cmpxchg(ptr, o, n) \ |
162 | ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ | 162 | ({ \ |
163 | (unsigned long)(o), \ | 163 | __typeof__(*(ptr)) __ret; \ |
164 | (unsigned long)(n), \ | 164 | __ret = (__typeof__(*(ptr))) \ |
165 | sizeof(*(ptr)))) | 165 | __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \ |
166 | 166 | sizeof(*(ptr))); \ | |
167 | #define cmpxchg_local(ptr,o,n) \ | 167 | __ret; \ |
168 | ((__typeof__(*(ptr)))__cmpxchg((ptr), \ | 168 | }) |
169 | (unsigned long)(o), \ | 169 | |
170 | (unsigned long)(n), \ | 170 | #define cmpxchg_local(ptr, o, n) \ |
171 | sizeof(*(ptr)))) | 171 | ({ \ |
172 | __typeof__(*(ptr)) __ret; \ | ||
173 | __ret = (__typeof__(*(ptr))) \ | ||
174 | __cmpxchg((ptr), (unsigned long)(o), \ | ||
175 | (unsigned long)(n), sizeof(*(ptr))); \ | ||
176 | __ret; \ | ||
177 | }) | ||
172 | 178 | ||
173 | #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) | 179 | #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) |
174 | #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) | 180 | #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) |
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index c4cdb5e5b73d..152413076503 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h | |||
@@ -39,6 +39,9 @@ struct device_node; | |||
39 | * from the cpu to be killed. | 39 | * from the cpu to be killed. |
40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the | 40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the |
41 | * cpu being killed. | 41 | * cpu being killed. |
42 | * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing | ||
43 | * to wrong parameters or error conditions. Called from the | ||
44 | * CPU being suspended. Must be called with IRQs disabled. | ||
42 | */ | 45 | */ |
43 | struct cpu_operations { | 46 | struct cpu_operations { |
44 | const char *name; | 47 | const char *name; |
@@ -50,6 +53,9 @@ struct cpu_operations { | |||
50 | int (*cpu_disable)(unsigned int cpu); | 53 | int (*cpu_disable)(unsigned int cpu); |
51 | void (*cpu_die)(unsigned int cpu); | 54 | void (*cpu_die)(unsigned int cpu); |
52 | #endif | 55 | #endif |
56 | #ifdef CONFIG_ARM64_CPU_SUSPEND | ||
57 | int (*cpu_suspend)(unsigned long); | ||
58 | #endif | ||
53 | }; | 59 | }; |
54 | 60 | ||
55 | extern const struct cpu_operations *cpu_ops[NR_CPUS]; | 61 | extern const struct cpu_operations *cpu_ops[NR_CPUS]; |
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 5fe138e0b828..c404fb0df3a6 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h | |||
@@ -16,23 +16,23 @@ | |||
16 | #ifndef __ASM_CPUTYPE_H | 16 | #ifndef __ASM_CPUTYPE_H |
17 | #define __ASM_CPUTYPE_H | 17 | #define __ASM_CPUTYPE_H |
18 | 18 | ||
19 | #define ID_MIDR_EL1 "midr_el1" | ||
20 | #define ID_MPIDR_EL1 "mpidr_el1" | ||
21 | #define ID_CTR_EL0 "ctr_el0" | ||
22 | |||
23 | #define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" | ||
24 | #define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" | ||
25 | #define ID_AA64AFR0_EL1 "id_aa64afr0_el1" | ||
26 | #define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" | ||
27 | #define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" | ||
28 | |||
29 | #define INVALID_HWID ULONG_MAX | 19 | #define INVALID_HWID ULONG_MAX |
30 | 20 | ||
31 | #define MPIDR_HWID_BITMASK 0xff00ffffff | 21 | #define MPIDR_HWID_BITMASK 0xff00ffffff |
32 | 22 | ||
23 | #define MPIDR_LEVEL_BITS_SHIFT 3 | ||
24 | #define MPIDR_LEVEL_BITS (1 << MPIDR_LEVEL_BITS_SHIFT) | ||
25 | #define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1) | ||
26 | |||
27 | #define MPIDR_LEVEL_SHIFT(level) \ | ||
28 | (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT) | ||
29 | |||
30 | #define MPIDR_AFFINITY_LEVEL(mpidr, level) \ | ||
31 | ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK) | ||
32 | |||
33 | #define read_cpuid(reg) ({ \ | 33 | #define read_cpuid(reg) ({ \ |
34 | u64 __val; \ | 34 | u64 __val; \ |
35 | asm("mrs %0, " reg : "=r" (__val)); \ | 35 | asm("mrs %0, " #reg : "=r" (__val)); \ |
36 | __val; \ | 36 | __val; \ |
37 | }) | 37 | }) |
38 | 38 | ||
@@ -54,12 +54,12 @@ | |||
54 | */ | 54 | */ |
55 | static inline u32 __attribute_const__ read_cpuid_id(void) | 55 | static inline u32 __attribute_const__ read_cpuid_id(void) |
56 | { | 56 | { |
57 | return read_cpuid(ID_MIDR_EL1); | 57 | return read_cpuid(MIDR_EL1); |
58 | } | 58 | } |
59 | 59 | ||
60 | static inline u64 __attribute_const__ read_cpuid_mpidr(void) | 60 | static inline u64 __attribute_const__ read_cpuid_mpidr(void) |
61 | { | 61 | { |
62 | return read_cpuid(ID_MPIDR_EL1); | 62 | return read_cpuid(MPIDR_EL1); |
63 | } | 63 | } |
64 | 64 | ||
65 | static inline unsigned int __attribute_const__ read_cpuid_implementor(void) | 65 | static inline unsigned int __attribute_const__ read_cpuid_implementor(void) |
@@ -74,7 +74,7 @@ static inline unsigned int __attribute_const__ read_cpuid_part_number(void) | |||
74 | 74 | ||
75 | static inline u32 __attribute_const__ read_cpuid_cachetype(void) | 75 | static inline u32 __attribute_const__ read_cpuid_cachetype(void) |
76 | { | 76 | { |
77 | return read_cpuid(ID_CTR_EL0); | 77 | return read_cpuid(CTR_EL0); |
78 | } | 78 | } |
79 | 79 | ||
80 | #endif /* __ASSEMBLY__ */ | 80 | #endif /* __ASSEMBLY__ */ |
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index a2232d07be9d..62314791570c 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h | |||
@@ -62,6 +62,27 @@ struct task_struct; | |||
62 | 62 | ||
63 | #define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */ | 63 | #define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */ |
64 | 64 | ||
65 | #define DBG_HOOK_HANDLED 0 | ||
66 | #define DBG_HOOK_ERROR 1 | ||
67 | |||
68 | struct step_hook { | ||
69 | struct list_head node; | ||
70 | int (*fn)(struct pt_regs *regs, unsigned int esr); | ||
71 | }; | ||
72 | |||
73 | void register_step_hook(struct step_hook *hook); | ||
74 | void unregister_step_hook(struct step_hook *hook); | ||
75 | |||
76 | struct break_hook { | ||
77 | struct list_head node; | ||
78 | u32 esr_val; | ||
79 | u32 esr_mask; | ||
80 | int (*fn)(struct pt_regs *regs, unsigned int esr); | ||
81 | }; | ||
82 | |||
83 | void register_break_hook(struct break_hook *hook); | ||
84 | void unregister_break_hook(struct break_hook *hook); | ||
85 | |||
65 | u8 debug_monitors_arch(void); | 86 | u8 debug_monitors_arch(void); |
66 | 87 | ||
67 | void enable_debug_monitors(enum debug_el el); | 88 | void enable_debug_monitors(enum debug_el el); |
diff --git a/arch/arm64/include/asm/dma-contiguous.h b/arch/arm64/include/asm/dma-contiguous.h new file mode 100644 index 000000000000..d6aacb61ff4a --- /dev/null +++ b/arch/arm64/include/asm/dma-contiguous.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | ||
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 and | ||
6 | * only version 2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef _ASM_DMA_CONTIGUOUS_H | ||
15 | #define _ASM_DMA_CONTIGUOUS_H | ||
16 | |||
17 | #ifdef __KERNEL__ | ||
18 | #ifdef CONFIG_DMA_CMA | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <asm-generic/dma-contiguous.h> | ||
22 | |||
23 | static inline void | ||
24 | dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } | ||
25 | |||
26 | #endif | ||
27 | #endif | ||
28 | |||
29 | #endif | ||
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index c582fa316366..78cc3aba5d69 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h | |||
@@ -30,6 +30,7 @@ | |||
30 | " cbnz %w3, 1b\n" \ | 30 | " cbnz %w3, 1b\n" \ |
31 | "3:\n" \ | 31 | "3:\n" \ |
32 | " .pushsection .fixup,\"ax\"\n" \ | 32 | " .pushsection .fixup,\"ax\"\n" \ |
33 | " .align 2\n" \ | ||
33 | "4: mov %w0, %w5\n" \ | 34 | "4: mov %w0, %w5\n" \ |
34 | " b 3b\n" \ | 35 | " b 3b\n" \ |
35 | " .popsection\n" \ | 36 | " .popsection\n" \ |
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index 990c051e7829..ae4801d77514 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/threads.h> | 20 | #include <linux/threads.h> |
21 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
22 | 22 | ||
23 | #define NR_IPI 4 | 23 | #define NR_IPI 5 |
24 | 24 | ||
25 | typedef struct { | 25 | typedef struct { |
26 | unsigned int __softirq_pending; | 26 | unsigned int __softirq_pending; |
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h new file mode 100644 index 000000000000..c44ad39ed310 --- /dev/null +++ b/arch/arm64/include/asm/insn.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Huawei Ltd. | ||
3 | * Author: Jiang Liu <liuj97@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #ifndef __ASM_INSN_H | ||
18 | #define __ASM_INSN_H | ||
19 | #include <linux/types.h> | ||
20 | |||
21 | /* A64 instructions are always 32 bits. */ | ||
22 | #define AARCH64_INSN_SIZE 4 | ||
23 | |||
24 | /* | ||
25 | * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a | ||
26 | * Section C3.1 "A64 instruction index by encoding": | ||
27 | * AArch64 main encoding table | ||
28 | * Bit position | ||
29 | * 28 27 26 25 Encoding Group | ||
30 | * 0 0 - - Unallocated | ||
31 | * 1 0 0 - Data processing, immediate | ||
32 | * 1 0 1 - Branch, exception generation and system instructions | ||
33 | * - 1 - 0 Loads and stores | ||
34 | * - 1 0 1 Data processing - register | ||
35 | * 0 1 1 1 Data processing - SIMD and floating point | ||
36 | * 1 1 1 1 Data processing - SIMD and floating point | ||
37 | * "-" means "don't care" | ||
38 | */ | ||
39 | enum aarch64_insn_encoding_class { | ||
40 | AARCH64_INSN_CLS_UNKNOWN, /* UNALLOCATED */ | ||
41 | AARCH64_INSN_CLS_DP_IMM, /* Data processing - immediate */ | ||
42 | AARCH64_INSN_CLS_DP_REG, /* Data processing - register */ | ||
43 | AARCH64_INSN_CLS_DP_FPSIMD, /* Data processing - SIMD and FP */ | ||
44 | AARCH64_INSN_CLS_LDST, /* Loads and stores */ | ||
45 | AARCH64_INSN_CLS_BR_SYS, /* Branch, exception generation and | ||
46 | * system instructions */ | ||
47 | }; | ||
48 | |||
49 | enum aarch64_insn_hint_op { | ||
50 | AARCH64_INSN_HINT_NOP = 0x0 << 5, | ||
51 | AARCH64_INSN_HINT_YIELD = 0x1 << 5, | ||
52 | AARCH64_INSN_HINT_WFE = 0x2 << 5, | ||
53 | AARCH64_INSN_HINT_WFI = 0x3 << 5, | ||
54 | AARCH64_INSN_HINT_SEV = 0x4 << 5, | ||
55 | AARCH64_INSN_HINT_SEVL = 0x5 << 5, | ||
56 | }; | ||
57 | |||
58 | enum aarch64_insn_imm_type { | ||
59 | AARCH64_INSN_IMM_ADR, | ||
60 | AARCH64_INSN_IMM_26, | ||
61 | AARCH64_INSN_IMM_19, | ||
62 | AARCH64_INSN_IMM_16, | ||
63 | AARCH64_INSN_IMM_14, | ||
64 | AARCH64_INSN_IMM_12, | ||
65 | AARCH64_INSN_IMM_9, | ||
66 | AARCH64_INSN_IMM_MAX | ||
67 | }; | ||
68 | |||
69 | enum aarch64_insn_branch_type { | ||
70 | AARCH64_INSN_BRANCH_NOLINK, | ||
71 | AARCH64_INSN_BRANCH_LINK, | ||
72 | }; | ||
73 | |||
74 | #define __AARCH64_INSN_FUNCS(abbr, mask, val) \ | ||
75 | static __always_inline bool aarch64_insn_is_##abbr(u32 code) \ | ||
76 | { return (code & (mask)) == (val); } \ | ||
77 | static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \ | ||
78 | { return (val); } | ||
79 | |||
80 | __AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000) | ||
81 | __AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000) | ||
82 | __AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001) | ||
83 | __AARCH64_INSN_FUNCS(hvc, 0xFFE0001F, 0xD4000002) | ||
84 | __AARCH64_INSN_FUNCS(smc, 0xFFE0001F, 0xD4000003) | ||
85 | __AARCH64_INSN_FUNCS(brk, 0xFFE0001F, 0xD4200000) | ||
86 | __AARCH64_INSN_FUNCS(hint, 0xFFFFF01F, 0xD503201F) | ||
87 | |||
88 | #undef __AARCH64_INSN_FUNCS | ||
89 | |||
90 | bool aarch64_insn_is_nop(u32 insn); | ||
91 | |||
92 | int aarch64_insn_read(void *addr, u32 *insnp); | ||
93 | int aarch64_insn_write(void *addr, u32 insn); | ||
94 | enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn); | ||
95 | u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, | ||
96 | u32 insn, u64 imm); | ||
97 | u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, | ||
98 | enum aarch64_insn_branch_type type); | ||
99 | u32 aarch64_insn_gen_hint(enum aarch64_insn_hint_op op); | ||
100 | u32 aarch64_insn_gen_nop(void); | ||
101 | |||
102 | bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); | ||
103 | |||
104 | int aarch64_insn_patch_text_nosync(void *addr, u32 insn); | ||
105 | int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); | ||
106 | int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); | ||
107 | |||
108 | #endif /* __ASM_INSN_H */ | ||
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h new file mode 100644 index 000000000000..076a1c714049 --- /dev/null +++ b/arch/arm64/include/asm/jump_label.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Huawei Ltd. | ||
3 | * Author: Jiang Liu <liuj97@gmail.com> | ||
4 | * | ||
5 | * Based on arch/arm/include/asm/jump_label.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 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #ifndef __ASM_JUMP_LABEL_H | ||
20 | #define __ASM_JUMP_LABEL_H | ||
21 | #include <linux/types.h> | ||
22 | #include <asm/insn.h> | ||
23 | |||
24 | #ifdef __KERNEL__ | ||
25 | |||
26 | #define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE | ||
27 | |||
28 | static __always_inline bool arch_static_branch(struct static_key *key) | ||
29 | { | ||
30 | asm goto("1: nop\n\t" | ||
31 | ".pushsection __jump_table, \"aw\"\n\t" | ||
32 | ".align 3\n\t" | ||
33 | ".quad 1b, %l[l_yes], %c0\n\t" | ||
34 | ".popsection\n\t" | ||
35 | : : "i"(key) : : l_yes); | ||
36 | |||
37 | return false; | ||
38 | l_yes: | ||
39 | return true; | ||
40 | } | ||
41 | |||
42 | #endif /* __KERNEL__ */ | ||
43 | |||
44 | typedef u64 jump_label_t; | ||
45 | |||
46 | struct jump_entry { | ||
47 | jump_label_t code; | ||
48 | jump_label_t target; | ||
49 | jump_label_t key; | ||
50 | }; | ||
51 | |||
52 | #endif /* __ASM_JUMP_LABEL_H */ | ||
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 37762175896f..9dc5dc39fded 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h | |||
@@ -146,8 +146,7 @@ static inline void *phys_to_virt(phys_addr_t x) | |||
146 | #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET | 146 | #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET |
147 | 147 | ||
148 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | 148 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) |
149 | #define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ | 149 | #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) |
150 | ((void *)(kaddr) < (void *)high_memory)) | ||
151 | 150 | ||
152 | #endif | 151 | #endif |
153 | 152 | ||
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h new file mode 100644 index 000000000000..13fb0b3efc5f --- /dev/null +++ b/arch/arm64/include/asm/percpu.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 ARM Ltd. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #ifndef __ASM_PERCPU_H | ||
17 | #define __ASM_PERCPU_H | ||
18 | |||
19 | static inline void set_my_cpu_offset(unsigned long off) | ||
20 | { | ||
21 | asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); | ||
22 | } | ||
23 | |||
24 | static inline unsigned long __my_cpu_offset(void) | ||
25 | { | ||
26 | unsigned long off; | ||
27 | register unsigned long *sp asm ("sp"); | ||
28 | |||
29 | /* | ||
30 | * We want to allow caching the value, so avoid using volatile and | ||
31 | * instead use a fake stack read to hazard against barrier(). | ||
32 | */ | ||
33 | asm("mrs %0, tpidr_el1" : "=r" (off) : "Q" (*sp)); | ||
34 | |||
35 | return off; | ||
36 | } | ||
37 | #define __my_cpu_offset __my_cpu_offset() | ||
38 | |||
39 | #include <asm-generic/percpu.h> | ||
40 | |||
41 | #endif /* __ASM_PERCPU_H */ | ||
diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h index 7cdf466fd0c5..0c657bb54597 100644 --- a/arch/arm64/include/asm/proc-fns.h +++ b/arch/arm64/include/asm/proc-fns.h | |||
@@ -26,11 +26,14 @@ | |||
26 | #include <asm/page.h> | 26 | #include <asm/page.h> |
27 | 27 | ||
28 | struct mm_struct; | 28 | struct mm_struct; |
29 | struct cpu_suspend_ctx; | ||
29 | 30 | ||
30 | extern void cpu_cache_off(void); | 31 | extern void cpu_cache_off(void); |
31 | extern void cpu_do_idle(void); | 32 | extern void cpu_do_idle(void); |
32 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); | 33 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); |
33 | extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); | 34 | extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); |
35 | extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr); | ||
36 | extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr); | ||
34 | 37 | ||
35 | #include <asm/memory.h> | 38 | #include <asm/memory.h> |
36 | 39 | ||
diff --git a/arch/arm64/include/asm/smp_plat.h b/arch/arm64/include/asm/smp_plat.h index ed43a0d2b1b2..59e282311b58 100644 --- a/arch/arm64/include/asm/smp_plat.h +++ b/arch/arm64/include/asm/smp_plat.h | |||
@@ -21,6 +21,19 @@ | |||
21 | 21 | ||
22 | #include <asm/types.h> | 22 | #include <asm/types.h> |
23 | 23 | ||
24 | struct mpidr_hash { | ||
25 | u64 mask; | ||
26 | u32 shift_aff[4]; | ||
27 | u32 bits; | ||
28 | }; | ||
29 | |||
30 | extern struct mpidr_hash mpidr_hash; | ||
31 | |||
32 | static inline u32 mpidr_hash_size(void) | ||
33 | { | ||
34 | return 1 << mpidr_hash.bits; | ||
35 | } | ||
36 | |||
24 | /* | 37 | /* |
25 | * Logical CPU mapping. | 38 | * Logical CPU mapping. |
26 | */ | 39 | */ |
diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h new file mode 100644 index 000000000000..e9c149c042e0 --- /dev/null +++ b/arch/arm64/include/asm/suspend.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef __ASM_SUSPEND_H | ||
2 | #define __ASM_SUSPEND_H | ||
3 | |||
4 | #define NR_CTX_REGS 11 | ||
5 | |||
6 | /* | ||
7 | * struct cpu_suspend_ctx must be 16-byte aligned since it is allocated on | ||
8 | * the stack, which must be 16-byte aligned on v8 | ||
9 | */ | ||
10 | struct cpu_suspend_ctx { | ||
11 | /* | ||
12 | * This struct must be kept in sync with | ||
13 | * cpu_do_{suspend/resume} in mm/proc.S | ||
14 | */ | ||
15 | u64 ctx_regs[NR_CTX_REGS]; | ||
16 | u64 sp; | ||
17 | } __aligned(16); | ||
18 | |||
19 | struct sleep_save_sp { | ||
20 | phys_addr_t *save_ptr_stash; | ||
21 | phys_addr_t save_ptr_stash_phys; | ||
22 | }; | ||
23 | |||
24 | extern void cpu_resume(void); | ||
25 | extern int cpu_suspend(unsigned long); | ||
26 | |||
27 | #endif | ||
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 7ecc2b23882e..6c0f684aca81 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h | |||
@@ -100,6 +100,7 @@ static inline void set_fs(mm_segment_t fs) | |||
100 | }) | 100 | }) |
101 | 101 | ||
102 | #define access_ok(type, addr, size) __range_ok(addr, size) | 102 | #define access_ok(type, addr, size) __range_ok(addr, size) |
103 | #define user_addr_max get_fs | ||
103 | 104 | ||
104 | /* | 105 | /* |
105 | * The "__xxx" versions of the user access functions do not verify the address | 106 | * The "__xxx" versions of the user access functions do not verify the address |
@@ -240,9 +241,6 @@ extern unsigned long __must_check __copy_to_user(void __user *to, const void *fr | |||
240 | extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); | 241 | extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); |
241 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); | 242 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); |
242 | 243 | ||
243 | extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count); | ||
244 | extern unsigned long __must_check __strnlen_user(const char __user *s, long n); | ||
245 | |||
246 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) | 244 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) |
247 | { | 245 | { |
248 | if (access_ok(VERIFY_READ, from, n)) | 246 | if (access_ok(VERIFY_READ, from, n)) |
@@ -276,24 +274,9 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo | |||
276 | return n; | 274 | return n; |
277 | } | 275 | } |
278 | 276 | ||
279 | static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count) | 277 | extern long strncpy_from_user(char *dest, const char __user *src, long count); |
280 | { | ||
281 | long res = -EFAULT; | ||
282 | if (access_ok(VERIFY_READ, src, 1)) | ||
283 | res = __strncpy_from_user(dst, src, count); | ||
284 | return res; | ||
285 | } | ||
286 | |||
287 | #define strlen_user(s) strnlen_user(s, ~0UL >> 1) | ||
288 | 278 | ||
289 | static inline long __must_check strnlen_user(const char __user *s, long n) | 279 | extern __must_check long strlen_user(const char __user *str); |
290 | { | 280 | extern __must_check long strnlen_user(const char __user *str, long n); |
291 | unsigned long res = 0; | ||
292 | |||
293 | if (__addr_ok(s)) | ||
294 | res = __strnlen_user(s, n); | ||
295 | |||
296 | return res; | ||
297 | } | ||
298 | 281 | ||
299 | #endif /* __ASM_UACCESS_H */ | 282 | #endif /* __ASM_UACCESS_H */ |
diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h new file mode 100644 index 000000000000..aab5bf09e9d9 --- /dev/null +++ b/arch/arm64/include/asm/word-at-a-time.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 ARM Ltd. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #ifndef __ASM_WORD_AT_A_TIME_H | ||
17 | #define __ASM_WORD_AT_A_TIME_H | ||
18 | |||
19 | #ifndef __AARCH64EB__ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | |||
23 | struct word_at_a_time { | ||
24 | const unsigned long one_bits, high_bits; | ||
25 | }; | ||
26 | |||
27 | #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } | ||
28 | |||
29 | static inline unsigned long has_zero(unsigned long a, unsigned long *bits, | ||
30 | const struct word_at_a_time *c) | ||
31 | { | ||
32 | unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; | ||
33 | *bits = mask; | ||
34 | return mask; | ||
35 | } | ||
36 | |||
37 | #define prep_zero_mask(a, bits, c) (bits) | ||
38 | |||
39 | static inline unsigned long create_zero_mask(unsigned long bits) | ||
40 | { | ||
41 | bits = (bits - 1) & ~bits; | ||
42 | return bits >> 7; | ||
43 | } | ||
44 | |||
45 | static inline unsigned long find_zero(unsigned long mask) | ||
46 | { | ||
47 | return fls64(mask) >> 3; | ||
48 | } | ||
49 | |||
50 | #define zero_bytemask(mask) (mask) | ||
51 | |||
52 | #else /* __AARCH64EB__ */ | ||
53 | #include <asm-generic/word-at-a-time.h> | ||
54 | #endif | ||
55 | |||
56 | /* | ||
57 | * Load an unaligned word from kernel space. | ||
58 | * | ||
59 | * In the (very unlikely) case of the word being a page-crosser | ||
60 | * and the next page not being mapped, take the exception and | ||
61 | * return zeroes in the non-existing part. | ||
62 | */ | ||
63 | static inline unsigned long load_unaligned_zeropad(const void *addr) | ||
64 | { | ||
65 | unsigned long ret, offset; | ||
66 | |||
67 | /* Load word from unaligned pointer addr */ | ||
68 | asm( | ||
69 | "1: ldr %0, %3\n" | ||
70 | "2:\n" | ||
71 | " .pushsection .fixup,\"ax\"\n" | ||
72 | " .align 2\n" | ||
73 | "3: and %1, %2, #0x7\n" | ||
74 | " bic %2, %2, #0x7\n" | ||
75 | " ldr %0, [%2]\n" | ||
76 | " lsl %1, %1, #0x3\n" | ||
77 | #ifndef __AARCH64EB__ | ||
78 | " lsr %0, %0, %1\n" | ||
79 | #else | ||
80 | " lsl %0, %0, %1\n" | ||
81 | #endif | ||
82 | " b 2b\n" | ||
83 | " .popsection\n" | ||
84 | " .pushsection __ex_table,\"a\"\n" | ||
85 | " .align 3\n" | ||
86 | " .quad 1b, 3b\n" | ||
87 | " .popsection" | ||
88 | : "=&r" (ret), "=&r" (offset) | ||
89 | : "r" (addr), "Q" (*(unsigned long *)addr)); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | #endif /* __ASM_WORD_AT_A_TIME_H */ | ||
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index 9b12476e9c85..73cf0f54d57c 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h | |||
@@ -22,6 +22,10 @@ | |||
22 | #define HWCAP_FP (1 << 0) | 22 | #define HWCAP_FP (1 << 0) |
23 | #define HWCAP_ASIMD (1 << 1) | 23 | #define HWCAP_ASIMD (1 << 1) |
24 | #define HWCAP_EVTSTRM (1 << 2) | 24 | #define HWCAP_EVTSTRM (1 << 2) |
25 | 25 | #define HWCAP_AES (1 << 3) | |
26 | #define HWCAP_PMULL (1 << 4) | ||
27 | #define HWCAP_SHA1 (1 << 5) | ||
28 | #define HWCAP_SHA2 (1 << 6) | ||
29 | #define HWCAP_CRC32 (1 << 7) | ||
26 | 30 | ||
27 | #endif /* _UAPI__ASM_HWCAP_H */ | 31 | #endif /* _UAPI__ASM_HWCAP_H */ |
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5ba2fd43a75b..2d4554b13410 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile | |||
@@ -9,7 +9,7 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | |||
9 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ | 9 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ |
10 | entry-fpsimd.o process.o ptrace.o setup.o signal.o \ | 10 | entry-fpsimd.o process.o ptrace.o setup.o signal.o \ |
11 | sys.o stacktrace.o time.o traps.o io.o vdso.o \ | 11 | sys.o stacktrace.o time.o traps.o io.o vdso.o \ |
12 | hyp-stub.o psci.o cpu_ops.o | 12 | hyp-stub.o psci.o cpu_ops.o insn.o |
13 | 13 | ||
14 | arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ | 14 | arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ |
15 | sys_compat.o | 15 | sys_compat.o |
@@ -18,6 +18,8 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o | |||
18 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 18 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
19 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o | 19 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o |
20 | arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 20 | arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
21 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o | ||
22 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o | ||
21 | 23 | ||
22 | obj-y += $(arm64-obj-y) vdso/ | 24 | obj-y += $(arm64-obj-y) vdso/ |
23 | obj-m += $(arm64-obj-m) | 25 | obj-m += $(arm64-obj-m) |
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index e7ee770c0697..338b568cd8ae 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c | |||
@@ -29,13 +29,10 @@ | |||
29 | 29 | ||
30 | #include <asm/checksum.h> | 30 | #include <asm/checksum.h> |
31 | 31 | ||
32 | /* user mem (segment) */ | ||
33 | EXPORT_SYMBOL(__strnlen_user); | ||
34 | EXPORT_SYMBOL(__strncpy_from_user); | ||
35 | |||
36 | EXPORT_SYMBOL(copy_page); | 32 | EXPORT_SYMBOL(copy_page); |
37 | EXPORT_SYMBOL(clear_page); | 33 | EXPORT_SYMBOL(clear_page); |
38 | 34 | ||
35 | /* user mem (segment) */ | ||
39 | EXPORT_SYMBOL(__copy_from_user); | 36 | EXPORT_SYMBOL(__copy_from_user); |
40 | EXPORT_SYMBOL(__copy_to_user); | 37 | EXPORT_SYMBOL(__copy_to_user); |
41 | EXPORT_SYMBOL(__clear_user); | 38 | EXPORT_SYMBOL(__clear_user); |
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 666e231d410b..646f888387cd 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <asm/thread_info.h> | 25 | #include <asm/thread_info.h> |
26 | #include <asm/memory.h> | 26 | #include <asm/memory.h> |
27 | #include <asm/cputable.h> | 27 | #include <asm/cputable.h> |
28 | #include <asm/smp_plat.h> | ||
29 | #include <asm/suspend.h> | ||
28 | #include <asm/vdso_datapage.h> | 30 | #include <asm/vdso_datapage.h> |
29 | #include <linux/kbuild.h> | 31 | #include <linux/kbuild.h> |
30 | 32 | ||
@@ -138,5 +140,14 @@ int main(void) | |||
138 | DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr)); | 140 | DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr)); |
139 | DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base)); | 141 | DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base)); |
140 | #endif | 142 | #endif |
143 | #ifdef CONFIG_ARM64_CPU_SUSPEND | ||
144 | DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx)); | ||
145 | DEFINE(CPU_CTX_SP, offsetof(struct cpu_suspend_ctx, sp)); | ||
146 | DEFINE(MPIDR_HASH_MASK, offsetof(struct mpidr_hash, mask)); | ||
147 | DEFINE(MPIDR_HASH_SHIFTS, offsetof(struct mpidr_hash, shift_aff)); | ||
148 | DEFINE(SLEEP_SAVE_SP_SZ, sizeof(struct sleep_save_sp)); | ||
149 | DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys)); | ||
150 | DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash)); | ||
151 | #endif | ||
141 | return 0; | 152 | return 0; |
142 | } | 153 | } |
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 4ae68579031d..636ba8b6240b 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c | |||
@@ -187,6 +187,48 @@ static void clear_regs_spsr_ss(struct pt_regs *regs) | |||
187 | regs->pstate = spsr; | 187 | regs->pstate = spsr; |
188 | } | 188 | } |
189 | 189 | ||
190 | /* EL1 Single Step Handler hooks */ | ||
191 | static LIST_HEAD(step_hook); | ||
192 | DEFINE_RWLOCK(step_hook_lock); | ||
193 | |||
194 | void register_step_hook(struct step_hook *hook) | ||
195 | { | ||
196 | write_lock(&step_hook_lock); | ||
197 | list_add(&hook->node, &step_hook); | ||
198 | write_unlock(&step_hook_lock); | ||
199 | } | ||
200 | |||
201 | void unregister_step_hook(struct step_hook *hook) | ||
202 | { | ||
203 | write_lock(&step_hook_lock); | ||
204 | list_del(&hook->node); | ||
205 | write_unlock(&step_hook_lock); | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * Call registered single step handers | ||
210 | * There is no Syndrome info to check for determining the handler. | ||
211 | * So we call all the registered handlers, until the right handler is | ||
212 | * found which returns zero. | ||
213 | */ | ||
214 | static int call_step_hook(struct pt_regs *regs, unsigned int esr) | ||
215 | { | ||
216 | struct step_hook *hook; | ||
217 | int retval = DBG_HOOK_ERROR; | ||
218 | |||
219 | read_lock(&step_hook_lock); | ||
220 | |||
221 | list_for_each_entry(hook, &step_hook, node) { | ||
222 | retval = hook->fn(regs, esr); | ||
223 | if (retval == DBG_HOOK_HANDLED) | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | read_unlock(&step_hook_lock); | ||
228 | |||
229 | return retval; | ||
230 | } | ||
231 | |||
190 | static int single_step_handler(unsigned long addr, unsigned int esr, | 232 | static int single_step_handler(unsigned long addr, unsigned int esr, |
191 | struct pt_regs *regs) | 233 | struct pt_regs *regs) |
192 | { | 234 | { |
@@ -214,7 +256,9 @@ static int single_step_handler(unsigned long addr, unsigned int esr, | |||
214 | */ | 256 | */ |
215 | user_rewind_single_step(current); | 257 | user_rewind_single_step(current); |
216 | } else { | 258 | } else { |
217 | /* TODO: route to KGDB */ | 259 | if (call_step_hook(regs, esr) == DBG_HOOK_HANDLED) |
260 | return 0; | ||
261 | |||
218 | pr_warning("Unexpected kernel single-step exception at EL1\n"); | 262 | pr_warning("Unexpected kernel single-step exception at EL1\n"); |
219 | /* | 263 | /* |
220 | * Re-enable stepping since we know that we will be | 264 | * Re-enable stepping since we know that we will be |
@@ -226,11 +270,53 @@ static int single_step_handler(unsigned long addr, unsigned int esr, | |||
226 | return 0; | 270 | return 0; |
227 | } | 271 | } |
228 | 272 | ||
273 | /* | ||
274 | * Breakpoint handler is re-entrant as another breakpoint can | ||
275 | * hit within breakpoint handler, especically in kprobes. | ||
276 | * Use reader/writer locks instead of plain spinlock. | ||
277 | */ | ||
278 | static LIST_HEAD(break_hook); | ||
279 | DEFINE_RWLOCK(break_hook_lock); | ||
280 | |||
281 | void register_break_hook(struct break_hook *hook) | ||
282 | { | ||
283 | write_lock(&break_hook_lock); | ||
284 | list_add(&hook->node, &break_hook); | ||
285 | write_unlock(&break_hook_lock); | ||
286 | } | ||
287 | |||
288 | void unregister_break_hook(struct break_hook *hook) | ||
289 | { | ||
290 | write_lock(&break_hook_lock); | ||
291 | list_del(&hook->node); | ||
292 | write_unlock(&break_hook_lock); | ||
293 | } | ||
294 | |||
295 | static int call_break_hook(struct pt_regs *regs, unsigned int esr) | ||
296 | { | ||
297 | struct break_hook *hook; | ||
298 | int (*fn)(struct pt_regs *regs, unsigned int esr) = NULL; | ||
299 | |||
300 | read_lock(&break_hook_lock); | ||
301 | list_for_each_entry(hook, &break_hook, node) | ||
302 | if ((esr & hook->esr_mask) == hook->esr_val) | ||
303 | fn = hook->fn; | ||
304 | read_unlock(&break_hook_lock); | ||
305 | |||
306 | return fn ? fn(regs, esr) : DBG_HOOK_ERROR; | ||
307 | } | ||
308 | |||
229 | static int brk_handler(unsigned long addr, unsigned int esr, | 309 | static int brk_handler(unsigned long addr, unsigned int esr, |
230 | struct pt_regs *regs) | 310 | struct pt_regs *regs) |
231 | { | 311 | { |
232 | siginfo_t info; | 312 | siginfo_t info; |
233 | 313 | ||
314 | if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED) | ||
315 | return 0; | ||
316 | |||
317 | pr_warn("unexpected brk exception at %lx, esr=0x%x\n", | ||
318 | (long)instruction_pointer(regs), esr); | ||
319 | |||
234 | if (!user_mode(regs)) | 320 | if (!user_mode(regs)) |
235 | return -EFAULT; | 321 | return -EFAULT; |
236 | 322 | ||
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 4d2c6f3f0c41..39ac630d83de 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S | |||
@@ -288,6 +288,8 @@ el1_dbg: | |||
288 | /* | 288 | /* |
289 | * Debug exception handling | 289 | * Debug exception handling |
290 | */ | 290 | */ |
291 | cmp x24, #ESR_EL1_EC_BRK64 // if BRK64 | ||
292 | cinc x24, x24, eq // set bit '0' | ||
291 | tbz x24, #0, el1_inv // EL1 only | 293 | tbz x24, #0, el1_inv // EL1 only |
292 | mrs x0, far_el1 | 294 | mrs x0, far_el1 |
293 | mov x2, sp // struct pt_regs | 295 | mov x2, sp // struct pt_regs |
@@ -314,7 +316,7 @@ el1_irq: | |||
314 | 316 | ||
315 | #ifdef CONFIG_PREEMPT | 317 | #ifdef CONFIG_PREEMPT |
316 | get_thread_info tsk | 318 | get_thread_info tsk |
317 | ldr w24, [tsk, #TI_PREEMPT] // restore preempt count | 319 | ldr w24, [tsk, #TI_PREEMPT] // get preempt count |
318 | cbnz w24, 1f // preempt count != 0 | 320 | cbnz w24, 1f // preempt count != 0 |
319 | ldr x0, [tsk, #TI_FLAGS] // get flags | 321 | ldr x0, [tsk, #TI_FLAGS] // get flags |
320 | tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? | 322 | tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? |
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index bb785d23dbde..4aef42a04bdc 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/cpu_pm.h> | ||
20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
22 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
@@ -113,6 +114,39 @@ EXPORT_SYMBOL(kernel_neon_end); | |||
113 | 114 | ||
114 | #endif /* CONFIG_KERNEL_MODE_NEON */ | 115 | #endif /* CONFIG_KERNEL_MODE_NEON */ |
115 | 116 | ||
117 | #ifdef CONFIG_CPU_PM | ||
118 | static int fpsimd_cpu_pm_notifier(struct notifier_block *self, | ||
119 | unsigned long cmd, void *v) | ||
120 | { | ||
121 | switch (cmd) { | ||
122 | case CPU_PM_ENTER: | ||
123 | if (current->mm) | ||
124 | fpsimd_save_state(¤t->thread.fpsimd_state); | ||
125 | break; | ||
126 | case CPU_PM_EXIT: | ||
127 | if (current->mm) | ||
128 | fpsimd_load_state(¤t->thread.fpsimd_state); | ||
129 | break; | ||
130 | case CPU_PM_ENTER_FAILED: | ||
131 | default: | ||
132 | return NOTIFY_DONE; | ||
133 | } | ||
134 | return NOTIFY_OK; | ||
135 | } | ||
136 | |||
137 | static struct notifier_block fpsimd_cpu_pm_notifier_block = { | ||
138 | .notifier_call = fpsimd_cpu_pm_notifier, | ||
139 | }; | ||
140 | |||
141 | static void fpsimd_pm_init(void) | ||
142 | { | ||
143 | cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block); | ||
144 | } | ||
145 | |||
146 | #else | ||
147 | static inline void fpsimd_pm_init(void) { } | ||
148 | #endif /* CONFIG_CPU_PM */ | ||
149 | |||
116 | /* | 150 | /* |
117 | * FP/SIMD support code initialisation. | 151 | * FP/SIMD support code initialisation. |
118 | */ | 152 | */ |
@@ -131,6 +165,8 @@ static int __init fpsimd_init(void) | |||
131 | else | 165 | else |
132 | elf_hwcap |= HWCAP_ASIMD; | 166 | elf_hwcap |= HWCAP_ASIMD; |
133 | 167 | ||
168 | fpsimd_pm_init(); | ||
169 | |||
134 | return 0; | 170 | return 0; |
135 | } | 171 | } |
136 | late_initcall(fpsimd_init); | 172 | late_initcall(fpsimd_init); |
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index c68cca5c3523..0b281fffda51 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S | |||
@@ -482,8 +482,6 @@ ENDPROC(__create_page_tables) | |||
482 | .type __switch_data, %object | 482 | .type __switch_data, %object |
483 | __switch_data: | 483 | __switch_data: |
484 | .quad __mmap_switched | 484 | .quad __mmap_switched |
485 | .quad __data_loc // x4 | ||
486 | .quad _data // x5 | ||
487 | .quad __bss_start // x6 | 485 | .quad __bss_start // x6 |
488 | .quad _end // x7 | 486 | .quad _end // x7 |
489 | .quad processor_id // x4 | 487 | .quad processor_id // x4 |
@@ -498,15 +496,7 @@ __switch_data: | |||
498 | __mmap_switched: | 496 | __mmap_switched: |
499 | adr x3, __switch_data + 8 | 497 | adr x3, __switch_data + 8 |
500 | 498 | ||
501 | ldp x4, x5, [x3], #16 | ||
502 | ldp x6, x7, [x3], #16 | 499 | ldp x6, x7, [x3], #16 |
503 | cmp x4, x5 // Copy data segment if needed | ||
504 | 1: ccmp x5, x6, #4, ne | ||
505 | b.eq 2f | ||
506 | ldr x16, [x4], #8 | ||
507 | str x16, [x5], #8 | ||
508 | b 1b | ||
509 | 2: | ||
510 | 1: cmp x6, x7 | 500 | 1: cmp x6, x7 |
511 | b.hs 2f | 501 | b.hs 2f |
512 | str xzr, [x6], #8 // Clear BSS | 502 | str xzr, [x6], #8 // Clear BSS |
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index ff516f6691e4..f17f581116fc 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #define pr_fmt(fmt) "hw-breakpoint: " fmt | 21 | #define pr_fmt(fmt) "hw-breakpoint: " fmt |
22 | 22 | ||
23 | #include <linux/cpu_pm.h> | ||
23 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
24 | #include <linux/hw_breakpoint.h> | 25 | #include <linux/hw_breakpoint.h> |
25 | #include <linux/perf_event.h> | 26 | #include <linux/perf_event.h> |
@@ -169,15 +170,68 @@ static enum debug_el debug_exception_level(int privilege) | |||
169 | } | 170 | } |
170 | } | 171 | } |
171 | 172 | ||
172 | /* | 173 | enum hw_breakpoint_ops { |
173 | * Install a perf counter breakpoint. | 174 | HW_BREAKPOINT_INSTALL, |
175 | HW_BREAKPOINT_UNINSTALL, | ||
176 | HW_BREAKPOINT_RESTORE | ||
177 | }; | ||
178 | |||
179 | /** | ||
180 | * hw_breakpoint_slot_setup - Find and setup a perf slot according to | ||
181 | * operations | ||
182 | * | ||
183 | * @slots: pointer to array of slots | ||
184 | * @max_slots: max number of slots | ||
185 | * @bp: perf_event to setup | ||
186 | * @ops: operation to be carried out on the slot | ||
187 | * | ||
188 | * Return: | ||
189 | * slot index on success | ||
190 | * -ENOSPC if no slot is available/matches | ||
191 | * -EINVAL on wrong operations parameter | ||
174 | */ | 192 | */ |
175 | int arch_install_hw_breakpoint(struct perf_event *bp) | 193 | static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots, |
194 | struct perf_event *bp, | ||
195 | enum hw_breakpoint_ops ops) | ||
196 | { | ||
197 | int i; | ||
198 | struct perf_event **slot; | ||
199 | |||
200 | for (i = 0; i < max_slots; ++i) { | ||
201 | slot = &slots[i]; | ||
202 | switch (ops) { | ||
203 | case HW_BREAKPOINT_INSTALL: | ||
204 | if (!*slot) { | ||
205 | *slot = bp; | ||
206 | return i; | ||
207 | } | ||
208 | break; | ||
209 | case HW_BREAKPOINT_UNINSTALL: | ||
210 | if (*slot == bp) { | ||
211 | *slot = NULL; | ||
212 | return i; | ||
213 | } | ||
214 | break; | ||
215 | case HW_BREAKPOINT_RESTORE: | ||
216 | if (*slot == bp) | ||
217 | return i; | ||
218 | break; | ||
219 | default: | ||
220 | pr_warn_once("Unhandled hw breakpoint ops %d\n", ops); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | } | ||
224 | return -ENOSPC; | ||
225 | } | ||
226 | |||
227 | static int hw_breakpoint_control(struct perf_event *bp, | ||
228 | enum hw_breakpoint_ops ops) | ||
176 | { | 229 | { |
177 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | 230 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); |
178 | struct perf_event **slot, **slots; | 231 | struct perf_event **slots; |
179 | struct debug_info *debug_info = ¤t->thread.debug; | 232 | struct debug_info *debug_info = ¤t->thread.debug; |
180 | int i, max_slots, ctrl_reg, val_reg, reg_enable; | 233 | int i, max_slots, ctrl_reg, val_reg, reg_enable; |
234 | enum debug_el dbg_el = debug_exception_level(info->ctrl.privilege); | ||
181 | u32 ctrl; | 235 | u32 ctrl; |
182 | 236 | ||
183 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | 237 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { |
@@ -196,67 +250,54 @@ int arch_install_hw_breakpoint(struct perf_event *bp) | |||
196 | reg_enable = !debug_info->wps_disabled; | 250 | reg_enable = !debug_info->wps_disabled; |
197 | } | 251 | } |
198 | 252 | ||
199 | for (i = 0; i < max_slots; ++i) { | 253 | i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops); |
200 | slot = &slots[i]; | ||
201 | |||
202 | if (!*slot) { | ||
203 | *slot = bp; | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) | ||
209 | return -ENOSPC; | ||
210 | 254 | ||
211 | /* Ensure debug monitors are enabled at the correct exception level. */ | 255 | if (WARN_ONCE(i < 0, "Can't find any breakpoint slot")) |
212 | enable_debug_monitors(debug_exception_level(info->ctrl.privilege)); | 256 | return i; |
213 | 257 | ||
214 | /* Setup the address register. */ | 258 | switch (ops) { |
215 | write_wb_reg(val_reg, i, info->address); | 259 | case HW_BREAKPOINT_INSTALL: |
260 | /* | ||
261 | * Ensure debug monitors are enabled at the correct exception | ||
262 | * level. | ||
263 | */ | ||
264 | enable_debug_monitors(dbg_el); | ||
265 | /* Fall through */ | ||
266 | case HW_BREAKPOINT_RESTORE: | ||
267 | /* Setup the address register. */ | ||
268 | write_wb_reg(val_reg, i, info->address); | ||
269 | |||
270 | /* Setup the control register. */ | ||
271 | ctrl = encode_ctrl_reg(info->ctrl); | ||
272 | write_wb_reg(ctrl_reg, i, | ||
273 | reg_enable ? ctrl | 0x1 : ctrl & ~0x1); | ||
274 | break; | ||
275 | case HW_BREAKPOINT_UNINSTALL: | ||
276 | /* Reset the control register. */ | ||
277 | write_wb_reg(ctrl_reg, i, 0); | ||
216 | 278 | ||
217 | /* Setup the control register. */ | 279 | /* |
218 | ctrl = encode_ctrl_reg(info->ctrl); | 280 | * Release the debug monitors for the correct exception |
219 | write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); | 281 | * level. |
282 | */ | ||
283 | disable_debug_monitors(dbg_el); | ||
284 | break; | ||
285 | } | ||
220 | 286 | ||
221 | return 0; | 287 | return 0; |
222 | } | 288 | } |
223 | 289 | ||
224 | void arch_uninstall_hw_breakpoint(struct perf_event *bp) | 290 | /* |
291 | * Install a perf counter breakpoint. | ||
292 | */ | ||
293 | int arch_install_hw_breakpoint(struct perf_event *bp) | ||
225 | { | 294 | { |
226 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | 295 | return hw_breakpoint_control(bp, HW_BREAKPOINT_INSTALL); |
227 | struct perf_event **slot, **slots; | 296 | } |
228 | int i, max_slots, base; | ||
229 | |||
230 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
231 | /* Breakpoint */ | ||
232 | base = AARCH64_DBG_REG_BCR; | ||
233 | slots = this_cpu_ptr(bp_on_reg); | ||
234 | max_slots = core_num_brps; | ||
235 | } else { | ||
236 | /* Watchpoint */ | ||
237 | base = AARCH64_DBG_REG_WCR; | ||
238 | slots = this_cpu_ptr(wp_on_reg); | ||
239 | max_slots = core_num_wrps; | ||
240 | } | ||
241 | |||
242 | /* Remove the breakpoint. */ | ||
243 | for (i = 0; i < max_slots; ++i) { | ||
244 | slot = &slots[i]; | ||
245 | |||
246 | if (*slot == bp) { | ||
247 | *slot = NULL; | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) | ||
253 | return; | ||
254 | |||
255 | /* Reset the control register. */ | ||
256 | write_wb_reg(base, i, 0); | ||
257 | 297 | ||
258 | /* Release the debug monitors for the correct exception level. */ | 298 | void arch_uninstall_hw_breakpoint(struct perf_event *bp) |
259 | disable_debug_monitors(debug_exception_level(info->ctrl.privilege)); | 299 | { |
300 | hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL); | ||
260 | } | 301 | } |
261 | 302 | ||
262 | static int get_hbp_len(u8 hbp_len) | 303 | static int get_hbp_len(u8 hbp_len) |
@@ -806,18 +847,36 @@ void hw_breakpoint_thread_switch(struct task_struct *next) | |||
806 | /* | 847 | /* |
807 | * CPU initialisation. | 848 | * CPU initialisation. |
808 | */ | 849 | */ |
809 | static void reset_ctrl_regs(void *unused) | 850 | static void hw_breakpoint_reset(void *unused) |
810 | { | 851 | { |
811 | int i; | 852 | int i; |
812 | 853 | struct perf_event **slots; | |
813 | for (i = 0; i < core_num_brps; ++i) { | 854 | /* |
814 | write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL); | 855 | * When a CPU goes through cold-boot, it does not have any installed |
815 | write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL); | 856 | * slot, so it is safe to share the same function for restoring and |
857 | * resetting breakpoints; when a CPU is hotplugged in, it goes | ||
858 | * through the slots, which are all empty, hence it just resets control | ||
859 | * and value for debug registers. | ||
860 | * When this function is triggered on warm-boot through a CPU PM | ||
861 | * notifier some slots might be initialized; if so they are | ||
862 | * reprogrammed according to the debug slots content. | ||
863 | */ | ||
864 | for (slots = this_cpu_ptr(bp_on_reg), i = 0; i < core_num_brps; ++i) { | ||
865 | if (slots[i]) { | ||
866 | hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE); | ||
867 | } else { | ||
868 | write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL); | ||
869 | write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL); | ||
870 | } | ||
816 | } | 871 | } |
817 | 872 | ||
818 | for (i = 0; i < core_num_wrps; ++i) { | 873 | for (slots = this_cpu_ptr(wp_on_reg), i = 0; i < core_num_wrps; ++i) { |
819 | write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL); | 874 | if (slots[i]) { |
820 | write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); | 875 | hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE); |
876 | } else { | ||
877 | write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL); | ||
878 | write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); | ||
879 | } | ||
821 | } | 880 | } |
822 | } | 881 | } |
823 | 882 | ||
@@ -827,7 +886,7 @@ static int hw_breakpoint_reset_notify(struct notifier_block *self, | |||
827 | { | 886 | { |
828 | int cpu = (long)hcpu; | 887 | int cpu = (long)hcpu; |
829 | if (action == CPU_ONLINE) | 888 | if (action == CPU_ONLINE) |
830 | smp_call_function_single(cpu, reset_ctrl_regs, NULL, 1); | 889 | smp_call_function_single(cpu, hw_breakpoint_reset, NULL, 1); |
831 | return NOTIFY_OK; | 890 | return NOTIFY_OK; |
832 | } | 891 | } |
833 | 892 | ||
@@ -835,6 +894,14 @@ static struct notifier_block hw_breakpoint_reset_nb = { | |||
835 | .notifier_call = hw_breakpoint_reset_notify, | 894 | .notifier_call = hw_breakpoint_reset_notify, |
836 | }; | 895 | }; |
837 | 896 | ||
897 | #ifdef CONFIG_ARM64_CPU_SUSPEND | ||
898 | extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)); | ||
899 | #else | ||
900 | static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) | ||
901 | { | ||
902 | } | ||
903 | #endif | ||
904 | |||
838 | /* | 905 | /* |
839 | * One-time initialisation. | 906 | * One-time initialisation. |
840 | */ | 907 | */ |
@@ -850,8 +917,8 @@ static int __init arch_hw_breakpoint_init(void) | |||
850 | * Reset the breakpoint resources. We assume that a halting | 917 | * Reset the breakpoint resources. We assume that a halting |
851 | * debugger will leave the world in a nice state for us. | 918 | * debugger will leave the world in a nice state for us. |
852 | */ | 919 | */ |
853 | smp_call_function(reset_ctrl_regs, NULL, 1); | 920 | smp_call_function(hw_breakpoint_reset, NULL, 1); |
854 | reset_ctrl_regs(NULL); | 921 | hw_breakpoint_reset(NULL); |
855 | 922 | ||
856 | /* Register debug fault handlers. */ | 923 | /* Register debug fault handlers. */ |
857 | hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, | 924 | hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, |
@@ -861,6 +928,8 @@ static int __init arch_hw_breakpoint_init(void) | |||
861 | 928 | ||
862 | /* Register hotplug notifier. */ | 929 | /* Register hotplug notifier. */ |
863 | register_cpu_notifier(&hw_breakpoint_reset_nb); | 930 | register_cpu_notifier(&hw_breakpoint_reset_nb); |
931 | /* Register cpu_suspend hw breakpoint restore hook */ | ||
932 | cpu_suspend_set_dbg_restorer(hw_breakpoint_reset); | ||
864 | 933 | ||
865 | return 0; | 934 | return 0; |
866 | } | 935 | } |
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c new file mode 100644 index 000000000000..92f36835486b --- /dev/null +++ b/arch/arm64/kernel/insn.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Huawei Ltd. | ||
3 | * Author: Jiang Liu <liuj97@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #include <linux/bitops.h> | ||
18 | #include <linux/compiler.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/stop_machine.h> | ||
22 | #include <linux/uaccess.h> | ||
23 | #include <asm/cacheflush.h> | ||
24 | #include <asm/insn.h> | ||
25 | |||
26 | static int aarch64_insn_encoding_class[] = { | ||
27 | AARCH64_INSN_CLS_UNKNOWN, | ||
28 | AARCH64_INSN_CLS_UNKNOWN, | ||
29 | AARCH64_INSN_CLS_UNKNOWN, | ||
30 | AARCH64_INSN_CLS_UNKNOWN, | ||
31 | AARCH64_INSN_CLS_LDST, | ||
32 | AARCH64_INSN_CLS_DP_REG, | ||
33 | AARCH64_INSN_CLS_LDST, | ||
34 | AARCH64_INSN_CLS_DP_FPSIMD, | ||
35 | AARCH64_INSN_CLS_DP_IMM, | ||
36 | AARCH64_INSN_CLS_DP_IMM, | ||
37 | AARCH64_INSN_CLS_BR_SYS, | ||
38 | AARCH64_INSN_CLS_BR_SYS, | ||
39 | AARCH64_INSN_CLS_LDST, | ||
40 | AARCH64_INSN_CLS_DP_REG, | ||
41 | AARCH64_INSN_CLS_LDST, | ||
42 | AARCH64_INSN_CLS_DP_FPSIMD, | ||
43 | }; | ||
44 | |||
45 | enum aarch64_insn_encoding_class __kprobes aarch64_get_insn_class(u32 insn) | ||
46 | { | ||
47 | return aarch64_insn_encoding_class[(insn >> 25) & 0xf]; | ||
48 | } | ||
49 | |||
50 | /* NOP is an alias of HINT */ | ||
51 | bool __kprobes aarch64_insn_is_nop(u32 insn) | ||
52 | { | ||
53 | if (!aarch64_insn_is_hint(insn)) | ||
54 | return false; | ||
55 | |||
56 | switch (insn & 0xFE0) { | ||
57 | case AARCH64_INSN_HINT_YIELD: | ||
58 | case AARCH64_INSN_HINT_WFE: | ||
59 | case AARCH64_INSN_HINT_WFI: | ||
60 | case AARCH64_INSN_HINT_SEV: | ||
61 | case AARCH64_INSN_HINT_SEVL: | ||
62 | return false; | ||
63 | default: | ||
64 | return true; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * In ARMv8-A, A64 instructions have a fixed length of 32 bits and are always | ||
70 | * little-endian. | ||
71 | */ | ||
72 | int __kprobes aarch64_insn_read(void *addr, u32 *insnp) | ||
73 | { | ||
74 | int ret; | ||
75 | u32 val; | ||
76 | |||
77 | ret = probe_kernel_read(&val, addr, AARCH64_INSN_SIZE); | ||
78 | if (!ret) | ||
79 | *insnp = le32_to_cpu(val); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | int __kprobes aarch64_insn_write(void *addr, u32 insn) | ||
85 | { | ||
86 | insn = cpu_to_le32(insn); | ||
87 | return probe_kernel_write(addr, &insn, AARCH64_INSN_SIZE); | ||
88 | } | ||
89 | |||
90 | static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn) | ||
91 | { | ||
92 | if (aarch64_get_insn_class(insn) != AARCH64_INSN_CLS_BR_SYS) | ||
93 | return false; | ||
94 | |||
95 | return aarch64_insn_is_b(insn) || | ||
96 | aarch64_insn_is_bl(insn) || | ||
97 | aarch64_insn_is_svc(insn) || | ||
98 | aarch64_insn_is_hvc(insn) || | ||
99 | aarch64_insn_is_smc(insn) || | ||
100 | aarch64_insn_is_brk(insn) || | ||
101 | aarch64_insn_is_nop(insn); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a | ||
106 | * Section B2.6.5 "Concurrent modification and execution of instructions": | ||
107 | * Concurrent modification and execution of instructions can lead to the | ||
108 | * resulting instruction performing any behavior that can be achieved by | ||
109 | * executing any sequence of instructions that can be executed from the | ||
110 | * same Exception level, except where the instruction before modification | ||
111 | * and the instruction after modification is a B, BL, NOP, BKPT, SVC, HVC, | ||
112 | * or SMC instruction. | ||
113 | */ | ||
114 | bool __kprobes aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn) | ||
115 | { | ||
116 | return __aarch64_insn_hotpatch_safe(old_insn) && | ||
117 | __aarch64_insn_hotpatch_safe(new_insn); | ||
118 | } | ||
119 | |||
120 | int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn) | ||
121 | { | ||
122 | u32 *tp = addr; | ||
123 | int ret; | ||
124 | |||
125 | /* A64 instructions must be word aligned */ | ||
126 | if ((uintptr_t)tp & 0x3) | ||
127 | return -EINVAL; | ||
128 | |||
129 | ret = aarch64_insn_write(tp, insn); | ||
130 | if (ret == 0) | ||
131 | flush_icache_range((uintptr_t)tp, | ||
132 | (uintptr_t)tp + AARCH64_INSN_SIZE); | ||
133 | |||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | struct aarch64_insn_patch { | ||
138 | void **text_addrs; | ||
139 | u32 *new_insns; | ||
140 | int insn_cnt; | ||
141 | atomic_t cpu_count; | ||
142 | }; | ||
143 | |||
144 | static int __kprobes aarch64_insn_patch_text_cb(void *arg) | ||
145 | { | ||
146 | int i, ret = 0; | ||
147 | struct aarch64_insn_patch *pp = arg; | ||
148 | |||
149 | /* The first CPU becomes master */ | ||
150 | if (atomic_inc_return(&pp->cpu_count) == 1) { | ||
151 | for (i = 0; ret == 0 && i < pp->insn_cnt; i++) | ||
152 | ret = aarch64_insn_patch_text_nosync(pp->text_addrs[i], | ||
153 | pp->new_insns[i]); | ||
154 | /* | ||
155 | * aarch64_insn_patch_text_nosync() calls flush_icache_range(), | ||
156 | * which ends with "dsb; isb" pair guaranteeing global | ||
157 | * visibility. | ||
158 | */ | ||
159 | atomic_set(&pp->cpu_count, -1); | ||
160 | } else { | ||
161 | while (atomic_read(&pp->cpu_count) != -1) | ||
162 | cpu_relax(); | ||
163 | isb(); | ||
164 | } | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | int __kprobes aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt) | ||
170 | { | ||
171 | struct aarch64_insn_patch patch = { | ||
172 | .text_addrs = addrs, | ||
173 | .new_insns = insns, | ||
174 | .insn_cnt = cnt, | ||
175 | .cpu_count = ATOMIC_INIT(0), | ||
176 | }; | ||
177 | |||
178 | if (cnt <= 0) | ||
179 | return -EINVAL; | ||
180 | |||
181 | return stop_machine(aarch64_insn_patch_text_cb, &patch, | ||
182 | cpu_online_mask); | ||
183 | } | ||
184 | |||
185 | int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt) | ||
186 | { | ||
187 | int ret; | ||
188 | u32 insn; | ||
189 | |||
190 | /* Unsafe to patch multiple instructions without synchronizaiton */ | ||
191 | if (cnt == 1) { | ||
192 | ret = aarch64_insn_read(addrs[0], &insn); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | if (aarch64_insn_hotpatch_safe(insn, insns[0])) { | ||
197 | /* | ||
198 | * ARMv8 architecture doesn't guarantee all CPUs see | ||
199 | * the new instruction after returning from function | ||
200 | * aarch64_insn_patch_text_nosync(). So send IPIs to | ||
201 | * all other CPUs to achieve instruction | ||
202 | * synchronization. | ||
203 | */ | ||
204 | ret = aarch64_insn_patch_text_nosync(addrs[0], insns[0]); | ||
205 | kick_all_cpus_sync(); | ||
206 | return ret; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return aarch64_insn_patch_text_sync(addrs, insns, cnt); | ||
211 | } | ||
212 | |||
213 | u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type, | ||
214 | u32 insn, u64 imm) | ||
215 | { | ||
216 | u32 immlo, immhi, lomask, himask, mask; | ||
217 | int shift; | ||
218 | |||
219 | switch (type) { | ||
220 | case AARCH64_INSN_IMM_ADR: | ||
221 | lomask = 0x3; | ||
222 | himask = 0x7ffff; | ||
223 | immlo = imm & lomask; | ||
224 | imm >>= 2; | ||
225 | immhi = imm & himask; | ||
226 | imm = (immlo << 24) | (immhi); | ||
227 | mask = (lomask << 24) | (himask); | ||
228 | shift = 5; | ||
229 | break; | ||
230 | case AARCH64_INSN_IMM_26: | ||
231 | mask = BIT(26) - 1; | ||
232 | shift = 0; | ||
233 | break; | ||
234 | case AARCH64_INSN_IMM_19: | ||
235 | mask = BIT(19) - 1; | ||
236 | shift = 5; | ||
237 | break; | ||
238 | case AARCH64_INSN_IMM_16: | ||
239 | mask = BIT(16) - 1; | ||
240 | shift = 5; | ||
241 | break; | ||
242 | case AARCH64_INSN_IMM_14: | ||
243 | mask = BIT(14) - 1; | ||
244 | shift = 5; | ||
245 | break; | ||
246 | case AARCH64_INSN_IMM_12: | ||
247 | mask = BIT(12) - 1; | ||
248 | shift = 10; | ||
249 | break; | ||
250 | case AARCH64_INSN_IMM_9: | ||
251 | mask = BIT(9) - 1; | ||
252 | shift = 12; | ||
253 | break; | ||
254 | default: | ||
255 | pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n", | ||
256 | type); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* Update the immediate field. */ | ||
261 | insn &= ~(mask << shift); | ||
262 | insn |= (imm & mask) << shift; | ||
263 | |||
264 | return insn; | ||
265 | } | ||
266 | |||
267 | u32 __kprobes aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr, | ||
268 | enum aarch64_insn_branch_type type) | ||
269 | { | ||
270 | u32 insn; | ||
271 | long offset; | ||
272 | |||
273 | /* | ||
274 | * PC: A 64-bit Program Counter holding the address of the current | ||
275 | * instruction. A64 instructions must be word-aligned. | ||
276 | */ | ||
277 | BUG_ON((pc & 0x3) || (addr & 0x3)); | ||
278 | |||
279 | /* | ||
280 | * B/BL support [-128M, 128M) offset | ||
281 | * ARM64 virtual address arrangement guarantees all kernel and module | ||
282 | * texts are within +/-128M. | ||
283 | */ | ||
284 | offset = ((long)addr - (long)pc); | ||
285 | BUG_ON(offset < -SZ_128M || offset >= SZ_128M); | ||
286 | |||
287 | if (type == AARCH64_INSN_BRANCH_LINK) | ||
288 | insn = aarch64_insn_get_bl_value(); | ||
289 | else | ||
290 | insn = aarch64_insn_get_b_value(); | ||
291 | |||
292 | return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_26, insn, | ||
293 | offset >> 2); | ||
294 | } | ||
295 | |||
296 | u32 __kprobes aarch64_insn_gen_hint(enum aarch64_insn_hint_op op) | ||
297 | { | ||
298 | return aarch64_insn_get_hint_value() | op; | ||
299 | } | ||
300 | |||
301 | u32 __kprobes aarch64_insn_gen_nop(void) | ||
302 | { | ||
303 | return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); | ||
304 | } | ||
diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c new file mode 100644 index 000000000000..263a166291fb --- /dev/null +++ b/arch/arm64/kernel/jump_label.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Huawei Ltd. | ||
3 | * Author: Jiang Liu <liuj97@gmail.com> | ||
4 | * | ||
5 | * Based on arch/arm/kernel/jump_label.c | ||
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 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/jump_label.h> | ||
21 | #include <asm/insn.h> | ||
22 | |||
23 | #ifdef HAVE_JUMP_LABEL | ||
24 | |||
25 | static void __arch_jump_label_transform(struct jump_entry *entry, | ||
26 | enum jump_label_type type, | ||
27 | bool is_static) | ||
28 | { | ||
29 | void *addr = (void *)entry->code; | ||
30 | u32 insn; | ||
31 | |||
32 | if (type == JUMP_LABEL_ENABLE) { | ||
33 | insn = aarch64_insn_gen_branch_imm(entry->code, | ||
34 | entry->target, | ||
35 | AARCH64_INSN_BRANCH_NOLINK); | ||
36 | } else { | ||
37 | insn = aarch64_insn_gen_nop(); | ||
38 | } | ||
39 | |||
40 | if (is_static) | ||
41 | aarch64_insn_patch_text_nosync(addr, insn); | ||
42 | else | ||
43 | aarch64_insn_patch_text(&addr, &insn, 1); | ||
44 | } | ||
45 | |||
46 | void arch_jump_label_transform(struct jump_entry *entry, | ||
47 | enum jump_label_type type) | ||
48 | { | ||
49 | __arch_jump_label_transform(entry, type, false); | ||
50 | } | ||
51 | |||
52 | void arch_jump_label_transform_static(struct jump_entry *entry, | ||
53 | enum jump_label_type type) | ||
54 | { | ||
55 | __arch_jump_label_transform(entry, type, true); | ||
56 | } | ||
57 | |||
58 | #endif /* HAVE_JUMP_LABEL */ | ||
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index e2ad0d87721f..1eb1cc955139 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
26 | #include <linux/moduleloader.h> | 26 | #include <linux/moduleloader.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <asm/insn.h> | ||
29 | |||
30 | #define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX | ||
31 | #define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 | ||
28 | 32 | ||
29 | void *module_alloc(unsigned long size) | 33 | void *module_alloc(unsigned long size) |
30 | { | 34 | { |
@@ -94,28 +98,18 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) | |||
94 | return 0; | 98 | return 0; |
95 | } | 99 | } |
96 | 100 | ||
97 | enum aarch64_imm_type { | 101 | static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, |
98 | INSN_IMM_MOVNZ, | 102 | int lsb, enum aarch64_insn_imm_type imm_type) |
99 | INSN_IMM_MOVK, | ||
100 | INSN_IMM_ADR, | ||
101 | INSN_IMM_26, | ||
102 | INSN_IMM_19, | ||
103 | INSN_IMM_16, | ||
104 | INSN_IMM_14, | ||
105 | INSN_IMM_12, | ||
106 | INSN_IMM_9, | ||
107 | }; | ||
108 | |||
109 | static u32 encode_insn_immediate(enum aarch64_imm_type type, u32 insn, u64 imm) | ||
110 | { | 103 | { |
111 | u32 immlo, immhi, lomask, himask, mask; | 104 | u64 imm, limit = 0; |
112 | int shift; | 105 | s64 sval; |
106 | u32 insn = le32_to_cpu(*(u32 *)place); | ||
113 | 107 | ||
114 | /* The instruction stream is always little endian. */ | 108 | sval = do_reloc(op, place, val); |
115 | insn = le32_to_cpu(insn); | 109 | sval >>= lsb; |
110 | imm = sval & 0xffff; | ||
116 | 111 | ||
117 | switch (type) { | 112 | if (imm_type == AARCH64_INSN_IMM_MOVNZ) { |
118 | case INSN_IMM_MOVNZ: | ||
119 | /* | 113 | /* |
120 | * For signed MOVW relocations, we have to manipulate the | 114 | * For signed MOVW relocations, we have to manipulate the |
121 | * instruction encoding depending on whether or not the | 115 | * instruction encoding depending on whether or not the |
@@ -134,70 +128,12 @@ static u32 encode_insn_immediate(enum aarch64_imm_type type, u32 insn, u64 imm) | |||
134 | */ | 128 | */ |
135 | imm = ~imm; | 129 | imm = ~imm; |
136 | } | 130 | } |
137 | case INSN_IMM_MOVK: | 131 | imm_type = AARCH64_INSN_IMM_MOVK; |
138 | mask = BIT(16) - 1; | ||
139 | shift = 5; | ||
140 | break; | ||
141 | case INSN_IMM_ADR: | ||
142 | lomask = 0x3; | ||
143 | himask = 0x7ffff; | ||
144 | immlo = imm & lomask; | ||
145 | imm >>= 2; | ||
146 | immhi = imm & himask; | ||
147 | imm = (immlo << 24) | (immhi); | ||
148 | mask = (lomask << 24) | (himask); | ||
149 | shift = 5; | ||
150 | break; | ||
151 | case INSN_IMM_26: | ||
152 | mask = BIT(26) - 1; | ||
153 | shift = 0; | ||
154 | break; | ||
155 | case INSN_IMM_19: | ||
156 | mask = BIT(19) - 1; | ||
157 | shift = 5; | ||
158 | break; | ||
159 | case INSN_IMM_16: | ||
160 | mask = BIT(16) - 1; | ||
161 | shift = 5; | ||
162 | break; | ||
163 | case INSN_IMM_14: | ||
164 | mask = BIT(14) - 1; | ||
165 | shift = 5; | ||
166 | break; | ||
167 | case INSN_IMM_12: | ||
168 | mask = BIT(12) - 1; | ||
169 | shift = 10; | ||
170 | break; | ||
171 | case INSN_IMM_9: | ||
172 | mask = BIT(9) - 1; | ||
173 | shift = 12; | ||
174 | break; | ||
175 | default: | ||
176 | pr_err("encode_insn_immediate: unknown immediate encoding %d\n", | ||
177 | type); | ||
178 | return 0; | ||
179 | } | 132 | } |
180 | 133 | ||
181 | /* Update the immediate field. */ | ||
182 | insn &= ~(mask << shift); | ||
183 | insn |= (imm & mask) << shift; | ||
184 | |||
185 | return cpu_to_le32(insn); | ||
186 | } | ||
187 | |||
188 | static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, | ||
189 | int lsb, enum aarch64_imm_type imm_type) | ||
190 | { | ||
191 | u64 imm, limit = 0; | ||
192 | s64 sval; | ||
193 | u32 insn = *(u32 *)place; | ||
194 | |||
195 | sval = do_reloc(op, place, val); | ||
196 | sval >>= lsb; | ||
197 | imm = sval & 0xffff; | ||
198 | |||
199 | /* Update the instruction with the new encoding. */ | 134 | /* Update the instruction with the new encoding. */ |
200 | *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); | 135 | insn = aarch64_insn_encode_immediate(imm_type, insn, imm); |
136 | *(u32 *)place = cpu_to_le32(insn); | ||
201 | 137 | ||
202 | /* Shift out the immediate field. */ | 138 | /* Shift out the immediate field. */ |
203 | sval >>= 16; | 139 | sval >>= 16; |
@@ -206,9 +142,9 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, | |||
206 | * For unsigned immediates, the overflow check is straightforward. | 142 | * For unsigned immediates, the overflow check is straightforward. |
207 | * For signed immediates, the sign bit is actually the bit past the | 143 | * For signed immediates, the sign bit is actually the bit past the |
208 | * most significant bit of the field. | 144 | * most significant bit of the field. |
209 | * The INSN_IMM_16 immediate type is unsigned. | 145 | * The AARCH64_INSN_IMM_16 immediate type is unsigned. |
210 | */ | 146 | */ |
211 | if (imm_type != INSN_IMM_16) { | 147 | if (imm_type != AARCH64_INSN_IMM_16) { |
212 | sval++; | 148 | sval++; |
213 | limit++; | 149 | limit++; |
214 | } | 150 | } |
@@ -221,11 +157,11 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, | |||
221 | } | 157 | } |
222 | 158 | ||
223 | static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, | 159 | static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, |
224 | int lsb, int len, enum aarch64_imm_type imm_type) | 160 | int lsb, int len, enum aarch64_insn_imm_type imm_type) |
225 | { | 161 | { |
226 | u64 imm, imm_mask; | 162 | u64 imm, imm_mask; |
227 | s64 sval; | 163 | s64 sval; |
228 | u32 insn = *(u32 *)place; | 164 | u32 insn = le32_to_cpu(*(u32 *)place); |
229 | 165 | ||
230 | /* Calculate the relocation value. */ | 166 | /* Calculate the relocation value. */ |
231 | sval = do_reloc(op, place, val); | 167 | sval = do_reloc(op, place, val); |
@@ -236,7 +172,8 @@ static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, | |||
236 | imm = sval & imm_mask; | 172 | imm = sval & imm_mask; |
237 | 173 | ||
238 | /* Update the instruction's immediate field. */ | 174 | /* Update the instruction's immediate field. */ |
239 | *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); | 175 | insn = aarch64_insn_encode_immediate(imm_type, insn, imm); |
176 | *(u32 *)place = cpu_to_le32(insn); | ||
240 | 177 | ||
241 | /* | 178 | /* |
242 | * Extract the upper value bits (including the sign bit) and | 179 | * Extract the upper value bits (including the sign bit) and |
@@ -318,125 +255,125 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
318 | overflow_check = false; | 255 | overflow_check = false; |
319 | case R_AARCH64_MOVW_UABS_G0: | 256 | case R_AARCH64_MOVW_UABS_G0: |
320 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, | 257 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, |
321 | INSN_IMM_16); | 258 | AARCH64_INSN_IMM_16); |
322 | break; | 259 | break; |
323 | case R_AARCH64_MOVW_UABS_G1_NC: | 260 | case R_AARCH64_MOVW_UABS_G1_NC: |
324 | overflow_check = false; | 261 | overflow_check = false; |
325 | case R_AARCH64_MOVW_UABS_G1: | 262 | case R_AARCH64_MOVW_UABS_G1: |
326 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, | 263 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, |
327 | INSN_IMM_16); | 264 | AARCH64_INSN_IMM_16); |
328 | break; | 265 | break; |
329 | case R_AARCH64_MOVW_UABS_G2_NC: | 266 | case R_AARCH64_MOVW_UABS_G2_NC: |
330 | overflow_check = false; | 267 | overflow_check = false; |
331 | case R_AARCH64_MOVW_UABS_G2: | 268 | case R_AARCH64_MOVW_UABS_G2: |
332 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, | 269 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, |
333 | INSN_IMM_16); | 270 | AARCH64_INSN_IMM_16); |
334 | break; | 271 | break; |
335 | case R_AARCH64_MOVW_UABS_G3: | 272 | case R_AARCH64_MOVW_UABS_G3: |
336 | /* We're using the top bits so we can't overflow. */ | 273 | /* We're using the top bits so we can't overflow. */ |
337 | overflow_check = false; | 274 | overflow_check = false; |
338 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, | 275 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, |
339 | INSN_IMM_16); | 276 | AARCH64_INSN_IMM_16); |
340 | break; | 277 | break; |
341 | case R_AARCH64_MOVW_SABS_G0: | 278 | case R_AARCH64_MOVW_SABS_G0: |
342 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, | 279 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, |
343 | INSN_IMM_MOVNZ); | 280 | AARCH64_INSN_IMM_MOVNZ); |
344 | break; | 281 | break; |
345 | case R_AARCH64_MOVW_SABS_G1: | 282 | case R_AARCH64_MOVW_SABS_G1: |
346 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, | 283 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, |
347 | INSN_IMM_MOVNZ); | 284 | AARCH64_INSN_IMM_MOVNZ); |
348 | break; | 285 | break; |
349 | case R_AARCH64_MOVW_SABS_G2: | 286 | case R_AARCH64_MOVW_SABS_G2: |
350 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, | 287 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, |
351 | INSN_IMM_MOVNZ); | 288 | AARCH64_INSN_IMM_MOVNZ); |
352 | break; | 289 | break; |
353 | case R_AARCH64_MOVW_PREL_G0_NC: | 290 | case R_AARCH64_MOVW_PREL_G0_NC: |
354 | overflow_check = false; | 291 | overflow_check = false; |
355 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, | 292 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, |
356 | INSN_IMM_MOVK); | 293 | AARCH64_INSN_IMM_MOVK); |
357 | break; | 294 | break; |
358 | case R_AARCH64_MOVW_PREL_G0: | 295 | case R_AARCH64_MOVW_PREL_G0: |
359 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, | 296 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, |
360 | INSN_IMM_MOVNZ); | 297 | AARCH64_INSN_IMM_MOVNZ); |
361 | break; | 298 | break; |
362 | case R_AARCH64_MOVW_PREL_G1_NC: | 299 | case R_AARCH64_MOVW_PREL_G1_NC: |
363 | overflow_check = false; | 300 | overflow_check = false; |
364 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, | 301 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, |
365 | INSN_IMM_MOVK); | 302 | AARCH64_INSN_IMM_MOVK); |
366 | break; | 303 | break; |
367 | case R_AARCH64_MOVW_PREL_G1: | 304 | case R_AARCH64_MOVW_PREL_G1: |
368 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, | 305 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, |
369 | INSN_IMM_MOVNZ); | 306 | AARCH64_INSN_IMM_MOVNZ); |
370 | break; | 307 | break; |
371 | case R_AARCH64_MOVW_PREL_G2_NC: | 308 | case R_AARCH64_MOVW_PREL_G2_NC: |
372 | overflow_check = false; | 309 | overflow_check = false; |
373 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, | 310 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, |
374 | INSN_IMM_MOVK); | 311 | AARCH64_INSN_IMM_MOVK); |
375 | break; | 312 | break; |
376 | case R_AARCH64_MOVW_PREL_G2: | 313 | case R_AARCH64_MOVW_PREL_G2: |
377 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, | 314 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, |
378 | INSN_IMM_MOVNZ); | 315 | AARCH64_INSN_IMM_MOVNZ); |
379 | break; | 316 | break; |
380 | case R_AARCH64_MOVW_PREL_G3: | 317 | case R_AARCH64_MOVW_PREL_G3: |
381 | /* We're using the top bits so we can't overflow. */ | 318 | /* We're using the top bits so we can't overflow. */ |
382 | overflow_check = false; | 319 | overflow_check = false; |
383 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, | 320 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, |
384 | INSN_IMM_MOVNZ); | 321 | AARCH64_INSN_IMM_MOVNZ); |
385 | break; | 322 | break; |
386 | 323 | ||
387 | /* Immediate instruction relocations. */ | 324 | /* Immediate instruction relocations. */ |
388 | case R_AARCH64_LD_PREL_LO19: | 325 | case R_AARCH64_LD_PREL_LO19: |
389 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, | 326 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, |
390 | INSN_IMM_19); | 327 | AARCH64_INSN_IMM_19); |
391 | break; | 328 | break; |
392 | case R_AARCH64_ADR_PREL_LO21: | 329 | case R_AARCH64_ADR_PREL_LO21: |
393 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, | 330 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, |
394 | INSN_IMM_ADR); | 331 | AARCH64_INSN_IMM_ADR); |
395 | break; | 332 | break; |
396 | case R_AARCH64_ADR_PREL_PG_HI21_NC: | 333 | case R_AARCH64_ADR_PREL_PG_HI21_NC: |
397 | overflow_check = false; | 334 | overflow_check = false; |
398 | case R_AARCH64_ADR_PREL_PG_HI21: | 335 | case R_AARCH64_ADR_PREL_PG_HI21: |
399 | ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, | 336 | ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, |
400 | INSN_IMM_ADR); | 337 | AARCH64_INSN_IMM_ADR); |
401 | break; | 338 | break; |
402 | case R_AARCH64_ADD_ABS_LO12_NC: | 339 | case R_AARCH64_ADD_ABS_LO12_NC: |
403 | case R_AARCH64_LDST8_ABS_LO12_NC: | 340 | case R_AARCH64_LDST8_ABS_LO12_NC: |
404 | overflow_check = false; | 341 | overflow_check = false; |
405 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, | 342 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, |
406 | INSN_IMM_12); | 343 | AARCH64_INSN_IMM_12); |
407 | break; | 344 | break; |
408 | case R_AARCH64_LDST16_ABS_LO12_NC: | 345 | case R_AARCH64_LDST16_ABS_LO12_NC: |
409 | overflow_check = false; | 346 | overflow_check = false; |
410 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, | 347 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, |
411 | INSN_IMM_12); | 348 | AARCH64_INSN_IMM_12); |
412 | break; | 349 | break; |
413 | case R_AARCH64_LDST32_ABS_LO12_NC: | 350 | case R_AARCH64_LDST32_ABS_LO12_NC: |
414 | overflow_check = false; | 351 | overflow_check = false; |
415 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, | 352 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, |
416 | INSN_IMM_12); | 353 | AARCH64_INSN_IMM_12); |
417 | break; | 354 | break; |
418 | case R_AARCH64_LDST64_ABS_LO12_NC: | 355 | case R_AARCH64_LDST64_ABS_LO12_NC: |
419 | overflow_check = false; | 356 | overflow_check = false; |
420 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, | 357 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, |
421 | INSN_IMM_12); | 358 | AARCH64_INSN_IMM_12); |
422 | break; | 359 | break; |
423 | case R_AARCH64_LDST128_ABS_LO12_NC: | 360 | case R_AARCH64_LDST128_ABS_LO12_NC: |
424 | overflow_check = false; | 361 | overflow_check = false; |
425 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, | 362 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, |
426 | INSN_IMM_12); | 363 | AARCH64_INSN_IMM_12); |
427 | break; | 364 | break; |
428 | case R_AARCH64_TSTBR14: | 365 | case R_AARCH64_TSTBR14: |
429 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, | 366 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, |
430 | INSN_IMM_14); | 367 | AARCH64_INSN_IMM_14); |
431 | break; | 368 | break; |
432 | case R_AARCH64_CONDBR19: | 369 | case R_AARCH64_CONDBR19: |
433 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, | 370 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, |
434 | INSN_IMM_19); | 371 | AARCH64_INSN_IMM_19); |
435 | break; | 372 | break; |
436 | case R_AARCH64_JUMP26: | 373 | case R_AARCH64_JUMP26: |
437 | case R_AARCH64_CALL26: | 374 | case R_AARCH64_CALL26: |
438 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, | 375 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, |
439 | INSN_IMM_26); | 376 | AARCH64_INSN_IMM_26); |
440 | break; | 377 | break; |
441 | 378 | ||
442 | default: | 379 | default: |
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 0e63c98d224c..5b1cd792274a 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/bitmap.h> | 23 | #include <linux/bitmap.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/irq.h> | ||
25 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
26 | #include <linux/export.h> | 27 | #include <linux/export.h> |
27 | #include <linux/perf_event.h> | 28 | #include <linux/perf_event.h> |
@@ -363,26 +364,53 @@ validate_group(struct perf_event *event) | |||
363 | } | 364 | } |
364 | 365 | ||
365 | static void | 366 | static void |
367 | armpmu_disable_percpu_irq(void *data) | ||
368 | { | ||
369 | unsigned int irq = *(unsigned int *)data; | ||
370 | disable_percpu_irq(irq); | ||
371 | } | ||
372 | |||
373 | static void | ||
366 | armpmu_release_hardware(struct arm_pmu *armpmu) | 374 | armpmu_release_hardware(struct arm_pmu *armpmu) |
367 | { | 375 | { |
368 | int i, irq, irqs; | 376 | int irq; |
377 | unsigned int i, irqs; | ||
369 | struct platform_device *pmu_device = armpmu->plat_device; | 378 | struct platform_device *pmu_device = armpmu->plat_device; |
370 | 379 | ||
371 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | 380 | irqs = min(pmu_device->num_resources, num_possible_cpus()); |
381 | if (!irqs) | ||
382 | return; | ||
372 | 383 | ||
373 | for (i = 0; i < irqs; ++i) { | 384 | irq = platform_get_irq(pmu_device, 0); |
374 | if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs)) | 385 | if (irq <= 0) |
375 | continue; | 386 | return; |
376 | irq = platform_get_irq(pmu_device, i); | 387 | |
377 | if (irq >= 0) | 388 | if (irq_is_percpu(irq)) { |
378 | free_irq(irq, armpmu); | 389 | on_each_cpu(armpmu_disable_percpu_irq, &irq, 1); |
390 | free_percpu_irq(irq, &cpu_hw_events); | ||
391 | } else { | ||
392 | for (i = 0; i < irqs; ++i) { | ||
393 | if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs)) | ||
394 | continue; | ||
395 | irq = platform_get_irq(pmu_device, i); | ||
396 | if (irq > 0) | ||
397 | free_irq(irq, armpmu); | ||
398 | } | ||
379 | } | 399 | } |
380 | } | 400 | } |
381 | 401 | ||
402 | static void | ||
403 | armpmu_enable_percpu_irq(void *data) | ||
404 | { | ||
405 | unsigned int irq = *(unsigned int *)data; | ||
406 | enable_percpu_irq(irq, IRQ_TYPE_NONE); | ||
407 | } | ||
408 | |||
382 | static int | 409 | static int |
383 | armpmu_reserve_hardware(struct arm_pmu *armpmu) | 410 | armpmu_reserve_hardware(struct arm_pmu *armpmu) |
384 | { | 411 | { |
385 | int i, err, irq, irqs; | 412 | int err, irq; |
413 | unsigned int i, irqs; | ||
386 | struct platform_device *pmu_device = armpmu->plat_device; | 414 | struct platform_device *pmu_device = armpmu->plat_device; |
387 | 415 | ||
388 | if (!pmu_device) { | 416 | if (!pmu_device) { |
@@ -391,39 +419,59 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) | |||
391 | } | 419 | } |
392 | 420 | ||
393 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | 421 | irqs = min(pmu_device->num_resources, num_possible_cpus()); |
394 | if (irqs < 1) { | 422 | if (!irqs) { |
395 | pr_err("no irqs for PMUs defined\n"); | 423 | pr_err("no irqs for PMUs defined\n"); |
396 | return -ENODEV; | 424 | return -ENODEV; |
397 | } | 425 | } |
398 | 426 | ||
399 | for (i = 0; i < irqs; ++i) { | 427 | irq = platform_get_irq(pmu_device, 0); |
400 | err = 0; | 428 | if (irq <= 0) { |
401 | irq = platform_get_irq(pmu_device, i); | 429 | pr_err("failed to get valid irq for PMU device\n"); |
402 | if (irq < 0) | 430 | return -ENODEV; |
403 | continue; | 431 | } |
404 | 432 | ||
405 | /* | 433 | if (irq_is_percpu(irq)) { |
406 | * If we have a single PMU interrupt that we can't shift, | 434 | err = request_percpu_irq(irq, armpmu->handle_irq, |
407 | * assume that we're running on a uniprocessor machine and | 435 | "arm-pmu", &cpu_hw_events); |
408 | * continue. Otherwise, continue without this interrupt. | ||
409 | */ | ||
410 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
411 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
412 | irq, i); | ||
413 | continue; | ||
414 | } | ||
415 | 436 | ||
416 | err = request_irq(irq, armpmu->handle_irq, | ||
417 | IRQF_NOBALANCING, | ||
418 | "arm-pmu", armpmu); | ||
419 | if (err) { | 437 | if (err) { |
420 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | 438 | pr_err("unable to request percpu IRQ%d for ARM PMU counters\n", |
421 | irq); | 439 | irq); |
422 | armpmu_release_hardware(armpmu); | 440 | armpmu_release_hardware(armpmu); |
423 | return err; | 441 | return err; |
424 | } | 442 | } |
425 | 443 | ||
426 | cpumask_set_cpu(i, &armpmu->active_irqs); | 444 | on_each_cpu(armpmu_enable_percpu_irq, &irq, 1); |
445 | } else { | ||
446 | for (i = 0; i < irqs; ++i) { | ||
447 | err = 0; | ||
448 | irq = platform_get_irq(pmu_device, i); | ||
449 | if (irq <= 0) | ||
450 | continue; | ||
451 | |||
452 | /* | ||
453 | * If we have a single PMU interrupt that we can't shift, | ||
454 | * assume that we're running on a uniprocessor machine and | ||
455 | * continue. Otherwise, continue without this interrupt. | ||
456 | */ | ||
457 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
458 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
459 | irq, i); | ||
460 | continue; | ||
461 | } | ||
462 | |||
463 | err = request_irq(irq, armpmu->handle_irq, | ||
464 | IRQF_NOBALANCING, | ||
465 | "arm-pmu", armpmu); | ||
466 | if (err) { | ||
467 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
468 | irq); | ||
469 | armpmu_release_hardware(armpmu); | ||
470 | return err; | ||
471 | } | ||
472 | |||
473 | cpumask_set_cpu(i, &armpmu->active_irqs); | ||
474 | } | ||
427 | } | 475 | } |
428 | 476 | ||
429 | return 0; | 477 | return 0; |
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index de17c89985db..248a15db37f2 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/kallsyms.h> | 33 | #include <linux/kallsyms.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/cpu.h> | 35 | #include <linux/cpu.h> |
36 | #include <linux/cpuidle.h> | ||
36 | #include <linux/elfcore.h> | 37 | #include <linux/elfcore.h> |
37 | #include <linux/pm.h> | 38 | #include <linux/pm.h> |
38 | #include <linux/tick.h> | 39 | #include <linux/tick.h> |
@@ -98,8 +99,10 @@ void arch_cpu_idle(void) | |||
98 | * This should do all the clock switching and wait for interrupt | 99 | * This should do all the clock switching and wait for interrupt |
99 | * tricks | 100 | * tricks |
100 | */ | 101 | */ |
101 | cpu_do_idle(); | 102 | if (cpuidle_idle_call()) { |
102 | local_irq_enable(); | 103 | cpu_do_idle(); |
104 | local_irq_enable(); | ||
105 | } | ||
103 | } | 106 | } |
104 | 107 | ||
105 | #ifdef CONFIG_HOTPLUG_CPU | 108 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -308,6 +311,7 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
308 | unsigned long get_wchan(struct task_struct *p) | 311 | unsigned long get_wchan(struct task_struct *p) |
309 | { | 312 | { |
310 | struct stackframe frame; | 313 | struct stackframe frame; |
314 | unsigned long stack_page; | ||
311 | int count = 0; | 315 | int count = 0; |
312 | if (!p || p == current || p->state == TASK_RUNNING) | 316 | if (!p || p == current || p->state == TASK_RUNNING) |
313 | return 0; | 317 | return 0; |
@@ -315,9 +319,11 @@ unsigned long get_wchan(struct task_struct *p) | |||
315 | frame.fp = thread_saved_fp(p); | 319 | frame.fp = thread_saved_fp(p); |
316 | frame.sp = thread_saved_sp(p); | 320 | frame.sp = thread_saved_sp(p); |
317 | frame.pc = thread_saved_pc(p); | 321 | frame.pc = thread_saved_pc(p); |
322 | stack_page = (unsigned long)task_stack_page(p); | ||
318 | do { | 323 | do { |
319 | int ret = unwind_frame(&frame); | 324 | if (frame.sp < stack_page || |
320 | if (ret < 0) | 325 | frame.sp >= stack_page + THREAD_SIZE || |
326 | unwind_frame(&frame)) | ||
321 | return 0; | 327 | return 0; |
322 | if (!in_sched_functions(frame.pc)) | 328 | if (!in_sched_functions(frame.pc)) |
323 | return frame.pc; | 329 | return frame.pc; |
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index bd9bbd0e44ed..c8e9effe52e1 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c | |||
@@ -108,20 +108,95 @@ void __init early_print(const char *str, ...) | |||
108 | printk("%s", buf); | 108 | printk("%s", buf); |
109 | } | 109 | } |
110 | 110 | ||
111 | void __init smp_setup_processor_id(void) | ||
112 | { | ||
113 | /* | ||
114 | * clear __my_cpu_offset on boot CPU to avoid hang caused by | ||
115 | * using percpu variable early, for example, lockdep will | ||
116 | * access percpu variable inside lock_release | ||
117 | */ | ||
118 | set_my_cpu_offset(0); | ||
119 | } | ||
120 | |||
111 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) | 121 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) |
112 | { | 122 | { |
113 | return phys_id == cpu_logical_map(cpu); | 123 | return phys_id == cpu_logical_map(cpu); |
114 | } | 124 | } |
115 | 125 | ||
126 | struct mpidr_hash mpidr_hash; | ||
127 | #ifdef CONFIG_SMP | ||
128 | /** | ||
129 | * smp_build_mpidr_hash - Pre-compute shifts required at each affinity | ||
130 | * level in order to build a linear index from an | ||
131 | * MPIDR value. Resulting algorithm is a collision | ||
132 | * free hash carried out through shifting and ORing | ||
133 | */ | ||
134 | static void __init smp_build_mpidr_hash(void) | ||
135 | { | ||
136 | u32 i, affinity, fs[4], bits[4], ls; | ||
137 | u64 mask = 0; | ||
138 | /* | ||
139 | * Pre-scan the list of MPIDRS and filter out bits that do | ||
140 | * not contribute to affinity levels, ie they never toggle. | ||
141 | */ | ||
142 | for_each_possible_cpu(i) | ||
143 | mask |= (cpu_logical_map(i) ^ cpu_logical_map(0)); | ||
144 | pr_debug("mask of set bits %#llx\n", mask); | ||
145 | /* | ||
146 | * Find and stash the last and first bit set at all affinity levels to | ||
147 | * check how many bits are required to represent them. | ||
148 | */ | ||
149 | for (i = 0; i < 4; i++) { | ||
150 | affinity = MPIDR_AFFINITY_LEVEL(mask, i); | ||
151 | /* | ||
152 | * Find the MSB bit and LSB bits position | ||
153 | * to determine how many bits are required | ||
154 | * to express the affinity level. | ||
155 | */ | ||
156 | ls = fls(affinity); | ||
157 | fs[i] = affinity ? ffs(affinity) - 1 : 0; | ||
158 | bits[i] = ls - fs[i]; | ||
159 | } | ||
160 | /* | ||
161 | * An index can be created from the MPIDR_EL1 by isolating the | ||
162 | * significant bits at each affinity level and by shifting | ||
163 | * them in order to compress the 32 bits values space to a | ||
164 | * compressed set of values. This is equivalent to hashing | ||
165 | * the MPIDR_EL1 through shifting and ORing. It is a collision free | ||
166 | * hash though not minimal since some levels might contain a number | ||
167 | * of CPUs that is not an exact power of 2 and their bit | ||
168 | * representation might contain holes, eg MPIDR_EL1[7:0] = {0x2, 0x80}. | ||
169 | */ | ||
170 | mpidr_hash.shift_aff[0] = MPIDR_LEVEL_SHIFT(0) + fs[0]; | ||
171 | mpidr_hash.shift_aff[1] = MPIDR_LEVEL_SHIFT(1) + fs[1] - bits[0]; | ||
172 | mpidr_hash.shift_aff[2] = MPIDR_LEVEL_SHIFT(2) + fs[2] - | ||
173 | (bits[1] + bits[0]); | ||
174 | mpidr_hash.shift_aff[3] = MPIDR_LEVEL_SHIFT(3) + | ||
175 | fs[3] - (bits[2] + bits[1] + bits[0]); | ||
176 | mpidr_hash.mask = mask; | ||
177 | mpidr_hash.bits = bits[3] + bits[2] + bits[1] + bits[0]; | ||
178 | pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] aff3[%u] mask[%#llx] bits[%u]\n", | ||
179 | mpidr_hash.shift_aff[0], | ||
180 | mpidr_hash.shift_aff[1], | ||
181 | mpidr_hash.shift_aff[2], | ||
182 | mpidr_hash.shift_aff[3], | ||
183 | mpidr_hash.mask, | ||
184 | mpidr_hash.bits); | ||
185 | /* | ||
186 | * 4x is an arbitrary value used to warn on a hash table much bigger | ||
187 | * than expected on most systems. | ||
188 | */ | ||
189 | if (mpidr_hash_size() > 4 * num_possible_cpus()) | ||
190 | pr_warn("Large number of MPIDR hash buckets detected\n"); | ||
191 | __flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash)); | ||
192 | } | ||
193 | #endif | ||
194 | |||
116 | static void __init setup_processor(void) | 195 | static void __init setup_processor(void) |
117 | { | 196 | { |
118 | struct cpu_info *cpu_info; | 197 | struct cpu_info *cpu_info; |
198 | u64 features, block; | ||
119 | 199 | ||
120 | /* | ||
121 | * locate processor in the list of supported processor | ||
122 | * types. The linker builds this table for us from the | ||
123 | * entries in arch/arm/mm/proc.S | ||
124 | */ | ||
125 | cpu_info = lookup_processor_type(read_cpuid_id()); | 200 | cpu_info = lookup_processor_type(read_cpuid_id()); |
126 | if (!cpu_info) { | 201 | if (!cpu_info) { |
127 | printk("CPU configuration botched (ID %08x), unable to continue.\n", | 202 | printk("CPU configuration botched (ID %08x), unable to continue.\n", |
@@ -136,6 +211,37 @@ static void __init setup_processor(void) | |||
136 | 211 | ||
137 | sprintf(init_utsname()->machine, ELF_PLATFORM); | 212 | sprintf(init_utsname()->machine, ELF_PLATFORM); |
138 | elf_hwcap = 0; | 213 | elf_hwcap = 0; |
214 | |||
215 | /* | ||
216 | * ID_AA64ISAR0_EL1 contains 4-bit wide signed feature blocks. | ||
217 | * The blocks we test below represent incremental functionality | ||
218 | * for non-negative values. Negative values are reserved. | ||
219 | */ | ||
220 | features = read_cpuid(ID_AA64ISAR0_EL1); | ||
221 | block = (features >> 4) & 0xf; | ||
222 | if (!(block & 0x8)) { | ||
223 | switch (block) { | ||
224 | default: | ||
225 | case 2: | ||
226 | elf_hwcap |= HWCAP_PMULL; | ||
227 | case 1: | ||
228 | elf_hwcap |= HWCAP_AES; | ||
229 | case 0: | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | block = (features >> 8) & 0xf; | ||
235 | if (block && !(block & 0x8)) | ||
236 | elf_hwcap |= HWCAP_SHA1; | ||
237 | |||
238 | block = (features >> 12) & 0xf; | ||
239 | if (block && !(block & 0x8)) | ||
240 | elf_hwcap |= HWCAP_SHA2; | ||
241 | |||
242 | block = (features >> 16) & 0xf; | ||
243 | if (block && !(block & 0x8)) | ||
244 | elf_hwcap |= HWCAP_CRC32; | ||
139 | } | 245 | } |
140 | 246 | ||
141 | static void __init setup_machine_fdt(phys_addr_t dt_phys) | 247 | static void __init setup_machine_fdt(phys_addr_t dt_phys) |
@@ -236,6 +342,7 @@ void __init setup_arch(char **cmdline_p) | |||
236 | cpu_read_bootcpu_ops(); | 342 | cpu_read_bootcpu_ops(); |
237 | #ifdef CONFIG_SMP | 343 | #ifdef CONFIG_SMP |
238 | smp_init_cpus(); | 344 | smp_init_cpus(); |
345 | smp_build_mpidr_hash(); | ||
239 | #endif | 346 | #endif |
240 | 347 | ||
241 | #ifdef CONFIG_VT | 348 | #ifdef CONFIG_VT |
@@ -275,6 +382,11 @@ static const char *hwcap_str[] = { | |||
275 | "fp", | 382 | "fp", |
276 | "asimd", | 383 | "asimd", |
277 | "evtstrm", | 384 | "evtstrm", |
385 | "aes", | ||
386 | "pmull", | ||
387 | "sha1", | ||
388 | "sha2", | ||
389 | "crc32", | ||
278 | NULL | 390 | NULL |
279 | }; | 391 | }; |
280 | 392 | ||
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S new file mode 100644 index 000000000000..b1925729c692 --- /dev/null +++ b/arch/arm64/kernel/sleep.S | |||
@@ -0,0 +1,184 @@ | |||
1 | #include <linux/errno.h> | ||
2 | #include <linux/linkage.h> | ||
3 | #include <asm/asm-offsets.h> | ||
4 | #include <asm/assembler.h> | ||
5 | |||
6 | .text | ||
7 | /* | ||
8 | * Implementation of MPIDR_EL1 hash algorithm through shifting | ||
9 | * and OR'ing. | ||
10 | * | ||
11 | * @dst: register containing hash result | ||
12 | * @rs0: register containing affinity level 0 bit shift | ||
13 | * @rs1: register containing affinity level 1 bit shift | ||
14 | * @rs2: register containing affinity level 2 bit shift | ||
15 | * @rs3: register containing affinity level 3 bit shift | ||
16 | * @mpidr: register containing MPIDR_EL1 value | ||
17 | * @mask: register containing MPIDR mask | ||
18 | * | ||
19 | * Pseudo C-code: | ||
20 | * | ||
21 | *u32 dst; | ||
22 | * | ||
23 | *compute_mpidr_hash(u32 rs0, u32 rs1, u32 rs2, u32 rs3, u64 mpidr, u64 mask) { | ||
24 | * u32 aff0, aff1, aff2, aff3; | ||
25 | * u64 mpidr_masked = mpidr & mask; | ||
26 | * aff0 = mpidr_masked & 0xff; | ||
27 | * aff1 = mpidr_masked & 0xff00; | ||
28 | * aff2 = mpidr_masked & 0xff0000; | ||
29 | * aff2 = mpidr_masked & 0xff00000000; | ||
30 | * dst = (aff0 >> rs0 | aff1 >> rs1 | aff2 >> rs2 | aff3 >> rs3); | ||
31 | *} | ||
32 | * Input registers: rs0, rs1, rs2, rs3, mpidr, mask | ||
33 | * Output register: dst | ||
34 | * Note: input and output registers must be disjoint register sets | ||
35 | (eg: a macro instance with mpidr = x1 and dst = x1 is invalid) | ||
36 | */ | ||
37 | .macro compute_mpidr_hash dst, rs0, rs1, rs2, rs3, mpidr, mask | ||
38 | and \mpidr, \mpidr, \mask // mask out MPIDR bits | ||
39 | and \dst, \mpidr, #0xff // mask=aff0 | ||
40 | lsr \dst ,\dst, \rs0 // dst=aff0>>rs0 | ||
41 | and \mask, \mpidr, #0xff00 // mask = aff1 | ||
42 | lsr \mask ,\mask, \rs1 | ||
43 | orr \dst, \dst, \mask // dst|=(aff1>>rs1) | ||
44 | and \mask, \mpidr, #0xff0000 // mask = aff2 | ||
45 | lsr \mask ,\mask, \rs2 | ||
46 | orr \dst, \dst, \mask // dst|=(aff2>>rs2) | ||
47 | and \mask, \mpidr, #0xff00000000 // mask = aff3 | ||
48 | lsr \mask ,\mask, \rs3 | ||
49 | orr \dst, \dst, \mask // dst|=(aff3>>rs3) | ||
50 | .endm | ||
51 | /* | ||
52 | * Save CPU state for a suspend. This saves callee registers, and allocates | ||
53 | * space on the kernel stack to save the CPU specific registers + some | ||
54 | * other data for resume. | ||
55 | * | ||
56 | * x0 = suspend finisher argument | ||
57 | */ | ||
58 | ENTRY(__cpu_suspend) | ||
59 | stp x29, lr, [sp, #-96]! | ||
60 | stp x19, x20, [sp,#16] | ||
61 | stp x21, x22, [sp,#32] | ||
62 | stp x23, x24, [sp,#48] | ||
63 | stp x25, x26, [sp,#64] | ||
64 | stp x27, x28, [sp,#80] | ||
65 | mov x2, sp | ||
66 | sub sp, sp, #CPU_SUSPEND_SZ // allocate cpu_suspend_ctx | ||
67 | mov x1, sp | ||
68 | /* | ||
69 | * x1 now points to struct cpu_suspend_ctx allocated on the stack | ||
70 | */ | ||
71 | str x2, [x1, #CPU_CTX_SP] | ||
72 | ldr x2, =sleep_save_sp | ||
73 | ldr x2, [x2, #SLEEP_SAVE_SP_VIRT] | ||
74 | #ifdef CONFIG_SMP | ||
75 | mrs x7, mpidr_el1 | ||
76 | ldr x9, =mpidr_hash | ||
77 | ldr x10, [x9, #MPIDR_HASH_MASK] | ||
78 | /* | ||
79 | * Following code relies on the struct mpidr_hash | ||
80 | * members size. | ||
81 | */ | ||
82 | ldp w3, w4, [x9, #MPIDR_HASH_SHIFTS] | ||
83 | ldp w5, w6, [x9, #(MPIDR_HASH_SHIFTS + 8)] | ||
84 | compute_mpidr_hash x8, x3, x4, x5, x6, x7, x10 | ||
85 | add x2, x2, x8, lsl #3 | ||
86 | #endif | ||
87 | bl __cpu_suspend_finisher | ||
88 | /* | ||
89 | * Never gets here, unless suspend fails. | ||
90 | * Successful cpu_suspend should return from cpu_resume, returning | ||
91 | * through this code path is considered an error | ||
92 | * If the return value is set to 0 force x0 = -EOPNOTSUPP | ||
93 | * to make sure a proper error condition is propagated | ||
94 | */ | ||
95 | cmp x0, #0 | ||
96 | mov x3, #-EOPNOTSUPP | ||
97 | csel x0, x3, x0, eq | ||
98 | add sp, sp, #CPU_SUSPEND_SZ // rewind stack pointer | ||
99 | ldp x19, x20, [sp, #16] | ||
100 | ldp x21, x22, [sp, #32] | ||
101 | ldp x23, x24, [sp, #48] | ||
102 | ldp x25, x26, [sp, #64] | ||
103 | ldp x27, x28, [sp, #80] | ||
104 | ldp x29, lr, [sp], #96 | ||
105 | ret | ||
106 | ENDPROC(__cpu_suspend) | ||
107 | .ltorg | ||
108 | |||
109 | /* | ||
110 | * x0 must contain the sctlr value retrieved from restored context | ||
111 | */ | ||
112 | ENTRY(cpu_resume_mmu) | ||
113 | ldr x3, =cpu_resume_after_mmu | ||
114 | msr sctlr_el1, x0 // restore sctlr_el1 | ||
115 | isb | ||
116 | br x3 // global jump to virtual address | ||
117 | ENDPROC(cpu_resume_mmu) | ||
118 | cpu_resume_after_mmu: | ||
119 | mov x0, #0 // return zero on success | ||
120 | ldp x19, x20, [sp, #16] | ||
121 | ldp x21, x22, [sp, #32] | ||
122 | ldp x23, x24, [sp, #48] | ||
123 | ldp x25, x26, [sp, #64] | ||
124 | ldp x27, x28, [sp, #80] | ||
125 | ldp x29, lr, [sp], #96 | ||
126 | ret | ||
127 | ENDPROC(cpu_resume_after_mmu) | ||
128 | |||
129 | .data | ||
130 | ENTRY(cpu_resume) | ||
131 | bl el2_setup // if in EL2 drop to EL1 cleanly | ||
132 | #ifdef CONFIG_SMP | ||
133 | mrs x1, mpidr_el1 | ||
134 | adr x4, mpidr_hash_ptr | ||
135 | ldr x5, [x4] | ||
136 | add x8, x4, x5 // x8 = struct mpidr_hash phys address | ||
137 | /* retrieve mpidr_hash members to compute the hash */ | ||
138 | ldr x2, [x8, #MPIDR_HASH_MASK] | ||
139 | ldp w3, w4, [x8, #MPIDR_HASH_SHIFTS] | ||
140 | ldp w5, w6, [x8, #(MPIDR_HASH_SHIFTS + 8)] | ||
141 | compute_mpidr_hash x7, x3, x4, x5, x6, x1, x2 | ||
142 | /* x7 contains hash index, let's use it to grab context pointer */ | ||
143 | #else | ||
144 | mov x7, xzr | ||
145 | #endif | ||
146 | adr x0, sleep_save_sp | ||
147 | ldr x0, [x0, #SLEEP_SAVE_SP_PHYS] | ||
148 | ldr x0, [x0, x7, lsl #3] | ||
149 | /* load sp from context */ | ||
150 | ldr x2, [x0, #CPU_CTX_SP] | ||
151 | adr x1, sleep_idmap_phys | ||
152 | /* load physical address of identity map page table in x1 */ | ||
153 | ldr x1, [x1] | ||
154 | mov sp, x2 | ||
155 | /* | ||
156 | * cpu_do_resume expects x0 to contain context physical address | ||
157 | * pointer and x1 to contain physical address of 1:1 page tables | ||
158 | */ | ||
159 | bl cpu_do_resume // PC relative jump, MMU off | ||
160 | b cpu_resume_mmu // Resume MMU, never returns | ||
161 | ENDPROC(cpu_resume) | ||
162 | |||
163 | .align 3 | ||
164 | mpidr_hash_ptr: | ||
165 | /* | ||
166 | * offset of mpidr_hash symbol from current location | ||
167 | * used to obtain run-time mpidr_hash address with MMU off | ||
168 | */ | ||
169 | .quad mpidr_hash - . | ||
170 | /* | ||
171 | * physical address of identity mapped page tables | ||
172 | */ | ||
173 | .type sleep_idmap_phys, #object | ||
174 | ENTRY(sleep_idmap_phys) | ||
175 | .quad 0 | ||
176 | /* | ||
177 | * struct sleep_save_sp { | ||
178 | * phys_addr_t *save_ptr_stash; | ||
179 | * phys_addr_t save_ptr_stash_phys; | ||
180 | * }; | ||
181 | */ | ||
182 | .type sleep_save_sp, #object | ||
183 | ENTRY(sleep_save_sp) | ||
184 | .space SLEEP_SAVE_SP_SZ // struct sleep_save_sp | ||
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a0c2ca602cf8..1b7617ab499b 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
@@ -61,6 +61,7 @@ enum ipi_msg_type { | |||
61 | IPI_CALL_FUNC, | 61 | IPI_CALL_FUNC, |
62 | IPI_CALL_FUNC_SINGLE, | 62 | IPI_CALL_FUNC_SINGLE, |
63 | IPI_CPU_STOP, | 63 | IPI_CPU_STOP, |
64 | IPI_TIMER, | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | /* | 67 | /* |
@@ -122,8 +123,6 @@ asmlinkage void secondary_start_kernel(void) | |||
122 | struct mm_struct *mm = &init_mm; | 123 | struct mm_struct *mm = &init_mm; |
123 | unsigned int cpu = smp_processor_id(); | 124 | unsigned int cpu = smp_processor_id(); |
124 | 125 | ||
125 | printk("CPU%u: Booted secondary processor\n", cpu); | ||
126 | |||
127 | /* | 126 | /* |
128 | * All kernel threads share the same mm context; grab a | 127 | * All kernel threads share the same mm context; grab a |
129 | * reference and switch to it. | 128 | * reference and switch to it. |
@@ -132,6 +131,9 @@ asmlinkage void secondary_start_kernel(void) | |||
132 | current->active_mm = mm; | 131 | current->active_mm = mm; |
133 | cpumask_set_cpu(cpu, mm_cpumask(mm)); | 132 | cpumask_set_cpu(cpu, mm_cpumask(mm)); |
134 | 133 | ||
134 | set_my_cpu_offset(per_cpu_offset(smp_processor_id())); | ||
135 | printk("CPU%u: Booted secondary processor\n", cpu); | ||
136 | |||
135 | /* | 137 | /* |
136 | * TTBR0 is only used for the identity mapping at this stage. Make it | 138 | * TTBR0 is only used for the identity mapping at this stage. Make it |
137 | * point to zero page to avoid speculatively fetching new entries. | 139 | * point to zero page to avoid speculatively fetching new entries. |
@@ -271,6 +273,7 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
271 | 273 | ||
272 | void __init smp_prepare_boot_cpu(void) | 274 | void __init smp_prepare_boot_cpu(void) |
273 | { | 275 | { |
276 | set_my_cpu_offset(per_cpu_offset(smp_processor_id())); | ||
274 | } | 277 | } |
275 | 278 | ||
276 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); | 279 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); |
@@ -447,6 +450,7 @@ static const char *ipi_types[NR_IPI] = { | |||
447 | S(IPI_CALL_FUNC, "Function call interrupts"), | 450 | S(IPI_CALL_FUNC, "Function call interrupts"), |
448 | S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), | 451 | S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), |
449 | S(IPI_CPU_STOP, "CPU stop interrupts"), | 452 | S(IPI_CPU_STOP, "CPU stop interrupts"), |
453 | S(IPI_TIMER, "Timer broadcast interrupts"), | ||
450 | }; | 454 | }; |
451 | 455 | ||
452 | void show_ipi_list(struct seq_file *p, int prec) | 456 | void show_ipi_list(struct seq_file *p, int prec) |
@@ -532,6 +536,14 @@ void handle_IPI(int ipinr, struct pt_regs *regs) | |||
532 | irq_exit(); | 536 | irq_exit(); |
533 | break; | 537 | break; |
534 | 538 | ||
539 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
540 | case IPI_TIMER: | ||
541 | irq_enter(); | ||
542 | tick_receive_broadcast(); | ||
543 | irq_exit(); | ||
544 | break; | ||
545 | #endif | ||
546 | |||
535 | default: | 547 | default: |
536 | pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); | 548 | pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); |
537 | break; | 549 | break; |
@@ -544,6 +556,13 @@ void smp_send_reschedule(int cpu) | |||
544 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); | 556 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); |
545 | } | 557 | } |
546 | 558 | ||
559 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
560 | void tick_broadcast(const struct cpumask *mask) | ||
561 | { | ||
562 | smp_cross_call(mask, IPI_TIMER); | ||
563 | } | ||
564 | #endif | ||
565 | |||
547 | void smp_send_stop(void) | 566 | void smp_send_stop(void) |
548 | { | 567 | { |
549 | unsigned long timeout; | 568 | unsigned long timeout; |
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index d25459ff57fc..c3b6c63ea5fb 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c | |||
@@ -43,7 +43,7 @@ int unwind_frame(struct stackframe *frame) | |||
43 | low = frame->sp; | 43 | low = frame->sp; |
44 | high = ALIGN(low, THREAD_SIZE); | 44 | high = ALIGN(low, THREAD_SIZE); |
45 | 45 | ||
46 | if (fp < low || fp > high || fp & 0xf) | 46 | if (fp < low || fp > high - 0x18 || fp & 0xf) |
47 | return -EINVAL; | 47 | return -EINVAL; |
48 | 48 | ||
49 | frame->sp = fp + 0x10; | 49 | frame->sp = fp + 0x10; |
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c new file mode 100644 index 000000000000..430344e2c989 --- /dev/null +++ b/arch/arm64/kernel/suspend.c | |||
@@ -0,0 +1,132 @@ | |||
1 | #include <linux/slab.h> | ||
2 | #include <asm/cacheflush.h> | ||
3 | #include <asm/cpu_ops.h> | ||
4 | #include <asm/debug-monitors.h> | ||
5 | #include <asm/pgtable.h> | ||
6 | #include <asm/memory.h> | ||
7 | #include <asm/smp_plat.h> | ||
8 | #include <asm/suspend.h> | ||
9 | #include <asm/tlbflush.h> | ||
10 | |||
11 | extern int __cpu_suspend(unsigned long); | ||
12 | /* | ||
13 | * This is called by __cpu_suspend() to save the state, and do whatever | ||
14 | * flushing is required to ensure that when the CPU goes to sleep we have | ||
15 | * the necessary data available when the caches are not searched. | ||
16 | * | ||
17 | * @arg: Argument to pass to suspend operations | ||
18 | * @ptr: CPU context virtual address | ||
19 | * @save_ptr: address of the location where the context physical address | ||
20 | * must be saved | ||
21 | */ | ||
22 | int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr, | ||
23 | phys_addr_t *save_ptr) | ||
24 | { | ||
25 | int cpu = smp_processor_id(); | ||
26 | |||
27 | *save_ptr = virt_to_phys(ptr); | ||
28 | |||
29 | cpu_do_suspend(ptr); | ||
30 | /* | ||
31 | * Only flush the context that must be retrieved with the MMU | ||
32 | * off. VA primitives ensure the flush is applied to all | ||
33 | * cache levels so context is pushed to DRAM. | ||
34 | */ | ||
35 | __flush_dcache_area(ptr, sizeof(*ptr)); | ||
36 | __flush_dcache_area(save_ptr, sizeof(*save_ptr)); | ||
37 | |||
38 | return cpu_ops[cpu]->cpu_suspend(arg); | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * This hook is provided so that cpu_suspend code can restore HW | ||
43 | * breakpoints as early as possible in the resume path, before reenabling | ||
44 | * debug exceptions. Code cannot be run from a CPU PM notifier since by the | ||
45 | * time the notifier runs debug exceptions might have been enabled already, | ||
46 | * with HW breakpoints registers content still in an unknown state. | ||
47 | */ | ||
48 | void (*hw_breakpoint_restore)(void *); | ||
49 | void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) | ||
50 | { | ||
51 | /* Prevent multiple restore hook initializations */ | ||
52 | if (WARN_ON(hw_breakpoint_restore)) | ||
53 | return; | ||
54 | hw_breakpoint_restore = hw_bp_restore; | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * cpu_suspend | ||
59 | * | ||
60 | * @arg: argument to pass to the finisher function | ||
61 | */ | ||
62 | int cpu_suspend(unsigned long arg) | ||
63 | { | ||
64 | struct mm_struct *mm = current->active_mm; | ||
65 | int ret, cpu = smp_processor_id(); | ||
66 | unsigned long flags; | ||
67 | |||
68 | /* | ||
69 | * If cpu_ops have not been registered or suspend | ||
70 | * has not been initialized, cpu_suspend call fails early. | ||
71 | */ | ||
72 | if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend) | ||
73 | return -EOPNOTSUPP; | ||
74 | |||
75 | /* | ||
76 | * From this point debug exceptions are disabled to prevent | ||
77 | * updates to mdscr register (saved and restored along with | ||
78 | * general purpose registers) from kernel debuggers. | ||
79 | */ | ||
80 | local_dbg_save(flags); | ||
81 | |||
82 | /* | ||
83 | * mm context saved on the stack, it will be restored when | ||
84 | * the cpu comes out of reset through the identity mapped | ||
85 | * page tables, so that the thread address space is properly | ||
86 | * set-up on function return. | ||
87 | */ | ||
88 | ret = __cpu_suspend(arg); | ||
89 | if (ret == 0) { | ||
90 | cpu_switch_mm(mm->pgd, mm); | ||
91 | flush_tlb_all(); | ||
92 | /* | ||
93 | * Restore HW breakpoint registers to sane values | ||
94 | * before debug exceptions are possibly reenabled | ||
95 | * through local_dbg_restore. | ||
96 | */ | ||
97 | if (hw_breakpoint_restore) | ||
98 | hw_breakpoint_restore(NULL); | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Restore pstate flags. OS lock and mdscr have been already | ||
103 | * restored, so from this point onwards, debugging is fully | ||
104 | * renabled if it was enabled when core started shutdown. | ||
105 | */ | ||
106 | local_dbg_restore(flags); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | extern struct sleep_save_sp sleep_save_sp; | ||
112 | extern phys_addr_t sleep_idmap_phys; | ||
113 | |||
114 | static int cpu_suspend_init(void) | ||
115 | { | ||
116 | void *ctx_ptr; | ||
117 | |||
118 | /* ctx_ptr is an array of physical addresses */ | ||
119 | ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(phys_addr_t), GFP_KERNEL); | ||
120 | |||
121 | if (WARN_ON(!ctx_ptr)) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | sleep_save_sp.save_ptr_stash = ctx_ptr; | ||
125 | sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr); | ||
126 | sleep_idmap_phys = virt_to_phys(idmap_pg_dir); | ||
127 | __flush_dcache_area(&sleep_save_sp, sizeof(struct sleep_save_sp)); | ||
128 | __flush_dcache_area(&sleep_idmap_phys, sizeof(sleep_idmap_phys)); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | early_initcall(cpu_suspend_init); | ||
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 5161ad992091..4ba7a55b49c7 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S | |||
@@ -99,17 +99,14 @@ SECTIONS | |||
99 | 99 | ||
100 | . = ALIGN(PAGE_SIZE); | 100 | . = ALIGN(PAGE_SIZE); |
101 | _data = .; | 101 | _data = .; |
102 | __data_loc = _data - LOAD_OFFSET; | ||
103 | _sdata = .; | 102 | _sdata = .; |
104 | RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) | 103 | RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) |
105 | _edata = .; | 104 | _edata = .; |
106 | _edata_loc = __data_loc + SIZEOF(.data); | ||
107 | 105 | ||
108 | BSS_SECTION(0, 0, 0) | 106 | BSS_SECTION(0, 0, 0) |
109 | _end = .; | 107 | _end = .; |
110 | 108 | ||
111 | STABS_DEBUG | 109 | STABS_DEBUG |
112 | .comment 0 : { *(.comment) } | ||
113 | } | 110 | } |
114 | 111 | ||
115 | /* | 112 | /* |
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index 59acc0ef0462..328ce1a99daa 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile | |||
@@ -1,6 +1,4 @@ | |||
1 | lib-y := bitops.o delay.o \ | 1 | lib-y := bitops.o clear_user.o delay.o copy_from_user.o \ |
2 | strncpy_from_user.o strnlen_user.o clear_user.o \ | 2 | copy_to_user.o copy_in_user.o copy_page.o \ |
3 | copy_from_user.o copy_to_user.o copy_in_user.o \ | 3 | clear_page.o memchr.o memcpy.o memmove.o memset.o \ |
4 | copy_page.o clear_page.o \ | ||
5 | memchr.o memcpy.o memmove.o memset.o \ | ||
6 | strchr.o strrchr.o | 4 | strchr.o strrchr.o |
diff --git a/arch/arm64/lib/strncpy_from_user.S b/arch/arm64/lib/strncpy_from_user.S deleted file mode 100644 index 56e448a831a0..000000000000 --- a/arch/arm64/lib/strncpy_from_user.S +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/lib/strncpy_from_user.S | ||
3 | * | ||
4 | * Copyright (C) 1995-2000 Russell King | ||
5 | * Copyright (C) 2012 ARM Ltd. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/linkage.h> | ||
21 | #include <asm/assembler.h> | ||
22 | #include <asm/errno.h> | ||
23 | |||
24 | .text | ||
25 | .align 5 | ||
26 | |||
27 | /* | ||
28 | * Copy a string from user space to kernel space. | ||
29 | * x0 = dst, x1 = src, x2 = byte length | ||
30 | * returns the number of characters copied (strlen of copied string), | ||
31 | * -EFAULT on exception, or "len" if we fill the whole buffer | ||
32 | */ | ||
33 | ENTRY(__strncpy_from_user) | ||
34 | mov x4, x1 | ||
35 | 1: subs x2, x2, #1 | ||
36 | bmi 2f | ||
37 | USER(9f, ldrb w3, [x1], #1 ) | ||
38 | strb w3, [x0], #1 | ||
39 | cbnz w3, 1b | ||
40 | sub x1, x1, #1 // take NUL character out of count | ||
41 | 2: sub x0, x1, x4 | ||
42 | ret | ||
43 | ENDPROC(__strncpy_from_user) | ||
44 | |||
45 | .section .fixup,"ax" | ||
46 | .align 0 | ||
47 | 9: strb wzr, [x0] // null terminate | ||
48 | mov x0, #-EFAULT | ||
49 | ret | ||
50 | .previous | ||
diff --git a/arch/arm64/lib/strnlen_user.S b/arch/arm64/lib/strnlen_user.S deleted file mode 100644 index 7f7b176a5646..000000000000 --- a/arch/arm64/lib/strnlen_user.S +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /* | ||
2 | * Based on arch/arm/lib/strnlen_user.S | ||
3 | * | ||
4 | * Copyright (C) 1995-2000 Russell King | ||
5 | * Copyright (C) 2012 ARM Ltd. | ||
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 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/linkage.h> | ||
21 | #include <asm/assembler.h> | ||
22 | #include <asm/errno.h> | ||
23 | |||
24 | .text | ||
25 | .align 5 | ||
26 | |||
27 | /* Prototype: unsigned long __strnlen_user(const char *str, long n) | ||
28 | * Purpose : get length of a string in user memory | ||
29 | * Params : str - address of string in user memory | ||
30 | * Returns : length of string *including terminator* | ||
31 | * or zero on exception, or n if too long | ||
32 | */ | ||
33 | ENTRY(__strnlen_user) | ||
34 | mov x2, x0 | ||
35 | 1: subs x1, x1, #1 | ||
36 | b.mi 2f | ||
37 | USER(9f, ldrb w3, [x0], #1 ) | ||
38 | cbnz w3, 1b | ||
39 | 2: sub x0, x0, x2 | ||
40 | ret | ||
41 | ENDPROC(__strnlen_user) | ||
42 | |||
43 | .section .fixup,"ax" | ||
44 | .align 0 | ||
45 | 9: mov x0, #0 | ||
46 | ret | ||
47 | .previous | ||
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 4bd7579ec9e6..45b5ab54c9ee 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/export.h> | 21 | #include <linux/export.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/dma-mapping.h> | 23 | #include <linux/dma-mapping.h> |
24 | #include <linux/dma-contiguous.h> | ||
24 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
25 | #include <linux/swiotlb.h> | 26 | #include <linux/swiotlb.h> |
26 | 27 | ||
@@ -33,17 +34,47 @@ static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size, | |||
33 | dma_addr_t *dma_handle, gfp_t flags, | 34 | dma_addr_t *dma_handle, gfp_t flags, |
34 | struct dma_attrs *attrs) | 35 | struct dma_attrs *attrs) |
35 | { | 36 | { |
37 | if (dev == NULL) { | ||
38 | WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); | ||
39 | return NULL; | ||
40 | } | ||
41 | |||
36 | if (IS_ENABLED(CONFIG_ZONE_DMA32) && | 42 | if (IS_ENABLED(CONFIG_ZONE_DMA32) && |
37 | dev->coherent_dma_mask <= DMA_BIT_MASK(32)) | 43 | dev->coherent_dma_mask <= DMA_BIT_MASK(32)) |
38 | flags |= GFP_DMA32; | 44 | flags |= GFP_DMA32; |
39 | return swiotlb_alloc_coherent(dev, size, dma_handle, flags); | 45 | if (IS_ENABLED(CONFIG_DMA_CMA)) { |
46 | struct page *page; | ||
47 | |||
48 | page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, | ||
49 | get_order(size)); | ||
50 | if (!page) | ||
51 | return NULL; | ||
52 | |||
53 | *dma_handle = phys_to_dma(dev, page_to_phys(page)); | ||
54 | return page_address(page); | ||
55 | } else { | ||
56 | return swiotlb_alloc_coherent(dev, size, dma_handle, flags); | ||
57 | } | ||
40 | } | 58 | } |
41 | 59 | ||
42 | static void arm64_swiotlb_free_coherent(struct device *dev, size_t size, | 60 | static void arm64_swiotlb_free_coherent(struct device *dev, size_t size, |
43 | void *vaddr, dma_addr_t dma_handle, | 61 | void *vaddr, dma_addr_t dma_handle, |
44 | struct dma_attrs *attrs) | 62 | struct dma_attrs *attrs) |
45 | { | 63 | { |
46 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | 64 | if (dev == NULL) { |
65 | WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | if (IS_ENABLED(CONFIG_DMA_CMA)) { | ||
70 | phys_addr_t paddr = dma_to_phys(dev, dma_handle); | ||
71 | |||
72 | dma_release_from_contiguous(dev, | ||
73 | phys_to_page(paddr), | ||
74 | size >> PAGE_SHIFT); | ||
75 | } else { | ||
76 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | ||
77 | } | ||
47 | } | 78 | } |
48 | 79 | ||
49 | static struct dma_map_ops arm64_swiotlb_dma_ops = { | 80 | static struct dma_map_ops arm64_swiotlb_dma_ops = { |
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 0cb8742de4f2..d0b4c2efda90 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/memblock.h> | 30 | #include <linux/memblock.h> |
31 | #include <linux/sort.h> | 31 | #include <linux/sort.h> |
32 | #include <linux/of_fdt.h> | 32 | #include <linux/of_fdt.h> |
33 | #include <linux/dma-contiguous.h> | ||
33 | 34 | ||
34 | #include <asm/sections.h> | 35 | #include <asm/sections.h> |
35 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
@@ -159,6 +160,8 @@ void __init arm64_memblock_init(void) | |||
159 | memblock_reserve(base, size); | 160 | memblock_reserve(base, size); |
160 | } | 161 | } |
161 | 162 | ||
163 | dma_contiguous_reserve(0); | ||
164 | |||
162 | memblock_allow_resize(); | 165 | memblock_allow_resize(); |
163 | memblock_dump_all(); | 166 | memblock_dump_all(); |
164 | } | 167 | } |
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 0f7fec52c7f8..bed1f1de1caf 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S | |||
@@ -80,6 +80,75 @@ ENTRY(cpu_do_idle) | |||
80 | ret | 80 | ret |
81 | ENDPROC(cpu_do_idle) | 81 | ENDPROC(cpu_do_idle) |
82 | 82 | ||
83 | #ifdef CONFIG_ARM64_CPU_SUSPEND | ||
84 | /** | ||
85 | * cpu_do_suspend - save CPU registers context | ||
86 | * | ||
87 | * x0: virtual address of context pointer | ||
88 | */ | ||
89 | ENTRY(cpu_do_suspend) | ||
90 | mrs x2, tpidr_el0 | ||
91 | mrs x3, tpidrro_el0 | ||
92 | mrs x4, contextidr_el1 | ||
93 | mrs x5, mair_el1 | ||
94 | mrs x6, cpacr_el1 | ||
95 | mrs x7, ttbr1_el1 | ||
96 | mrs x8, tcr_el1 | ||
97 | mrs x9, vbar_el1 | ||
98 | mrs x10, mdscr_el1 | ||
99 | mrs x11, oslsr_el1 | ||
100 | mrs x12, sctlr_el1 | ||
101 | stp x2, x3, [x0] | ||
102 | stp x4, x5, [x0, #16] | ||
103 | stp x6, x7, [x0, #32] | ||
104 | stp x8, x9, [x0, #48] | ||
105 | stp x10, x11, [x0, #64] | ||
106 | str x12, [x0, #80] | ||
107 | ret | ||
108 | ENDPROC(cpu_do_suspend) | ||
109 | |||
110 | /** | ||
111 | * cpu_do_resume - restore CPU register context | ||
112 | * | ||
113 | * x0: Physical address of context pointer | ||
114 | * x1: ttbr0_el1 to be restored | ||
115 | * | ||
116 | * Returns: | ||
117 | * sctlr_el1 value in x0 | ||
118 | */ | ||
119 | ENTRY(cpu_do_resume) | ||
120 | /* | ||
121 | * Invalidate local tlb entries before turning on MMU | ||
122 | */ | ||
123 | tlbi vmalle1 | ||
124 | ldp x2, x3, [x0] | ||
125 | ldp x4, x5, [x0, #16] | ||
126 | ldp x6, x7, [x0, #32] | ||
127 | ldp x8, x9, [x0, #48] | ||
128 | ldp x10, x11, [x0, #64] | ||
129 | ldr x12, [x0, #80] | ||
130 | msr tpidr_el0, x2 | ||
131 | msr tpidrro_el0, x3 | ||
132 | msr contextidr_el1, x4 | ||
133 | msr mair_el1, x5 | ||
134 | msr cpacr_el1, x6 | ||
135 | msr ttbr0_el1, x1 | ||
136 | msr ttbr1_el1, x7 | ||
137 | msr tcr_el1, x8 | ||
138 | msr vbar_el1, x9 | ||
139 | msr mdscr_el1, x10 | ||
140 | /* | ||
141 | * Restore oslsr_el1 by writing oslar_el1 | ||
142 | */ | ||
143 | ubfx x11, x11, #1, #1 | ||
144 | msr oslar_el1, x11 | ||
145 | mov x0, x12 | ||
146 | dsb nsh // Make sure local tlb invalidation completed | ||
147 | isb | ||
148 | ret | ||
149 | ENDPROC(cpu_do_resume) | ||
150 | #endif | ||
151 | |||
83 | /* | 152 | /* |
84 | * cpu_switch_mm(pgd_phys, tsk) | 153 | * cpu_switch_mm(pgd_phys, tsk) |
85 | * | 154 | * |