diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 15:20:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 15:20:00 -0400 |
commit | e8a0b37d28ace440776c0a4fe3c65f5832a9a7ee (patch) | |
tree | 9475608c22849e5039d4dc00d3f8e3a30eeac2b9 | |
parent | abea9629486cf973369a641e190e739b3010bb03 (diff) | |
parent | 002af195a8c720ca47c7884fd0390f3b327423b9 (diff) |
Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
Pull ARM updates from Russell King:
"Bigger items included in this update are:
- A series of updates from Arnd for ARM randconfig build failures
- Updates from Dmitry for StrongARM SA-1100 to move IRQ handling to
drivers/irqchip/
- Move ARMs SP804 timer to drivers/clocksource/
- Perf updates from Mark Rutland in preparation to move the ARM perf
code into drivers/ so it can be shared with ARM64.
- MCPM updates from Nicolas
- Add support for taking platform serial number from DT
- Re-implement Keystone2 physical address space switch to conform to
architecture requirements
- Clean up ARMv7 LPAE code, which goes in hand with the Keystone2
changes.
- L2C cleanups to avoid unlocking caches if we're prevented by the
secure support to unlock.
- Avoid cleaning a potentially dirty cache containing stale data on
CPU initialisation
- Add ARM-only entry point for secondary startup (for machines that
can only call into a Thumb kernel in ARM mode). Same thing is also
done for the resume entry point.
- Provide arch_irqs_disabled via asm-generic
- Enlarge ARMv7M vector table
- Always use BFD linker for VDSO, as gold doesn't accept some of the
options we need.
- Fix an incorrect BSYM (for Thumb symbols) usage, and convert all
BSYM compiler macros to a "badr" (for branch address).
- Shut up compiler warnings provoked by our cmpxchg() implementation.
- Ensure bad xchg sizes fail to link"
* 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (75 commits)
ARM: Fix build if CLKDEV_LOOKUP is not configured
ARM: fix new BSYM() usage introduced via for-arm-soc branch
ARM: 8383/1: nommu: avoid deprecated source register on mov
ARM: 8391/1: l2c: add options to overwrite prefetching behavior
ARM: 8390/1: irqflags: Get arch_irqs_disabled from asm-generic
ARM: 8387/1: arm/mm/dma-mapping.c: Add arm_coherent_dma_mmap
ARM: 8388/1: tcm: Don't crash when TCM banks are protected by TrustZone
ARM: 8384/1: VDSO: force use of BFD linker
ARM: 8385/1: VDSO: group link options
ARM: cmpxchg: avoid warnings from macro-ized cmpxchg() implementations
ARM: remove __bad_xchg definition
ARM: 8369/1: ARMv7M: define size of vector table for Vybrid
ARM: 8382/1: clocksource: make ARM_TIMER_SP804 depend on GENERIC_SCHED_CLOCK
ARM: 8366/1: move Dual-Timer SP804 driver to drivers/clocksource
ARM: 8365/1: introduce sp804_timer_disable and remove arm_timer.h inclusion
ARM: 8364/1: fix BE32 module loading
ARM: 8360/1: add secondary_startup_arm prototype in header file
ARM: 8359/1: correct secondary_startup_arm mode
ARM: proc-v7: sanitise and document registers around errata
ARM: proc-v7: clean up MIDR access
...
83 files changed, 1889 insertions, 1361 deletions
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt index 0dbabe9a6b0a..2251dccb141e 100644 --- a/Documentation/devicetree/bindings/arm/l2cc.txt +++ b/Documentation/devicetree/bindings/arm/l2cc.txt | |||
@@ -67,6 +67,11 @@ Optional properties: | |||
67 | disable if zero. | 67 | disable if zero. |
68 | - arm,prefetch-offset : Override prefetch offset value. Valid values are | 68 | - arm,prefetch-offset : Override prefetch offset value. Valid values are |
69 | 0-7, 15, 23, and 31. | 69 | 0-7, 15, 23, and 31. |
70 | - prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1> | ||
71 | (forcibly enable), property absent (retain settings set by firmware) | ||
72 | - prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable), | ||
73 | <1> (forcibly enable), property absent (retain settings set by | ||
74 | firmware) | ||
70 | 75 | ||
71 | Example: | 76 | Example: |
72 | 77 | ||
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt index e49e423268c0..04d34f6a58f3 100644 --- a/Documentation/devicetree/booting-without-of.txt +++ b/Documentation/devicetree/booting-without-of.txt | |||
@@ -856,6 +856,10 @@ address which can extend beyond that limit. | |||
856 | name may clash with standard defined ones, you prefix them with your | 856 | name may clash with standard defined ones, you prefix them with your |
857 | vendor name and a comma. | 857 | vendor name and a comma. |
858 | 858 | ||
859 | Additional properties for the root node: | ||
860 | |||
861 | - serial-number : a string representing the device's serial number | ||
862 | |||
859 | b) The /cpus node | 863 | b) The /cpus node |
860 | 864 | ||
861 | This node is the parent of all individual CPU nodes. It doesn't | 865 | This node is the parent of all individual CPU nodes. It doesn't |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cf292d3ec27f..a750c1425c3a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -33,8 +33,8 @@ config ARM | |||
33 | select HARDIRQS_SW_RESEND | 33 | select HARDIRQS_SW_RESEND |
34 | select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) | 34 | select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) |
35 | select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 | 35 | select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 |
36 | select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL | 36 | select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 |
37 | select HAVE_ARCH_KGDB | 37 | select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 |
38 | select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) | 38 | select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT) |
39 | select HAVE_ARCH_TRACEHOOK | 39 | select HAVE_ARCH_TRACEHOOK |
40 | select HAVE_BPF_JIT | 40 | select HAVE_BPF_JIT |
@@ -45,7 +45,7 @@ config ARM | |||
45 | select HAVE_DMA_API_DEBUG | 45 | select HAVE_DMA_API_DEBUG |
46 | select HAVE_DMA_ATTRS | 46 | select HAVE_DMA_ATTRS |
47 | select HAVE_DMA_CONTIGUOUS if MMU | 47 | select HAVE_DMA_CONTIGUOUS if MMU |
48 | select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) | 48 | select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 |
49 | select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU | 49 | select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU |
50 | select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) | 50 | select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) |
51 | select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) | 51 | select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL) |
@@ -59,10 +59,10 @@ config ARM | |||
59 | select HAVE_KERNEL_LZMA | 59 | select HAVE_KERNEL_LZMA |
60 | select HAVE_KERNEL_LZO | 60 | select HAVE_KERNEL_LZO |
61 | select HAVE_KERNEL_XZ | 61 | select HAVE_KERNEL_XZ |
62 | select HAVE_KPROBES if !XIP_KERNEL | 62 | select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M |
63 | select HAVE_KRETPROBES if (HAVE_KPROBES) | 63 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
64 | select HAVE_MEMBLOCK | 64 | select HAVE_MEMBLOCK |
65 | select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND | 65 | select HAVE_MOD_ARCH_SPECIFIC |
66 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) | 66 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) |
67 | select HAVE_OPTPROBES if !THUMB2_KERNEL | 67 | select HAVE_OPTPROBES if !THUMB2_KERNEL |
68 | select HAVE_PERF_EVENTS | 68 | select HAVE_PERF_EVENTS |
@@ -173,7 +173,7 @@ config LOCKDEP_SUPPORT | |||
173 | 173 | ||
174 | config TRACE_IRQFLAGS_SUPPORT | 174 | config TRACE_IRQFLAGS_SUPPORT |
175 | bool | 175 | bool |
176 | default y | 176 | default !CPU_V7M |
177 | 177 | ||
178 | config RWSEM_XCHGADD_ALGORITHM | 178 | config RWSEM_XCHGADD_ALGORITHM |
179 | bool | 179 | bool |
@@ -1010,11 +1010,6 @@ config PLAT_PXA | |||
1010 | config PLAT_VERSATILE | 1010 | config PLAT_VERSATILE |
1011 | bool | 1011 | bool |
1012 | 1012 | ||
1013 | config ARM_TIMER_SP804 | ||
1014 | bool | ||
1015 | select CLKSRC_MMIO | ||
1016 | select CLKSRC_OF if OF | ||
1017 | |||
1018 | source "arch/arm/firmware/Kconfig" | 1013 | source "arch/arm/firmware/Kconfig" |
1019 | 1014 | ||
1020 | source arch/arm/mm/Kconfig | 1015 | source arch/arm/mm/Kconfig |
@@ -1342,6 +1337,7 @@ config SMP | |||
1342 | depends on GENERIC_CLOCKEVENTS | 1337 | depends on GENERIC_CLOCKEVENTS |
1343 | depends on HAVE_SMP | 1338 | depends on HAVE_SMP |
1344 | depends on MMU || ARM_MPU | 1339 | depends on MMU || ARM_MPU |
1340 | select IRQ_WORK | ||
1345 | help | 1341 | help |
1346 | This enables support for systems with more than one CPU. If you have | 1342 | This enables support for systems with more than one CPU. If you have |
1347 | a system with only one CPU, say N. If you have a system with more | 1343 | a system with only one CPU, say N. If you have a system with more |
@@ -1717,6 +1713,21 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE | |||
1717 | config ARCH_WANT_GENERAL_HUGETLB | 1713 | config ARCH_WANT_GENERAL_HUGETLB |
1718 | def_bool y | 1714 | def_bool y |
1719 | 1715 | ||
1716 | config ARM_MODULE_PLTS | ||
1717 | bool "Use PLTs to allow module memory to spill over into vmalloc area" | ||
1718 | depends on MODULES | ||
1719 | help | ||
1720 | Allocate PLTs when loading modules so that jumps and calls whose | ||
1721 | targets are too far away for their relative offsets to be encoded | ||
1722 | in the instructions themselves can be bounced via veneers in the | ||
1723 | module's PLT. This allows modules to be allocated in the generic | ||
1724 | vmalloc area after the dedicated module memory area has been | ||
1725 | exhausted. The modules will use slightly more memory, but after | ||
1726 | rounding up to page size, the actual memory footprint is usually | ||
1727 | the same. | ||
1728 | |||
1729 | Say y if you are getting out of memory errors while loading modules | ||
1730 | |||
1720 | source "mm/Kconfig" | 1731 | source "mm/Kconfig" |
1721 | 1732 | ||
1722 | config FORCE_MAX_ZONEORDER | 1733 | config FORCE_MAX_ZONEORDER |
@@ -1987,6 +1998,7 @@ config XIP_PHYS_ADDR | |||
1987 | config KEXEC | 1998 | config KEXEC |
1988 | bool "Kexec system call (EXPERIMENTAL)" | 1999 | bool "Kexec system call (EXPERIMENTAL)" |
1989 | depends on (!SMP || PM_SLEEP_SMP) | 2000 | depends on (!SMP || PM_SLEEP_SMP) |
2001 | depends on !CPU_V7M | ||
1990 | help | 2002 | help |
1991 | kexec is a system call that implements the ability to shutdown your | 2003 | kexec is a system call that implements the ability to shutdown your |
1992 | current kernel, and to start another kernel. It is like a reboot | 2004 | current kernel, and to start another kernel. It is like a reboot |
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index a6b5d0e35968..f1b157971366 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug | |||
@@ -5,6 +5,7 @@ source "lib/Kconfig.debug" | |||
5 | config ARM_PTDUMP | 5 | config ARM_PTDUMP |
6 | bool "Export kernel pagetable layout to userspace via debugfs" | 6 | bool "Export kernel pagetable layout to userspace via debugfs" |
7 | depends on DEBUG_KERNEL | 7 | depends on DEBUG_KERNEL |
8 | depends on MMU | ||
8 | select DEBUG_FS | 9 | select DEBUG_FS |
9 | ---help--- | 10 | ---help--- |
10 | Say Y here if you want to show the kernel pagetable layout in a | 11 | Say Y here if you want to show the kernel pagetable layout in a |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 2a4fae7e9c44..07ab3d203916 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -19,6 +19,10 @@ LDFLAGS_vmlinux += --be8 | |||
19 | LDFLAGS_MODULE += --be8 | 19 | LDFLAGS_MODULE += --be8 |
20 | endif | 20 | endif |
21 | 21 | ||
22 | ifeq ($(CONFIG_ARM_MODULE_PLTS),y) | ||
23 | LDFLAGS_MODULE += -T $(srctree)/arch/arm/kernel/module.lds | ||
24 | endif | ||
25 | |||
22 | OBJCOPYFLAGS :=-O binary -R .comment -S | 26 | OBJCOPYFLAGS :=-O binary -R .comment -S |
23 | GZFLAGS :=-9 | 27 | GZFLAGS :=-9 |
24 | #KBUILD_CFLAGS +=-pipe | 28 | #KBUILD_CFLAGS +=-pipe |
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 6e1fb2b2ecc7..7a13aebacf81 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile | |||
@@ -103,6 +103,8 @@ extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 \ | |||
103 | lib1funcs.S ashldi3.S bswapsdi2.S $(libfdt) $(libfdt_hdrs) \ | 103 | lib1funcs.S ashldi3.S bswapsdi2.S $(libfdt) $(libfdt_hdrs) \ |
104 | hyp-stub.S | 104 | hyp-stub.S |
105 | 105 | ||
106 | KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING | ||
107 | |||
106 | ifeq ($(CONFIG_FUNCTION_TRACER),y) | 108 | ifeq ($(CONFIG_FUNCTION_TRACER),y) |
107 | ORIG_CFLAGS := $(KBUILD_CFLAGS) | 109 | ORIG_CFLAGS := $(KBUILD_CFLAGS) |
108 | KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) | 110 | KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) |
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 2c45b5709fa4..06e983f59980 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S | |||
@@ -130,7 +130,7 @@ start: | |||
130 | .endr | 130 | .endr |
131 | ARM( mov r0, r0 ) | 131 | ARM( mov r0, r0 ) |
132 | ARM( b 1f ) | 132 | ARM( b 1f ) |
133 | THUMB( adr r12, BSYM(1f) ) | 133 | THUMB( badr r12, 1f ) |
134 | THUMB( bx r12 ) | 134 | THUMB( bx r12 ) |
135 | 135 | ||
136 | .word _magic_sig @ Magic numbers to help the loader | 136 | .word _magic_sig @ Magic numbers to help the loader |
@@ -447,7 +447,7 @@ dtb_check_done: | |||
447 | 447 | ||
448 | bl cache_clean_flush | 448 | bl cache_clean_flush |
449 | 449 | ||
450 | adr r0, BSYM(restart) | 450 | badr r0, restart |
451 | add r0, r0, r6 | 451 | add r0, r0, r6 |
452 | mov pc, r0 | 452 | mov pc, r0 |
453 | 453 | ||
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 70b1eff477b3..6ee5959a813b 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile | |||
@@ -11,7 +11,6 @@ obj-$(CONFIG_SHARP_LOCOMO) += locomo.o | |||
11 | obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o | 11 | obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o |
12 | obj-$(CONFIG_SHARP_SCOOP) += scoop.o | 12 | obj-$(CONFIG_SHARP_SCOOP) += scoop.o |
13 | obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o | 13 | obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o |
14 | obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o | ||
15 | obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o | 14 | obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o |
16 | CFLAGS_REMOVE_mcpm_entry.o = -pg | 15 | CFLAGS_REMOVE_mcpm_entry.o = -pg |
17 | AFLAGS_mcpm_head.o := -march=armv7-a | 16 | AFLAGS_mcpm_head.o := -march=armv7-a |
diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index 5f8a52ac7edf..a923524d1040 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c | |||
@@ -20,6 +20,126 @@ | |||
20 | #include <asm/cputype.h> | 20 | #include <asm/cputype.h> |
21 | #include <asm/suspend.h> | 21 | #include <asm/suspend.h> |
22 | 22 | ||
23 | /* | ||
24 | * The public API for this code is documented in arch/arm/include/asm/mcpm.h. | ||
25 | * For a comprehensive description of the main algorithm used here, please | ||
26 | * see Documentation/arm/cluster-pm-race-avoidance.txt. | ||
27 | */ | ||
28 | |||
29 | struct sync_struct mcpm_sync; | ||
30 | |||
31 | /* | ||
32 | * __mcpm_cpu_going_down: Indicates that the cpu is being torn down. | ||
33 | * This must be called at the point of committing to teardown of a CPU. | ||
34 | * The CPU cache (SCTRL.C bit) is expected to still be active. | ||
35 | */ | ||
36 | static void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster) | ||
37 | { | ||
38 | mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_GOING_DOWN; | ||
39 | sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu); | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * __mcpm_cpu_down: Indicates that cpu teardown is complete and that the | ||
44 | * cluster can be torn down without disrupting this CPU. | ||
45 | * To avoid deadlocks, this must be called before a CPU is powered down. | ||
46 | * The CPU cache (SCTRL.C bit) is expected to be off. | ||
47 | * However L2 cache might or might not be active. | ||
48 | */ | ||
49 | static void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster) | ||
50 | { | ||
51 | dmb(); | ||
52 | mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_DOWN; | ||
53 | sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu); | ||
54 | sev(); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * __mcpm_outbound_leave_critical: Leave the cluster teardown critical section. | ||
59 | * @state: the final state of the cluster: | ||
60 | * CLUSTER_UP: no destructive teardown was done and the cluster has been | ||
61 | * restored to the previous state (CPU cache still active); or | ||
62 | * CLUSTER_DOWN: the cluster has been torn-down, ready for power-off | ||
63 | * (CPU cache disabled, L2 cache either enabled or disabled). | ||
64 | */ | ||
65 | static void __mcpm_outbound_leave_critical(unsigned int cluster, int state) | ||
66 | { | ||
67 | dmb(); | ||
68 | mcpm_sync.clusters[cluster].cluster = state; | ||
69 | sync_cache_w(&mcpm_sync.clusters[cluster].cluster); | ||
70 | sev(); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * __mcpm_outbound_enter_critical: Enter the cluster teardown critical section. | ||
75 | * This function should be called by the last man, after local CPU teardown | ||
76 | * is complete. CPU cache expected to be active. | ||
77 | * | ||
78 | * Returns: | ||
79 | * false: the critical section was not entered because an inbound CPU was | ||
80 | * observed, or the cluster is already being set up; | ||
81 | * true: the critical section was entered: it is now safe to tear down the | ||
82 | * cluster. | ||
83 | */ | ||
84 | static bool __mcpm_outbound_enter_critical(unsigned int cpu, unsigned int cluster) | ||
85 | { | ||
86 | unsigned int i; | ||
87 | struct mcpm_sync_struct *c = &mcpm_sync.clusters[cluster]; | ||
88 | |||
89 | /* Warn inbound CPUs that the cluster is being torn down: */ | ||
90 | c->cluster = CLUSTER_GOING_DOWN; | ||
91 | sync_cache_w(&c->cluster); | ||
92 | |||
93 | /* Back out if the inbound cluster is already in the critical region: */ | ||
94 | sync_cache_r(&c->inbound); | ||
95 | if (c->inbound == INBOUND_COMING_UP) | ||
96 | goto abort; | ||
97 | |||
98 | /* | ||
99 | * Wait for all CPUs to get out of the GOING_DOWN state, so that local | ||
100 | * teardown is complete on each CPU before tearing down the cluster. | ||
101 | * | ||
102 | * If any CPU has been woken up again from the DOWN state, then we | ||
103 | * shouldn't be taking the cluster down at all: abort in that case. | ||
104 | */ | ||
105 | sync_cache_r(&c->cpus); | ||
106 | for (i = 0; i < MAX_CPUS_PER_CLUSTER; i++) { | ||
107 | int cpustate; | ||
108 | |||
109 | if (i == cpu) | ||
110 | continue; | ||
111 | |||
112 | while (1) { | ||
113 | cpustate = c->cpus[i].cpu; | ||
114 | if (cpustate != CPU_GOING_DOWN) | ||
115 | break; | ||
116 | |||
117 | wfe(); | ||
118 | sync_cache_r(&c->cpus[i].cpu); | ||
119 | } | ||
120 | |||
121 | switch (cpustate) { | ||
122 | case CPU_DOWN: | ||
123 | continue; | ||
124 | |||
125 | default: | ||
126 | goto abort; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return true; | ||
131 | |||
132 | abort: | ||
133 | __mcpm_outbound_leave_critical(cluster, CLUSTER_UP); | ||
134 | return false; | ||
135 | } | ||
136 | |||
137 | static int __mcpm_cluster_state(unsigned int cluster) | ||
138 | { | ||
139 | sync_cache_r(&mcpm_sync.clusters[cluster].cluster); | ||
140 | return mcpm_sync.clusters[cluster].cluster; | ||
141 | } | ||
142 | |||
23 | extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER]; | 143 | extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER]; |
24 | 144 | ||
25 | void mcpm_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr) | 145 | void mcpm_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr) |
@@ -78,16 +198,11 @@ int mcpm_cpu_power_up(unsigned int cpu, unsigned int cluster) | |||
78 | bool cpu_is_down, cluster_is_down; | 198 | bool cpu_is_down, cluster_is_down; |
79 | int ret = 0; | 199 | int ret = 0; |
80 | 200 | ||
201 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); | ||
81 | if (!platform_ops) | 202 | if (!platform_ops) |
82 | return -EUNATCH; /* try not to shadow power_up errors */ | 203 | return -EUNATCH; /* try not to shadow power_up errors */ |
83 | might_sleep(); | 204 | might_sleep(); |
84 | 205 | ||
85 | /* backward compatibility callback */ | ||
86 | if (platform_ops->power_up) | ||
87 | return platform_ops->power_up(cpu, cluster); | ||
88 | |||
89 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); | ||
90 | |||
91 | /* | 206 | /* |
92 | * Since this is called with IRQs enabled, and no arch_spin_lock_irq | 207 | * Since this is called with IRQs enabled, and no arch_spin_lock_irq |
93 | * variant exists, we need to disable IRQs manually here. | 208 | * variant exists, we need to disable IRQs manually here. |
@@ -128,29 +243,17 @@ void mcpm_cpu_power_down(void) | |||
128 | bool cpu_going_down, last_man; | 243 | bool cpu_going_down, last_man; |
129 | phys_reset_t phys_reset; | 244 | phys_reset_t phys_reset; |
130 | 245 | ||
246 | mpidr = read_cpuid_mpidr(); | ||
247 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
248 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
249 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); | ||
131 | if (WARN_ON_ONCE(!platform_ops)) | 250 | if (WARN_ON_ONCE(!platform_ops)) |
132 | return; | 251 | return; |
133 | BUG_ON(!irqs_disabled()); | 252 | BUG_ON(!irqs_disabled()); |
134 | 253 | ||
135 | /* | ||
136 | * Do this before calling into the power_down method, | ||
137 | * as it might not always be safe to do afterwards. | ||
138 | */ | ||
139 | setup_mm_for_reboot(); | 254 | setup_mm_for_reboot(); |
140 | 255 | ||
141 | /* backward compatibility callback */ | ||
142 | if (platform_ops->power_down) { | ||
143 | platform_ops->power_down(); | ||
144 | goto not_dead; | ||
145 | } | ||
146 | |||
147 | mpidr = read_cpuid_mpidr(); | ||
148 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
149 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
150 | pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); | ||
151 | |||
152 | __mcpm_cpu_going_down(cpu, cluster); | 256 | __mcpm_cpu_going_down(cpu, cluster); |
153 | |||
154 | arch_spin_lock(&mcpm_lock); | 257 | arch_spin_lock(&mcpm_lock); |
155 | BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); | 258 | BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); |
156 | 259 | ||
@@ -187,7 +290,6 @@ void mcpm_cpu_power_down(void) | |||
187 | if (cpu_going_down) | 290 | if (cpu_going_down) |
188 | wfi(); | 291 | wfi(); |
189 | 292 | ||
190 | not_dead: | ||
191 | /* | 293 | /* |
192 | * It is possible for a power_up request to happen concurrently | 294 | * It is possible for a power_up request to happen concurrently |
193 | * with a power_down request for the same CPU. In this case the | 295 | * with a power_down request for the same CPU. In this case the |
@@ -219,22 +321,11 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster) | |||
219 | return ret; | 321 | return ret; |
220 | } | 322 | } |
221 | 323 | ||
222 | void mcpm_cpu_suspend(u64 expected_residency) | 324 | void mcpm_cpu_suspend(void) |
223 | { | 325 | { |
224 | if (WARN_ON_ONCE(!platform_ops)) | 326 | if (WARN_ON_ONCE(!platform_ops)) |
225 | return; | 327 | return; |
226 | 328 | ||
227 | /* backward compatibility callback */ | ||
228 | if (platform_ops->suspend) { | ||
229 | phys_reset_t phys_reset; | ||
230 | BUG_ON(!irqs_disabled()); | ||
231 | setup_mm_for_reboot(); | ||
232 | platform_ops->suspend(expected_residency); | ||
233 | phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); | ||
234 | phys_reset(virt_to_phys(mcpm_entry_point)); | ||
235 | BUG(); | ||
236 | } | ||
237 | |||
238 | /* Some platforms might have to enable special resume modes, etc. */ | 329 | /* Some platforms might have to enable special resume modes, etc. */ |
239 | if (platform_ops->cpu_suspend_prepare) { | 330 | if (platform_ops->cpu_suspend_prepare) { |
240 | unsigned int mpidr = read_cpuid_mpidr(); | 331 | unsigned int mpidr = read_cpuid_mpidr(); |
@@ -256,12 +347,6 @@ int mcpm_cpu_powered_up(void) | |||
256 | if (!platform_ops) | 347 | if (!platform_ops) |
257 | return -EUNATCH; | 348 | return -EUNATCH; |
258 | 349 | ||
259 | /* backward compatibility callback */ | ||
260 | if (platform_ops->powered_up) { | ||
261 | platform_ops->powered_up(); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | mpidr = read_cpuid_mpidr(); | 350 | mpidr = read_cpuid_mpidr(); |
266 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | 351 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); |
267 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | 352 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); |
@@ -334,120 +419,6 @@ int __init mcpm_loopback(void (*cache_disable)(void)) | |||
334 | 419 | ||
335 | #endif | 420 | #endif |
336 | 421 | ||
337 | struct sync_struct mcpm_sync; | ||
338 | |||
339 | /* | ||
340 | * __mcpm_cpu_going_down: Indicates that the cpu is being torn down. | ||
341 | * This must be called at the point of committing to teardown of a CPU. | ||
342 | * The CPU cache (SCTRL.C bit) is expected to still be active. | ||
343 | */ | ||
344 | void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster) | ||
345 | { | ||
346 | mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_GOING_DOWN; | ||
347 | sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu); | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * __mcpm_cpu_down: Indicates that cpu teardown is complete and that the | ||
352 | * cluster can be torn down without disrupting this CPU. | ||
353 | * To avoid deadlocks, this must be called before a CPU is powered down. | ||
354 | * The CPU cache (SCTRL.C bit) is expected to be off. | ||
355 | * However L2 cache might or might not be active. | ||
356 | */ | ||
357 | void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster) | ||
358 | { | ||
359 | dmb(); | ||
360 | mcpm_sync.clusters[cluster].cpus[cpu].cpu = CPU_DOWN; | ||
361 | sync_cache_w(&mcpm_sync.clusters[cluster].cpus[cpu].cpu); | ||
362 | sev(); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * __mcpm_outbound_leave_critical: Leave the cluster teardown critical section. | ||
367 | * @state: the final state of the cluster: | ||
368 | * CLUSTER_UP: no destructive teardown was done and the cluster has been | ||
369 | * restored to the previous state (CPU cache still active); or | ||
370 | * CLUSTER_DOWN: the cluster has been torn-down, ready for power-off | ||
371 | * (CPU cache disabled, L2 cache either enabled or disabled). | ||
372 | */ | ||
373 | void __mcpm_outbound_leave_critical(unsigned int cluster, int state) | ||
374 | { | ||
375 | dmb(); | ||
376 | mcpm_sync.clusters[cluster].cluster = state; | ||
377 | sync_cache_w(&mcpm_sync.clusters[cluster].cluster); | ||
378 | sev(); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * __mcpm_outbound_enter_critical: Enter the cluster teardown critical section. | ||
383 | * This function should be called by the last man, after local CPU teardown | ||
384 | * is complete. CPU cache expected to be active. | ||
385 | * | ||
386 | * Returns: | ||
387 | * false: the critical section was not entered because an inbound CPU was | ||
388 | * observed, or the cluster is already being set up; | ||
389 | * true: the critical section was entered: it is now safe to tear down the | ||
390 | * cluster. | ||
391 | */ | ||
392 | bool __mcpm_outbound_enter_critical(unsigned int cpu, unsigned int cluster) | ||
393 | { | ||
394 | unsigned int i; | ||
395 | struct mcpm_sync_struct *c = &mcpm_sync.clusters[cluster]; | ||
396 | |||
397 | /* Warn inbound CPUs that the cluster is being torn down: */ | ||
398 | c->cluster = CLUSTER_GOING_DOWN; | ||
399 | sync_cache_w(&c->cluster); | ||
400 | |||
401 | /* Back out if the inbound cluster is already in the critical region: */ | ||
402 | sync_cache_r(&c->inbound); | ||
403 | if (c->inbound == INBOUND_COMING_UP) | ||
404 | goto abort; | ||
405 | |||
406 | /* | ||
407 | * Wait for all CPUs to get out of the GOING_DOWN state, so that local | ||
408 | * teardown is complete on each CPU before tearing down the cluster. | ||
409 | * | ||
410 | * If any CPU has been woken up again from the DOWN state, then we | ||
411 | * shouldn't be taking the cluster down at all: abort in that case. | ||
412 | */ | ||
413 | sync_cache_r(&c->cpus); | ||
414 | for (i = 0; i < MAX_CPUS_PER_CLUSTER; i++) { | ||
415 | int cpustate; | ||
416 | |||
417 | if (i == cpu) | ||
418 | continue; | ||
419 | |||
420 | while (1) { | ||
421 | cpustate = c->cpus[i].cpu; | ||
422 | if (cpustate != CPU_GOING_DOWN) | ||
423 | break; | ||
424 | |||
425 | wfe(); | ||
426 | sync_cache_r(&c->cpus[i].cpu); | ||
427 | } | ||
428 | |||
429 | switch (cpustate) { | ||
430 | case CPU_DOWN: | ||
431 | continue; | ||
432 | |||
433 | default: | ||
434 | goto abort; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return true; | ||
439 | |||
440 | abort: | ||
441 | __mcpm_outbound_leave_critical(cluster, CLUSTER_UP); | ||
442 | return false; | ||
443 | } | ||
444 | |||
445 | int __mcpm_cluster_state(unsigned int cluster) | ||
446 | { | ||
447 | sync_cache_r(&mcpm_sync.clusters[cluster].cluster); | ||
448 | return mcpm_sync.clusters[cluster].cluster; | ||
449 | } | ||
450 | |||
451 | extern unsigned long mcpm_power_up_setup_phys; | 422 | extern unsigned long mcpm_power_up_setup_phys; |
452 | 423 | ||
453 | int __init mcpm_sync_init( | 424 | int __init mcpm_sync_init( |
diff --git a/arch/arm/common/mcpm_head.S b/arch/arm/common/mcpm_head.S index e02db4b81a66..08b3bb9bc6a2 100644 --- a/arch/arm/common/mcpm_head.S +++ b/arch/arm/common/mcpm_head.S | |||
@@ -49,7 +49,7 @@ | |||
49 | ENTRY(mcpm_entry_point) | 49 | ENTRY(mcpm_entry_point) |
50 | 50 | ||
51 | ARM_BE8(setend be) | 51 | ARM_BE8(setend be) |
52 | THUMB( adr r12, BSYM(1f) ) | 52 | THUMB( badr r12, 1f ) |
53 | THUMB( bx r12 ) | 53 | THUMB( bx r12 ) |
54 | THUMB( .thumb ) | 54 | THUMB( .thumb ) |
55 | 1: | 55 | 1: |
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 186270b3e194..4abe57279c66 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h | |||
@@ -178,6 +178,21 @@ | |||
178 | .endm | 178 | .endm |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * Assembly version of "adr rd, BSYM(sym)". This should only be used to | ||
182 | * reference local symbols in the same assembly file which are to be | ||
183 | * resolved by the assembler. Other usage is undefined. | ||
184 | */ | ||
185 | .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo | ||
186 | .macro badr\c, rd, sym | ||
187 | #ifdef CONFIG_THUMB2_KERNEL | ||
188 | adr\c \rd, \sym + 1 | ||
189 | #else | ||
190 | adr\c \rd, \sym | ||
191 | #endif | ||
192 | .endm | ||
193 | .endr | ||
194 | |||
195 | /* | ||
181 | * Get current thread_info. | 196 | * Get current thread_info. |
182 | */ | 197 | */ |
183 | .macro get_thread_info, rd | 198 | .macro get_thread_info, rd |
@@ -326,7 +341,7 @@ | |||
326 | THUMB( orr \reg , \reg , #PSR_T_BIT ) | 341 | THUMB( orr \reg , \reg , #PSR_T_BIT ) |
327 | bne 1f | 342 | bne 1f |
328 | orr \reg, \reg, #PSR_A_BIT | 343 | orr \reg, \reg, #PSR_A_BIT |
329 | adr lr, BSYM(2f) | 344 | badr lr, 2f |
330 | msr spsr_cxsf, \reg | 345 | msr spsr_cxsf, \reg |
331 | __MSR_ELR_HYP(14) | 346 | __MSR_ELR_HYP(14) |
332 | __ERET | 347 | __ERET |
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 2d46862e7bef..4812cda8fd17 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h | |||
@@ -482,10 +482,17 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size) | |||
482 | : : : "r0","r1","r2","r3","r4","r5","r6","r7", \ | 482 | : : : "r0","r1","r2","r3","r4","r5","r6","r7", \ |
483 | "r9","r10","lr","memory" ) | 483 | "r9","r10","lr","memory" ) |
484 | 484 | ||
485 | #ifdef CONFIG_MMU | ||
485 | int set_memory_ro(unsigned long addr, int numpages); | 486 | int set_memory_ro(unsigned long addr, int numpages); |
486 | int set_memory_rw(unsigned long addr, int numpages); | 487 | int set_memory_rw(unsigned long addr, int numpages); |
487 | int set_memory_x(unsigned long addr, int numpages); | 488 | int set_memory_x(unsigned long addr, int numpages); |
488 | int set_memory_nx(unsigned long addr, int numpages); | 489 | int set_memory_nx(unsigned long addr, int numpages); |
490 | #else | ||
491 | static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; } | ||
492 | static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; } | ||
493 | static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } | ||
494 | static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } | ||
495 | #endif | ||
489 | 496 | ||
490 | #ifdef CONFIG_DEBUG_RODATA | 497 | #ifdef CONFIG_DEBUG_RODATA |
491 | void mark_rodata_ro(void); | 498 | void mark_rodata_ro(void); |
diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h index abb2c3769b01..1692a05d3207 100644 --- a/arch/arm/include/asm/cmpxchg.h +++ b/arch/arm/include/asm/cmpxchg.h | |||
@@ -94,6 +94,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size | |||
94 | break; | 94 | break; |
95 | #endif | 95 | #endif |
96 | default: | 96 | default: |
97 | /* Cause a link-time error, the xchg() size is not supported */ | ||
97 | __bad_xchg(ptr, size), ret = 0; | 98 | __bad_xchg(ptr, size), ret = 0; |
98 | break; | 99 | break; |
99 | } | 100 | } |
@@ -102,8 +103,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size | |||
102 | return ret; | 103 | return ret; |
103 | } | 104 | } |
104 | 105 | ||
105 | #define xchg(ptr,x) \ | 106 | #define xchg(ptr, x) ({ \ |
106 | ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | 107 | (__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \ |
108 | sizeof(*(ptr))); \ | ||
109 | }) | ||
107 | 110 | ||
108 | #include <asm-generic/cmpxchg-local.h> | 111 | #include <asm-generic/cmpxchg-local.h> |
109 | 112 | ||
@@ -118,14 +121,16 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size | |||
118 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | 121 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make |
119 | * them available. | 122 | * them available. |
120 | */ | 123 | */ |
121 | #define cmpxchg_local(ptr, o, n) \ | 124 | #define cmpxchg_local(ptr, o, n) ({ \ |
122 | ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ | 125 | (__typeof(*ptr))__cmpxchg_local_generic((ptr), \ |
123 | (unsigned long)(n), sizeof(*(ptr)))) | 126 | (unsigned long)(o), \ |
127 | (unsigned long)(n), \ | ||
128 | sizeof(*(ptr))); \ | ||
129 | }) | ||
130 | |||
124 | #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) | 131 | #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) |
125 | 132 | ||
126 | #ifndef CONFIG_SMP | ||
127 | #include <asm-generic/cmpxchg.h> | 133 | #include <asm-generic/cmpxchg.h> |
128 | #endif | ||
129 | 134 | ||
130 | #else /* min ARCH >= ARMv6 */ | 135 | #else /* min ARCH >= ARMv6 */ |
131 | 136 | ||
@@ -201,11 +206,12 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, | |||
201 | return ret; | 206 | return ret; |
202 | } | 207 | } |
203 | 208 | ||
204 | #define cmpxchg(ptr,o,n) \ | 209 | #define cmpxchg(ptr,o,n) ({ \ |
205 | ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ | 210 | (__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ |
206 | (unsigned long)(o), \ | 211 | (unsigned long)(o), \ |
207 | (unsigned long)(n), \ | 212 | (unsigned long)(n), \ |
208 | sizeof(*(ptr)))) | 213 | sizeof(*(ptr))); \ |
214 | }) | ||
209 | 215 | ||
210 | static inline unsigned long __cmpxchg_local(volatile void *ptr, | 216 | static inline unsigned long __cmpxchg_local(volatile void *ptr, |
211 | unsigned long old, | 217 | unsigned long old, |
@@ -227,6 +233,13 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr, | |||
227 | return ret; | 233 | return ret; |
228 | } | 234 | } |
229 | 235 | ||
236 | #define cmpxchg_local(ptr, o, n) ({ \ | ||
237 | (__typeof(*ptr))__cmpxchg_local((ptr), \ | ||
238 | (unsigned long)(o), \ | ||
239 | (unsigned long)(n), \ | ||
240 | sizeof(*(ptr))); \ | ||
241 | }) | ||
242 | |||
230 | static inline unsigned long long __cmpxchg64(unsigned long long *ptr, | 243 | static inline unsigned long long __cmpxchg64(unsigned long long *ptr, |
231 | unsigned long long old, | 244 | unsigned long long old, |
232 | unsigned long long new) | 245 | unsigned long long new) |
@@ -252,6 +265,14 @@ static inline unsigned long long __cmpxchg64(unsigned long long *ptr, | |||
252 | return oldval; | 265 | return oldval; |
253 | } | 266 | } |
254 | 267 | ||
268 | #define cmpxchg64_relaxed(ptr, o, n) ({ \ | ||
269 | (__typeof__(*(ptr)))__cmpxchg64((ptr), \ | ||
270 | (unsigned long long)(o), \ | ||
271 | (unsigned long long)(n)); \ | ||
272 | }) | ||
273 | |||
274 | #define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n)) | ||
275 | |||
255 | static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr, | 276 | static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr, |
256 | unsigned long long old, | 277 | unsigned long long old, |
257 | unsigned long long new) | 278 | unsigned long long new) |
@@ -265,23 +286,11 @@ static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr, | |||
265 | return ret; | 286 | return ret; |
266 | } | 287 | } |
267 | 288 | ||
268 | #define cmpxchg_local(ptr,o,n) \ | 289 | #define cmpxchg64(ptr, o, n) ({ \ |
269 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \ | 290 | (__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \ |
270 | (unsigned long)(o), \ | 291 | (unsigned long long)(o), \ |
271 | (unsigned long)(n), \ | 292 | (unsigned long long)(n)); \ |
272 | sizeof(*(ptr)))) | 293 | }) |
273 | |||
274 | #define cmpxchg64(ptr, o, n) \ | ||
275 | ((__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \ | ||
276 | (unsigned long long)(o), \ | ||
277 | (unsigned long long)(n))) | ||
278 | |||
279 | #define cmpxchg64_relaxed(ptr, o, n) \ | ||
280 | ((__typeof__(*(ptr)))__cmpxchg64((ptr), \ | ||
281 | (unsigned long long)(o), \ | ||
282 | (unsigned long long)(n))) | ||
283 | |||
284 | #define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n)) | ||
285 | 294 | ||
286 | #endif /* __LINUX_ARM_ARCH__ >= 6 */ | 295 | #endif /* __LINUX_ARM_ARCH__ >= 6 */ |
287 | 296 | ||
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S index 469a2b30fa27..609184f522ee 100644 --- a/arch/arm/include/asm/entry-macro-multi.S +++ b/arch/arm/include/asm/entry-macro-multi.S | |||
@@ -10,7 +10,7 @@ | |||
10 | @ | 10 | @ |
11 | @ routine called with r0 = irq number, r1 = struct pt_regs * | 11 | @ routine called with r0 = irq number, r1 = struct pt_regs * |
12 | @ | 12 | @ |
13 | adrne lr, BSYM(1b) | 13 | badrne lr, 1b |
14 | bne asm_do_IRQ | 14 | bne asm_do_IRQ |
15 | 15 | ||
16 | #ifdef CONFIG_SMP | 16 | #ifdef CONFIG_SMP |
@@ -23,7 +23,7 @@ | |||
23 | ALT_SMP(test_for_ipi r0, r2, r6, lr) | 23 | ALT_SMP(test_for_ipi r0, r2, r6, lr) |
24 | ALT_UP_B(9997f) | 24 | ALT_UP_B(9997f) |
25 | movne r1, sp | 25 | movne r1, sp |
26 | adrne lr, BSYM(1b) | 26 | badrne lr, 1b |
27 | bne do_IPI | 27 | bne do_IPI |
28 | #endif | 28 | #endif |
29 | 9997: | 29 | 9997: |
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 1b7677d1e5e1..1c3938f26beb 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #ifdef __KERNEL__ | 24 | #ifdef __KERNEL__ |
25 | 25 | ||
26 | #include <linux/string.h> | ||
26 | #include <linux/types.h> | 27 | #include <linux/types.h> |
27 | #include <linux/blk_types.h> | 28 | #include <linux/blk_types.h> |
28 | #include <asm/byteorder.h> | 29 | #include <asm/byteorder.h> |
@@ -73,17 +74,16 @@ void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen); | |||
73 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) | 74 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) |
74 | { | 75 | { |
75 | asm volatile("strh %1, %0" | 76 | asm volatile("strh %1, %0" |
76 | : "+Q" (*(volatile u16 __force *)addr) | 77 | : : "Q" (*(volatile u16 __force *)addr), "r" (val)); |
77 | : "r" (val)); | ||
78 | } | 78 | } |
79 | 79 | ||
80 | #define __raw_readw __raw_readw | 80 | #define __raw_readw __raw_readw |
81 | static inline u16 __raw_readw(const volatile void __iomem *addr) | 81 | static inline u16 __raw_readw(const volatile void __iomem *addr) |
82 | { | 82 | { |
83 | u16 val; | 83 | u16 val; |
84 | asm volatile("ldrh %1, %0" | 84 | asm volatile("ldrh %0, %1" |
85 | : "+Q" (*(volatile u16 __force *)addr), | 85 | : "=r" (val) |
86 | "=r" (val)); | 86 | : "Q" (*(volatile u16 __force *)addr)); |
87 | return val; | 87 | return val; |
88 | } | 88 | } |
89 | #endif | 89 | #endif |
@@ -92,25 +92,23 @@ static inline u16 __raw_readw(const volatile void __iomem *addr) | |||
92 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) | 92 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) |
93 | { | 93 | { |
94 | asm volatile("strb %1, %0" | 94 | asm volatile("strb %1, %0" |
95 | : "+Qo" (*(volatile u8 __force *)addr) | 95 | : : "Qo" (*(volatile u8 __force *)addr), "r" (val)); |
96 | : "r" (val)); | ||
97 | } | 96 | } |
98 | 97 | ||
99 | #define __raw_writel __raw_writel | 98 | #define __raw_writel __raw_writel |
100 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) | 99 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) |
101 | { | 100 | { |
102 | asm volatile("str %1, %0" | 101 | asm volatile("str %1, %0" |
103 | : "+Qo" (*(volatile u32 __force *)addr) | 102 | : : "Qo" (*(volatile u32 __force *)addr), "r" (val)); |
104 | : "r" (val)); | ||
105 | } | 103 | } |
106 | 104 | ||
107 | #define __raw_readb __raw_readb | 105 | #define __raw_readb __raw_readb |
108 | static inline u8 __raw_readb(const volatile void __iomem *addr) | 106 | static inline u8 __raw_readb(const volatile void __iomem *addr) |
109 | { | 107 | { |
110 | u8 val; | 108 | u8 val; |
111 | asm volatile("ldrb %1, %0" | 109 | asm volatile("ldrb %0, %1" |
112 | : "+Qo" (*(volatile u8 __force *)addr), | 110 | : "=r" (val) |
113 | "=r" (val)); | 111 | : "Qo" (*(volatile u8 __force *)addr)); |
114 | return val; | 112 | return val; |
115 | } | 113 | } |
116 | 114 | ||
@@ -118,9 +116,9 @@ static inline u8 __raw_readb(const volatile void __iomem *addr) | |||
118 | static inline u32 __raw_readl(const volatile void __iomem *addr) | 116 | static inline u32 __raw_readl(const volatile void __iomem *addr) |
119 | { | 117 | { |
120 | u32 val; | 118 | u32 val; |
121 | asm volatile("ldr %1, %0" | 119 | asm volatile("ldr %0, %1" |
122 | : "+Qo" (*(volatile u32 __force *)addr), | 120 | : "=r" (val) |
123 | "=r" (val)); | 121 | : "Qo" (*(volatile u32 __force *)addr)); |
124 | return val; | 122 | return val; |
125 | } | 123 | } |
126 | 124 | ||
@@ -319,9 +317,33 @@ extern void _memset_io(volatile void __iomem *, int, size_t); | |||
319 | #define writesw(p,d,l) __raw_writesw(p,d,l) | 317 | #define writesw(p,d,l) __raw_writesw(p,d,l) |
320 | #define writesl(p,d,l) __raw_writesl(p,d,l) | 318 | #define writesl(p,d,l) __raw_writesl(p,d,l) |
321 | 319 | ||
320 | #ifndef __ARMBE__ | ||
321 | static inline void memset_io(volatile void __iomem *dst, unsigned c, | ||
322 | size_t count) | ||
323 | { | ||
324 | memset((void __force *)dst, c, count); | ||
325 | } | ||
326 | #define memset_io(dst,c,count) memset_io(dst,c,count) | ||
327 | |||
328 | static inline void memcpy_fromio(void *to, const volatile void __iomem *from, | ||
329 | size_t count) | ||
330 | { | ||
331 | memcpy(to, (const void __force *)from, count); | ||
332 | } | ||
333 | #define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count) | ||
334 | |||
335 | static inline void memcpy_toio(volatile void __iomem *to, const void *from, | ||
336 | size_t count) | ||
337 | { | ||
338 | memcpy((void __force *)to, from, count); | ||
339 | } | ||
340 | #define memcpy_toio(to,from,count) memcpy_toio(to,from,count) | ||
341 | |||
342 | #else | ||
322 | #define memset_io(c,v,l) _memset_io(c,(v),(l)) | 343 | #define memset_io(c,v,l) _memset_io(c,(v),(l)) |
323 | #define memcpy_fromio(a,c,l) _memcpy_fromio((a),c,(l)) | 344 | #define memcpy_fromio(a,c,l) _memcpy_fromio((a),c,(l)) |
324 | #define memcpy_toio(c,a,l) _memcpy_toio(c,(a),(l)) | 345 | #define memcpy_toio(c,a,l) _memcpy_toio(c,(a),(l)) |
346 | #endif | ||
325 | 347 | ||
326 | #endif /* readl */ | 348 | #endif /* readl */ |
327 | 349 | ||
diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h index 3b763d6652a0..43908146a5cf 100644 --- a/arch/arm/include/asm/irqflags.h +++ b/arch/arm/include/asm/irqflags.h | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #if __LINUX_ARM_ARCH__ >= 6 | 21 | #if __LINUX_ARM_ARCH__ >= 6 |
22 | 22 | ||
23 | #define arch_local_irq_save arch_local_irq_save | ||
23 | static inline unsigned long arch_local_irq_save(void) | 24 | static inline unsigned long arch_local_irq_save(void) |
24 | { | 25 | { |
25 | unsigned long flags; | 26 | unsigned long flags; |
@@ -31,6 +32,7 @@ static inline unsigned long arch_local_irq_save(void) | |||
31 | return flags; | 32 | return flags; |
32 | } | 33 | } |
33 | 34 | ||
35 | #define arch_local_irq_enable arch_local_irq_enable | ||
34 | static inline void arch_local_irq_enable(void) | 36 | static inline void arch_local_irq_enable(void) |
35 | { | 37 | { |
36 | asm volatile( | 38 | asm volatile( |
@@ -40,6 +42,7 @@ static inline void arch_local_irq_enable(void) | |||
40 | : "memory", "cc"); | 42 | : "memory", "cc"); |
41 | } | 43 | } |
42 | 44 | ||
45 | #define arch_local_irq_disable arch_local_irq_disable | ||
43 | static inline void arch_local_irq_disable(void) | 46 | static inline void arch_local_irq_disable(void) |
44 | { | 47 | { |
45 | asm volatile( | 48 | asm volatile( |
@@ -56,6 +59,7 @@ static inline void arch_local_irq_disable(void) | |||
56 | /* | 59 | /* |
57 | * Save the current interrupt enable state & disable IRQs | 60 | * Save the current interrupt enable state & disable IRQs |
58 | */ | 61 | */ |
62 | #define arch_local_irq_save arch_local_irq_save | ||
59 | static inline unsigned long arch_local_irq_save(void) | 63 | static inline unsigned long arch_local_irq_save(void) |
60 | { | 64 | { |
61 | unsigned long flags, temp; | 65 | unsigned long flags, temp; |
@@ -73,6 +77,7 @@ static inline unsigned long arch_local_irq_save(void) | |||
73 | /* | 77 | /* |
74 | * Enable IRQs | 78 | * Enable IRQs |
75 | */ | 79 | */ |
80 | #define arch_local_irq_enable arch_local_irq_enable | ||
76 | static inline void arch_local_irq_enable(void) | 81 | static inline void arch_local_irq_enable(void) |
77 | { | 82 | { |
78 | unsigned long temp; | 83 | unsigned long temp; |
@@ -88,6 +93,7 @@ static inline void arch_local_irq_enable(void) | |||
88 | /* | 93 | /* |
89 | * Disable IRQs | 94 | * Disable IRQs |
90 | */ | 95 | */ |
96 | #define arch_local_irq_disable arch_local_irq_disable | ||
91 | static inline void arch_local_irq_disable(void) | 97 | static inline void arch_local_irq_disable(void) |
92 | { | 98 | { |
93 | unsigned long temp; | 99 | unsigned long temp; |
@@ -135,6 +141,7 @@ static inline void arch_local_irq_disable(void) | |||
135 | /* | 141 | /* |
136 | * Save the current interrupt enable state. | 142 | * Save the current interrupt enable state. |
137 | */ | 143 | */ |
144 | #define arch_local_save_flags arch_local_save_flags | ||
138 | static inline unsigned long arch_local_save_flags(void) | 145 | static inline unsigned long arch_local_save_flags(void) |
139 | { | 146 | { |
140 | unsigned long flags; | 147 | unsigned long flags; |
@@ -147,6 +154,7 @@ static inline unsigned long arch_local_save_flags(void) | |||
147 | /* | 154 | /* |
148 | * restore saved IRQ & FIQ state | 155 | * restore saved IRQ & FIQ state |
149 | */ | 156 | */ |
157 | #define arch_local_irq_restore arch_local_irq_restore | ||
150 | static inline void arch_local_irq_restore(unsigned long flags) | 158 | static inline void arch_local_irq_restore(unsigned long flags) |
151 | { | 159 | { |
152 | asm volatile( | 160 | asm volatile( |
@@ -156,10 +164,13 @@ static inline void arch_local_irq_restore(unsigned long flags) | |||
156 | : "memory", "cc"); | 164 | : "memory", "cc"); |
157 | } | 165 | } |
158 | 166 | ||
167 | #define arch_irqs_disabled_flags arch_irqs_disabled_flags | ||
159 | static inline int arch_irqs_disabled_flags(unsigned long flags) | 168 | static inline int arch_irqs_disabled_flags(unsigned long flags) |
160 | { | 169 | { |
161 | return flags & IRQMASK_I_BIT; | 170 | return flags & IRQMASK_I_BIT; |
162 | } | 171 | } |
163 | 172 | ||
173 | #include <asm-generic/irqflags.h> | ||
174 | |||
164 | #endif /* ifdef __KERNEL__ */ | 175 | #endif /* ifdef __KERNEL__ */ |
165 | #endif /* ifndef __ASM_ARM_IRQFLAGS_H */ | 176 | #endif /* ifndef __ASM_ARM_IRQFLAGS_H */ |
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 0406cb3f1af7..cb3a40717edd 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h | |||
@@ -51,7 +51,7 @@ struct machine_desc { | |||
51 | bool (*smp_init)(void); | 51 | bool (*smp_init)(void); |
52 | void (*fixup)(struct tag *, char **); | 52 | void (*fixup)(struct tag *, char **); |
53 | void (*dt_fixup)(void); | 53 | void (*dt_fixup)(void); |
54 | void (*init_meminfo)(void); | 54 | long long (*pv_fixup)(void); |
55 | void (*reserve)(void);/* reserve mem blocks */ | 55 | void (*reserve)(void);/* reserve mem blocks */ |
56 | void (*map_io)(void);/* IO mapping function */ | 56 | void (*map_io)(void);/* IO mapping function */ |
57 | void (*init_early)(void); | 57 | void (*init_early)(void); |
diff --git a/arch/arm/include/asm/mcpm.h b/arch/arm/include/asm/mcpm.h index 50b378f59e08..acd4983d9b1f 100644 --- a/arch/arm/include/asm/mcpm.h +++ b/arch/arm/include/asm/mcpm.h | |||
@@ -137,17 +137,12 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster); | |||
137 | /** | 137 | /** |
138 | * mcpm_cpu_suspend - bring the calling CPU in a suspended state | 138 | * mcpm_cpu_suspend - bring the calling CPU in a suspended state |
139 | * | 139 | * |
140 | * @expected_residency: duration in microseconds the CPU is expected | 140 | * The calling CPU is suspended. This is similar to mcpm_cpu_power_down() |
141 | * to remain suspended, or 0 if unknown/infinity. | 141 | * except for possible extra platform specific configuration steps to allow |
142 | * | 142 | * an asynchronous wake-up e.g. with a pending interrupt. |
143 | * The calling CPU is suspended. The expected residency argument is used | ||
144 | * as a hint by the platform specific backend to implement the appropriate | ||
145 | * sleep state level according to the knowledge it has on wake-up latency | ||
146 | * for the given hardware. | ||
147 | * | 143 | * |
148 | * If this CPU is found to be the "last man standing" in the cluster | 144 | * If this CPU is found to be the "last man standing" in the cluster |
149 | * then the cluster may be prepared for power-down too, if the expected | 145 | * then the cluster may be prepared for power-down too. |
150 | * residency makes it worthwhile. | ||
151 | * | 146 | * |
152 | * This must be called with interrupts disabled. | 147 | * This must be called with interrupts disabled. |
153 | * | 148 | * |
@@ -157,7 +152,7 @@ int mcpm_wait_for_cpu_powerdown(unsigned int cpu, unsigned int cluster); | |||
157 | * This will return if mcpm_platform_register() has not been called | 152 | * This will return if mcpm_platform_register() has not been called |
158 | * previously in which case the caller should take appropriate action. | 153 | * previously in which case the caller should take appropriate action. |
159 | */ | 154 | */ |
160 | void mcpm_cpu_suspend(u64 expected_residency); | 155 | void mcpm_cpu_suspend(void); |
161 | 156 | ||
162 | /** | 157 | /** |
163 | * mcpm_cpu_powered_up - housekeeping workafter a CPU has been powered up | 158 | * mcpm_cpu_powered_up - housekeeping workafter a CPU has been powered up |
@@ -234,12 +229,6 @@ struct mcpm_platform_ops { | |||
234 | void (*cpu_is_up)(unsigned int cpu, unsigned int cluster); | 229 | void (*cpu_is_up)(unsigned int cpu, unsigned int cluster); |
235 | void (*cluster_is_up)(unsigned int cluster); | 230 | void (*cluster_is_up)(unsigned int cluster); |
236 | int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster); | 231 | int (*wait_for_powerdown)(unsigned int cpu, unsigned int cluster); |
237 | |||
238 | /* deprecated callbacks */ | ||
239 | int (*power_up)(unsigned int cpu, unsigned int cluster); | ||
240 | void (*power_down)(void); | ||
241 | void (*suspend)(u64); | ||
242 | void (*powered_up)(void); | ||
243 | }; | 232 | }; |
244 | 233 | ||
245 | /** | 234 | /** |
@@ -251,35 +240,6 @@ struct mcpm_platform_ops { | |||
251 | */ | 240 | */ |
252 | int __init mcpm_platform_register(const struct mcpm_platform_ops *ops); | 241 | int __init mcpm_platform_register(const struct mcpm_platform_ops *ops); |
253 | 242 | ||
254 | /* Synchronisation structures for coordinating safe cluster setup/teardown: */ | ||
255 | |||
256 | /* | ||
257 | * When modifying this structure, make sure you update the MCPM_SYNC_ defines | ||
258 | * to match. | ||
259 | */ | ||
260 | struct mcpm_sync_struct { | ||
261 | /* individual CPU states */ | ||
262 | struct { | ||
263 | s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE); | ||
264 | } cpus[MAX_CPUS_PER_CLUSTER]; | ||
265 | |||
266 | /* cluster state */ | ||
267 | s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE); | ||
268 | |||
269 | /* inbound-side state */ | ||
270 | s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE); | ||
271 | }; | ||
272 | |||
273 | struct sync_struct { | ||
274 | struct mcpm_sync_struct clusters[MAX_NR_CLUSTERS]; | ||
275 | }; | ||
276 | |||
277 | void __mcpm_cpu_going_down(unsigned int cpu, unsigned int cluster); | ||
278 | void __mcpm_cpu_down(unsigned int cpu, unsigned int cluster); | ||
279 | void __mcpm_outbound_leave_critical(unsigned int cluster, int state); | ||
280 | bool __mcpm_outbound_enter_critical(unsigned int this_cpu, unsigned int cluster); | ||
281 | int __mcpm_cluster_state(unsigned int cluster); | ||
282 | |||
283 | /** | 243 | /** |
284 | * mcpm_sync_init - Initialize the cluster synchronization support | 244 | * mcpm_sync_init - Initialize the cluster synchronization support |
285 | * | 245 | * |
@@ -318,6 +278,29 @@ int __init mcpm_loopback(void (*cache_disable)(void)); | |||
318 | 278 | ||
319 | void __init mcpm_smp_set_ops(void); | 279 | void __init mcpm_smp_set_ops(void); |
320 | 280 | ||
281 | /* | ||
282 | * Synchronisation structures for coordinating safe cluster setup/teardown. | ||
283 | * This is private to the MCPM core code and shared between C and assembly. | ||
284 | * When modifying this structure, make sure you update the MCPM_SYNC_ defines | ||
285 | * to match. | ||
286 | */ | ||
287 | struct mcpm_sync_struct { | ||
288 | /* individual CPU states */ | ||
289 | struct { | ||
290 | s8 cpu __aligned(__CACHE_WRITEBACK_GRANULE); | ||
291 | } cpus[MAX_CPUS_PER_CLUSTER]; | ||
292 | |||
293 | /* cluster state */ | ||
294 | s8 cluster __aligned(__CACHE_WRITEBACK_GRANULE); | ||
295 | |||
296 | /* inbound-side state */ | ||
297 | s8 inbound __aligned(__CACHE_WRITEBACK_GRANULE); | ||
298 | }; | ||
299 | |||
300 | struct sync_struct { | ||
301 | struct mcpm_sync_struct clusters[MAX_NR_CLUSTERS]; | ||
302 | }; | ||
303 | |||
321 | #else | 304 | #else |
322 | 305 | ||
323 | /* | 306 | /* |
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 184def0e1652..3a72d69b3255 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h | |||
@@ -18,8 +18,6 @@ | |||
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/sizes.h> | 19 | #include <linux/sizes.h> |
20 | 20 | ||
21 | #include <asm/cache.h> | ||
22 | |||
23 | #ifdef CONFIG_NEED_MACH_MEMORY_H | 21 | #ifdef CONFIG_NEED_MACH_MEMORY_H |
24 | #include <mach/memory.h> | 22 | #include <mach/memory.h> |
25 | #endif | 23 | #endif |
@@ -133,20 +131,6 @@ | |||
133 | #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) | 131 | #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) |
134 | 132 | ||
135 | /* | 133 | /* |
136 | * Minimum guaranted alignment in pgd_alloc(). The page table pointers passed | ||
137 | * around in head.S and proc-*.S are shifted by this amount, in order to | ||
138 | * leave spare high bits for systems with physical address extension. This | ||
139 | * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but | ||
140 | * gives us about 38-bits or so. | ||
141 | */ | ||
142 | #ifdef CONFIG_ARM_LPAE | ||
143 | #define ARCH_PGD_SHIFT L1_CACHE_SHIFT | ||
144 | #else | ||
145 | #define ARCH_PGD_SHIFT 0 | ||
146 | #endif | ||
147 | #define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1) | ||
148 | |||
149 | /* | ||
150 | * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical | 134 | * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical |
151 | * memory. This is used for XIP and NoMMU kernels, and on platforms that don't | 135 | * memory. This is used for XIP and NoMMU kernels, and on platforms that don't |
152 | * have CONFIG_ARM_PATCH_PHYS_VIRT. Assembly code must always use | 136 | * have CONFIG_ARM_PATCH_PHYS_VIRT. Assembly code must always use |
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index ed690c49ef93..e358b7966c06 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h | |||
@@ -16,11 +16,21 @@ enum { | |||
16 | ARM_SEC_UNLIKELY, | 16 | ARM_SEC_UNLIKELY, |
17 | ARM_SEC_MAX, | 17 | ARM_SEC_MAX, |
18 | }; | 18 | }; |
19 | #endif | ||
19 | 20 | ||
20 | struct mod_arch_specific { | 21 | struct mod_arch_specific { |
22 | #ifdef CONFIG_ARM_UNWIND | ||
21 | struct unwind_table *unwind[ARM_SEC_MAX]; | 23 | struct unwind_table *unwind[ARM_SEC_MAX]; |
22 | }; | ||
23 | #endif | 24 | #endif |
25 | #ifdef CONFIG_ARM_MODULE_PLTS | ||
26 | struct elf32_shdr *core_plt; | ||
27 | struct elf32_shdr *init_plt; | ||
28 | int core_plt_count; | ||
29 | int init_plt_count; | ||
30 | #endif | ||
31 | }; | ||
32 | |||
33 | u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val); | ||
24 | 34 | ||
25 | /* | 35 | /* |
26 | * Add the ARM architecture version to the version magic string | 36 | * Add the ARM architecture version to the version magic string |
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index d9cf138fd7d4..4f9dec489931 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h | |||
@@ -19,4 +19,11 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); | |||
19 | #define perf_misc_flags(regs) perf_misc_flags(regs) | 19 | #define perf_misc_flags(regs) perf_misc_flags(regs) |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #define perf_arch_fetch_caller_regs(regs, __ip) { \ | ||
23 | (regs)->ARM_pc = (__ip); \ | ||
24 | (regs)->ARM_fp = (unsigned long) __builtin_frame_address(0); \ | ||
25 | (regs)->ARM_sp = current_stack_pointer; \ | ||
26 | (regs)->ARM_cpsr = SVC_MODE; \ | ||
27 | } | ||
28 | |||
22 | #endif /* __ARM_PERF_EVENT_H__ */ | 29 | #endif /* __ARM_PERF_EVENT_H__ */ |
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 675e4ab79f68..3fc87dfd77e6 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h | |||
@@ -24,22 +24,10 @@ | |||
24 | * interrupt and passed the address of the low level handler, | 24 | * interrupt and passed the address of the low level handler, |
25 | * and can be used to implement any platform specific handling | 25 | * and can be used to implement any platform specific handling |
26 | * before or after calling it. | 26 | * before or after calling it. |
27 | * @runtime_resume: an optional handler which will be called by the | ||
28 | * runtime PM framework following a call to pm_runtime_get(). | ||
29 | * Note that if pm_runtime_get() is called more than once in | ||
30 | * succession this handler will only be called once. | ||
31 | * @runtime_suspend: an optional handler which will be called by the | ||
32 | * runtime PM framework following a call to pm_runtime_put(). | ||
33 | * Note that if pm_runtime_get() is called more than once in | ||
34 | * succession this handler will only be called following the | ||
35 | * final call to pm_runtime_put() that actually disables the | ||
36 | * hardware. | ||
37 | */ | 27 | */ |
38 | struct arm_pmu_platdata { | 28 | struct arm_pmu_platdata { |
39 | irqreturn_t (*handle_irq)(int irq, void *dev, | 29 | irqreturn_t (*handle_irq)(int irq, void *dev, |
40 | irq_handler_t pmu_handler); | 30 | irq_handler_t pmu_handler); |
41 | int (*runtime_resume)(struct device *dev); | ||
42 | int (*runtime_suspend)(struct device *dev); | ||
43 | }; | 31 | }; |
44 | 32 | ||
45 | #ifdef CONFIG_HW_PERF_EVENTS | 33 | #ifdef CONFIG_HW_PERF_EVENTS |
@@ -92,6 +80,7 @@ struct pmu_hw_events { | |||
92 | struct arm_pmu { | 80 | struct arm_pmu { |
93 | struct pmu pmu; | 81 | struct pmu pmu; |
94 | cpumask_t active_irqs; | 82 | cpumask_t active_irqs; |
83 | cpumask_t supported_cpus; | ||
95 | int *irq_affinity; | 84 | int *irq_affinity; |
96 | char *name; | 85 | char *name; |
97 | irqreturn_t (*handle_irq)(int irq_num, void *dev); | 86 | irqreturn_t (*handle_irq)(int irq_num, void *dev); |
@@ -122,8 +111,6 @@ struct arm_pmu { | |||
122 | 111 | ||
123 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | 112 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) |
124 | 113 | ||
125 | extern const struct dev_pm_ops armpmu_dev_pm_ops; | ||
126 | |||
127 | int armpmu_register(struct arm_pmu *armpmu, int type); | 114 | int armpmu_register(struct arm_pmu *armpmu, int type); |
128 | 115 | ||
129 | u64 armpmu_event_update(struct perf_event *event); | 116 | u64 armpmu_event_update(struct perf_event *event); |
@@ -158,6 +145,10 @@ struct pmu_probe_info { | |||
158 | #define XSCALE_PMU_PROBE(_version, _fn) \ | 145 | #define XSCALE_PMU_PROBE(_version, _fn) \ |
159 | PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn) | 146 | PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn) |
160 | 147 | ||
148 | int arm_pmu_device_probe(struct platform_device *pdev, | ||
149 | const struct of_device_id *of_table, | ||
150 | const struct pmu_probe_info *probe_table); | ||
151 | |||
161 | #endif /* CONFIG_HW_PERF_EVENTS */ | 152 | #endif /* CONFIG_HW_PERF_EVENTS */ |
162 | 153 | ||
163 | #endif /* __ARM_PMU_H__ */ | 154 | #endif /* __ARM_PMU_H__ */ |
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index 5324c1112f3a..8877ad5ffe10 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h | |||
@@ -125,13 +125,6 @@ extern void cpu_resume(void); | |||
125 | ttbr; \ | 125 | ttbr; \ |
126 | }) | 126 | }) |
127 | 127 | ||
128 | #define cpu_set_ttbr(nr, val) \ | ||
129 | do { \ | ||
130 | u64 ttbr = val; \ | ||
131 | __asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \ | ||
132 | : : "r" (ttbr)); \ | ||
133 | } while (0) | ||
134 | |||
135 | #define cpu_get_pgd() \ | 128 | #define cpu_get_pgd() \ |
136 | ({ \ | 129 | ({ \ |
137 | u64 pg = cpu_get_ttbr(0); \ | 130 | u64 pg = cpu_get_ttbr(0); \ |
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 18f5a554134f..2f3ac1ba6fb4 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h | |||
@@ -61,7 +61,7 @@ asmlinkage void secondary_start_kernel(void); | |||
61 | struct secondary_data { | 61 | struct secondary_data { |
62 | union { | 62 | union { |
63 | unsigned long mpu_rgn_szr; | 63 | unsigned long mpu_rgn_szr; |
64 | unsigned long pgdir; | 64 | u64 pgdir; |
65 | }; | 65 | }; |
66 | unsigned long swapper_pg_dir; | 66 | unsigned long swapper_pg_dir; |
67 | void *stack; | 67 | void *stack; |
@@ -69,6 +69,7 @@ struct secondary_data { | |||
69 | extern struct secondary_data secondary_data; | 69 | extern struct secondary_data secondary_data; |
70 | extern volatile int pen_release; | 70 | extern volatile int pen_release; |
71 | extern void secondary_startup(void); | 71 | extern void secondary_startup(void); |
72 | extern void secondary_startup_arm(void); | ||
72 | 73 | ||
73 | extern int __cpu_disable(void); | 74 | extern int __cpu_disable(void); |
74 | 75 | ||
diff --git a/arch/arm/include/asm/system_info.h b/arch/arm/include/asm/system_info.h index 720ea0320a6d..3860cbd401ec 100644 --- a/arch/arm/include/asm/system_info.h +++ b/arch/arm/include/asm/system_info.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | /* information about the system we're running on */ | 18 | /* information about the system we're running on */ |
19 | extern unsigned int system_rev; | 19 | extern unsigned int system_rev; |
20 | extern const char *system_serial; | ||
20 | extern unsigned int system_serial_low; | 21 | extern unsigned int system_serial_low; |
21 | extern unsigned int system_serial_high; | 22 | extern unsigned int system_serial_high; |
22 | extern unsigned int mem_fclk_21285; | 23 | extern unsigned int mem_fclk_21285; |
diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h index 200f9a7cd623..a91ae499614c 100644 --- a/arch/arm/include/asm/unified.h +++ b/arch/arm/include/asm/unified.h | |||
@@ -45,7 +45,6 @@ | |||
45 | #define THUMB(x...) x | 45 | #define THUMB(x...) x |
46 | #ifdef __ASSEMBLY__ | 46 | #ifdef __ASSEMBLY__ |
47 | #define W(instr) instr.w | 47 | #define W(instr) instr.w |
48 | #define BSYM(sym) sym + 1 | ||
49 | #else | 48 | #else |
50 | #define WASM(instr) #instr ".w" | 49 | #define WASM(instr) #instr ".w" |
51 | #endif | 50 | #endif |
@@ -59,7 +58,6 @@ | |||
59 | #define THUMB(x...) | 58 | #define THUMB(x...) |
60 | #ifdef __ASSEMBLY__ | 59 | #ifdef __ASSEMBLY__ |
61 | #define W(instr) instr | 60 | #define W(instr) instr |
62 | #define BSYM(sym) sym | ||
63 | #else | 61 | #else |
64 | #define WASM(instr) #instr | 62 | #define WASM(instr) #instr |
65 | #endif | 63 | #endif |
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 752725dcbf42..e69f7a19735d 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o | |||
34 | obj-$(CONFIG_ISA_DMA_API) += dma.o | 34 | obj-$(CONFIG_ISA_DMA_API) += dma.o |
35 | obj-$(CONFIG_FIQ) += fiq.o fiqasm.o | 35 | obj-$(CONFIG_FIQ) += fiq.o fiqasm.o |
36 | obj-$(CONFIG_MODULES) += armksyms.o module.o | 36 | obj-$(CONFIG_MODULES) += armksyms.o module.o |
37 | obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o | ||
37 | obj-$(CONFIG_ISA_DMA) += dma-isa.o | 38 | obj-$(CONFIG_ISA_DMA) += dma-isa.o |
38 | obj-$(CONFIG_PCI) += bios32.o isa.o | 39 | obj-$(CONFIG_PCI) += bios32.o isa.o |
39 | obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o | 40 | obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o |
@@ -70,7 +71,9 @@ obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o | |||
70 | obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o | 71 | obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o |
71 | obj-$(CONFIG_IWMMXT) += iwmmxt.o | 72 | obj-$(CONFIG_IWMMXT) += iwmmxt.o |
72 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o | 73 | obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o |
73 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o | 74 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o \ |
75 | perf_event_xscale.o perf_event_v6.o \ | ||
76 | perf_event_v7.o | ||
74 | CFLAGS_pj4-cp0.o := -marm | 77 | CFLAGS_pj4-cp0.o := -marm |
75 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 78 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
76 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o | 79 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 570306c49406..f8f7398c74c2 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -40,7 +40,7 @@ | |||
40 | #ifdef CONFIG_MULTI_IRQ_HANDLER | 40 | #ifdef CONFIG_MULTI_IRQ_HANDLER |
41 | ldr r1, =handle_arch_irq | 41 | ldr r1, =handle_arch_irq |
42 | mov r0, sp | 42 | mov r0, sp |
43 | adr lr, BSYM(9997f) | 43 | badr lr, 9997f |
44 | ldr pc, [r1] | 44 | ldr pc, [r1] |
45 | #else | 45 | #else |
46 | arch_irq_handler_default | 46 | arch_irq_handler_default |
@@ -273,7 +273,7 @@ __und_svc: | |||
273 | str r4, [sp, #S_PC] | 273 | str r4, [sp, #S_PC] |
274 | orr r0, r9, r0, lsl #16 | 274 | orr r0, r9, r0, lsl #16 |
275 | #endif | 275 | #endif |
276 | adr r9, BSYM(__und_svc_finish) | 276 | badr r9, __und_svc_finish |
277 | mov r2, r4 | 277 | mov r2, r4 |
278 | bl call_fpe | 278 | bl call_fpe |
279 | 279 | ||
@@ -469,7 +469,7 @@ __und_usr: | |||
469 | @ instruction, or the more conventional lr if we are to treat | 469 | @ instruction, or the more conventional lr if we are to treat |
470 | @ this as a real undefined instruction | 470 | @ this as a real undefined instruction |
471 | @ | 471 | @ |
472 | adr r9, BSYM(ret_from_exception) | 472 | badr r9, ret_from_exception |
473 | 473 | ||
474 | @ IRQs must be enabled before attempting to read the instruction from | 474 | @ IRQs must be enabled before attempting to read the instruction from |
475 | @ user space since that could cause a page/translation fault if the | 475 | @ user space since that could cause a page/translation fault if the |
@@ -486,7 +486,7 @@ __und_usr: | |||
486 | @ r2 = PC value for the following instruction (:= regs->ARM_pc) | 486 | @ r2 = PC value for the following instruction (:= regs->ARM_pc) |
487 | @ r4 = PC value for the faulting instruction | 487 | @ r4 = PC value for the faulting instruction |
488 | @ lr = 32-bit undefined instruction function | 488 | @ lr = 32-bit undefined instruction function |
489 | adr lr, BSYM(__und_usr_fault_32) | 489 | badr lr, __und_usr_fault_32 |
490 | b call_fpe | 490 | b call_fpe |
491 | 491 | ||
492 | __und_usr_thumb: | 492 | __und_usr_thumb: |
@@ -522,7 +522,7 @@ ARM_BE8(rev16 r0, r0) @ little endian instruction | |||
522 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 | 522 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 |
523 | str r2, [sp, #S_PC] @ it's a 2x16bit instr, update | 523 | str r2, [sp, #S_PC] @ it's a 2x16bit instr, update |
524 | orr r0, r0, r5, lsl #16 | 524 | orr r0, r0, r5, lsl #16 |
525 | adr lr, BSYM(__und_usr_fault_32) | 525 | badr lr, __und_usr_fault_32 |
526 | @ r0 = the two 16-bit Thumb instructions which caused the exception | 526 | @ r0 = the two 16-bit Thumb instructions which caused the exception |
527 | @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc) | 527 | @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc) |
528 | @ r4 = PC value for the first 16-bit Thumb instruction | 528 | @ r4 = PC value for the first 16-bit Thumb instruction |
@@ -716,7 +716,7 @@ __und_usr_fault_32: | |||
716 | __und_usr_fault_16: | 716 | __und_usr_fault_16: |
717 | mov r1, #2 | 717 | mov r1, #2 |
718 | 1: mov r0, sp | 718 | 1: mov r0, sp |
719 | adr lr, BSYM(ret_from_exception) | 719 | badr lr, ret_from_exception |
720 | b __und_fault | 720 | b __und_fault |
721 | ENDPROC(__und_usr_fault_32) | 721 | ENDPROC(__und_usr_fault_32) |
722 | ENDPROC(__und_usr_fault_16) | 722 | ENDPROC(__und_usr_fault_16) |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 4e7f40c577e6..92828a1dec80 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -90,7 +90,7 @@ ENTRY(ret_from_fork) | |||
90 | bl schedule_tail | 90 | bl schedule_tail |
91 | cmp r5, #0 | 91 | cmp r5, #0 |
92 | movne r0, r4 | 92 | movne r0, r4 |
93 | adrne lr, BSYM(1f) | 93 | badrne lr, 1f |
94 | retne r5 | 94 | retne r5 |
95 | 1: get_thread_info tsk | 95 | 1: get_thread_info tsk |
96 | b ret_slow_syscall | 96 | b ret_slow_syscall |
@@ -198,7 +198,7 @@ local_restart: | |||
198 | bne __sys_trace | 198 | bne __sys_trace |
199 | 199 | ||
200 | cmp scno, #NR_syscalls @ check upper syscall limit | 200 | cmp scno, #NR_syscalls @ check upper syscall limit |
201 | adr lr, BSYM(ret_fast_syscall) @ return address | 201 | badr lr, ret_fast_syscall @ return address |
202 | ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine | 202 | ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine |
203 | 203 | ||
204 | add r1, sp, #S_OFF | 204 | add r1, sp, #S_OFF |
@@ -233,7 +233,7 @@ __sys_trace: | |||
233 | add r0, sp, #S_OFF | 233 | add r0, sp, #S_OFF |
234 | bl syscall_trace_enter | 234 | bl syscall_trace_enter |
235 | 235 | ||
236 | adr lr, BSYM(__sys_trace_return) @ return address | 236 | badr lr, __sys_trace_return @ return address |
237 | mov scno, r0 @ syscall number (possibly new) | 237 | mov scno, r0 @ syscall number (possibly new) |
238 | add r1, sp, #S_R0 + S_OFF @ pointer to regs | 238 | add r1, sp, #S_R0 + S_OFF @ pointer to regs |
239 | cmp scno, #NR_syscalls @ check upper syscall limit | 239 | cmp scno, #NR_syscalls @ check upper syscall limit |
diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index fe57c73e70a4..c73c4030ca5d 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S | |||
@@ -87,7 +87,7 @@ | |||
87 | 87 | ||
88 | 1: mcount_get_lr r1 @ lr of instrumented func | 88 | 1: mcount_get_lr r1 @ lr of instrumented func |
89 | mcount_adjust_addr r0, lr @ instrumented function | 89 | mcount_adjust_addr r0, lr @ instrumented function |
90 | adr lr, BSYM(2f) | 90 | badr lr, 2f |
91 | mov pc, r2 | 91 | mov pc, r2 |
92 | 2: mcount_exit | 92 | 2: mcount_exit |
93 | .endm | 93 | .endm |
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S index 8944f4991c3c..b6c8bb9315e7 100644 --- a/arch/arm/kernel/entry-v7m.S +++ b/arch/arm/kernel/entry-v7m.S | |||
@@ -117,9 +117,14 @@ ENTRY(__switch_to) | |||
117 | ENDPROC(__switch_to) | 117 | ENDPROC(__switch_to) |
118 | 118 | ||
119 | .data | 119 | .data |
120 | .align 8 | 120 | #if CONFIG_CPU_V7M_NUM_IRQ <= 112 |
121 | .align 9 | ||
122 | #else | ||
123 | .align 10 | ||
124 | #endif | ||
125 | |||
121 | /* | 126 | /* |
122 | * Vector table (64 words => 256 bytes natural alignment) | 127 | * Vector table (Natural alignment need to be ensured) |
123 | */ | 128 | */ |
124 | ENTRY(vector_table) | 129 | ENTRY(vector_table) |
125 | .long 0 @ 0 - Reset stack pointer | 130 | .long 0 @ 0 - Reset stack pointer |
@@ -138,6 +143,6 @@ ENTRY(vector_table) | |||
138 | .long __invalid_entry @ 13 - Reserved | 143 | .long __invalid_entry @ 13 - Reserved |
139 | .long __pendsv_entry @ 14 - PendSV | 144 | .long __pendsv_entry @ 14 - PendSV |
140 | .long __invalid_entry @ 15 - SysTick | 145 | .long __invalid_entry @ 15 - SysTick |
141 | .rept 64 - 16 | 146 | .rept CONFIG_CPU_V7M_NUM_IRQ |
142 | .long __irq_entry @ 16..64 - External Interrupts | 147 | .long __irq_entry @ External Interrupts |
143 | .endr | 148 | .endr |
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index aebfbf79a1a3..9b8c5a113434 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -46,7 +46,7 @@ ENTRY(stext) | |||
46 | .arm | 46 | .arm |
47 | ENTRY(stext) | 47 | ENTRY(stext) |
48 | 48 | ||
49 | THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. | 49 | THUMB( badr r9, 1f ) @ Kernel is always entered in ARM. |
50 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, | 50 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, |
51 | THUMB( .thumb ) @ switch to Thumb now. | 51 | THUMB( .thumb ) @ switch to Thumb now. |
52 | THUMB(1: ) | 52 | THUMB(1: ) |
@@ -77,13 +77,13 @@ ENTRY(stext) | |||
77 | orr r6, r6, #(1 << MPU_RSR_EN) @ Set region enabled bit | 77 | orr r6, r6, #(1 << MPU_RSR_EN) @ Set region enabled bit |
78 | bl __setup_mpu | 78 | bl __setup_mpu |
79 | #endif | 79 | #endif |
80 | ldr r13, =__mmap_switched @ address to jump to after | 80 | |
81 | @ initialising sctlr | 81 | badr lr, 1f @ return (PIC) address |
82 | adr lr, BSYM(1f) @ return (PIC) address | ||
83 | ldr r12, [r10, #PROCINFO_INITFUNC] | 82 | ldr r12, [r10, #PROCINFO_INITFUNC] |
84 | add r12, r12, r10 | 83 | add r12, r12, r10 |
85 | ret r12 | 84 | ret r12 |
86 | 1: b __after_proc_init | 85 | 1: bl __after_proc_init |
86 | b __mmap_switched | ||
87 | ENDPROC(stext) | 87 | ENDPROC(stext) |
88 | 88 | ||
89 | #ifdef CONFIG_SMP | 89 | #ifdef CONFIG_SMP |
@@ -106,8 +106,7 @@ ENTRY(secondary_startup) | |||
106 | movs r10, r5 @ invalid processor? | 106 | movs r10, r5 @ invalid processor? |
107 | beq __error_p @ yes, error 'p' | 107 | beq __error_p @ yes, error 'p' |
108 | 108 | ||
109 | adr r4, __secondary_data | 109 | ldr r7, __secondary_data |
110 | ldmia r4, {r7, r12} | ||
111 | 110 | ||
112 | #ifdef CONFIG_ARM_MPU | 111 | #ifdef CONFIG_ARM_MPU |
113 | /* Use MPU region info supplied by __cpu_up */ | 112 | /* Use MPU region info supplied by __cpu_up */ |
@@ -115,23 +114,19 @@ ENTRY(secondary_startup) | |||
115 | bl __setup_mpu @ Initialize the MPU | 114 | bl __setup_mpu @ Initialize the MPU |
116 | #endif | 115 | #endif |
117 | 116 | ||
118 | adr lr, BSYM(__after_proc_init) @ return address | 117 | badr lr, 1f @ return (PIC) address |
119 | mov r13, r12 @ __secondary_switched address | ||
120 | ldr r12, [r10, #PROCINFO_INITFUNC] | 118 | ldr r12, [r10, #PROCINFO_INITFUNC] |
121 | add r12, r12, r10 | 119 | add r12, r12, r10 |
122 | ret r12 | 120 | ret r12 |
123 | ENDPROC(secondary_startup) | 121 | 1: bl __after_proc_init |
124 | 122 | ldr sp, [r7, #12] @ set up the stack pointer | |
125 | ENTRY(__secondary_switched) | ||
126 | ldr sp, [r7, #8] @ set up the stack pointer | ||
127 | mov fp, #0 | 123 | mov fp, #0 |
128 | b secondary_start_kernel | 124 | b secondary_start_kernel |
129 | ENDPROC(__secondary_switched) | 125 | ENDPROC(secondary_startup) |
130 | 126 | ||
131 | .type __secondary_data, %object | 127 | .type __secondary_data, %object |
132 | __secondary_data: | 128 | __secondary_data: |
133 | .long secondary_data | 129 | .long secondary_data |
134 | .long __secondary_switched | ||
135 | #endif /* CONFIG_SMP */ | 130 | #endif /* CONFIG_SMP */ |
136 | 131 | ||
137 | /* | 132 | /* |
@@ -164,7 +159,7 @@ __after_proc_init: | |||
164 | #endif | 159 | #endif |
165 | mcr p15, 0, r0, c1, c0, 0 @ write control reg | 160 | mcr p15, 0, r0, c1, c0, 0 @ write control reg |
166 | #endif /* CONFIG_CPU_CP15 */ | 161 | #endif /* CONFIG_CPU_CP15 */ |
167 | ret r13 | 162 | ret lr |
168 | ENDPROC(__after_proc_init) | 163 | ENDPROC(__after_proc_init) |
169 | .ltorg | 164 | .ltorg |
170 | 165 | ||
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 3637973a9708..bd755d97e459 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -80,7 +80,7 @@ | |||
80 | ENTRY(stext) | 80 | ENTRY(stext) |
81 | ARM_BE8(setend be ) @ ensure we are in BE8 mode | 81 | ARM_BE8(setend be ) @ ensure we are in BE8 mode |
82 | 82 | ||
83 | THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. | 83 | THUMB( badr r9, 1f ) @ Kernel is always entered in ARM. |
84 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, | 84 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, |
85 | THUMB( .thumb ) @ switch to Thumb now. | 85 | THUMB( .thumb ) @ switch to Thumb now. |
86 | THUMB(1: ) | 86 | THUMB(1: ) |
@@ -131,13 +131,30 @@ ENTRY(stext) | |||
131 | * The following calls CPU specific code in a position independent | 131 | * The following calls CPU specific code in a position independent |
132 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of | 132 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of |
133 | * xxx_proc_info structure selected by __lookup_processor_type | 133 | * xxx_proc_info structure selected by __lookup_processor_type |
134 | * above. On return, the CPU will be ready for the MMU to be | 134 | * above. |
135 | * turned on, and r0 will hold the CPU control register value. | 135 | * |
136 | * The processor init function will be called with: | ||
137 | * r1 - machine type | ||
138 | * r2 - boot data (atags/dt) pointer | ||
139 | * r4 - translation table base (low word) | ||
140 | * r5 - translation table base (high word, if LPAE) | ||
141 | * r8 - translation table base 1 (pfn if LPAE) | ||
142 | * r9 - cpuid | ||
143 | * r13 - virtual address for __enable_mmu -> __turn_mmu_on | ||
144 | * | ||
145 | * On return, the CPU will be ready for the MMU to be turned on, | ||
146 | * r0 will hold the CPU control register value, r1, r2, r4, and | ||
147 | * r9 will be preserved. r5 will also be preserved if LPAE. | ||
136 | */ | 148 | */ |
137 | ldr r13, =__mmap_switched @ address to jump to after | 149 | ldr r13, =__mmap_switched @ address to jump to after |
138 | @ mmu has been enabled | 150 | @ mmu has been enabled |
139 | adr lr, BSYM(1f) @ return (PIC) address | 151 | badr lr, 1f @ return (PIC) address |
152 | #ifdef CONFIG_ARM_LPAE | ||
153 | mov r5, #0 @ high TTBR0 | ||
154 | mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn | ||
155 | #else | ||
140 | mov r8, r4 @ set TTBR1 to swapper_pg_dir | 156 | mov r8, r4 @ set TTBR1 to swapper_pg_dir |
157 | #endif | ||
141 | ldr r12, [r10, #PROCINFO_INITFUNC] | 158 | ldr r12, [r10, #PROCINFO_INITFUNC] |
142 | add r12, r12, r10 | 159 | add r12, r12, r10 |
143 | ret r12 | 160 | ret r12 |
@@ -158,7 +175,7 @@ ENDPROC(stext) | |||
158 | * | 175 | * |
159 | * Returns: | 176 | * Returns: |
160 | * r0, r3, r5-r7 corrupted | 177 | * r0, r3, r5-r7 corrupted |
161 | * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) | 178 | * r4 = physical page table address |
162 | */ | 179 | */ |
163 | __create_page_tables: | 180 | __create_page_tables: |
164 | pgtbl r4, r8 @ page table address | 181 | pgtbl r4, r8 @ page table address |
@@ -333,7 +350,6 @@ __create_page_tables: | |||
333 | #endif | 350 | #endif |
334 | #ifdef CONFIG_ARM_LPAE | 351 | #ifdef CONFIG_ARM_LPAE |
335 | sub r4, r4, #0x1000 @ point to the PGD table | 352 | sub r4, r4, #0x1000 @ point to the PGD table |
336 | mov r4, r4, lsr #ARCH_PGD_SHIFT | ||
337 | #endif | 353 | #endif |
338 | ret lr | 354 | ret lr |
339 | ENDPROC(__create_page_tables) | 355 | ENDPROC(__create_page_tables) |
@@ -346,9 +362,9 @@ __turn_mmu_on_loc: | |||
346 | 362 | ||
347 | #if defined(CONFIG_SMP) | 363 | #if defined(CONFIG_SMP) |
348 | .text | 364 | .text |
349 | ENTRY(secondary_startup_arm) | ||
350 | .arm | 365 | .arm |
351 | THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM. | 366 | ENTRY(secondary_startup_arm) |
367 | THUMB( badr r9, 1f ) @ Kernel is entered in ARM. | ||
352 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, | 368 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, |
353 | THUMB( .thumb ) @ switch to Thumb now. | 369 | THUMB( .thumb ) @ switch to Thumb now. |
354 | THUMB(1: ) | 370 | THUMB(1: ) |
@@ -381,10 +397,10 @@ ENTRY(secondary_startup) | |||
381 | adr r4, __secondary_data | 397 | adr r4, __secondary_data |
382 | ldmia r4, {r5, r7, r12} @ address to jump to after | 398 | ldmia r4, {r5, r7, r12} @ address to jump to after |
383 | sub lr, r4, r5 @ mmu has been enabled | 399 | sub lr, r4, r5 @ mmu has been enabled |
384 | ldr r4, [r7, lr] @ get secondary_data.pgdir | 400 | add r3, r7, lr |
385 | add r7, r7, #4 | 401 | ldrd r4, [r3, #0] @ get secondary_data.pgdir |
386 | ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir | 402 | ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir |
387 | adr lr, BSYM(__enable_mmu) @ return address | 403 | badr lr, __enable_mmu @ return address |
388 | mov r13, r12 @ __secondary_switched address | 404 | mov r13, r12 @ __secondary_switched address |
389 | ldr r12, [r10, #PROCINFO_INITFUNC] | 405 | ldr r12, [r10, #PROCINFO_INITFUNC] |
390 | add r12, r12, r10 @ initialise processor | 406 | add r12, r12, r10 @ initialise processor |
@@ -397,7 +413,7 @@ ENDPROC(secondary_startup_arm) | |||
397 | * r6 = &secondary_data | 413 | * r6 = &secondary_data |
398 | */ | 414 | */ |
399 | ENTRY(__secondary_switched) | 415 | ENTRY(__secondary_switched) |
400 | ldr sp, [r7, #4] @ get secondary_data.stack | 416 | ldr sp, [r7, #12] @ get secondary_data.stack |
401 | mov fp, #0 | 417 | mov fp, #0 |
402 | b secondary_start_kernel | 418 | b secondary_start_kernel |
403 | ENDPROC(__secondary_switched) | 419 | ENDPROC(__secondary_switched) |
@@ -416,12 +432,14 @@ __secondary_data: | |||
416 | /* | 432 | /* |
417 | * Setup common bits before finally enabling the MMU. Essentially | 433 | * Setup common bits before finally enabling the MMU. Essentially |
418 | * this is just loading the page table pointer and domain access | 434 | * this is just loading the page table pointer and domain access |
419 | * registers. | 435 | * registers. All these registers need to be preserved by the |
436 | * processor setup function (or set in the case of r0) | ||
420 | * | 437 | * |
421 | * r0 = cp#15 control register | 438 | * r0 = cp#15 control register |
422 | * r1 = machine ID | 439 | * r1 = machine ID |
423 | * r2 = atags or dtb pointer | 440 | * r2 = atags or dtb pointer |
424 | * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) | 441 | * r4 = TTBR pointer (low word) |
442 | * r5 = TTBR pointer (high word if LPAE) | ||
425 | * r9 = processor ID | 443 | * r9 = processor ID |
426 | * r13 = *virtual* address to jump to upon completion | 444 | * r13 = *virtual* address to jump to upon completion |
427 | */ | 445 | */ |
@@ -440,7 +458,9 @@ __enable_mmu: | |||
440 | #ifdef CONFIG_CPU_ICACHE_DISABLE | 458 | #ifdef CONFIG_CPU_ICACHE_DISABLE |
441 | bic r0, r0, #CR_I | 459 | bic r0, r0, #CR_I |
442 | #endif | 460 | #endif |
443 | #ifndef CONFIG_ARM_LPAE | 461 | #ifdef CONFIG_ARM_LPAE |
462 | mcrr p15, 0, r4, r5, c2 @ load TTBR0 | ||
463 | #else | ||
444 | mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ | 464 | mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ |
445 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ | 465 | domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ |
446 | domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ | 466 | domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ |
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c new file mode 100644 index 000000000000..097e2e201b9f --- /dev/null +++ b/arch/arm/kernel/module-plts.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> | ||
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 | |||
9 | #include <linux/elf.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | #include <asm/cache.h> | ||
14 | #include <asm/opcodes.h> | ||
15 | |||
16 | #define PLT_ENT_STRIDE L1_CACHE_BYTES | ||
17 | #define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32)) | ||
18 | #define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT) | ||
19 | |||
20 | #ifdef CONFIG_THUMB2_KERNEL | ||
21 | #define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \ | ||
22 | (PLT_ENT_STRIDE - 4)) | ||
23 | #else | ||
24 | #define PLT_ENT_LDR __opcode_to_mem_arm(0xe59ff000 | \ | ||
25 | (PLT_ENT_STRIDE - 8)) | ||
26 | #endif | ||
27 | |||
28 | struct plt_entries { | ||
29 | u32 ldr[PLT_ENT_COUNT]; | ||
30 | u32 lit[PLT_ENT_COUNT]; | ||
31 | }; | ||
32 | |||
33 | static bool in_init(const struct module *mod, u32 addr) | ||
34 | { | ||
35 | return addr - (u32)mod->module_init < mod->init_size; | ||
36 | } | ||
37 | |||
38 | u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) | ||
39 | { | ||
40 | struct plt_entries *plt, *plt_end; | ||
41 | int c, *count; | ||
42 | |||
43 | if (in_init(mod, loc)) { | ||
44 | plt = (void *)mod->arch.init_plt->sh_addr; | ||
45 | plt_end = (void *)plt + mod->arch.init_plt->sh_size; | ||
46 | count = &mod->arch.init_plt_count; | ||
47 | } else { | ||
48 | plt = (void *)mod->arch.core_plt->sh_addr; | ||
49 | plt_end = (void *)plt + mod->arch.core_plt->sh_size; | ||
50 | count = &mod->arch.core_plt_count; | ||
51 | } | ||
52 | |||
53 | /* Look for an existing entry pointing to 'val' */ | ||
54 | for (c = *count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) { | ||
55 | int i; | ||
56 | |||
57 | if (!c) { | ||
58 | /* Populate a new set of entries */ | ||
59 | *plt = (struct plt_entries){ | ||
60 | { [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, }, | ||
61 | { val, } | ||
62 | }; | ||
63 | ++*count; | ||
64 | return (u32)plt->ldr; | ||
65 | } | ||
66 | for (i = 0; i < PLT_ENT_COUNT; i++) { | ||
67 | if (!plt->lit[i]) { | ||
68 | plt->lit[i] = val; | ||
69 | ++*count; | ||
70 | } | ||
71 | if (plt->lit[i] == val) | ||
72 | return (u32)&plt->ldr[i]; | ||
73 | } | ||
74 | } | ||
75 | BUG(); | ||
76 | } | ||
77 | |||
78 | static int duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num, | ||
79 | u32 mask) | ||
80 | { | ||
81 | u32 *loc1, *loc2; | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < num; i++) { | ||
85 | if (rel[i].r_info != rel[num].r_info) | ||
86 | continue; | ||
87 | |||
88 | /* | ||
89 | * Identical relocation types against identical symbols can | ||
90 | * still result in different PLT entries if the addend in the | ||
91 | * place is different. So resolve the target of the relocation | ||
92 | * to compare the values. | ||
93 | */ | ||
94 | loc1 = (u32 *)(base + rel[i].r_offset); | ||
95 | loc2 = (u32 *)(base + rel[num].r_offset); | ||
96 | if (((*loc1 ^ *loc2) & mask) == 0) | ||
97 | return 1; | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | /* Count how many PLT entries we may need */ | ||
103 | static unsigned int count_plts(Elf32_Addr base, const Elf32_Rel *rel, int num) | ||
104 | { | ||
105 | unsigned int ret = 0; | ||
106 | int i; | ||
107 | |||
108 | /* | ||
109 | * Sure, this is order(n^2), but it's usually short, and not | ||
110 | * time critical | ||
111 | */ | ||
112 | for (i = 0; i < num; i++) | ||
113 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
114 | case R_ARM_CALL: | ||
115 | case R_ARM_PC24: | ||
116 | case R_ARM_JUMP24: | ||
117 | if (!duplicate_rel(base, rel, i, | ||
118 | __opcode_to_mem_arm(0x00ffffff))) | ||
119 | ret++; | ||
120 | break; | ||
121 | #ifdef CONFIG_THUMB2_KERNEL | ||
122 | case R_ARM_THM_CALL: | ||
123 | case R_ARM_THM_JUMP24: | ||
124 | if (!duplicate_rel(base, rel, i, | ||
125 | __opcode_to_mem_thumb32(0x07ff2fff))) | ||
126 | ret++; | ||
127 | #endif | ||
128 | } | ||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | ||
133 | char *secstrings, struct module *mod) | ||
134 | { | ||
135 | unsigned long core_plts = 0, init_plts = 0; | ||
136 | Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; | ||
137 | |||
138 | /* | ||
139 | * To store the PLTs, we expand the .text section for core module code | ||
140 | * and the .init.text section for initialization code. | ||
141 | */ | ||
142 | for (s = sechdrs; s < sechdrs_end; ++s) | ||
143 | if (strcmp(".core.plt", secstrings + s->sh_name) == 0) | ||
144 | mod->arch.core_plt = s; | ||
145 | else if (strcmp(".init.plt", secstrings + s->sh_name) == 0) | ||
146 | mod->arch.init_plt = s; | ||
147 | |||
148 | if (!mod->arch.core_plt || !mod->arch.init_plt) { | ||
149 | pr_err("%s: sections missing\n", mod->name); | ||
150 | return -ENOEXEC; | ||
151 | } | ||
152 | |||
153 | for (s = sechdrs + 1; s < sechdrs_end; ++s) { | ||
154 | const Elf32_Rel *rels = (void *)ehdr + s->sh_offset; | ||
155 | int numrels = s->sh_size / sizeof(Elf32_Rel); | ||
156 | Elf32_Shdr *dstsec = sechdrs + s->sh_info; | ||
157 | |||
158 | if (s->sh_type != SHT_REL) | ||
159 | continue; | ||
160 | |||
161 | if (strstr(secstrings + s->sh_name, ".init")) | ||
162 | init_plts += count_plts(dstsec->sh_addr, rels, numrels); | ||
163 | else | ||
164 | core_plts += count_plts(dstsec->sh_addr, rels, numrels); | ||
165 | } | ||
166 | |||
167 | mod->arch.core_plt->sh_type = SHT_NOBITS; | ||
168 | mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; | ||
169 | mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES; | ||
170 | mod->arch.core_plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, | ||
171 | sizeof(struct plt_entries)); | ||
172 | mod->arch.core_plt_count = 0; | ||
173 | |||
174 | mod->arch.init_plt->sh_type = SHT_NOBITS; | ||
175 | mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; | ||
176 | mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES; | ||
177 | mod->arch.init_plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, | ||
178 | sizeof(struct plt_entries)); | ||
179 | mod->arch.init_plt_count = 0; | ||
180 | pr_debug("%s: core.plt=%x, init.plt=%x\n", __func__, | ||
181 | mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size); | ||
182 | return 0; | ||
183 | } | ||
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index af791f4a6205..efdddcb97dd1 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -40,7 +40,12 @@ | |||
40 | #ifdef CONFIG_MMU | 40 | #ifdef CONFIG_MMU |
41 | void *module_alloc(unsigned long size) | 41 | void *module_alloc(unsigned long size) |
42 | { | 42 | { |
43 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, | 43 | void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, |
44 | GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, | ||
45 | __builtin_return_address(0)); | ||
46 | if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p) | ||
47 | return p; | ||
48 | return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, | ||
44 | GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, | 49 | GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, |
45 | __builtin_return_address(0)); | 50 | __builtin_return_address(0)); |
46 | } | 51 | } |
@@ -110,6 +115,20 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
110 | offset -= 0x04000000; | 115 | offset -= 0x04000000; |
111 | 116 | ||
112 | offset += sym->st_value - loc; | 117 | offset += sym->st_value - loc; |
118 | |||
119 | /* | ||
120 | * Route through a PLT entry if 'offset' exceeds the | ||
121 | * supported range. Note that 'offset + loc + 8' | ||
122 | * contains the absolute jump target, i.e., | ||
123 | * @sym + addend, corrected for the +8 PC bias. | ||
124 | */ | ||
125 | if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) && | ||
126 | (offset <= (s32)0xfe000000 || | ||
127 | offset >= (s32)0x02000000)) | ||
128 | offset = get_module_plt(module, loc, | ||
129 | offset + loc + 8) | ||
130 | - loc - 8; | ||
131 | |||
113 | if (offset <= (s32)0xfe000000 || | 132 | if (offset <= (s32)0xfe000000 || |
114 | offset >= (s32)0x02000000) { | 133 | offset >= (s32)0x02000000) { |
115 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", | 134 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
@@ -203,6 +222,17 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
203 | offset -= 0x02000000; | 222 | offset -= 0x02000000; |
204 | offset += sym->st_value - loc; | 223 | offset += sym->st_value - loc; |
205 | 224 | ||
225 | /* | ||
226 | * Route through a PLT entry if 'offset' exceeds the | ||
227 | * supported range. | ||
228 | */ | ||
229 | if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) && | ||
230 | (offset <= (s32)0xff000000 || | ||
231 | offset >= (s32)0x01000000)) | ||
232 | offset = get_module_plt(module, loc, | ||
233 | offset + loc + 4) | ||
234 | - loc - 4; | ||
235 | |||
206 | if (offset <= (s32)0xff000000 || | 236 | if (offset <= (s32)0xff000000 || |
207 | offset >= (s32)0x01000000) { | 237 | offset >= (s32)0x01000000) { |
208 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", | 238 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
diff --git a/arch/arm/kernel/module.lds b/arch/arm/kernel/module.lds new file mode 100644 index 000000000000..3682fa107918 --- /dev/null +++ b/arch/arm/kernel/module.lds | |||
@@ -0,0 +1,4 @@ | |||
1 | SECTIONS { | ||
2 | .core.plt : { BYTE(0) } | ||
3 | .init.plt : { BYTE(0) } | ||
4 | } | ||
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 4a86a0133ac3..357f57ea83f4 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -11,12 +11,18 @@ | |||
11 | */ | 11 | */ |
12 | #define pr_fmt(fmt) "hw perfevents: " fmt | 12 | #define pr_fmt(fmt) "hw perfevents: " fmt |
13 | 13 | ||
14 | #include <linux/bitmap.h> | ||
15 | #include <linux/cpumask.h> | ||
16 | #include <linux/export.h> | ||
14 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/of.h> | ||
15 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/spinlock.h> | ||
17 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
18 | #include <linux/irqdesc.h> | 23 | #include <linux/irqdesc.h> |
19 | 24 | ||
25 | #include <asm/cputype.h> | ||
20 | #include <asm/irq_regs.h> | 26 | #include <asm/irq_regs.h> |
21 | #include <asm/pmu.h> | 27 | #include <asm/pmu.h> |
22 | 28 | ||
@@ -229,6 +235,10 @@ armpmu_add(struct perf_event *event, int flags) | |||
229 | int idx; | 235 | int idx; |
230 | int err = 0; | 236 | int err = 0; |
231 | 237 | ||
238 | /* An event following a process won't be stopped earlier */ | ||
239 | if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) | ||
240 | return -ENOENT; | ||
241 | |||
232 | perf_pmu_disable(event->pmu); | 242 | perf_pmu_disable(event->pmu); |
233 | 243 | ||
234 | /* If we don't have a space for the counter then finish early. */ | 244 | /* If we don't have a space for the counter then finish early. */ |
@@ -344,20 +354,12 @@ static void | |||
344 | armpmu_release_hardware(struct arm_pmu *armpmu) | 354 | armpmu_release_hardware(struct arm_pmu *armpmu) |
345 | { | 355 | { |
346 | armpmu->free_irq(armpmu); | 356 | armpmu->free_irq(armpmu); |
347 | pm_runtime_put_sync(&armpmu->plat_device->dev); | ||
348 | } | 357 | } |
349 | 358 | ||
350 | static int | 359 | static int |
351 | armpmu_reserve_hardware(struct arm_pmu *armpmu) | 360 | armpmu_reserve_hardware(struct arm_pmu *armpmu) |
352 | { | 361 | { |
353 | int err; | 362 | int err = armpmu->request_irq(armpmu, armpmu_dispatch_irq); |
354 | struct platform_device *pmu_device = armpmu->plat_device; | ||
355 | |||
356 | if (!pmu_device) | ||
357 | return -ENODEV; | ||
358 | |||
359 | pm_runtime_get_sync(&pmu_device->dev); | ||
360 | err = armpmu->request_irq(armpmu, armpmu_dispatch_irq); | ||
361 | if (err) { | 363 | if (err) { |
362 | armpmu_release_hardware(armpmu); | 364 | armpmu_release_hardware(armpmu); |
363 | return err; | 365 | return err; |
@@ -454,6 +456,17 @@ static int armpmu_event_init(struct perf_event *event) | |||
454 | int err = 0; | 456 | int err = 0; |
455 | atomic_t *active_events = &armpmu->active_events; | 457 | atomic_t *active_events = &armpmu->active_events; |
456 | 458 | ||
459 | /* | ||
460 | * Reject CPU-affine events for CPUs that are of a different class to | ||
461 | * that which this PMU handles. Process-following events (where | ||
462 | * event->cpu == -1) can be migrated between CPUs, and thus we have to | ||
463 | * reject them later (in armpmu_add) if they're scheduled on a | ||
464 | * different class of CPU. | ||
465 | */ | ||
466 | if (event->cpu != -1 && | ||
467 | !cpumask_test_cpu(event->cpu, &armpmu->supported_cpus)) | ||
468 | return -ENOENT; | ||
469 | |||
457 | /* does not support taken branch sampling */ | 470 | /* does not support taken branch sampling */ |
458 | if (has_branch_stack(event)) | 471 | if (has_branch_stack(event)) |
459 | return -EOPNOTSUPP; | 472 | return -EOPNOTSUPP; |
@@ -489,6 +502,10 @@ static void armpmu_enable(struct pmu *pmu) | |||
489 | struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); | 502 | struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); |
490 | int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); | 503 | int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); |
491 | 504 | ||
505 | /* For task-bound events we may be called on other CPUs */ | ||
506 | if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) | ||
507 | return; | ||
508 | |||
492 | if (enabled) | 509 | if (enabled) |
493 | armpmu->start(armpmu); | 510 | armpmu->start(armpmu); |
494 | } | 511 | } |
@@ -496,34 +513,25 @@ static void armpmu_enable(struct pmu *pmu) | |||
496 | static void armpmu_disable(struct pmu *pmu) | 513 | static void armpmu_disable(struct pmu *pmu) |
497 | { | 514 | { |
498 | struct arm_pmu *armpmu = to_arm_pmu(pmu); | 515 | struct arm_pmu *armpmu = to_arm_pmu(pmu); |
499 | armpmu->stop(armpmu); | ||
500 | } | ||
501 | |||
502 | #ifdef CONFIG_PM | ||
503 | static int armpmu_runtime_resume(struct device *dev) | ||
504 | { | ||
505 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | ||
506 | 516 | ||
507 | if (plat && plat->runtime_resume) | 517 | /* For task-bound events we may be called on other CPUs */ |
508 | return plat->runtime_resume(dev); | 518 | if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) |
519 | return; | ||
509 | 520 | ||
510 | return 0; | 521 | armpmu->stop(armpmu); |
511 | } | 522 | } |
512 | 523 | ||
513 | static int armpmu_runtime_suspend(struct device *dev) | 524 | /* |
525 | * In heterogeneous systems, events are specific to a particular | ||
526 | * microarchitecture, and aren't suitable for another. Thus, only match CPUs of | ||
527 | * the same microarchitecture. | ||
528 | */ | ||
529 | static int armpmu_filter_match(struct perf_event *event) | ||
514 | { | 530 | { |
515 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | 531 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); |
516 | 532 | unsigned int cpu = smp_processor_id(); | |
517 | if (plat && plat->runtime_suspend) | 533 | return cpumask_test_cpu(cpu, &armpmu->supported_cpus); |
518 | return plat->runtime_suspend(dev); | ||
519 | |||
520 | return 0; | ||
521 | } | 534 | } |
522 | #endif | ||
523 | |||
524 | const struct dev_pm_ops armpmu_dev_pm_ops = { | ||
525 | SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL) | ||
526 | }; | ||
527 | 535 | ||
528 | static void armpmu_init(struct arm_pmu *armpmu) | 536 | static void armpmu_init(struct arm_pmu *armpmu) |
529 | { | 537 | { |
@@ -539,15 +547,349 @@ static void armpmu_init(struct arm_pmu *armpmu) | |||
539 | .start = armpmu_start, | 547 | .start = armpmu_start, |
540 | .stop = armpmu_stop, | 548 | .stop = armpmu_stop, |
541 | .read = armpmu_read, | 549 | .read = armpmu_read, |
550 | .filter_match = armpmu_filter_match, | ||
542 | }; | 551 | }; |
543 | } | 552 | } |
544 | 553 | ||
545 | int armpmu_register(struct arm_pmu *armpmu, int type) | 554 | int armpmu_register(struct arm_pmu *armpmu, int type) |
546 | { | 555 | { |
547 | armpmu_init(armpmu); | 556 | armpmu_init(armpmu); |
548 | pm_runtime_enable(&armpmu->plat_device->dev); | ||
549 | pr_info("enabled with %s PMU driver, %d counters available\n", | 557 | pr_info("enabled with %s PMU driver, %d counters available\n", |
550 | armpmu->name, armpmu->num_events); | 558 | armpmu->name, armpmu->num_events); |
551 | return perf_pmu_register(&armpmu->pmu, armpmu->name, type); | 559 | return perf_pmu_register(&armpmu->pmu, armpmu->name, type); |
552 | } | 560 | } |
553 | 561 | ||
562 | /* Set at runtime when we know what CPU type we are. */ | ||
563 | static struct arm_pmu *__oprofile_cpu_pmu; | ||
564 | |||
565 | /* | ||
566 | * Despite the names, these two functions are CPU-specific and are used | ||
567 | * by the OProfile/perf code. | ||
568 | */ | ||
569 | const char *perf_pmu_name(void) | ||
570 | { | ||
571 | if (!__oprofile_cpu_pmu) | ||
572 | return NULL; | ||
573 | |||
574 | return __oprofile_cpu_pmu->name; | ||
575 | } | ||
576 | EXPORT_SYMBOL_GPL(perf_pmu_name); | ||
577 | |||
578 | int perf_num_counters(void) | ||
579 | { | ||
580 | int max_events = 0; | ||
581 | |||
582 | if (__oprofile_cpu_pmu != NULL) | ||
583 | max_events = __oprofile_cpu_pmu->num_events; | ||
584 | |||
585 | return max_events; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
588 | |||
589 | static void cpu_pmu_enable_percpu_irq(void *data) | ||
590 | { | ||
591 | int irq = *(int *)data; | ||
592 | |||
593 | enable_percpu_irq(irq, IRQ_TYPE_NONE); | ||
594 | } | ||
595 | |||
596 | static void cpu_pmu_disable_percpu_irq(void *data) | ||
597 | { | ||
598 | int irq = *(int *)data; | ||
599 | |||
600 | disable_percpu_irq(irq); | ||
601 | } | ||
602 | |||
603 | static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) | ||
604 | { | ||
605 | int i, irq, irqs; | ||
606 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
607 | struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; | ||
608 | |||
609 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
610 | |||
611 | irq = platform_get_irq(pmu_device, 0); | ||
612 | if (irq >= 0 && irq_is_percpu(irq)) { | ||
613 | on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1); | ||
614 | free_percpu_irq(irq, &hw_events->percpu_pmu); | ||
615 | } else { | ||
616 | for (i = 0; i < irqs; ++i) { | ||
617 | int cpu = i; | ||
618 | |||
619 | if (cpu_pmu->irq_affinity) | ||
620 | cpu = cpu_pmu->irq_affinity[i]; | ||
621 | |||
622 | if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs)) | ||
623 | continue; | ||
624 | irq = platform_get_irq(pmu_device, i); | ||
625 | if (irq >= 0) | ||
626 | free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); | ||
627 | } | ||
628 | } | ||
629 | } | ||
630 | |||
631 | static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) | ||
632 | { | ||
633 | int i, err, irq, irqs; | ||
634 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
635 | struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; | ||
636 | |||
637 | if (!pmu_device) | ||
638 | return -ENODEV; | ||
639 | |||
640 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
641 | if (irqs < 1) { | ||
642 | pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | irq = platform_get_irq(pmu_device, 0); | ||
647 | if (irq >= 0 && irq_is_percpu(irq)) { | ||
648 | err = request_percpu_irq(irq, handler, "arm-pmu", | ||
649 | &hw_events->percpu_pmu); | ||
650 | if (err) { | ||
651 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
652 | irq); | ||
653 | return err; | ||
654 | } | ||
655 | on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1); | ||
656 | } else { | ||
657 | for (i = 0; i < irqs; ++i) { | ||
658 | int cpu = i; | ||
659 | |||
660 | err = 0; | ||
661 | irq = platform_get_irq(pmu_device, i); | ||
662 | if (irq < 0) | ||
663 | continue; | ||
664 | |||
665 | if (cpu_pmu->irq_affinity) | ||
666 | cpu = cpu_pmu->irq_affinity[i]; | ||
667 | |||
668 | /* | ||
669 | * If we have a single PMU interrupt that we can't shift, | ||
670 | * assume that we're running on a uniprocessor machine and | ||
671 | * continue. Otherwise, continue without this interrupt. | ||
672 | */ | ||
673 | if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) { | ||
674 | pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
675 | irq, cpu); | ||
676 | continue; | ||
677 | } | ||
678 | |||
679 | err = request_irq(irq, handler, | ||
680 | IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", | ||
681 | per_cpu_ptr(&hw_events->percpu_pmu, cpu)); | ||
682 | if (err) { | ||
683 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
684 | irq); | ||
685 | return err; | ||
686 | } | ||
687 | |||
688 | cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * PMU hardware loses all context when a CPU goes offline. | ||
697 | * When a CPU is hotplugged back in, since some hardware registers are | ||
698 | * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading | ||
699 | * junk values out of them. | ||
700 | */ | ||
701 | static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, | ||
702 | void *hcpu) | ||
703 | { | ||
704 | int cpu = (unsigned long)hcpu; | ||
705 | struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); | ||
706 | |||
707 | if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) | ||
708 | return NOTIFY_DONE; | ||
709 | |||
710 | if (!cpumask_test_cpu(cpu, &pmu->supported_cpus)) | ||
711 | return NOTIFY_DONE; | ||
712 | |||
713 | if (pmu->reset) | ||
714 | pmu->reset(pmu); | ||
715 | else | ||
716 | return NOTIFY_DONE; | ||
717 | |||
718 | return NOTIFY_OK; | ||
719 | } | ||
720 | |||
721 | static int cpu_pmu_init(struct arm_pmu *cpu_pmu) | ||
722 | { | ||
723 | int err; | ||
724 | int cpu; | ||
725 | struct pmu_hw_events __percpu *cpu_hw_events; | ||
726 | |||
727 | cpu_hw_events = alloc_percpu(struct pmu_hw_events); | ||
728 | if (!cpu_hw_events) | ||
729 | return -ENOMEM; | ||
730 | |||
731 | cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify; | ||
732 | err = register_cpu_notifier(&cpu_pmu->hotplug_nb); | ||
733 | if (err) | ||
734 | goto out_hw_events; | ||
735 | |||
736 | for_each_possible_cpu(cpu) { | ||
737 | struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); | ||
738 | raw_spin_lock_init(&events->pmu_lock); | ||
739 | events->percpu_pmu = cpu_pmu; | ||
740 | } | ||
741 | |||
742 | cpu_pmu->hw_events = cpu_hw_events; | ||
743 | cpu_pmu->request_irq = cpu_pmu_request_irq; | ||
744 | cpu_pmu->free_irq = cpu_pmu_free_irq; | ||
745 | |||
746 | /* Ensure the PMU has sane values out of reset. */ | ||
747 | if (cpu_pmu->reset) | ||
748 | on_each_cpu_mask(&cpu_pmu->supported_cpus, cpu_pmu->reset, | ||
749 | cpu_pmu, 1); | ||
750 | |||
751 | /* If no interrupts available, set the corresponding capability flag */ | ||
752 | if (!platform_get_irq(cpu_pmu->plat_device, 0)) | ||
753 | cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; | ||
754 | |||
755 | return 0; | ||
756 | |||
757 | out_hw_events: | ||
758 | free_percpu(cpu_hw_events); | ||
759 | return err; | ||
760 | } | ||
761 | |||
762 | static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) | ||
763 | { | ||
764 | unregister_cpu_notifier(&cpu_pmu->hotplug_nb); | ||
765 | free_percpu(cpu_pmu->hw_events); | ||
766 | } | ||
767 | |||
768 | /* | ||
769 | * CPU PMU identification and probing. | ||
770 | */ | ||
771 | static int probe_current_pmu(struct arm_pmu *pmu, | ||
772 | const struct pmu_probe_info *info) | ||
773 | { | ||
774 | int cpu = get_cpu(); | ||
775 | unsigned int cpuid = read_cpuid_id(); | ||
776 | int ret = -ENODEV; | ||
777 | |||
778 | pr_info("probing PMU on CPU %d\n", cpu); | ||
779 | |||
780 | for (; info->init != NULL; info++) { | ||
781 | if ((cpuid & info->mask) != info->cpuid) | ||
782 | continue; | ||
783 | ret = info->init(pmu); | ||
784 | break; | ||
785 | } | ||
786 | |||
787 | put_cpu(); | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | static int of_pmu_irq_cfg(struct arm_pmu *pmu) | ||
792 | { | ||
793 | int i, irq, *irqs; | ||
794 | struct platform_device *pdev = pmu->plat_device; | ||
795 | |||
796 | /* Don't bother with PPIs; they're already affine */ | ||
797 | irq = platform_get_irq(pdev, 0); | ||
798 | if (irq >= 0 && irq_is_percpu(irq)) | ||
799 | return 0; | ||
800 | |||
801 | irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); | ||
802 | if (!irqs) | ||
803 | return -ENOMEM; | ||
804 | |||
805 | for (i = 0; i < pdev->num_resources; ++i) { | ||
806 | struct device_node *dn; | ||
807 | int cpu; | ||
808 | |||
809 | dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", | ||
810 | i); | ||
811 | if (!dn) { | ||
812 | pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", | ||
813 | of_node_full_name(pdev->dev.of_node), i); | ||
814 | break; | ||
815 | } | ||
816 | |||
817 | for_each_possible_cpu(cpu) | ||
818 | if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL)) | ||
819 | break; | ||
820 | |||
821 | of_node_put(dn); | ||
822 | if (cpu >= nr_cpu_ids) { | ||
823 | pr_warn("Failed to find logical CPU for %s\n", | ||
824 | dn->name); | ||
825 | break; | ||
826 | } | ||
827 | |||
828 | irqs[i] = cpu; | ||
829 | cpumask_set_cpu(cpu, &pmu->supported_cpus); | ||
830 | } | ||
831 | |||
832 | if (i == pdev->num_resources) { | ||
833 | pmu->irq_affinity = irqs; | ||
834 | } else { | ||
835 | kfree(irqs); | ||
836 | cpumask_setall(&pmu->supported_cpus); | ||
837 | } | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | int arm_pmu_device_probe(struct platform_device *pdev, | ||
843 | const struct of_device_id *of_table, | ||
844 | const struct pmu_probe_info *probe_table) | ||
845 | { | ||
846 | const struct of_device_id *of_id; | ||
847 | const int (*init_fn)(struct arm_pmu *); | ||
848 | struct device_node *node = pdev->dev.of_node; | ||
849 | struct arm_pmu *pmu; | ||
850 | int ret = -ENODEV; | ||
851 | |||
852 | pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); | ||
853 | if (!pmu) { | ||
854 | pr_info("failed to allocate PMU device!\n"); | ||
855 | return -ENOMEM; | ||
856 | } | ||
857 | |||
858 | if (!__oprofile_cpu_pmu) | ||
859 | __oprofile_cpu_pmu = pmu; | ||
860 | |||
861 | pmu->plat_device = pdev; | ||
862 | |||
863 | if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { | ||
864 | init_fn = of_id->data; | ||
865 | |||
866 | ret = of_pmu_irq_cfg(pmu); | ||
867 | if (!ret) | ||
868 | ret = init_fn(pmu); | ||
869 | } else { | ||
870 | ret = probe_current_pmu(pmu, probe_table); | ||
871 | cpumask_setall(&pmu->supported_cpus); | ||
872 | } | ||
873 | |||
874 | if (ret) { | ||
875 | pr_info("failed to probe PMU!\n"); | ||
876 | goto out_free; | ||
877 | } | ||
878 | |||
879 | ret = cpu_pmu_init(pmu); | ||
880 | if (ret) | ||
881 | goto out_free; | ||
882 | |||
883 | ret = armpmu_register(pmu, -1); | ||
884 | if (ret) | ||
885 | goto out_destroy; | ||
886 | |||
887 | return 0; | ||
888 | |||
889 | out_destroy: | ||
890 | cpu_pmu_destroy(pmu); | ||
891 | out_free: | ||
892 | pr_info("failed to register PMU devices!\n"); | ||
893 | kfree(pmu); | ||
894 | return ret; | ||
895 | } | ||
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c deleted file mode 100644 index 3b8c2833c537..000000000000 --- a/arch/arm/kernel/perf_event_cpu.c +++ /dev/null | |||
@@ -1,421 +0,0 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
14 | * | ||
15 | * Copyright (C) 2012 ARM Limited | ||
16 | * | ||
17 | * Author: Will Deacon <will.deacon@arm.com> | ||
18 | */ | ||
19 | #define pr_fmt(fmt) "CPU PMU: " fmt | ||
20 | |||
21 | #include <linux/bitmap.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/irqdesc.h> | ||
30 | |||
31 | #include <asm/cputype.h> | ||
32 | #include <asm/irq_regs.h> | ||
33 | #include <asm/pmu.h> | ||
34 | |||
35 | /* Set at runtime when we know what CPU type we are. */ | ||
36 | static struct arm_pmu *cpu_pmu; | ||
37 | |||
38 | /* | ||
39 | * Despite the names, these two functions are CPU-specific and are used | ||
40 | * by the OProfile/perf code. | ||
41 | */ | ||
42 | const char *perf_pmu_name(void) | ||
43 | { | ||
44 | if (!cpu_pmu) | ||
45 | return NULL; | ||
46 | |||
47 | return cpu_pmu->name; | ||
48 | } | ||
49 | EXPORT_SYMBOL_GPL(perf_pmu_name); | ||
50 | |||
51 | int perf_num_counters(void) | ||
52 | { | ||
53 | int max_events = 0; | ||
54 | |||
55 | if (cpu_pmu != NULL) | ||
56 | max_events = cpu_pmu->num_events; | ||
57 | |||
58 | return max_events; | ||
59 | } | ||
60 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
61 | |||
62 | /* Include the PMU-specific implementations. */ | ||
63 | #include "perf_event_xscale.c" | ||
64 | #include "perf_event_v6.c" | ||
65 | #include "perf_event_v7.c" | ||
66 | |||
67 | static void cpu_pmu_enable_percpu_irq(void *data) | ||
68 | { | ||
69 | int irq = *(int *)data; | ||
70 | |||
71 | enable_percpu_irq(irq, IRQ_TYPE_NONE); | ||
72 | } | ||
73 | |||
74 | static void cpu_pmu_disable_percpu_irq(void *data) | ||
75 | { | ||
76 | int irq = *(int *)data; | ||
77 | |||
78 | disable_percpu_irq(irq); | ||
79 | } | ||
80 | |||
81 | static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) | ||
82 | { | ||
83 | int i, irq, irqs; | ||
84 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
85 | struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; | ||
86 | |||
87 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
88 | |||
89 | irq = platform_get_irq(pmu_device, 0); | ||
90 | if (irq >= 0 && irq_is_percpu(irq)) { | ||
91 | on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1); | ||
92 | free_percpu_irq(irq, &hw_events->percpu_pmu); | ||
93 | } else { | ||
94 | for (i = 0; i < irqs; ++i) { | ||
95 | int cpu = i; | ||
96 | |||
97 | if (cpu_pmu->irq_affinity) | ||
98 | cpu = cpu_pmu->irq_affinity[i]; | ||
99 | |||
100 | if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs)) | ||
101 | continue; | ||
102 | irq = platform_get_irq(pmu_device, i); | ||
103 | if (irq >= 0) | ||
104 | free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) | ||
110 | { | ||
111 | int i, err, irq, irqs; | ||
112 | struct platform_device *pmu_device = cpu_pmu->plat_device; | ||
113 | struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; | ||
114 | |||
115 | if (!pmu_device) | ||
116 | return -ENODEV; | ||
117 | |||
118 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
119 | if (irqs < 1) { | ||
120 | pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | irq = platform_get_irq(pmu_device, 0); | ||
125 | if (irq >= 0 && irq_is_percpu(irq)) { | ||
126 | err = request_percpu_irq(irq, handler, "arm-pmu", | ||
127 | &hw_events->percpu_pmu); | ||
128 | if (err) { | ||
129 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
130 | irq); | ||
131 | return err; | ||
132 | } | ||
133 | on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1); | ||
134 | } else { | ||
135 | for (i = 0; i < irqs; ++i) { | ||
136 | int cpu = i; | ||
137 | |||
138 | err = 0; | ||
139 | irq = platform_get_irq(pmu_device, i); | ||
140 | if (irq < 0) | ||
141 | continue; | ||
142 | |||
143 | if (cpu_pmu->irq_affinity) | ||
144 | cpu = cpu_pmu->irq_affinity[i]; | ||
145 | |||
146 | /* | ||
147 | * If we have a single PMU interrupt that we can't shift, | ||
148 | * assume that we're running on a uniprocessor machine and | ||
149 | * continue. Otherwise, continue without this interrupt. | ||
150 | */ | ||
151 | if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) { | ||
152 | pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
153 | irq, cpu); | ||
154 | continue; | ||
155 | } | ||
156 | |||
157 | err = request_irq(irq, handler, | ||
158 | IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", | ||
159 | per_cpu_ptr(&hw_events->percpu_pmu, cpu)); | ||
160 | if (err) { | ||
161 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
162 | irq); | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * PMU hardware loses all context when a CPU goes offline. | ||
175 | * When a CPU is hotplugged back in, since some hardware registers are | ||
176 | * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading | ||
177 | * junk values out of them. | ||
178 | */ | ||
179 | static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, | ||
180 | void *hcpu) | ||
181 | { | ||
182 | struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); | ||
183 | |||
184 | if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) | ||
185 | return NOTIFY_DONE; | ||
186 | |||
187 | if (pmu->reset) | ||
188 | pmu->reset(pmu); | ||
189 | else | ||
190 | return NOTIFY_DONE; | ||
191 | |||
192 | return NOTIFY_OK; | ||
193 | } | ||
194 | |||
195 | static int cpu_pmu_init(struct arm_pmu *cpu_pmu) | ||
196 | { | ||
197 | int err; | ||
198 | int cpu; | ||
199 | struct pmu_hw_events __percpu *cpu_hw_events; | ||
200 | |||
201 | cpu_hw_events = alloc_percpu(struct pmu_hw_events); | ||
202 | if (!cpu_hw_events) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify; | ||
206 | err = register_cpu_notifier(&cpu_pmu->hotplug_nb); | ||
207 | if (err) | ||
208 | goto out_hw_events; | ||
209 | |||
210 | for_each_possible_cpu(cpu) { | ||
211 | struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); | ||
212 | raw_spin_lock_init(&events->pmu_lock); | ||
213 | events->percpu_pmu = cpu_pmu; | ||
214 | } | ||
215 | |||
216 | cpu_pmu->hw_events = cpu_hw_events; | ||
217 | cpu_pmu->request_irq = cpu_pmu_request_irq; | ||
218 | cpu_pmu->free_irq = cpu_pmu_free_irq; | ||
219 | |||
220 | /* Ensure the PMU has sane values out of reset. */ | ||
221 | if (cpu_pmu->reset) | ||
222 | on_each_cpu(cpu_pmu->reset, cpu_pmu, 1); | ||
223 | |||
224 | /* If no interrupts available, set the corresponding capability flag */ | ||
225 | if (!platform_get_irq(cpu_pmu->plat_device, 0)) | ||
226 | cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; | ||
227 | |||
228 | return 0; | ||
229 | |||
230 | out_hw_events: | ||
231 | free_percpu(cpu_hw_events); | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) | ||
236 | { | ||
237 | unregister_cpu_notifier(&cpu_pmu->hotplug_nb); | ||
238 | free_percpu(cpu_pmu->hw_events); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * PMU platform driver and devicetree bindings. | ||
243 | */ | ||
244 | static const struct of_device_id cpu_pmu_of_device_ids[] = { | ||
245 | {.compatible = "arm,cortex-a17-pmu", .data = armv7_a17_pmu_init}, | ||
246 | {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init}, | ||
247 | {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init}, | ||
248 | {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init}, | ||
249 | {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init}, | ||
250 | {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init}, | ||
251 | {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init}, | ||
252 | {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, | ||
253 | {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init}, | ||
254 | {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init}, | ||
255 | {.compatible = "qcom,krait-pmu", .data = krait_pmu_init}, | ||
256 | {.compatible = "qcom,scorpion-pmu", .data = scorpion_pmu_init}, | ||
257 | {.compatible = "qcom,scorpion-mp-pmu", .data = scorpion_mp_pmu_init}, | ||
258 | {}, | ||
259 | }; | ||
260 | |||
261 | static struct platform_device_id cpu_pmu_plat_device_ids[] = { | ||
262 | {.name = "arm-pmu"}, | ||
263 | {.name = "armv6-pmu"}, | ||
264 | {.name = "armv7-pmu"}, | ||
265 | {.name = "xscale-pmu"}, | ||
266 | {}, | ||
267 | }; | ||
268 | |||
269 | static const struct pmu_probe_info pmu_probe_table[] = { | ||
270 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init), | ||
271 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init), | ||
272 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init), | ||
273 | ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init), | ||
274 | ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init), | ||
275 | ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init), | ||
276 | XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init), | ||
277 | XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init), | ||
278 | { /* sentinel value */ } | ||
279 | }; | ||
280 | |||
281 | /* | ||
282 | * CPU PMU identification and probing. | ||
283 | */ | ||
284 | static int probe_current_pmu(struct arm_pmu *pmu) | ||
285 | { | ||
286 | int cpu = get_cpu(); | ||
287 | unsigned int cpuid = read_cpuid_id(); | ||
288 | int ret = -ENODEV; | ||
289 | const struct pmu_probe_info *info; | ||
290 | |||
291 | pr_info("probing PMU on CPU %d\n", cpu); | ||
292 | |||
293 | for (info = pmu_probe_table; info->init != NULL; info++) { | ||
294 | if ((cpuid & info->mask) != info->cpuid) | ||
295 | continue; | ||
296 | ret = info->init(pmu); | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | put_cpu(); | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int of_pmu_irq_cfg(struct platform_device *pdev) | ||
305 | { | ||
306 | int i, irq; | ||
307 | int *irqs; | ||
308 | |||
309 | /* Don't bother with PPIs; they're already affine */ | ||
310 | irq = platform_get_irq(pdev, 0); | ||
311 | if (irq >= 0 && irq_is_percpu(irq)) | ||
312 | return 0; | ||
313 | |||
314 | irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); | ||
315 | if (!irqs) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | for (i = 0; i < pdev->num_resources; ++i) { | ||
319 | struct device_node *dn; | ||
320 | int cpu; | ||
321 | |||
322 | dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", | ||
323 | i); | ||
324 | if (!dn) { | ||
325 | pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", | ||
326 | of_node_full_name(pdev->dev.of_node), i); | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | for_each_possible_cpu(cpu) | ||
331 | if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL)) | ||
332 | break; | ||
333 | |||
334 | of_node_put(dn); | ||
335 | if (cpu >= nr_cpu_ids) { | ||
336 | pr_warn("Failed to find logical CPU for %s\n", | ||
337 | dn->name); | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | irqs[i] = cpu; | ||
342 | } | ||
343 | |||
344 | if (i == pdev->num_resources) | ||
345 | cpu_pmu->irq_affinity = irqs; | ||
346 | else | ||
347 | kfree(irqs); | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static int cpu_pmu_device_probe(struct platform_device *pdev) | ||
353 | { | ||
354 | const struct of_device_id *of_id; | ||
355 | const int (*init_fn)(struct arm_pmu *); | ||
356 | struct device_node *node = pdev->dev.of_node; | ||
357 | struct arm_pmu *pmu; | ||
358 | int ret = -ENODEV; | ||
359 | |||
360 | if (cpu_pmu) { | ||
361 | pr_info("attempt to register multiple PMU devices!\n"); | ||
362 | return -ENOSPC; | ||
363 | } | ||
364 | |||
365 | pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); | ||
366 | if (!pmu) { | ||
367 | pr_info("failed to allocate PMU device!\n"); | ||
368 | return -ENOMEM; | ||
369 | } | ||
370 | |||
371 | cpu_pmu = pmu; | ||
372 | cpu_pmu->plat_device = pdev; | ||
373 | |||
374 | if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) { | ||
375 | init_fn = of_id->data; | ||
376 | |||
377 | ret = of_pmu_irq_cfg(pdev); | ||
378 | if (!ret) | ||
379 | ret = init_fn(pmu); | ||
380 | } else { | ||
381 | ret = probe_current_pmu(pmu); | ||
382 | } | ||
383 | |||
384 | if (ret) { | ||
385 | pr_info("failed to probe PMU!\n"); | ||
386 | goto out_free; | ||
387 | } | ||
388 | |||
389 | ret = cpu_pmu_init(cpu_pmu); | ||
390 | if (ret) | ||
391 | goto out_free; | ||
392 | |||
393 | ret = armpmu_register(cpu_pmu, -1); | ||
394 | if (ret) | ||
395 | goto out_destroy; | ||
396 | |||
397 | return 0; | ||
398 | |||
399 | out_destroy: | ||
400 | cpu_pmu_destroy(cpu_pmu); | ||
401 | out_free: | ||
402 | pr_info("failed to register PMU devices!\n"); | ||
403 | kfree(pmu); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | static struct platform_driver cpu_pmu_driver = { | ||
408 | .driver = { | ||
409 | .name = "arm-pmu", | ||
410 | .pm = &armpmu_dev_pm_ops, | ||
411 | .of_match_table = cpu_pmu_of_device_ids, | ||
412 | }, | ||
413 | .probe = cpu_pmu_device_probe, | ||
414 | .id_table = cpu_pmu_plat_device_ids, | ||
415 | }; | ||
416 | |||
417 | static int __init register_pmu_driver(void) | ||
418 | { | ||
419 | return platform_driver_register(&cpu_pmu_driver); | ||
420 | } | ||
421 | device_initcall(register_pmu_driver); | ||
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index f2ffd5c542ed..09f83e414a72 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c | |||
@@ -31,6 +31,14 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) | 33 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) |
34 | |||
35 | #include <asm/cputype.h> | ||
36 | #include <asm/irq_regs.h> | ||
37 | #include <asm/pmu.h> | ||
38 | |||
39 | #include <linux/of.h> | ||
40 | #include <linux/platform_device.h> | ||
41 | |||
34 | enum armv6_perf_types { | 42 | enum armv6_perf_types { |
35 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, | 43 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, |
36 | ARMV6_PERFCTR_IBUF_STALL = 0x1, | 44 | ARMV6_PERFCTR_IBUF_STALL = 0x1, |
@@ -543,24 +551,39 @@ static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu) | |||
543 | 551 | ||
544 | return 0; | 552 | return 0; |
545 | } | 553 | } |
546 | #else | ||
547 | static int armv6_1136_pmu_init(struct arm_pmu *cpu_pmu) | ||
548 | { | ||
549 | return -ENODEV; | ||
550 | } | ||
551 | 554 | ||
552 | static int armv6_1156_pmu_init(struct arm_pmu *cpu_pmu) | 555 | static struct of_device_id armv6_pmu_of_device_ids[] = { |
553 | { | 556 | {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, |
554 | return -ENODEV; | 557 | {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init}, |
555 | } | 558 | {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init}, |
559 | { /* sentinel value */ } | ||
560 | }; | ||
556 | 561 | ||
557 | static int armv6_1176_pmu_init(struct arm_pmu *cpu_pmu) | 562 | static const struct pmu_probe_info armv6_pmu_probe_table[] = { |
563 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init), | ||
564 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init), | ||
565 | ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init), | ||
566 | ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init), | ||
567 | { /* sentinel value */ } | ||
568 | }; | ||
569 | |||
570 | static int armv6_pmu_device_probe(struct platform_device *pdev) | ||
558 | { | 571 | { |
559 | return -ENODEV; | 572 | return arm_pmu_device_probe(pdev, armv6_pmu_of_device_ids, |
573 | armv6_pmu_probe_table); | ||
560 | } | 574 | } |
561 | 575 | ||
562 | static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu) | 576 | static struct platform_driver armv6_pmu_driver = { |
577 | .driver = { | ||
578 | .name = "armv6-pmu", | ||
579 | .of_match_table = armv6_pmu_of_device_ids, | ||
580 | }, | ||
581 | .probe = armv6_pmu_device_probe, | ||
582 | }; | ||
583 | |||
584 | static int __init register_armv6_pmu_driver(void) | ||
563 | { | 585 | { |
564 | return -ENODEV; | 586 | return platform_driver_register(&armv6_pmu_driver); |
565 | } | 587 | } |
588 | device_initcall(register_armv6_pmu_driver); | ||
566 | #endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */ | 589 | #endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */ |
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index f4207a4dcb01..f9b37f876e20 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c | |||
@@ -19,9 +19,15 @@ | |||
19 | #ifdef CONFIG_CPU_V7 | 19 | #ifdef CONFIG_CPU_V7 |
20 | 20 | ||
21 | #include <asm/cp15.h> | 21 | #include <asm/cp15.h> |
22 | #include <asm/cputype.h> | ||
23 | #include <asm/irq_regs.h> | ||
24 | #include <asm/pmu.h> | ||
22 | #include <asm/vfp.h> | 25 | #include <asm/vfp.h> |
23 | #include "../vfp/vfpinstr.h" | 26 | #include "../vfp/vfpinstr.h" |
24 | 27 | ||
28 | #include <linux/of.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | |||
25 | /* | 31 | /* |
26 | * Common ARMv7 event types | 32 | * Common ARMv7 event types |
27 | * | 33 | * |
@@ -1056,15 +1062,22 @@ static void armv7pmu_init(struct arm_pmu *cpu_pmu) | |||
1056 | cpu_pmu->max_period = (1LLU << 32) - 1; | 1062 | cpu_pmu->max_period = (1LLU << 32) - 1; |
1057 | }; | 1063 | }; |
1058 | 1064 | ||
1059 | static u32 armv7_read_num_pmnc_events(void) | 1065 | static void armv7_read_num_pmnc_events(void *info) |
1060 | { | 1066 | { |
1061 | u32 nb_cnt; | 1067 | int *nb_cnt = info; |
1062 | 1068 | ||
1063 | /* Read the nb of CNTx counters supported from PMNC */ | 1069 | /* Read the nb of CNTx counters supported from PMNC */ |
1064 | nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK; | 1070 | *nb_cnt = (armv7_pmnc_read() >> ARMV7_PMNC_N_SHIFT) & ARMV7_PMNC_N_MASK; |
1065 | 1071 | ||
1066 | /* Add the CPU cycles counter and return */ | 1072 | /* Add the CPU cycles counter */ |
1067 | return nb_cnt + 1; | 1073 | *nb_cnt += 1; |
1074 | } | ||
1075 | |||
1076 | static int armv7_probe_num_events(struct arm_pmu *arm_pmu) | ||
1077 | { | ||
1078 | return smp_call_function_any(&arm_pmu->supported_cpus, | ||
1079 | armv7_read_num_pmnc_events, | ||
1080 | &arm_pmu->num_events, 1); | ||
1068 | } | 1081 | } |
1069 | 1082 | ||
1070 | static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) | 1083 | static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1072,8 +1085,7 @@ static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) | |||
1072 | armv7pmu_init(cpu_pmu); | 1085 | armv7pmu_init(cpu_pmu); |
1073 | cpu_pmu->name = "armv7_cortex_a8"; | 1086 | cpu_pmu->name = "armv7_cortex_a8"; |
1074 | cpu_pmu->map_event = armv7_a8_map_event; | 1087 | cpu_pmu->map_event = armv7_a8_map_event; |
1075 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | 1088 | return armv7_probe_num_events(cpu_pmu); |
1076 | return 0; | ||
1077 | } | 1089 | } |
1078 | 1090 | ||
1079 | static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) | 1091 | static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1081,8 +1093,7 @@ static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) | |||
1081 | armv7pmu_init(cpu_pmu); | 1093 | armv7pmu_init(cpu_pmu); |
1082 | cpu_pmu->name = "armv7_cortex_a9"; | 1094 | cpu_pmu->name = "armv7_cortex_a9"; |
1083 | cpu_pmu->map_event = armv7_a9_map_event; | 1095 | cpu_pmu->map_event = armv7_a9_map_event; |
1084 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | 1096 | return armv7_probe_num_events(cpu_pmu); |
1085 | return 0; | ||
1086 | } | 1097 | } |
1087 | 1098 | ||
1088 | static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) | 1099 | static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1090,8 +1101,7 @@ static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) | |||
1090 | armv7pmu_init(cpu_pmu); | 1101 | armv7pmu_init(cpu_pmu); |
1091 | cpu_pmu->name = "armv7_cortex_a5"; | 1102 | cpu_pmu->name = "armv7_cortex_a5"; |
1092 | cpu_pmu->map_event = armv7_a5_map_event; | 1103 | cpu_pmu->map_event = armv7_a5_map_event; |
1093 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | 1104 | return armv7_probe_num_events(cpu_pmu); |
1094 | return 0; | ||
1095 | } | 1105 | } |
1096 | 1106 | ||
1097 | static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) | 1107 | static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1099,9 +1109,8 @@ static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) | |||
1099 | armv7pmu_init(cpu_pmu); | 1109 | armv7pmu_init(cpu_pmu); |
1100 | cpu_pmu->name = "armv7_cortex_a15"; | 1110 | cpu_pmu->name = "armv7_cortex_a15"; |
1101 | cpu_pmu->map_event = armv7_a15_map_event; | 1111 | cpu_pmu->map_event = armv7_a15_map_event; |
1102 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1103 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; | 1112 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; |
1104 | return 0; | 1113 | return armv7_probe_num_events(cpu_pmu); |
1105 | } | 1114 | } |
1106 | 1115 | ||
1107 | static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) | 1116 | static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1109,9 +1118,8 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) | |||
1109 | armv7pmu_init(cpu_pmu); | 1118 | armv7pmu_init(cpu_pmu); |
1110 | cpu_pmu->name = "armv7_cortex_a7"; | 1119 | cpu_pmu->name = "armv7_cortex_a7"; |
1111 | cpu_pmu->map_event = armv7_a7_map_event; | 1120 | cpu_pmu->map_event = armv7_a7_map_event; |
1112 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1113 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; | 1121 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; |
1114 | return 0; | 1122 | return armv7_probe_num_events(cpu_pmu); |
1115 | } | 1123 | } |
1116 | 1124 | ||
1117 | static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) | 1125 | static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1119,16 +1127,15 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) | |||
1119 | armv7pmu_init(cpu_pmu); | 1127 | armv7pmu_init(cpu_pmu); |
1120 | cpu_pmu->name = "armv7_cortex_a12"; | 1128 | cpu_pmu->name = "armv7_cortex_a12"; |
1121 | cpu_pmu->map_event = armv7_a12_map_event; | 1129 | cpu_pmu->map_event = armv7_a12_map_event; |
1122 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1123 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; | 1130 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; |
1124 | return 0; | 1131 | return armv7_probe_num_events(cpu_pmu); |
1125 | } | 1132 | } |
1126 | 1133 | ||
1127 | static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) | 1134 | static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) |
1128 | { | 1135 | { |
1129 | armv7_a12_pmu_init(cpu_pmu); | 1136 | int ret = armv7_a12_pmu_init(cpu_pmu); |
1130 | cpu_pmu->name = "armv7_cortex_a17"; | 1137 | cpu_pmu->name = "armv7_cortex_a17"; |
1131 | return 0; | 1138 | return ret; |
1132 | } | 1139 | } |
1133 | 1140 | ||
1134 | /* | 1141 | /* |
@@ -1508,14 +1515,13 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu) | |||
1508 | cpu_pmu->map_event = krait_map_event_no_branch; | 1515 | cpu_pmu->map_event = krait_map_event_no_branch; |
1509 | else | 1516 | else |
1510 | cpu_pmu->map_event = krait_map_event; | 1517 | cpu_pmu->map_event = krait_map_event; |
1511 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1512 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; | 1518 | cpu_pmu->set_event_filter = armv7pmu_set_event_filter; |
1513 | cpu_pmu->reset = krait_pmu_reset; | 1519 | cpu_pmu->reset = krait_pmu_reset; |
1514 | cpu_pmu->enable = krait_pmu_enable_event; | 1520 | cpu_pmu->enable = krait_pmu_enable_event; |
1515 | cpu_pmu->disable = krait_pmu_disable_event; | 1521 | cpu_pmu->disable = krait_pmu_disable_event; |
1516 | cpu_pmu->get_event_idx = krait_pmu_get_event_idx; | 1522 | cpu_pmu->get_event_idx = krait_pmu_get_event_idx; |
1517 | cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx; | 1523 | cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx; |
1518 | return 0; | 1524 | return armv7_probe_num_events(cpu_pmu); |
1519 | } | 1525 | } |
1520 | 1526 | ||
1521 | /* | 1527 | /* |
@@ -1833,13 +1839,12 @@ static int scorpion_pmu_init(struct arm_pmu *cpu_pmu) | |||
1833 | armv7pmu_init(cpu_pmu); | 1839 | armv7pmu_init(cpu_pmu); |
1834 | cpu_pmu->name = "armv7_scorpion"; | 1840 | cpu_pmu->name = "armv7_scorpion"; |
1835 | cpu_pmu->map_event = scorpion_map_event; | 1841 | cpu_pmu->map_event = scorpion_map_event; |
1836 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1837 | cpu_pmu->reset = scorpion_pmu_reset; | 1842 | cpu_pmu->reset = scorpion_pmu_reset; |
1838 | cpu_pmu->enable = scorpion_pmu_enable_event; | 1843 | cpu_pmu->enable = scorpion_pmu_enable_event; |
1839 | cpu_pmu->disable = scorpion_pmu_disable_event; | 1844 | cpu_pmu->disable = scorpion_pmu_disable_event; |
1840 | cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; | 1845 | cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; |
1841 | cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; | 1846 | cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; |
1842 | return 0; | 1847 | return armv7_probe_num_events(cpu_pmu); |
1843 | } | 1848 | } |
1844 | 1849 | ||
1845 | static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) | 1850 | static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) |
@@ -1847,62 +1852,52 @@ static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) | |||
1847 | armv7pmu_init(cpu_pmu); | 1852 | armv7pmu_init(cpu_pmu); |
1848 | cpu_pmu->name = "armv7_scorpion_mp"; | 1853 | cpu_pmu->name = "armv7_scorpion_mp"; |
1849 | cpu_pmu->map_event = scorpion_map_event; | 1854 | cpu_pmu->map_event = scorpion_map_event; |
1850 | cpu_pmu->num_events = armv7_read_num_pmnc_events(); | ||
1851 | cpu_pmu->reset = scorpion_pmu_reset; | 1855 | cpu_pmu->reset = scorpion_pmu_reset; |
1852 | cpu_pmu->enable = scorpion_pmu_enable_event; | 1856 | cpu_pmu->enable = scorpion_pmu_enable_event; |
1853 | cpu_pmu->disable = scorpion_pmu_disable_event; | 1857 | cpu_pmu->disable = scorpion_pmu_disable_event; |
1854 | cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; | 1858 | cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; |
1855 | cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; | 1859 | cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; |
1856 | return 0; | 1860 | return armv7_probe_num_events(cpu_pmu); |
1857 | } | 1861 | } |
1858 | #else | 1862 | |
1859 | static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) | 1863 | static const struct of_device_id armv7_pmu_of_device_ids[] = { |
1860 | { | 1864 | {.compatible = "arm,cortex-a17-pmu", .data = armv7_a17_pmu_init}, |
1861 | return -ENODEV; | 1865 | {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init}, |
1862 | } | 1866 | {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init}, |
1863 | 1867 | {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init}, | |
1864 | static inline int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) | 1868 | {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init}, |
1865 | { | 1869 | {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init}, |
1866 | return -ENODEV; | 1870 | {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init}, |
1867 | } | 1871 | {.compatible = "qcom,krait-pmu", .data = krait_pmu_init}, |
1868 | 1872 | {.compatible = "qcom,scorpion-pmu", .data = scorpion_pmu_init}, | |
1869 | static inline int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) | 1873 | {.compatible = "qcom,scorpion-mp-pmu", .data = scorpion_mp_pmu_init}, |
1870 | { | 1874 | {}, |
1871 | return -ENODEV; | 1875 | }; |
1872 | } | ||
1873 | |||
1874 | static inline int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) | ||
1875 | { | ||
1876 | return -ENODEV; | ||
1877 | } | ||
1878 | |||
1879 | static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) | ||
1880 | { | ||
1881 | return -ENODEV; | ||
1882 | } | ||
1883 | 1876 | ||
1884 | static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) | 1877 | static const struct pmu_probe_info armv7_pmu_probe_table[] = { |
1885 | { | 1878 | ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init), |
1886 | return -ENODEV; | 1879 | ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init), |
1887 | } | 1880 | { /* sentinel value */ } |
1881 | }; | ||
1888 | 1882 | ||
1889 | static inline int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) | ||
1890 | { | ||
1891 | return -ENODEV; | ||
1892 | } | ||
1893 | 1883 | ||
1894 | static inline int krait_pmu_init(struct arm_pmu *cpu_pmu) | 1884 | static int armv7_pmu_device_probe(struct platform_device *pdev) |
1895 | { | 1885 | { |
1896 | return -ENODEV; | 1886 | return arm_pmu_device_probe(pdev, armv7_pmu_of_device_ids, |
1887 | armv7_pmu_probe_table); | ||
1897 | } | 1888 | } |
1898 | 1889 | ||
1899 | static inline int scorpion_pmu_init(struct arm_pmu *cpu_pmu) | 1890 | static struct platform_driver armv7_pmu_driver = { |
1900 | { | 1891 | .driver = { |
1901 | return -ENODEV; | 1892 | .name = "armv7-pmu", |
1902 | } | 1893 | .of_match_table = armv7_pmu_of_device_ids, |
1894 | }, | ||
1895 | .probe = armv7_pmu_device_probe, | ||
1896 | }; | ||
1903 | 1897 | ||
1904 | static inline int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) | 1898 | static int __init register_armv7_pmu_driver(void) |
1905 | { | 1899 | { |
1906 | return -ENODEV; | 1900 | return platform_driver_register(&armv7_pmu_driver); |
1907 | } | 1901 | } |
1902 | device_initcall(register_armv7_pmu_driver); | ||
1908 | #endif /* CONFIG_CPU_V7 */ | 1903 | #endif /* CONFIG_CPU_V7 */ |
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index 8af9f1f82c68..304d056d5b25 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c | |||
@@ -13,6 +13,14 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #ifdef CONFIG_CPU_XSCALE | 15 | #ifdef CONFIG_CPU_XSCALE |
16 | |||
17 | #include <asm/cputype.h> | ||
18 | #include <asm/irq_regs.h> | ||
19 | #include <asm/pmu.h> | ||
20 | |||
21 | #include <linux/of.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
16 | enum xscale_perf_types { | 24 | enum xscale_perf_types { |
17 | XSCALE_PERFCTR_ICACHE_MISS = 0x00, | 25 | XSCALE_PERFCTR_ICACHE_MISS = 0x00, |
18 | XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01, | 26 | XSCALE_PERFCTR_ICACHE_NO_DELIVER = 0x01, |
@@ -740,14 +748,28 @@ static int xscale2pmu_init(struct arm_pmu *cpu_pmu) | |||
740 | 748 | ||
741 | return 0; | 749 | return 0; |
742 | } | 750 | } |
743 | #else | 751 | |
744 | static inline int xscale1pmu_init(struct arm_pmu *cpu_pmu) | 752 | static const struct pmu_probe_info xscale_pmu_probe_table[] = { |
753 | XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init), | ||
754 | XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init), | ||
755 | { /* sentinel value */ } | ||
756 | }; | ||
757 | |||
758 | static int xscale_pmu_device_probe(struct platform_device *pdev) | ||
745 | { | 759 | { |
746 | return -ENODEV; | 760 | return arm_pmu_device_probe(pdev, NULL, xscale_pmu_probe_table); |
747 | } | 761 | } |
748 | 762 | ||
749 | static inline int xscale2pmu_init(struct arm_pmu *cpu_pmu) | 763 | static struct platform_driver xscale_pmu_driver = { |
764 | .driver = { | ||
765 | .name = "xscale-pmu", | ||
766 | }, | ||
767 | .probe = xscale_pmu_device_probe, | ||
768 | }; | ||
769 | |||
770 | static int __init register_xscale_pmu_driver(void) | ||
750 | { | 771 | { |
751 | return -ENODEV; | 772 | return platform_driver_register(&xscale_pmu_driver); |
752 | } | 773 | } |
774 | device_initcall(register_xscale_pmu_driver); | ||
753 | #endif /* CONFIG_CPU_XSCALE */ | 775 | #endif /* CONFIG_CPU_XSCALE */ |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 6c777e908a24..e6d8c7658ffd 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -75,8 +75,7 @@ __setup("fpe=", fpe_setup); | |||
75 | 75 | ||
76 | extern void init_default_cache_policy(unsigned long); | 76 | extern void init_default_cache_policy(unsigned long); |
77 | extern void paging_init(const struct machine_desc *desc); | 77 | extern void paging_init(const struct machine_desc *desc); |
78 | extern void early_paging_init(const struct machine_desc *, | 78 | extern void early_paging_init(const struct machine_desc *); |
79 | struct proc_info_list *); | ||
80 | extern void sanity_check_meminfo(void); | 79 | extern void sanity_check_meminfo(void); |
81 | extern enum reboot_mode reboot_mode; | 80 | extern enum reboot_mode reboot_mode; |
82 | extern void setup_dma_zone(const struct machine_desc *desc); | 81 | extern void setup_dma_zone(const struct machine_desc *desc); |
@@ -93,6 +92,9 @@ unsigned int __atags_pointer __initdata; | |||
93 | unsigned int system_rev; | 92 | unsigned int system_rev; |
94 | EXPORT_SYMBOL(system_rev); | 93 | EXPORT_SYMBOL(system_rev); |
95 | 94 | ||
95 | const char *system_serial; | ||
96 | EXPORT_SYMBOL(system_serial); | ||
97 | |||
96 | unsigned int system_serial_low; | 98 | unsigned int system_serial_low; |
97 | EXPORT_SYMBOL(system_serial_low); | 99 | EXPORT_SYMBOL(system_serial_low); |
98 | 100 | ||
@@ -839,8 +841,25 @@ arch_initcall(customize_machine); | |||
839 | 841 | ||
840 | static int __init init_machine_late(void) | 842 | static int __init init_machine_late(void) |
841 | { | 843 | { |
844 | struct device_node *root; | ||
845 | int ret; | ||
846 | |||
842 | if (machine_desc->init_late) | 847 | if (machine_desc->init_late) |
843 | machine_desc->init_late(); | 848 | machine_desc->init_late(); |
849 | |||
850 | root = of_find_node_by_path("/"); | ||
851 | if (root) { | ||
852 | ret = of_property_read_string(root, "serial-number", | ||
853 | &system_serial); | ||
854 | if (ret) | ||
855 | system_serial = NULL; | ||
856 | } | ||
857 | |||
858 | if (!system_serial) | ||
859 | system_serial = kasprintf(GFP_KERNEL, "%08x%08x", | ||
860 | system_serial_high, | ||
861 | system_serial_low); | ||
862 | |||
844 | return 0; | 863 | return 0; |
845 | } | 864 | } |
846 | late_initcall(init_machine_late); | 865 | late_initcall(init_machine_late); |
@@ -936,7 +955,9 @@ void __init setup_arch(char **cmdline_p) | |||
936 | 955 | ||
937 | parse_early_param(); | 956 | parse_early_param(); |
938 | 957 | ||
939 | early_paging_init(mdesc, lookup_processor_type(read_cpuid_id())); | 958 | #ifdef CONFIG_MMU |
959 | early_paging_init(mdesc); | ||
960 | #endif | ||
940 | setup_dma_zone(mdesc); | 961 | setup_dma_zone(mdesc); |
941 | sanity_check_meminfo(); | 962 | sanity_check_meminfo(); |
942 | arm_memblock_init(mdesc); | 963 | arm_memblock_init(mdesc); |
@@ -1109,8 +1130,7 @@ static int c_show(struct seq_file *m, void *v) | |||
1109 | 1130 | ||
1110 | seq_printf(m, "Hardware\t: %s\n", machine_name); | 1131 | seq_printf(m, "Hardware\t: %s\n", machine_name); |
1111 | seq_printf(m, "Revision\t: %04x\n", system_rev); | 1132 | seq_printf(m, "Revision\t: %04x\n", system_rev); |
1112 | seq_printf(m, "Serial\t\t: %08x%08x\n", | 1133 | seq_printf(m, "Serial\t\t: %s\n", system_serial); |
1113 | system_serial_high, system_serial_low); | ||
1114 | 1134 | ||
1115 | return 0; | 1135 | return 0; |
1116 | } | 1136 | } |
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index 6060dbc7844e..0f6c1000582c 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S | |||
@@ -81,7 +81,7 @@ ENTRY(__cpu_suspend) | |||
81 | mov r1, r4 @ size of save block | 81 | mov r1, r4 @ size of save block |
82 | add r0, sp, #8 @ pointer to save block | 82 | add r0, sp, #8 @ pointer to save block |
83 | bl __cpu_suspend_save | 83 | bl __cpu_suspend_save |
84 | adr lr, BSYM(cpu_suspend_abort) | 84 | badr lr, cpu_suspend_abort |
85 | ldmfd sp!, {r0, pc} @ call suspend fn | 85 | ldmfd sp!, {r0, pc} @ call suspend fn |
86 | ENDPROC(__cpu_suspend) | 86 | ENDPROC(__cpu_suspend) |
87 | .ltorg | 87 | .ltorg |
@@ -122,7 +122,7 @@ ENDPROC(cpu_resume_after_mmu) | |||
122 | #ifdef CONFIG_MMU | 122 | #ifdef CONFIG_MMU |
123 | .arm | 123 | .arm |
124 | ENTRY(cpu_resume_arm) | 124 | ENTRY(cpu_resume_arm) |
125 | THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM. | 125 | THUMB( badr r9, 1f ) @ Kernel is entered in ARM. |
126 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, | 126 | THUMB( bx r9 ) @ If this is a Thumb-2 kernel, |
127 | THUMB( .thumb ) @ switch to Thumb now. | 127 | THUMB( .thumb ) @ switch to Thumb now. |
128 | THUMB(1: ) | 128 | THUMB(1: ) |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index cca5b8758185..90dfbedfbfb8 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -86,9 +86,11 @@ void __init smp_set_ops(struct smp_operations *ops) | |||
86 | 86 | ||
87 | static unsigned long get_arch_pgd(pgd_t *pgd) | 87 | static unsigned long get_arch_pgd(pgd_t *pgd) |
88 | { | 88 | { |
89 | phys_addr_t pgdir = virt_to_idmap(pgd); | 89 | #ifdef CONFIG_ARM_LPAE |
90 | BUG_ON(pgdir & ARCH_PGD_MASK); | 90 | return __phys_to_pfn(virt_to_phys(pgd)); |
91 | return pgdir >> ARCH_PGD_SHIFT; | 91 | #else |
92 | return virt_to_phys(pgd); | ||
93 | #endif | ||
92 | } | 94 | } |
93 | 95 | ||
94 | int __cpu_up(unsigned int cpu, struct task_struct *idle) | 96 | int __cpu_up(unsigned int cpu, struct task_struct *idle) |
@@ -108,7 +110,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) | |||
108 | #endif | 110 | #endif |
109 | 111 | ||
110 | #ifdef CONFIG_MMU | 112 | #ifdef CONFIG_MMU |
111 | secondary_data.pgdir = get_arch_pgd(idmap_pgd); | 113 | secondary_data.pgdir = virt_to_phys(idmap_pgd); |
112 | secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir); | 114 | secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir); |
113 | #endif | 115 | #endif |
114 | sync_cache_w(&secondary_data); | 116 | sync_cache_w(&secondary_data); |
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index 7a3be1d4d0b1..b10e1360762e 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <asm/mach/map.h> | 17 | #include <asm/mach/map.h> |
18 | #include <asm/memory.h> | 18 | #include <asm/memory.h> |
19 | #include <asm/system_info.h> | 19 | #include <asm/system_info.h> |
20 | #include <asm/traps.h> | ||
21 | |||
22 | #define TCMTR_FORMAT_MASK 0xe0000000U | ||
20 | 23 | ||
21 | static struct gen_pool *tcm_pool; | 24 | static struct gen_pool *tcm_pool; |
22 | static bool dtcm_present; | 25 | static bool dtcm_present; |
@@ -176,6 +179,77 @@ static int __init setup_tcm_bank(u8 type, u8 bank, u8 banks, | |||
176 | } | 179 | } |
177 | 180 | ||
178 | /* | 181 | /* |
182 | * When we are running in the non-secure world and the secure world | ||
183 | * has not explicitly given us access to the TCM we will get an | ||
184 | * undefined error when reading the TCM region register in the | ||
185 | * setup_tcm_bank function (above). | ||
186 | * | ||
187 | * There are two variants of this register read that we need to trap, | ||
188 | * the read for the data TCM and the read for the instruction TCM: | ||
189 | * c0370628: ee196f11 mrc 15, 0, r6, cr9, cr1, {0} | ||
190 | * c0370674: ee196f31 mrc 15, 0, r6, cr9, cr1, {1} | ||
191 | * | ||
192 | * Our undef hook mask explicitly matches all fields of the encoded | ||
193 | * instruction other than the destination register. The mask also | ||
194 | * only allows operand 2 to have the values 0 or 1. | ||
195 | * | ||
196 | * The undefined hook is defined as __init and __initdata, and therefore | ||
197 | * must be removed before tcm_init returns. | ||
198 | * | ||
199 | * In this particular case (MRC with ARM condition code ALways) the | ||
200 | * Thumb-2 and ARM instruction encoding are identical, so this hook | ||
201 | * will work on a Thumb-2 kernel. | ||
202 | * | ||
203 | * See A8.8.107, DDI0406C_C ARM Architecture Reference Manual, Encoding | ||
204 | * T1/A1 for the bit-by-bit details. | ||
205 | * | ||
206 | * mrc p15, 0, XX, c9, c1, 0 | ||
207 | * mrc p15, 0, XX, c9, c1, 1 | ||
208 | * | | | | | | | +---- opc2 0|1 = 000|001 | ||
209 | * | | | | | | +------- CRm 0 = 0001 | ||
210 | * | | | | | +----------- CRn 0 = 1001 | ||
211 | * | | | | +--------------- Rt ? = ???? | ||
212 | * | | | +------------------- opc1 0 = 000 | ||
213 | * | | +----------------------- coproc 15 = 1111 | ||
214 | * | +-------------------------- condition ALways = 1110 | ||
215 | * +----------------------------- instruction MRC = 1110 | ||
216 | * | ||
217 | * Encoding this as per A8.8.107 of DDI0406C, Encoding T1/A1, yields: | ||
218 | * 1111 1111 1111 1111 0000 1111 1101 1111 Required Mask | ||
219 | * 1110 1110 0001 1001 ???? 1111 0001 0001 mrc p15, 0, XX, c9, c1, 0 | ||
220 | * 1110 1110 0001 1001 ???? 1111 0011 0001 mrc p15, 0, XX, c9, c1, 1 | ||
221 | * [ ] [ ] [ ]| [ ] [ ] [ ] [ ]| +--- CRm | ||
222 | * | | | | | | | | +----- SBO | ||
223 | * | | | | | | | +------- opc2 | ||
224 | * | | | | | | +----------- coproc | ||
225 | * | | | | | +---------------- Rt | ||
226 | * | | | | +--------------------- CRn | ||
227 | * | | | +------------------------- SBO | ||
228 | * | | +--------------------------- opc1 | ||
229 | * | +------------------------------- instruction | ||
230 | * +------------------------------------ condition | ||
231 | */ | ||
232 | #define TCM_REGION_READ_MASK 0xffff0fdf | ||
233 | #define TCM_REGION_READ_INSTR 0xee190f11 | ||
234 | #define DEST_REG_SHIFT 12 | ||
235 | #define DEST_REG_MASK 0xf | ||
236 | |||
237 | static int __init tcm_handler(struct pt_regs *regs, unsigned int instr) | ||
238 | { | ||
239 | regs->uregs[(instr >> DEST_REG_SHIFT) & DEST_REG_MASK] = 0; | ||
240 | regs->ARM_pc += 4; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static struct undef_hook tcm_hook __initdata = { | ||
245 | .instr_mask = TCM_REGION_READ_MASK, | ||
246 | .instr_val = TCM_REGION_READ_INSTR, | ||
247 | .cpsr_mask = MODE_MASK, | ||
248 | .cpsr_val = SVC_MODE, | ||
249 | .fn = tcm_handler | ||
250 | }; | ||
251 | |||
252 | /* | ||
179 | * This initializes the TCM memory | 253 | * This initializes the TCM memory |
180 | */ | 254 | */ |
181 | void __init tcm_init(void) | 255 | void __init tcm_init(void) |
@@ -204,9 +278,18 @@ void __init tcm_init(void) | |||
204 | } | 278 | } |
205 | 279 | ||
206 | tcm_status = read_cpuid_tcmstatus(); | 280 | tcm_status = read_cpuid_tcmstatus(); |
281 | |||
282 | /* | ||
283 | * This code only supports v6-compatible TCMTR implementations. | ||
284 | */ | ||
285 | if (tcm_status & TCMTR_FORMAT_MASK) | ||
286 | return; | ||
287 | |||
207 | dtcm_banks = (tcm_status >> 16) & 0x03; | 288 | dtcm_banks = (tcm_status >> 16) & 0x03; |
208 | itcm_banks = (tcm_status & 0x03); | 289 | itcm_banks = (tcm_status & 0x03); |
209 | 290 | ||
291 | register_undef_hook(&tcm_hook); | ||
292 | |||
210 | /* Values greater than 2 for D/ITCM banks are "reserved" */ | 293 | /* Values greater than 2 for D/ITCM banks are "reserved" */ |
211 | if (dtcm_banks > 2) | 294 | if (dtcm_banks > 2) |
212 | dtcm_banks = 0; | 295 | dtcm_banks = 0; |
@@ -218,7 +301,7 @@ void __init tcm_init(void) | |||
218 | for (i = 0; i < dtcm_banks; i++) { | 301 | for (i = 0; i < dtcm_banks; i++) { |
219 | ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end); | 302 | ret = setup_tcm_bank(0, i, dtcm_banks, &dtcm_end); |
220 | if (ret) | 303 | if (ret) |
221 | return; | 304 | goto unregister; |
222 | } | 305 | } |
223 | /* This means you compiled more code than fits into DTCM */ | 306 | /* This means you compiled more code than fits into DTCM */ |
224 | if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { | 307 | if (dtcm_code_sz > (dtcm_end - DTCM_OFFSET)) { |
@@ -227,6 +310,12 @@ void __init tcm_init(void) | |||
227 | dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); | 310 | dtcm_code_sz, (dtcm_end - DTCM_OFFSET)); |
228 | goto no_dtcm; | 311 | goto no_dtcm; |
229 | } | 312 | } |
313 | /* | ||
314 | * This means that the DTCM sizes were 0 or the DTCM banks | ||
315 | * were inaccessible due to TrustZone configuration. | ||
316 | */ | ||
317 | if (!(dtcm_end - DTCM_OFFSET)) | ||
318 | goto no_dtcm; | ||
230 | dtcm_res.end = dtcm_end - 1; | 319 | dtcm_res.end = dtcm_end - 1; |
231 | request_resource(&iomem_resource, &dtcm_res); | 320 | request_resource(&iomem_resource, &dtcm_res); |
232 | dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; | 321 | dtcm_iomap[0].length = dtcm_end - DTCM_OFFSET; |
@@ -250,15 +339,21 @@ no_dtcm: | |||
250 | for (i = 0; i < itcm_banks; i++) { | 339 | for (i = 0; i < itcm_banks; i++) { |
251 | ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end); | 340 | ret = setup_tcm_bank(1, i, itcm_banks, &itcm_end); |
252 | if (ret) | 341 | if (ret) |
253 | return; | 342 | goto unregister; |
254 | } | 343 | } |
255 | /* This means you compiled more code than fits into ITCM */ | 344 | /* This means you compiled more code than fits into ITCM */ |
256 | if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { | 345 | if (itcm_code_sz > (itcm_end - ITCM_OFFSET)) { |
257 | pr_info("CPU ITCM: %u bytes of code compiled to " | 346 | pr_info("CPU ITCM: %u bytes of code compiled to " |
258 | "ITCM but only %lu bytes of ITCM present\n", | 347 | "ITCM but only %lu bytes of ITCM present\n", |
259 | itcm_code_sz, (itcm_end - ITCM_OFFSET)); | 348 | itcm_code_sz, (itcm_end - ITCM_OFFSET)); |
260 | return; | 349 | goto unregister; |
261 | } | 350 | } |
351 | /* | ||
352 | * This means that the ITCM sizes were 0 or the ITCM banks | ||
353 | * were inaccessible due to TrustZone configuration. | ||
354 | */ | ||
355 | if (!(itcm_end - ITCM_OFFSET)) | ||
356 | goto unregister; | ||
262 | itcm_res.end = itcm_end - 1; | 357 | itcm_res.end = itcm_end - 1; |
263 | request_resource(&iomem_resource, &itcm_res); | 358 | request_resource(&iomem_resource, &itcm_res); |
264 | itcm_iomap[0].length = itcm_end - ITCM_OFFSET; | 359 | itcm_iomap[0].length = itcm_end - ITCM_OFFSET; |
@@ -275,6 +370,9 @@ no_dtcm: | |||
275 | pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " | 370 | pr_info("CPU ITCM: %u bytes of code compiled to ITCM but no " |
276 | "ITCM banks present in CPU\n", itcm_code_sz); | 371 | "ITCM banks present in CPU\n", itcm_code_sz); |
277 | } | 372 | } |
373 | |||
374 | unregister: | ||
375 | unregister_undef_hook(&tcm_hook); | ||
278 | } | 376 | } |
279 | 377 | ||
280 | /* | 378 | /* |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3dce1a342030..d358226236f2 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -749,14 +749,6 @@ late_initcall(arm_mrc_hook_init); | |||
749 | 749 | ||
750 | #endif | 750 | #endif |
751 | 751 | ||
752 | void __bad_xchg(volatile void *ptr, int size) | ||
753 | { | ||
754 | pr_err("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", | ||
755 | __builtin_return_address(0), ptr, size); | ||
756 | BUG(); | ||
757 | } | ||
758 | EXPORT_SYMBOL(__bad_xchg); | ||
759 | |||
760 | /* | 752 | /* |
761 | * A data abort trap was taken, but we did not handle the instruction. | 753 | * A data abort trap was taken, but we did not handle the instruction. |
762 | * Try to abort the user program, or panic if it was the kernel. | 754 | * Try to abort the user program, or panic if it was the kernel. |
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S index f7db3a5d80e3..568494dbbbb5 100644 --- a/arch/arm/kvm/interrupts.S +++ b/arch/arm/kvm/interrupts.S | |||
@@ -307,7 +307,7 @@ ENTRY(kvm_call_hyp) | |||
307 | THUMB( orr r2, r2, #PSR_T_BIT ) | 307 | THUMB( orr r2, r2, #PSR_T_BIT ) |
308 | msr spsr_cxsf, r2 | 308 | msr spsr_cxsf, r2 |
309 | mrs r1, ELR_hyp | 309 | mrs r1, ELR_hyp |
310 | ldr r2, =BSYM(panic) | 310 | ldr r2, =panic |
311 | msr ELR_hyp, r2 | 311 | msr ELR_hyp, r2 |
312 | ldr r0, =\panic_str | 312 | ldr r0, =\panic_str |
313 | clrex @ Clear exclusive monitor | 313 | clrex @ Clear exclusive monitor |
diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S index ed1a421813cb..bf3a40889205 100644 --- a/arch/arm/lib/call_with_stack.S +++ b/arch/arm/lib/call_with_stack.S | |||
@@ -35,7 +35,7 @@ ENTRY(call_with_stack) | |||
35 | mov r2, r0 | 35 | mov r2, r0 |
36 | mov r0, r1 | 36 | mov r0, r1 |
37 | 37 | ||
38 | adr lr, BSYM(1f) | 38 | badr lr, 1f |
39 | ret r2 | 39 | ret r2 |
40 | 40 | ||
41 | 1: ldr lr, [sp] | 41 | 1: ldr lr, [sp] |
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 96866d03d281..f572219c7a40 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c | |||
@@ -311,13 +311,7 @@ static int exynos5420_cpu_suspend(unsigned long arg) | |||
311 | 311 | ||
312 | if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { | 312 | if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { |
313 | mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); | 313 | mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); |
314 | 314 | mcpm_cpu_suspend(); | |
315 | /* | ||
316 | * Residency value passed to mcpm_cpu_suspend back-end | ||
317 | * has to be given clear semantics. Set to 0 as a | ||
318 | * temporary value. | ||
319 | */ | ||
320 | mcpm_cpu_suspend(0); | ||
321 | } | 315 | } |
322 | 316 | ||
323 | pr_info("Failed to suspend the system\n"); | 317 | pr_info("Failed to suspend the system\n"); |
diff --git a/arch/arm/mach-hisi/platmcpm.c b/arch/arm/mach-hisi/platmcpm.c index 280f3f14f77c..b5f8f5ffda79 100644 --- a/arch/arm/mach-hisi/platmcpm.c +++ b/arch/arm/mach-hisi/platmcpm.c | |||
@@ -6,6 +6,8 @@ | |||
6 | * under the terms and conditions of the GNU General Public License, | 6 | * under the terms and conditions of the GNU General Public License, |
7 | * version 2, as published by the Free Software Foundation. | 7 | * version 2, as published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | #include <linux/init.h> | ||
10 | #include <linux/smp.h> | ||
9 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
10 | #include <linux/io.h> | 12 | #include <linux/io.h> |
11 | #include <linux/memblock.h> | 13 | #include <linux/memblock.h> |
@@ -13,7 +15,9 @@ | |||
13 | 15 | ||
14 | #include <asm/cputype.h> | 16 | #include <asm/cputype.h> |
15 | #include <asm/cp15.h> | 17 | #include <asm/cp15.h> |
16 | #include <asm/mcpm.h> | 18 | #include <asm/cacheflush.h> |
19 | #include <asm/smp.h> | ||
20 | #include <asm/smp_plat.h> | ||
17 | 21 | ||
18 | #include "core.h" | 22 | #include "core.h" |
19 | 23 | ||
@@ -94,11 +98,16 @@ static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on) | |||
94 | } while (data != readl_relaxed(fabric + FAB_SF_MODE)); | 98 | } while (data != readl_relaxed(fabric + FAB_SF_MODE)); |
95 | } | 99 | } |
96 | 100 | ||
97 | static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) | 101 | static int hip04_boot_secondary(unsigned int l_cpu, struct task_struct *idle) |
98 | { | 102 | { |
103 | unsigned int mpidr, cpu, cluster; | ||
99 | unsigned long data; | 104 | unsigned long data; |
100 | void __iomem *sys_dreq, *sys_status; | 105 | void __iomem *sys_dreq, *sys_status; |
101 | 106 | ||
107 | mpidr = cpu_logical_map(l_cpu); | ||
108 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
109 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
110 | |||
102 | if (!sysctrl) | 111 | if (!sysctrl) |
103 | return -ENODEV; | 112 | return -ENODEV; |
104 | if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER) | 113 | if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER) |
@@ -118,6 +127,7 @@ static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) | |||
118 | cpu_relax(); | 127 | cpu_relax(); |
119 | data = readl_relaxed(sys_status); | 128 | data = readl_relaxed(sys_status); |
120 | } while (data & CLUSTER_DEBUG_RESET_STATUS); | 129 | } while (data & CLUSTER_DEBUG_RESET_STATUS); |
130 | hip04_set_snoop_filter(cluster, 1); | ||
121 | } | 131 | } |
122 | 132 | ||
123 | data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ | 133 | data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \ |
@@ -126,11 +136,15 @@ static int hip04_mcpm_power_up(unsigned int cpu, unsigned int cluster) | |||
126 | do { | 136 | do { |
127 | cpu_relax(); | 137 | cpu_relax(); |
128 | } while (data == readl_relaxed(sys_status)); | 138 | } while (data == readl_relaxed(sys_status)); |
139 | |||
129 | /* | 140 | /* |
130 | * We may fail to power up core again without this delay. | 141 | * We may fail to power up core again without this delay. |
131 | * It's not mentioned in document. It's found by test. | 142 | * It's not mentioned in document. It's found by test. |
132 | */ | 143 | */ |
133 | udelay(20); | 144 | udelay(20); |
145 | |||
146 | arch_send_wakeup_ipi_mask(cpumask_of(l_cpu)); | ||
147 | |||
134 | out: | 148 | out: |
135 | hip04_cpu_table[cluster][cpu]++; | 149 | hip04_cpu_table[cluster][cpu]++; |
136 | spin_unlock_irq(&boot_lock); | 150 | spin_unlock_irq(&boot_lock); |
@@ -138,31 +152,30 @@ out: | |||
138 | return 0; | 152 | return 0; |
139 | } | 153 | } |
140 | 154 | ||
141 | static void hip04_mcpm_power_down(void) | 155 | #ifdef CONFIG_HOTPLUG_CPU |
156 | static void hip04_cpu_die(unsigned int l_cpu) | ||
142 | { | 157 | { |
143 | unsigned int mpidr, cpu, cluster; | 158 | unsigned int mpidr, cpu, cluster; |
144 | bool skip_wfi = false, last_man = false; | 159 | bool last_man; |
145 | 160 | ||
146 | mpidr = read_cpuid_mpidr(); | 161 | mpidr = cpu_logical_map(l_cpu); |
147 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | 162 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); |
148 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | 163 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); |
149 | 164 | ||
150 | __mcpm_cpu_going_down(cpu, cluster); | ||
151 | |||
152 | spin_lock(&boot_lock); | 165 | spin_lock(&boot_lock); |
153 | BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); | ||
154 | hip04_cpu_table[cluster][cpu]--; | 166 | hip04_cpu_table[cluster][cpu]--; |
155 | if (hip04_cpu_table[cluster][cpu] == 1) { | 167 | if (hip04_cpu_table[cluster][cpu] == 1) { |
156 | /* A power_up request went ahead of us. */ | 168 | /* A power_up request went ahead of us. */ |
157 | skip_wfi = true; | 169 | spin_unlock(&boot_lock); |
170 | return; | ||
158 | } else if (hip04_cpu_table[cluster][cpu] > 1) { | 171 | } else if (hip04_cpu_table[cluster][cpu] > 1) { |
159 | pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu); | 172 | pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu); |
160 | BUG(); | 173 | BUG(); |
161 | } | 174 | } |
162 | 175 | ||
163 | last_man = hip04_cluster_is_down(cluster); | 176 | last_man = hip04_cluster_is_down(cluster); |
164 | if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { | 177 | spin_unlock(&boot_lock); |
165 | spin_unlock(&boot_lock); | 178 | if (last_man) { |
166 | /* Since it's Cortex A15, disable L2 prefetching. */ | 179 | /* Since it's Cortex A15, disable L2 prefetching. */ |
167 | asm volatile( | 180 | asm volatile( |
168 | "mcr p15, 1, %0, c15, c0, 3 \n\t" | 181 | "mcr p15, 1, %0, c15, c0, 3 \n\t" |
@@ -170,34 +183,30 @@ static void hip04_mcpm_power_down(void) | |||
170 | "dsb " | 183 | "dsb " |
171 | : : "r" (0x400) ); | 184 | : : "r" (0x400) ); |
172 | v7_exit_coherency_flush(all); | 185 | v7_exit_coherency_flush(all); |
173 | hip04_set_snoop_filter(cluster, 0); | ||
174 | __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); | ||
175 | } else { | 186 | } else { |
176 | spin_unlock(&boot_lock); | ||
177 | v7_exit_coherency_flush(louis); | 187 | v7_exit_coherency_flush(louis); |
178 | } | 188 | } |
179 | 189 | ||
180 | __mcpm_cpu_down(cpu, cluster); | 190 | for (;;) |
181 | |||
182 | if (!skip_wfi) | ||
183 | wfi(); | 191 | wfi(); |
184 | } | 192 | } |
185 | 193 | ||
186 | static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) | 194 | static int hip04_cpu_kill(unsigned int l_cpu) |
187 | { | 195 | { |
196 | unsigned int mpidr, cpu, cluster; | ||
188 | unsigned int data, tries, count; | 197 | unsigned int data, tries, count; |
189 | int ret = -ETIMEDOUT; | ||
190 | 198 | ||
199 | mpidr = cpu_logical_map(l_cpu); | ||
200 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
201 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
191 | BUG_ON(cluster >= HIP04_MAX_CLUSTERS || | 202 | BUG_ON(cluster >= HIP04_MAX_CLUSTERS || |
192 | cpu >= HIP04_MAX_CPUS_PER_CLUSTER); | 203 | cpu >= HIP04_MAX_CPUS_PER_CLUSTER); |
193 | 204 | ||
194 | count = TIMEOUT_MSEC / POLL_MSEC; | 205 | count = TIMEOUT_MSEC / POLL_MSEC; |
195 | spin_lock_irq(&boot_lock); | 206 | spin_lock_irq(&boot_lock); |
196 | for (tries = 0; tries < count; tries++) { | 207 | for (tries = 0; tries < count; tries++) { |
197 | if (hip04_cpu_table[cluster][cpu]) { | 208 | if (hip04_cpu_table[cluster][cpu]) |
198 | ret = -EBUSY; | ||
199 | goto err; | 209 | goto err; |
200 | } | ||
201 | cpu_relax(); | 210 | cpu_relax(); |
202 | data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); | 211 | data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster)); |
203 | if (data & CORE_WFI_STATUS(cpu)) | 212 | if (data & CORE_WFI_STATUS(cpu)) |
@@ -220,64 +229,22 @@ static int hip04_mcpm_wait_for_powerdown(unsigned int cpu, unsigned int cluster) | |||
220 | } | 229 | } |
221 | if (tries >= count) | 230 | if (tries >= count) |
222 | goto err; | 231 | goto err; |
232 | if (hip04_cluster_is_down(cluster)) | ||
233 | hip04_set_snoop_filter(cluster, 0); | ||
223 | spin_unlock_irq(&boot_lock); | 234 | spin_unlock_irq(&boot_lock); |
224 | return 0; | 235 | return 1; |
225 | err: | 236 | err: |
226 | spin_unlock_irq(&boot_lock); | 237 | spin_unlock_irq(&boot_lock); |
227 | return ret; | 238 | return 0; |
228 | } | ||
229 | |||
230 | static void hip04_mcpm_powered_up(void) | ||
231 | { | ||
232 | unsigned int mpidr, cpu, cluster; | ||
233 | |||
234 | mpidr = read_cpuid_mpidr(); | ||
235 | cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
236 | cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
237 | |||
238 | spin_lock(&boot_lock); | ||
239 | if (!hip04_cpu_table[cluster][cpu]) | ||
240 | hip04_cpu_table[cluster][cpu] = 1; | ||
241 | spin_unlock(&boot_lock); | ||
242 | } | ||
243 | |||
244 | static void __naked hip04_mcpm_power_up_setup(unsigned int affinity_level) | ||
245 | { | ||
246 | asm volatile (" \n" | ||
247 | " cmp r0, #0 \n" | ||
248 | " bxeq lr \n" | ||
249 | /* calculate fabric phys address */ | ||
250 | " adr r2, 2f \n" | ||
251 | " ldmia r2, {r1, r3} \n" | ||
252 | " sub r0, r2, r1 \n" | ||
253 | " ldr r2, [r0, r3] \n" | ||
254 | /* get cluster id from MPIDR */ | ||
255 | " mrc p15, 0, r0, c0, c0, 5 \n" | ||
256 | " ubfx r1, r0, #8, #8 \n" | ||
257 | /* 1 << cluster id */ | ||
258 | " mov r0, #1 \n" | ||
259 | " mov r3, r0, lsl r1 \n" | ||
260 | " ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n" | ||
261 | " tst r0, r3 \n" | ||
262 | " bxne lr \n" | ||
263 | " orr r1, r0, r3 \n" | ||
264 | " str r1, [r2, #"__stringify(FAB_SF_MODE)"] \n" | ||
265 | "1: ldr r0, [r2, #"__stringify(FAB_SF_MODE)"] \n" | ||
266 | " tst r0, r3 \n" | ||
267 | " beq 1b \n" | ||
268 | " bx lr \n" | ||
269 | |||
270 | " .align 2 \n" | ||
271 | "2: .word . \n" | ||
272 | " .word fabric_phys_addr \n" | ||
273 | ); | ||
274 | } | 239 | } |
275 | 240 | #endif | |
276 | static const struct mcpm_platform_ops hip04_mcpm_ops = { | 241 | |
277 | .power_up = hip04_mcpm_power_up, | 242 | static struct smp_operations __initdata hip04_smp_ops = { |
278 | .power_down = hip04_mcpm_power_down, | 243 | .smp_boot_secondary = hip04_boot_secondary, |
279 | .wait_for_powerdown = hip04_mcpm_wait_for_powerdown, | 244 | #ifdef CONFIG_HOTPLUG_CPU |
280 | .powered_up = hip04_mcpm_powered_up, | 245 | .cpu_die = hip04_cpu_die, |
246 | .cpu_kill = hip04_cpu_kill, | ||
247 | #endif | ||
281 | }; | 248 | }; |
282 | 249 | ||
283 | static bool __init hip04_cpu_table_init(void) | 250 | static bool __init hip04_cpu_table_init(void) |
@@ -298,7 +265,7 @@ static bool __init hip04_cpu_table_init(void) | |||
298 | return true; | 265 | return true; |
299 | } | 266 | } |
300 | 267 | ||
301 | static int __init hip04_mcpm_init(void) | 268 | static int __init hip04_smp_init(void) |
302 | { | 269 | { |
303 | struct device_node *np, *np_sctl, *np_fab; | 270 | struct device_node *np, *np_sctl, *np_fab; |
304 | struct resource fab_res; | 271 | struct resource fab_res; |
@@ -353,10 +320,6 @@ static int __init hip04_mcpm_init(void) | |||
353 | ret = -EINVAL; | 320 | ret = -EINVAL; |
354 | goto err_table; | 321 | goto err_table; |
355 | } | 322 | } |
356 | ret = mcpm_platform_register(&hip04_mcpm_ops); | ||
357 | if (ret) { | ||
358 | goto err_table; | ||
359 | } | ||
360 | 323 | ||
361 | /* | 324 | /* |
362 | * Fill the instruction address that is used after secondary core | 325 | * Fill the instruction address that is used after secondary core |
@@ -364,13 +327,11 @@ static int __init hip04_mcpm_init(void) | |||
364 | */ | 327 | */ |
365 | writel_relaxed(hip04_boot_method[0], relocation); | 328 | writel_relaxed(hip04_boot_method[0], relocation); |
366 | writel_relaxed(0xa5a5a5a5, relocation + 4); /* magic number */ | 329 | writel_relaxed(0xa5a5a5a5, relocation + 4); /* magic number */ |
367 | writel_relaxed(virt_to_phys(mcpm_entry_point), relocation + 8); | 330 | writel_relaxed(virt_to_phys(secondary_startup), relocation + 8); |
368 | writel_relaxed(0, relocation + 12); | 331 | writel_relaxed(0, relocation + 12); |
369 | iounmap(relocation); | 332 | iounmap(relocation); |
370 | 333 | ||
371 | mcpm_sync_init(hip04_mcpm_power_up_setup); | 334 | smp_set_ops(&hip04_smp_ops); |
372 | mcpm_smp_set_ops(); | ||
373 | pr_info("HiP04 MCPM initialized\n"); | ||
374 | return ret; | 335 | return ret; |
375 | err_table: | 336 | err_table: |
376 | iounmap(fabric); | 337 | iounmap(fabric); |
@@ -383,4 +344,4 @@ err_reloc: | |||
383 | err: | 344 | err: |
384 | return ret; | 345 | return ret; |
385 | } | 346 | } |
386 | early_initcall(hip04_mcpm_init); | 347 | early_initcall(hip04_smp_init); |
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 30003ba447a5..5b0e363fe5ba 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/stat.h> | 37 | #include <linux/stat.h> |
38 | #include <linux/termios.h> | 38 | #include <linux/termios.h> |
39 | 39 | ||
40 | #include <asm/hardware/arm_timer.h> | ||
41 | #include <asm/setup.h> | 40 | #include <asm/setup.h> |
42 | #include <asm/param.h> /* HZ */ | 41 | #include <asm/param.h> /* HZ */ |
43 | #include <asm/mach-types.h> | 42 | #include <asm/mach-types.h> |
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c index 06620875813a..e288010522f9 100644 --- a/arch/arm/mach-keystone/keystone.c +++ b/arch/arm/mach-keystone/keystone.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | #include "keystone.h" | 28 | #include "keystone.h" |
29 | 29 | ||
30 | static struct notifier_block platform_nb; | ||
31 | static unsigned long keystone_dma_pfn_offset __read_mostly; | 30 | static unsigned long keystone_dma_pfn_offset __read_mostly; |
32 | 31 | ||
33 | static int keystone_platform_notifier(struct notifier_block *nb, | 32 | static int keystone_platform_notifier(struct notifier_block *nb, |
@@ -49,11 +48,18 @@ static int keystone_platform_notifier(struct notifier_block *nb, | |||
49 | return NOTIFY_OK; | 48 | return NOTIFY_OK; |
50 | } | 49 | } |
51 | 50 | ||
51 | static struct notifier_block platform_nb = { | ||
52 | .notifier_call = keystone_platform_notifier, | ||
53 | }; | ||
54 | |||
52 | static void __init keystone_init(void) | 55 | static void __init keystone_init(void) |
53 | { | 56 | { |
54 | keystone_pm_runtime_init(); | 57 | if (PHYS_OFFSET >= KEYSTONE_HIGH_PHYS_START) { |
55 | if (platform_nb.notifier_call) | 58 | keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START - |
59 | KEYSTONE_LOW_PHYS_START); | ||
56 | bus_register_notifier(&platform_bus_type, &platform_nb); | 60 | bus_register_notifier(&platform_bus_type, &platform_nb); |
61 | } | ||
62 | keystone_pm_runtime_init(); | ||
57 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 63 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
58 | } | 64 | } |
59 | 65 | ||
@@ -62,11 +68,9 @@ static phys_addr_t keystone_virt_to_idmap(unsigned long x) | |||
62 | return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET + KEYSTONE_LOW_PHYS_START; | 68 | return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET + KEYSTONE_LOW_PHYS_START; |
63 | } | 69 | } |
64 | 70 | ||
65 | static void __init keystone_init_meminfo(void) | 71 | static long long __init keystone_pv_fixup(void) |
66 | { | 72 | { |
67 | bool lpae = IS_ENABLED(CONFIG_ARM_LPAE); | 73 | long long offset; |
68 | bool pvpatch = IS_ENABLED(CONFIG_ARM_PATCH_PHYS_VIRT); | ||
69 | phys_addr_t offset = PHYS_OFFSET - KEYSTONE_LOW_PHYS_START; | ||
70 | phys_addr_t mem_start, mem_end; | 74 | phys_addr_t mem_start, mem_end; |
71 | 75 | ||
72 | mem_start = memblock_start_of_DRAM(); | 76 | mem_start = memblock_start_of_DRAM(); |
@@ -75,32 +79,21 @@ static void __init keystone_init_meminfo(void) | |||
75 | /* nothing to do if we are running out of the <32-bit space */ | 79 | /* nothing to do if we are running out of the <32-bit space */ |
76 | if (mem_start >= KEYSTONE_LOW_PHYS_START && | 80 | if (mem_start >= KEYSTONE_LOW_PHYS_START && |
77 | mem_end <= KEYSTONE_LOW_PHYS_END) | 81 | mem_end <= KEYSTONE_LOW_PHYS_END) |
78 | return; | 82 | return 0; |
79 | |||
80 | if (!lpae || !pvpatch) { | ||
81 | pr_crit("Enable %s%s%s to run outside 32-bit space\n", | ||
82 | !lpae ? __stringify(CONFIG_ARM_LPAE) : "", | ||
83 | (!lpae && !pvpatch) ? " and " : "", | ||
84 | !pvpatch ? __stringify(CONFIG_ARM_PATCH_PHYS_VIRT) : ""); | ||
85 | } | ||
86 | 83 | ||
87 | if (mem_start < KEYSTONE_HIGH_PHYS_START || | 84 | if (mem_start < KEYSTONE_HIGH_PHYS_START || |
88 | mem_end > KEYSTONE_HIGH_PHYS_END) { | 85 | mem_end > KEYSTONE_HIGH_PHYS_END) { |
89 | pr_crit("Invalid address space for memory (%08llx-%08llx)\n", | 86 | pr_crit("Invalid address space for memory (%08llx-%08llx)\n", |
90 | (u64)mem_start, (u64)mem_end); | 87 | (u64)mem_start, (u64)mem_end); |
88 | return 0; | ||
91 | } | 89 | } |
92 | 90 | ||
93 | offset += KEYSTONE_HIGH_PHYS_START; | 91 | offset = KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START; |
94 | __pv_phys_pfn_offset = PFN_DOWN(offset); | ||
95 | __pv_offset = (offset - PAGE_OFFSET); | ||
96 | 92 | ||
97 | /* Populate the arch idmap hook */ | 93 | /* Populate the arch idmap hook */ |
98 | arch_virt_to_idmap = keystone_virt_to_idmap; | 94 | arch_virt_to_idmap = keystone_virt_to_idmap; |
99 | platform_nb.notifier_call = keystone_platform_notifier; | ||
100 | keystone_dma_pfn_offset = PFN_DOWN(KEYSTONE_HIGH_PHYS_START - | ||
101 | KEYSTONE_LOW_PHYS_START); | ||
102 | 95 | ||
103 | pr_info("Switching to high address space at 0x%llx\n", (u64)offset); | 96 | return offset; |
104 | } | 97 | } |
105 | 98 | ||
106 | static const char *const keystone_match[] __initconst = { | 99 | static const char *const keystone_match[] __initconst = { |
@@ -115,5 +108,5 @@ DT_MACHINE_START(KEYSTONE, "Keystone") | |||
115 | .smp = smp_ops(keystone_smp_ops), | 108 | .smp = smp_ops(keystone_smp_ops), |
116 | .init_machine = keystone_init, | 109 | .init_machine = keystone_init, |
117 | .dt_compat = keystone_match, | 110 | .dt_compat = keystone_match, |
118 | .init_meminfo = keystone_init_meminfo, | 111 | .pv_fixup = keystone_pv_fixup, |
119 | MACHINE_END | 112 | MACHINE_END |
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c index 5f46a7cf907b..4bbb18463bfd 100644 --- a/arch/arm/mach-keystone/platsmp.c +++ b/arch/arm/mach-keystone/platsmp.c | |||
@@ -39,19 +39,6 @@ static int keystone_smp_boot_secondary(unsigned int cpu, | |||
39 | return error; | 39 | return error; |
40 | } | 40 | } |
41 | 41 | ||
42 | #ifdef CONFIG_ARM_LPAE | ||
43 | static void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) | ||
44 | { | ||
45 | pgd_t *pgd0 = pgd_offset_k(0); | ||
46 | cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); | ||
47 | local_flush_tlb_all(); | ||
48 | } | ||
49 | #else | ||
50 | static inline void __cpuinit keystone_smp_secondary_initmem(unsigned int cpu) | ||
51 | {} | ||
52 | #endif | ||
53 | |||
54 | struct smp_operations keystone_smp_ops __initdata = { | 42 | struct smp_operations keystone_smp_ops __initdata = { |
55 | .smp_boot_secondary = keystone_smp_boot_secondary, | 43 | .smp_boot_secondary = keystone_smp_boot_secondary, |
56 | .smp_secondary_init = keystone_smp_secondary_initmem, | ||
57 | }; | 44 | }; |
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c index 3445a5686805..34c2a1b32e7d 100644 --- a/arch/arm/mach-nspire/nspire.c +++ b/arch/arm/mach-nspire/nspire.c | |||
@@ -22,8 +22,6 @@ | |||
22 | #include <asm/mach-types.h> | 22 | #include <asm/mach-types.h> |
23 | #include <asm/mach/map.h> | 23 | #include <asm/mach/map.h> |
24 | 24 | ||
25 | #include <asm/hardware/timer-sp.h> | ||
26 | |||
27 | #include "mmio.h" | 25 | #include "mmio.h" |
28 | #include "clcd.h" | 26 | #include "clcd.h" |
29 | 27 | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index c309593abdb2..44575edc44b1 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c | |||
@@ -35,20 +35,19 @@ | |||
35 | #include <linux/mtd/physmap.h> | 35 | #include <linux/mtd/physmap.h> |
36 | #include <linux/memblock.h> | 36 | #include <linux/memblock.h> |
37 | 37 | ||
38 | #include <clocksource/timer-sp804.h> | ||
39 | |||
38 | #include <mach/hardware.h> | 40 | #include <mach/hardware.h> |
39 | #include <asm/irq.h> | 41 | #include <asm/irq.h> |
40 | #include <asm/mach-types.h> | 42 | #include <asm/mach-types.h> |
41 | #include <asm/hardware/arm_timer.h> | ||
42 | #include <asm/hardware/icst.h> | 43 | #include <asm/hardware/icst.h> |
43 | 44 | ||
44 | #include <asm/mach/arch.h> | 45 | #include <asm/mach/arch.h> |
45 | #include <asm/mach/irq.h> | 46 | #include <asm/mach/irq.h> |
46 | #include <asm/mach/map.h> | 47 | #include <asm/mach/map.h> |
47 | 48 | ||
48 | |||
49 | #include <mach/platform.h> | 49 | #include <mach/platform.h> |
50 | #include <mach/irqs.h> | 50 | #include <mach/irqs.h> |
51 | #include <asm/hardware/timer-sp.h> | ||
52 | 51 | ||
53 | #include <plat/sched_clock.h> | 52 | #include <plat/sched_clock.h> |
54 | 53 | ||
@@ -381,10 +380,10 @@ void __init realview_timer_init(unsigned int timer_irq) | |||
381 | /* | 380 | /* |
382 | * Initialise to a known state (all timers off) | 381 | * Initialise to a known state (all timers off) |
383 | */ | 382 | */ |
384 | writel(0, timer0_va_base + TIMER_CTRL); | 383 | sp804_timer_disable(timer0_va_base); |
385 | writel(0, timer1_va_base + TIMER_CTRL); | 384 | sp804_timer_disable(timer1_va_base); |
386 | writel(0, timer2_va_base + TIMER_CTRL); | 385 | sp804_timer_disable(timer2_va_base); |
387 | writel(0, timer3_va_base + TIMER_CTRL); | 386 | sp804_timer_disable(timer3_va_base); |
388 | 387 | ||
389 | sp804_clocksource_init(timer3_va_base, "timer3"); | 388 | sp804_clocksource_init(timer3_va_base, "timer3"); |
390 | sp804_clockevents_init(timer0_va_base, timer_irq, "timer0"); | 389 | sp804_clockevents_init(timer0_va_base, timer_irq, "timer0"); |
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 61ff91e76e0a..ebc4d58e1a32 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := clock.o generic.o irq.o #nmi-oopser.o | 6 | obj-y := clock.o generic.o #nmi-oopser.o |
7 | 7 | ||
8 | # Specific board support | 8 | # Specific board support |
9 | obj-$(CONFIG_SA1100_ASSABET) += assabet.o | 9 | obj-$(CONFIG_SA1100_ASSABET) += assabet.o |
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 40e0d8619a2d..345e63f4eb71 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -20,9 +20,12 @@ | |||
20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/reboot.h> | 22 | #include <linux/reboot.h> |
23 | #include <linux/irqchip/irq-sa11x0.h> | ||
23 | 24 | ||
24 | #include <video/sa1100fb.h> | 25 | #include <video/sa1100fb.h> |
25 | 26 | ||
27 | #include <soc/sa1100/pwer.h> | ||
28 | |||
26 | #include <asm/div64.h> | 29 | #include <asm/div64.h> |
27 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
28 | #include <asm/mach/flash.h> | 31 | #include <asm/mach/flash.h> |
@@ -375,6 +378,18 @@ void __init sa1100_timer_init(void) | |||
375 | pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400); | 378 | pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400); |
376 | } | 379 | } |
377 | 380 | ||
381 | static struct resource irq_resource = | ||
382 | DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); | ||
383 | |||
384 | void __init sa1100_init_irq(void) | ||
385 | { | ||
386 | request_resource(&iomem_resource, &irq_resource); | ||
387 | |||
388 | sa11x0_init_irq_nodt(IRQ_GPIO0_SC, irq_resource.start); | ||
389 | |||
390 | sa1100_init_gpio(); | ||
391 | } | ||
392 | |||
378 | /* | 393 | /* |
379 | * Disable the memory bus request/grant signals on the SA1110 to | 394 | * Disable the memory bus request/grant signals on the SA1110 to |
380 | * ensure that we don't receive spurious memory requests. We set | 395 | * ensure that we don't receive spurious memory requests. We set |
@@ -416,3 +431,25 @@ void sa1110_mb_enable(void) | |||
416 | local_irq_restore(flags); | 431 | local_irq_restore(flags); |
417 | } | 432 | } |
418 | 433 | ||
434 | int sa11x0_gpio_set_wake(unsigned int gpio, unsigned int on) | ||
435 | { | ||
436 | if (on) | ||
437 | PWER |= BIT(gpio); | ||
438 | else | ||
439 | PWER &= ~BIT(gpio); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | int sa11x0_sc_set_wake(unsigned int irq, unsigned int on) | ||
445 | { | ||
446 | if (BIT(irq) != IC_RTCAlrm) | ||
447 | return -EINVAL; | ||
448 | |||
449 | if (on) | ||
450 | PWER |= PWER_RTC; | ||
451 | else | ||
452 | PWER &= ~PWER_RTC; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 6ea09fe53426..23a04fe5d2ad 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -41,8 +41,9 @@ | |||
41 | #include <linux/bitops.h> | 41 | #include <linux/bitops.h> |
42 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
43 | 43 | ||
44 | #include <clocksource/timer-sp804.h> | ||
45 | |||
44 | #include <asm/irq.h> | 46 | #include <asm/irq.h> |
45 | #include <asm/hardware/arm_timer.h> | ||
46 | #include <asm/hardware/icst.h> | 47 | #include <asm/hardware/icst.h> |
47 | #include <asm/mach-types.h> | 48 | #include <asm/mach-types.h> |
48 | 49 | ||
@@ -52,7 +53,6 @@ | |||
52 | #include <asm/mach/map.h> | 53 | #include <asm/mach/map.h> |
53 | #include <mach/hardware.h> | 54 | #include <mach/hardware.h> |
54 | #include <mach/platform.h> | 55 | #include <mach/platform.h> |
55 | #include <asm/hardware/timer-sp.h> | ||
56 | 56 | ||
57 | #include <plat/sched_clock.h> | 57 | #include <plat/sched_clock.h> |
58 | 58 | ||
@@ -798,10 +798,10 @@ void __init versatile_timer_init(void) | |||
798 | /* | 798 | /* |
799 | * Initialise to a known state (all timers off) | 799 | * Initialise to a known state (all timers off) |
800 | */ | 800 | */ |
801 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | 801 | sp804_timer_disable(TIMER0_VA_BASE); |
802 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | 802 | sp804_timer_disable(TIMER1_VA_BASE); |
803 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 803 | sp804_timer_disable(TIMER2_VA_BASE); |
804 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | 804 | sp804_timer_disable(TIMER3_VA_BASE); |
805 | 805 | ||
806 | sp804_clocksource_init(TIMER3_VA_BASE, "timer3"); | 806 | sp804_clocksource_init(TIMER3_VA_BASE, "timer3"); |
807 | sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0"); | 807 | sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0"); |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index b4f92b9a13ac..7c6b976ab8d3 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -6,7 +6,7 @@ comment "Processor Type" | |||
6 | 6 | ||
7 | # ARM7TDMI | 7 | # ARM7TDMI |
8 | config CPU_ARM7TDMI | 8 | config CPU_ARM7TDMI |
9 | bool "Support ARM7TDMI processor" | 9 | bool |
10 | depends on !MMU | 10 | depends on !MMU |
11 | select CPU_32v4T | 11 | select CPU_32v4T |
12 | select CPU_ABRT_LV4T | 12 | select CPU_ABRT_LV4T |
@@ -56,7 +56,7 @@ config CPU_ARM740T | |||
56 | 56 | ||
57 | # ARM9TDMI | 57 | # ARM9TDMI |
58 | config CPU_ARM9TDMI | 58 | config CPU_ARM9TDMI |
59 | bool "Support ARM9TDMI processor" | 59 | bool |
60 | depends on !MMU | 60 | depends on !MMU |
61 | select CPU_32v4T | 61 | select CPU_32v4T |
62 | select CPU_ABRT_NOMMU | 62 | select CPU_ABRT_NOMMU |
@@ -604,6 +604,22 @@ config CPU_USE_DOMAINS | |||
604 | This option enables or disables the use of domain switching | 604 | This option enables or disables the use of domain switching |
605 | via the set_fs() function. | 605 | via the set_fs() function. |
606 | 606 | ||
607 | config CPU_V7M_NUM_IRQ | ||
608 | int "Number of external interrupts connected to the NVIC" | ||
609 | depends on CPU_V7M | ||
610 | default 90 if ARCH_STM32 | ||
611 | default 38 if ARCH_EFM32 | ||
612 | default 112 if SOC_VF610 | ||
613 | default 240 | ||
614 | help | ||
615 | This option indicates the number of interrupts connected to the NVIC. | ||
616 | The value can be larger than the real number of interrupts supported | ||
617 | by the system, but must not be lower. | ||
618 | The default value is 240, corresponding to the maximum number of | ||
619 | interrupts supported by the NVIC on Cortex-M family. | ||
620 | |||
621 | If unsure, keep default value. | ||
622 | |||
607 | # | 623 | # |
608 | # CPU supports 36-bit I/O | 624 | # CPU supports 36-bit I/O |
609 | # | 625 | # |
@@ -624,6 +640,10 @@ config ARM_LPAE | |||
624 | 640 | ||
625 | If unsure, say N. | 641 | If unsure, say N. |
626 | 642 | ||
643 | config ARM_PV_FIXUP | ||
644 | def_bool y | ||
645 | depends on ARM_LPAE && ARM_PATCH_PHYS_VIRT && ARCH_KEYSTONE | ||
646 | |||
627 | config ARCH_PHYS_ADDR_T_64BIT | 647 | config ARCH_PHYS_ADDR_T_64BIT |
628 | def_bool ARM_LPAE | 648 | def_bool ARM_LPAE |
629 | 649 | ||
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index d3afdf9eb65a..57c8df500e8c 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o | |||
18 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o | 18 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o |
19 | obj-$(CONFIG_HIGHMEM) += highmem.o | 19 | obj-$(CONFIG_HIGHMEM) += highmem.o |
20 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 20 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
21 | obj-$(CONFIG_ARM_PV_FIXUP) += pv-fixup-asm.o | ||
21 | 22 | ||
22 | obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o | 23 | obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o |
23 | obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o | 24 | obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o |
@@ -55,6 +56,8 @@ obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o | |||
55 | obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o | 56 | obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o |
56 | obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o | 57 | obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o |
57 | 58 | ||
59 | CFLAGS_copypage-feroceon.o := -march=armv5te | ||
60 | |||
58 | obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o | 61 | obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o |
59 | obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o | 62 | obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o |
60 | obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o | 63 | obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index e309c8f35af5..71b3d3309024 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -38,10 +38,11 @@ struct l2c_init_data { | |||
38 | unsigned way_size_0; | 38 | unsigned way_size_0; |
39 | unsigned num_lock; | 39 | unsigned num_lock; |
40 | void (*of_parse)(const struct device_node *, u32 *, u32 *); | 40 | void (*of_parse)(const struct device_node *, u32 *, u32 *); |
41 | void (*enable)(void __iomem *, u32, unsigned); | 41 | void (*enable)(void __iomem *, unsigned); |
42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); | 42 | void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); |
43 | void (*save)(void __iomem *); | 43 | void (*save)(void __iomem *); |
44 | void (*configure)(void __iomem *); | 44 | void (*configure)(void __iomem *); |
45 | void (*unlock)(void __iomem *, unsigned); | ||
45 | struct outer_cache_fns outer_cache; | 46 | struct outer_cache_fns outer_cache; |
46 | }; | 47 | }; |
47 | 48 | ||
@@ -110,14 +111,6 @@ static inline void l2c_unlock(void __iomem *base, unsigned num) | |||
110 | 111 | ||
111 | static void l2c_configure(void __iomem *base) | 112 | static void l2c_configure(void __iomem *base) |
112 | { | 113 | { |
113 | if (outer_cache.configure) { | ||
114 | outer_cache.configure(&l2x0_saved_regs); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | if (l2x0_data->configure) | ||
119 | l2x0_data->configure(base); | ||
120 | |||
121 | l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL); | 114 | l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL); |
122 | } | 115 | } |
123 | 116 | ||
@@ -125,18 +118,16 @@ static void l2c_configure(void __iomem *base) | |||
125 | * Enable the L2 cache controller. This function must only be | 118 | * Enable the L2 cache controller. This function must only be |
126 | * called when the cache controller is known to be disabled. | 119 | * called when the cache controller is known to be disabled. |
127 | */ | 120 | */ |
128 | static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) | 121 | static void l2c_enable(void __iomem *base, unsigned num_lock) |
129 | { | 122 | { |
130 | unsigned long flags; | 123 | unsigned long flags; |
131 | 124 | ||
132 | /* Do not touch the controller if already enabled. */ | 125 | if (outer_cache.configure) |
133 | if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN) | 126 | outer_cache.configure(&l2x0_saved_regs); |
134 | return; | 127 | else |
135 | 128 | l2x0_data->configure(base); | |
136 | l2x0_saved_regs.aux_ctrl = aux; | ||
137 | l2c_configure(base); | ||
138 | 129 | ||
139 | l2c_unlock(base, num_lock); | 130 | l2x0_data->unlock(base, num_lock); |
140 | 131 | ||
141 | local_irq_save(flags); | 132 | local_irq_save(flags); |
142 | __l2c_op_way(base + L2X0_INV_WAY); | 133 | __l2c_op_way(base + L2X0_INV_WAY); |
@@ -163,7 +154,11 @@ static void l2c_save(void __iomem *base) | |||
163 | 154 | ||
164 | static void l2c_resume(void) | 155 | static void l2c_resume(void) |
165 | { | 156 | { |
166 | l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock); | 157 | void __iomem *base = l2x0_base; |
158 | |||
159 | /* Do not touch the controller if already enabled. */ | ||
160 | if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) | ||
161 | l2c_enable(base, l2x0_data->num_lock); | ||
167 | } | 162 | } |
168 | 163 | ||
169 | /* | 164 | /* |
@@ -252,6 +247,8 @@ static const struct l2c_init_data l2c210_data __initconst = { | |||
252 | .num_lock = 1, | 247 | .num_lock = 1, |
253 | .enable = l2c_enable, | 248 | .enable = l2c_enable, |
254 | .save = l2c_save, | 249 | .save = l2c_save, |
250 | .configure = l2c_configure, | ||
251 | .unlock = l2c_unlock, | ||
255 | .outer_cache = { | 252 | .outer_cache = { |
256 | .inv_range = l2c210_inv_range, | 253 | .inv_range = l2c210_inv_range, |
257 | .clean_range = l2c210_clean_range, | 254 | .clean_range = l2c210_clean_range, |
@@ -391,16 +388,22 @@ static void l2c220_sync(void) | |||
391 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); | 388 | raw_spin_unlock_irqrestore(&l2x0_lock, flags); |
392 | } | 389 | } |
393 | 390 | ||
394 | static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock) | 391 | static void l2c220_enable(void __iomem *base, unsigned num_lock) |
395 | { | 392 | { |
396 | /* | 393 | /* |
397 | * Always enable non-secure access to the lockdown registers - | 394 | * Always enable non-secure access to the lockdown registers - |
398 | * we write to them as part of the L2C enable sequence so they | 395 | * we write to them as part of the L2C enable sequence so they |
399 | * need to be accessible. | 396 | * need to be accessible. |
400 | */ | 397 | */ |
401 | aux |= L220_AUX_CTRL_NS_LOCKDOWN; | 398 | l2x0_saved_regs.aux_ctrl |= L220_AUX_CTRL_NS_LOCKDOWN; |
402 | 399 | ||
403 | l2c_enable(base, aux, num_lock); | 400 | l2c_enable(base, num_lock); |
401 | } | ||
402 | |||
403 | static void l2c220_unlock(void __iomem *base, unsigned num_lock) | ||
404 | { | ||
405 | if (readl_relaxed(base + L2X0_AUX_CTRL) & L220_AUX_CTRL_NS_LOCKDOWN) | ||
406 | l2c_unlock(base, num_lock); | ||
404 | } | 407 | } |
405 | 408 | ||
406 | static const struct l2c_init_data l2c220_data = { | 409 | static const struct l2c_init_data l2c220_data = { |
@@ -409,6 +412,8 @@ static const struct l2c_init_data l2c220_data = { | |||
409 | .num_lock = 1, | 412 | .num_lock = 1, |
410 | .enable = l2c220_enable, | 413 | .enable = l2c220_enable, |
411 | .save = l2c_save, | 414 | .save = l2c_save, |
415 | .configure = l2c_configure, | ||
416 | .unlock = l2c220_unlock, | ||
412 | .outer_cache = { | 417 | .outer_cache = { |
413 | .inv_range = l2c220_inv_range, | 418 | .inv_range = l2c220_inv_range, |
414 | .clean_range = l2c220_clean_range, | 419 | .clean_range = l2c220_clean_range, |
@@ -569,6 +574,8 @@ static void l2c310_configure(void __iomem *base) | |||
569 | { | 574 | { |
570 | unsigned revision; | 575 | unsigned revision; |
571 | 576 | ||
577 | l2c_configure(base); | ||
578 | |||
572 | /* restore pl310 setup */ | 579 | /* restore pl310 setup */ |
573 | l2c_write_sec(l2x0_saved_regs.tag_latency, base, | 580 | l2c_write_sec(l2x0_saved_regs.tag_latency, base, |
574 | L310_TAG_LATENCY_CTRL); | 581 | L310_TAG_LATENCY_CTRL); |
@@ -603,10 +610,11 @@ static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, v | |||
603 | return NOTIFY_OK; | 610 | return NOTIFY_OK; |
604 | } | 611 | } |
605 | 612 | ||
606 | static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | 613 | static void __init l2c310_enable(void __iomem *base, unsigned num_lock) |
607 | { | 614 | { |
608 | unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK; | 615 | unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK; |
609 | bool cortex_a9 = read_cpuid_part() == ARM_CPU_PART_CORTEX_A9; | 616 | bool cortex_a9 = read_cpuid_part() == ARM_CPU_PART_CORTEX_A9; |
617 | u32 aux = l2x0_saved_regs.aux_ctrl; | ||
610 | 618 | ||
611 | if (rev >= L310_CACHE_ID_RTL_R2P0) { | 619 | if (rev >= L310_CACHE_ID_RTL_R2P0) { |
612 | if (cortex_a9) { | 620 | if (cortex_a9) { |
@@ -649,9 +657,9 @@ static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) | |||
649 | * we write to them as part of the L2C enable sequence so they | 657 | * we write to them as part of the L2C enable sequence so they |
650 | * need to be accessible. | 658 | * need to be accessible. |
651 | */ | 659 | */ |
652 | aux |= L310_AUX_CTRL_NS_LOCKDOWN; | 660 | l2x0_saved_regs.aux_ctrl = aux | L310_AUX_CTRL_NS_LOCKDOWN; |
653 | 661 | ||
654 | l2c_enable(base, aux, num_lock); | 662 | l2c_enable(base, num_lock); |
655 | 663 | ||
656 | /* Read back resulting AUX_CTRL value as it could have been altered. */ | 664 | /* Read back resulting AUX_CTRL value as it could have been altered. */ |
657 | aux = readl_relaxed(base + L2X0_AUX_CTRL); | 665 | aux = readl_relaxed(base + L2X0_AUX_CTRL); |
@@ -755,6 +763,12 @@ static void l2c310_resume(void) | |||
755 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); | 763 | set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); |
756 | } | 764 | } |
757 | 765 | ||
766 | static void l2c310_unlock(void __iomem *base, unsigned num_lock) | ||
767 | { | ||
768 | if (readl_relaxed(base + L2X0_AUX_CTRL) & L310_AUX_CTRL_NS_LOCKDOWN) | ||
769 | l2c_unlock(base, num_lock); | ||
770 | } | ||
771 | |||
758 | static const struct l2c_init_data l2c310_init_fns __initconst = { | 772 | static const struct l2c_init_data l2c310_init_fns __initconst = { |
759 | .type = "L2C-310", | 773 | .type = "L2C-310", |
760 | .way_size_0 = SZ_8K, | 774 | .way_size_0 = SZ_8K, |
@@ -763,6 +777,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = { | |||
763 | .fixup = l2c310_fixup, | 777 | .fixup = l2c310_fixup, |
764 | .save = l2c310_save, | 778 | .save = l2c310_save, |
765 | .configure = l2c310_configure, | 779 | .configure = l2c310_configure, |
780 | .unlock = l2c310_unlock, | ||
766 | .outer_cache = { | 781 | .outer_cache = { |
767 | .inv_range = l2c210_inv_range, | 782 | .inv_range = l2c210_inv_range, |
768 | .clean_range = l2c210_clean_range, | 783 | .clean_range = l2c210_clean_range, |
@@ -856,8 +871,11 @@ static int __init __l2c_init(const struct l2c_init_data *data, | |||
856 | * Check if l2x0 controller is already enabled. If we are booting | 871 | * Check if l2x0 controller is already enabled. If we are booting |
857 | * in non-secure mode accessing the below registers will fault. | 872 | * in non-secure mode accessing the below registers will fault. |
858 | */ | 873 | */ |
859 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) | 874 | if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { |
860 | data->enable(l2x0_base, aux, data->num_lock); | 875 | l2x0_saved_regs.aux_ctrl = aux; |
876 | |||
877 | data->enable(l2x0_base, data->num_lock); | ||
878 | } | ||
861 | 879 | ||
862 | outer_cache = fns; | 880 | outer_cache = fns; |
863 | 881 | ||
@@ -1066,6 +1084,8 @@ static const struct l2c_init_data of_l2c210_data __initconst = { | |||
1066 | .of_parse = l2x0_of_parse, | 1084 | .of_parse = l2x0_of_parse, |
1067 | .enable = l2c_enable, | 1085 | .enable = l2c_enable, |
1068 | .save = l2c_save, | 1086 | .save = l2c_save, |
1087 | .configure = l2c_configure, | ||
1088 | .unlock = l2c_unlock, | ||
1069 | .outer_cache = { | 1089 | .outer_cache = { |
1070 | .inv_range = l2c210_inv_range, | 1090 | .inv_range = l2c210_inv_range, |
1071 | .clean_range = l2c210_clean_range, | 1091 | .clean_range = l2c210_clean_range, |
@@ -1084,6 +1104,8 @@ static const struct l2c_init_data of_l2c220_data __initconst = { | |||
1084 | .of_parse = l2x0_of_parse, | 1104 | .of_parse = l2x0_of_parse, |
1085 | .enable = l2c220_enable, | 1105 | .enable = l2c220_enable, |
1086 | .save = l2c_save, | 1106 | .save = l2c_save, |
1107 | .configure = l2c_configure, | ||
1108 | .unlock = l2c220_unlock, | ||
1087 | .outer_cache = { | 1109 | .outer_cache = { |
1088 | .inv_range = l2c220_inv_range, | 1110 | .inv_range = l2c220_inv_range, |
1089 | .clean_range = l2c220_clean_range, | 1111 | .clean_range = l2c220_clean_range, |
@@ -1199,6 +1221,26 @@ static void __init l2c310_of_parse(const struct device_node *np, | |||
1199 | pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n"); | 1221 | pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n"); |
1200 | } | 1222 | } |
1201 | 1223 | ||
1224 | ret = of_property_read_u32(np, "prefetch-data", &val); | ||
1225 | if (ret == 0) { | ||
1226 | if (val) | ||
1227 | prefetch |= L310_PREFETCH_CTRL_DATA_PREFETCH; | ||
1228 | else | ||
1229 | prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH; | ||
1230 | } else if (ret != -EINVAL) { | ||
1231 | pr_err("L2C-310 OF prefetch-data property value is missing\n"); | ||
1232 | } | ||
1233 | |||
1234 | ret = of_property_read_u32(np, "prefetch-instr", &val); | ||
1235 | if (ret == 0) { | ||
1236 | if (val) | ||
1237 | prefetch |= L310_PREFETCH_CTRL_INSTR_PREFETCH; | ||
1238 | else | ||
1239 | prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH; | ||
1240 | } else if (ret != -EINVAL) { | ||
1241 | pr_err("L2C-310 OF prefetch-instr property value is missing\n"); | ||
1242 | } | ||
1243 | |||
1202 | l2x0_saved_regs.prefetch_ctrl = prefetch; | 1244 | l2x0_saved_regs.prefetch_ctrl = prefetch; |
1203 | } | 1245 | } |
1204 | 1246 | ||
@@ -1211,6 +1253,7 @@ static const struct l2c_init_data of_l2c310_data __initconst = { | |||
1211 | .fixup = l2c310_fixup, | 1253 | .fixup = l2c310_fixup, |
1212 | .save = l2c310_save, | 1254 | .save = l2c310_save, |
1213 | .configure = l2c310_configure, | 1255 | .configure = l2c310_configure, |
1256 | .unlock = l2c310_unlock, | ||
1214 | .outer_cache = { | 1257 | .outer_cache = { |
1215 | .inv_range = l2c210_inv_range, | 1258 | .inv_range = l2c210_inv_range, |
1216 | .clean_range = l2c210_clean_range, | 1259 | .clean_range = l2c210_clean_range, |
@@ -1240,6 +1283,7 @@ static const struct l2c_init_data of_l2c310_coherent_data __initconst = { | |||
1240 | .fixup = l2c310_fixup, | 1283 | .fixup = l2c310_fixup, |
1241 | .save = l2c310_save, | 1284 | .save = l2c310_save, |
1242 | .configure = l2c310_configure, | 1285 | .configure = l2c310_configure, |
1286 | .unlock = l2c310_unlock, | ||
1243 | .outer_cache = { | 1287 | .outer_cache = { |
1244 | .inv_range = l2c210_inv_range, | 1288 | .inv_range = l2c210_inv_range, |
1245 | .clean_range = l2c210_clean_range, | 1289 | .clean_range = l2c210_clean_range, |
@@ -1366,7 +1410,7 @@ static void aurora_save(void __iomem *base) | |||
1366 | * For Aurora cache in no outer mode, enable via the CP15 coprocessor | 1410 | * For Aurora cache in no outer mode, enable via the CP15 coprocessor |
1367 | * broadcasting of cache commands to L2. | 1411 | * broadcasting of cache commands to L2. |
1368 | */ | 1412 | */ |
1369 | static void __init aurora_enable_no_outer(void __iomem *base, u32 aux, | 1413 | static void __init aurora_enable_no_outer(void __iomem *base, |
1370 | unsigned num_lock) | 1414 | unsigned num_lock) |
1371 | { | 1415 | { |
1372 | u32 u; | 1416 | u32 u; |
@@ -1377,7 +1421,7 @@ static void __init aurora_enable_no_outer(void __iomem *base, u32 aux, | |||
1377 | 1421 | ||
1378 | isb(); | 1422 | isb(); |
1379 | 1423 | ||
1380 | l2c_enable(base, aux, num_lock); | 1424 | l2c_enable(base, num_lock); |
1381 | } | 1425 | } |
1382 | 1426 | ||
1383 | static void __init aurora_fixup(void __iomem *base, u32 cache_id, | 1427 | static void __init aurora_fixup(void __iomem *base, u32 cache_id, |
@@ -1416,6 +1460,8 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { | |||
1416 | .enable = l2c_enable, | 1460 | .enable = l2c_enable, |
1417 | .fixup = aurora_fixup, | 1461 | .fixup = aurora_fixup, |
1418 | .save = aurora_save, | 1462 | .save = aurora_save, |
1463 | .configure = l2c_configure, | ||
1464 | .unlock = l2c_unlock, | ||
1419 | .outer_cache = { | 1465 | .outer_cache = { |
1420 | .inv_range = aurora_inv_range, | 1466 | .inv_range = aurora_inv_range, |
1421 | .clean_range = aurora_clean_range, | 1467 | .clean_range = aurora_clean_range, |
@@ -1435,6 +1481,8 @@ static const struct l2c_init_data of_aurora_no_outer_data __initconst = { | |||
1435 | .enable = aurora_enable_no_outer, | 1481 | .enable = aurora_enable_no_outer, |
1436 | .fixup = aurora_fixup, | 1482 | .fixup = aurora_fixup, |
1437 | .save = aurora_save, | 1483 | .save = aurora_save, |
1484 | .configure = l2c_configure, | ||
1485 | .unlock = l2c_unlock, | ||
1438 | .outer_cache = { | 1486 | .outer_cache = { |
1439 | .resume = l2c_resume, | 1487 | .resume = l2c_resume, |
1440 | }, | 1488 | }, |
@@ -1585,6 +1633,7 @@ static const struct l2c_init_data of_bcm_l2x0_data __initconst = { | |||
1585 | .enable = l2c310_enable, | 1633 | .enable = l2c310_enable, |
1586 | .save = l2c310_save, | 1634 | .save = l2c310_save, |
1587 | .configure = l2c310_configure, | 1635 | .configure = l2c310_configure, |
1636 | .unlock = l2c310_unlock, | ||
1588 | .outer_cache = { | 1637 | .outer_cache = { |
1589 | .inv_range = bcm_inv_range, | 1638 | .inv_range = bcm_inv_range, |
1590 | .clean_range = bcm_clean_range, | 1639 | .clean_range = bcm_clean_range, |
@@ -1608,6 +1657,7 @@ static void __init tauros3_save(void __iomem *base) | |||
1608 | 1657 | ||
1609 | static void tauros3_configure(void __iomem *base) | 1658 | static void tauros3_configure(void __iomem *base) |
1610 | { | 1659 | { |
1660 | l2c_configure(base); | ||
1611 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, | 1661 | writel_relaxed(l2x0_saved_regs.aux2_ctrl, |
1612 | base + TAUROS3_AUX2_CTRL); | 1662 | base + TAUROS3_AUX2_CTRL); |
1613 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, | 1663 | writel_relaxed(l2x0_saved_regs.prefetch_ctrl, |
@@ -1621,6 +1671,7 @@ static const struct l2c_init_data of_tauros3_data __initconst = { | |||
1621 | .enable = l2c_enable, | 1671 | .enable = l2c_enable, |
1622 | .save = tauros3_save, | 1672 | .save = tauros3_save, |
1623 | .configure = tauros3_configure, | 1673 | .configure = tauros3_configure, |
1674 | .unlock = l2c_unlock, | ||
1624 | /* Tauros3 broadcasts L1 cache operations to L2 */ | 1675 | /* Tauros3 broadcasts L1 cache operations to L2 */ |
1625 | .outer_cache = { | 1676 | .outer_cache = { |
1626 | .resume = l2c_resume, | 1677 | .resume = l2c_resume, |
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 7e7583ddd607..1ced8a0f7a52 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -148,11 +148,14 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size, | |||
148 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs); | 148 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs); |
149 | static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr, | 149 | static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr, |
150 | dma_addr_t handle, struct dma_attrs *attrs); | 150 | dma_addr_t handle, struct dma_attrs *attrs); |
151 | static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma, | ||
152 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | ||
153 | struct dma_attrs *attrs); | ||
151 | 154 | ||
152 | struct dma_map_ops arm_coherent_dma_ops = { | 155 | struct dma_map_ops arm_coherent_dma_ops = { |
153 | .alloc = arm_coherent_dma_alloc, | 156 | .alloc = arm_coherent_dma_alloc, |
154 | .free = arm_coherent_dma_free, | 157 | .free = arm_coherent_dma_free, |
155 | .mmap = arm_dma_mmap, | 158 | .mmap = arm_coherent_dma_mmap, |
156 | .get_sgtable = arm_dma_get_sgtable, | 159 | .get_sgtable = arm_dma_get_sgtable, |
157 | .map_page = arm_coherent_dma_map_page, | 160 | .map_page = arm_coherent_dma_map_page, |
158 | .map_sg = arm_dma_map_sg, | 161 | .map_sg = arm_dma_map_sg, |
@@ -690,10 +693,7 @@ static void *arm_coherent_dma_alloc(struct device *dev, size_t size, | |||
690 | attrs, __builtin_return_address(0)); | 693 | attrs, __builtin_return_address(0)); |
691 | } | 694 | } |
692 | 695 | ||
693 | /* | 696 | static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, |
694 | * Create userspace mapping for the DMA-coherent memory. | ||
695 | */ | ||
696 | int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, | ||
697 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | 697 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
698 | struct dma_attrs *attrs) | 698 | struct dma_attrs *attrs) |
699 | { | 699 | { |
@@ -704,8 +704,6 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, | |||
704 | unsigned long pfn = dma_to_pfn(dev, dma_addr); | 704 | unsigned long pfn = dma_to_pfn(dev, dma_addr); |
705 | unsigned long off = vma->vm_pgoff; | 705 | unsigned long off = vma->vm_pgoff; |
706 | 706 | ||
707 | vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); | ||
708 | |||
709 | if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) | 707 | if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) |
710 | return ret; | 708 | return ret; |
711 | 709 | ||
@@ -721,6 +719,26 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, | |||
721 | } | 719 | } |
722 | 720 | ||
723 | /* | 721 | /* |
722 | * Create userspace mapping for the DMA-coherent memory. | ||
723 | */ | ||
724 | static int arm_coherent_dma_mmap(struct device *dev, struct vm_area_struct *vma, | ||
725 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | ||
726 | struct dma_attrs *attrs) | ||
727 | { | ||
728 | return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); | ||
729 | } | ||
730 | |||
731 | int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, | ||
732 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | ||
733 | struct dma_attrs *attrs) | ||
734 | { | ||
735 | #ifdef CONFIG_MMU | ||
736 | vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); | ||
737 | #endif /* CONFIG_MMU */ | ||
738 | return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); | ||
739 | } | ||
740 | |||
741 | /* | ||
724 | * Free a buffer as defined by the above mapping. | 742 | * Free a buffer as defined by the above mapping. |
725 | */ | 743 | */ |
726 | static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, | 744 | static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, |
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 7186382672b5..6ca7d9aa896f 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -1387,123 +1387,98 @@ static void __init map_lowmem(void) | |||
1387 | } | 1387 | } |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | #ifdef CONFIG_ARM_LPAE | 1390 | #ifdef CONFIG_ARM_PV_FIXUP |
1391 | extern unsigned long __atags_pointer; | ||
1392 | typedef void pgtables_remap(long long offset, unsigned long pgd, void *bdata); | ||
1393 | pgtables_remap lpae_pgtables_remap_asm; | ||
1394 | |||
1391 | /* | 1395 | /* |
1392 | * early_paging_init() recreates boot time page table setup, allowing machines | 1396 | * early_paging_init() recreates boot time page table setup, allowing machines |
1393 | * to switch over to a high (>4G) address space on LPAE systems | 1397 | * to switch over to a high (>4G) address space on LPAE systems |
1394 | */ | 1398 | */ |
1395 | void __init early_paging_init(const struct machine_desc *mdesc, | 1399 | void __init early_paging_init(const struct machine_desc *mdesc) |
1396 | struct proc_info_list *procinfo) | ||
1397 | { | 1400 | { |
1398 | pmdval_t pmdprot = procinfo->__cpu_mm_mmu_flags; | 1401 | pgtables_remap *lpae_pgtables_remap; |
1399 | unsigned long map_start, map_end; | 1402 | unsigned long pa_pgd; |
1400 | pgd_t *pgd0, *pgdk; | 1403 | unsigned int cr, ttbcr; |
1401 | pud_t *pud0, *pudk, *pud_start; | 1404 | long long offset; |
1402 | pmd_t *pmd0, *pmdk; | 1405 | void *boot_data; |
1403 | phys_addr_t phys; | ||
1404 | int i; | ||
1405 | 1406 | ||
1406 | if (!(mdesc->init_meminfo)) | 1407 | if (!mdesc->pv_fixup) |
1407 | return; | 1408 | return; |
1408 | 1409 | ||
1409 | /* remap kernel code and data */ | 1410 | offset = mdesc->pv_fixup(); |
1410 | map_start = init_mm.start_code & PMD_MASK; | 1411 | if (offset == 0) |
1411 | map_end = ALIGN(init_mm.brk, PMD_SIZE); | 1412 | return; |
1412 | 1413 | ||
1413 | /* get a handle on things... */ | 1414 | /* |
1414 | pgd0 = pgd_offset_k(0); | 1415 | * Get the address of the remap function in the 1:1 identity |
1415 | pud_start = pud0 = pud_offset(pgd0, 0); | 1416 | * mapping setup by the early page table assembly code. We |
1416 | pmd0 = pmd_offset(pud0, 0); | 1417 | * must get this prior to the pv update. The following barrier |
1418 | * ensures that this is complete before we fixup any P:V offsets. | ||
1419 | */ | ||
1420 | lpae_pgtables_remap = (pgtables_remap *)(unsigned long)__pa(lpae_pgtables_remap_asm); | ||
1421 | pa_pgd = __pa(swapper_pg_dir); | ||
1422 | boot_data = __va(__atags_pointer); | ||
1423 | barrier(); | ||
1417 | 1424 | ||
1418 | pgdk = pgd_offset_k(map_start); | 1425 | pr_info("Switching physical address space to 0x%08llx\n", |
1419 | pudk = pud_offset(pgdk, map_start); | 1426 | (u64)PHYS_OFFSET + offset); |
1420 | pmdk = pmd_offset(pudk, map_start); | ||
1421 | 1427 | ||
1422 | mdesc->init_meminfo(); | 1428 | /* Re-set the phys pfn offset, and the pv offset */ |
1429 | __pv_offset += offset; | ||
1430 | __pv_phys_pfn_offset += PFN_DOWN(offset); | ||
1423 | 1431 | ||
1424 | /* Run the patch stub to update the constants */ | 1432 | /* Run the patch stub to update the constants */ |
1425 | fixup_pv_table(&__pv_table_begin, | 1433 | fixup_pv_table(&__pv_table_begin, |
1426 | (&__pv_table_end - &__pv_table_begin) << 2); | 1434 | (&__pv_table_end - &__pv_table_begin) << 2); |
1427 | 1435 | ||
1428 | /* | 1436 | /* |
1429 | * Cache cleaning operations for self-modifying code | 1437 | * We changing not only the virtual to physical mapping, but also |
1430 | * We should clean the entries by MVA but running a | 1438 | * the physical addresses used to access memory. We need to flush |
1431 | * for loop over every pv_table entry pointer would | 1439 | * all levels of cache in the system with caching disabled to |
1432 | * just complicate the code. | 1440 | * ensure that all data is written back, and nothing is prefetched |
1433 | */ | 1441 | * into the caches. We also need to prevent the TLB walkers |
1434 | flush_cache_louis(); | 1442 | * allocating into the caches too. Note that this is ARMv7 LPAE |
1435 | dsb(ishst); | 1443 | * specific. |
1436 | isb(); | ||
1437 | |||
1438 | /* | ||
1439 | * FIXME: This code is not architecturally compliant: we modify | ||
1440 | * the mappings in-place, indeed while they are in use by this | ||
1441 | * very same code. This may lead to unpredictable behaviour of | ||
1442 | * the CPU. | ||
1443 | * | ||
1444 | * Even modifying the mappings in a separate page table does | ||
1445 | * not resolve this. | ||
1446 | * | ||
1447 | * The architecture strongly recommends that when a mapping is | ||
1448 | * changed, that it is changed by first going via an invalid | ||
1449 | * mapping and back to the new mapping. This is to ensure that | ||
1450 | * no TLB conflicts (caused by the TLB having more than one TLB | ||
1451 | * entry match a translation) can occur. However, doing that | ||
1452 | * here will result in unmapping the code we are running. | ||
1453 | */ | ||
1454 | pr_warn("WARNING: unsafe modification of in-place page tables - tainting kernel\n"); | ||
1455 | add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); | ||
1456 | |||
1457 | /* | ||
1458 | * Remap level 1 table. This changes the physical addresses | ||
1459 | * used to refer to the level 2 page tables to the high | ||
1460 | * physical address alias, leaving everything else the same. | ||
1461 | */ | ||
1462 | for (i = 0; i < PTRS_PER_PGD; pud0++, i++) { | ||
1463 | set_pud(pud0, | ||
1464 | __pud(__pa(pmd0) | PMD_TYPE_TABLE | L_PGD_SWAPPER)); | ||
1465 | pmd0 += PTRS_PER_PMD; | ||
1466 | } | ||
1467 | |||
1468 | /* | ||
1469 | * Remap the level 2 table, pointing the mappings at the high | ||
1470 | * physical address alias of these pages. | ||
1471 | */ | ||
1472 | phys = __pa(map_start); | ||
1473 | do { | ||
1474 | *pmdk++ = __pmd(phys | pmdprot); | ||
1475 | phys += PMD_SIZE; | ||
1476 | } while (phys < map_end); | ||
1477 | |||
1478 | /* | ||
1479 | * Ensure that the above updates are flushed out of the cache. | ||
1480 | * This is not strictly correct; on a system where the caches | ||
1481 | * are coherent with each other, but the MMU page table walks | ||
1482 | * may not be coherent, flush_cache_all() may be a no-op, and | ||
1483 | * this will fail. | ||
1484 | */ | 1444 | */ |
1445 | cr = get_cr(); | ||
1446 | set_cr(cr & ~(CR_I | CR_C)); | ||
1447 | asm("mrc p15, 0, %0, c2, c0, 2" : "=r" (ttbcr)); | ||
1448 | asm volatile("mcr p15, 0, %0, c2, c0, 2" | ||
1449 | : : "r" (ttbcr & ~(3 << 8 | 3 << 10))); | ||
1485 | flush_cache_all(); | 1450 | flush_cache_all(); |
1486 | 1451 | ||
1487 | /* | 1452 | /* |
1488 | * Re-write the TTBR values to point them at the high physical | 1453 | * Fixup the page tables - this must be in the idmap region as |
1489 | * alias of the page tables. We expect __va() will work on | 1454 | * we need to disable the MMU to do this safely, and hence it |
1490 | * cpu_get_pgd(), which returns the value of TTBR0. | 1455 | * needs to be assembly. It's fairly simple, as we're using the |
1456 | * temporary tables setup by the initial assembly code. | ||
1491 | */ | 1457 | */ |
1492 | cpu_switch_mm(pgd0, &init_mm); | 1458 | lpae_pgtables_remap(offset, pa_pgd, boot_data); |
1493 | cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET); | ||
1494 | 1459 | ||
1495 | /* Finally flush any stale TLB values. */ | 1460 | /* Re-enable the caches and cacheable TLB walks */ |
1496 | local_flush_bp_all(); | 1461 | asm volatile("mcr p15, 0, %0, c2, c0, 2" : : "r" (ttbcr)); |
1497 | local_flush_tlb_all(); | 1462 | set_cr(cr); |
1498 | } | 1463 | } |
1499 | 1464 | ||
1500 | #else | 1465 | #else |
1501 | 1466 | ||
1502 | void __init early_paging_init(const struct machine_desc *mdesc, | 1467 | void __init early_paging_init(const struct machine_desc *mdesc) |
1503 | struct proc_info_list *procinfo) | ||
1504 | { | 1468 | { |
1505 | if (mdesc->init_meminfo) | 1469 | long long offset; |
1506 | mdesc->init_meminfo(); | 1470 | |
1471 | if (!mdesc->pv_fixup) | ||
1472 | return; | ||
1473 | |||
1474 | offset = mdesc->pv_fixup(); | ||
1475 | if (offset == 0) | ||
1476 | return; | ||
1477 | |||
1478 | pr_crit("Physical address space modification is only to support Keystone2.\n"); | ||
1479 | pr_crit("Please enable ARM_LPAE and ARM_PATCH_PHYS_VIRT support to use this\n"); | ||
1480 | pr_crit("feature. Your kernel may crash now, have a good day.\n"); | ||
1481 | add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); | ||
1507 | } | 1482 | } |
1508 | 1483 | ||
1509 | #endif | 1484 | #endif |
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index a014dfacd5ca..afd7e05d95f1 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c | |||
@@ -304,15 +304,6 @@ void __init sanity_check_meminfo(void) | |||
304 | } | 304 | } |
305 | 305 | ||
306 | /* | 306 | /* |
307 | * early_paging_init() recreates boot time page table setup, allowing machines | ||
308 | * to switch over to a high (>4G) address space on LPAE systems | ||
309 | */ | ||
310 | void __init early_paging_init(const struct machine_desc *mdesc, | ||
311 | struct proc_info_list *procinfo) | ||
312 | { | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * paging_init() sets up the page tables, initialises the zone memory | 307 | * paging_init() sets up the page tables, initialises the zone memory |
317 | * maps, and sets up the zero page, bad page and bad page tables. | 308 | * maps, and sets up the zero page, bad page and bad page tables. |
318 | */ | 309 | */ |
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index 10405b8d31af..c6141a5435c3 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S | |||
@@ -36,14 +36,16 @@ | |||
36 | * | 36 | * |
37 | * It is assumed that: | 37 | * It is assumed that: |
38 | * - we are not using split page tables | 38 | * - we are not using split page tables |
39 | * | ||
40 | * Note that we always need to flush BTAC/BTB if IBE is set | ||
41 | * even on Cortex-A8 revisions not affected by 430973. | ||
42 | * If IBE is not set, the flush BTAC/BTB won't do anything. | ||
39 | */ | 43 | */ |
40 | ENTRY(cpu_ca8_switch_mm) | 44 | ENTRY(cpu_ca8_switch_mm) |
41 | #ifdef CONFIG_MMU | 45 | #ifdef CONFIG_MMU |
42 | mov r2, #0 | 46 | mov r2, #0 |
43 | #ifdef CONFIG_ARM_ERRATA_430973 | ||
44 | mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB | 47 | mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB |
45 | #endif | 48 | #endif |
46 | #endif | ||
47 | ENTRY(cpu_v7_switch_mm) | 49 | ENTRY(cpu_v7_switch_mm) |
48 | #ifdef CONFIG_MMU | 50 | #ifdef CONFIG_MMU |
49 | mmid r1, r1 @ get mm->context.id | 51 | mmid r1, r1 @ get mm->context.id |
@@ -148,10 +150,10 @@ ENDPROC(cpu_v7_set_pte_ext) | |||
148 | * Macro for setting up the TTBRx and TTBCR registers. | 150 | * Macro for setting up the TTBRx and TTBCR registers. |
149 | * - \ttb0 and \ttb1 updated with the corresponding flags. | 151 | * - \ttb0 and \ttb1 updated with the corresponding flags. |
150 | */ | 152 | */ |
151 | .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp | 153 | .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp |
152 | mcr p15, 0, \zero, c2, c0, 2 @ TTB control register | 154 | mcr p15, 0, \zero, c2, c0, 2 @ TTB control register |
153 | ALT_SMP(orr \ttbr0, \ttbr0, #TTB_FLAGS_SMP) | 155 | ALT_SMP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_SMP) |
154 | ALT_UP(orr \ttbr0, \ttbr0, #TTB_FLAGS_UP) | 156 | ALT_UP(orr \ttbr0l, \ttbr0l, #TTB_FLAGS_UP) |
155 | ALT_SMP(orr \ttbr1, \ttbr1, #TTB_FLAGS_SMP) | 157 | ALT_SMP(orr \ttbr1, \ttbr1, #TTB_FLAGS_SMP) |
156 | ALT_UP(orr \ttbr1, \ttbr1, #TTB_FLAGS_UP) | 158 | ALT_UP(orr \ttbr1, \ttbr1, #TTB_FLAGS_UP) |
157 | mcr p15, 0, \ttbr1, c2, c0, 1 @ load TTB1 | 159 | mcr p15, 0, \ttbr1, c2, c0, 1 @ load TTB1 |
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index d3daed0ae0ad..5e5720e8bc5f 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S | |||
@@ -126,11 +126,10 @@ ENDPROC(cpu_v7_set_pte_ext) | |||
126 | * Macro for setting up the TTBRx and TTBCR registers. | 126 | * Macro for setting up the TTBRx and TTBCR registers. |
127 | * - \ttbr1 updated. | 127 | * - \ttbr1 updated. |
128 | */ | 128 | */ |
129 | .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp | 129 | .macro v7_ttb_setup, zero, ttbr0l, ttbr0h, ttbr1, tmp |
130 | ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address | 130 | ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address |
131 | mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT | 131 | cmp \ttbr1, \tmp, lsr #12 @ PHYS_OFFSET > PAGE_OFFSET? |
132 | cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET? | 132 | mrc p15, 0, \tmp, c2, c0, 2 @ TTB control egister |
133 | mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register | ||
134 | orr \tmp, \tmp, #TTB_EAE | 133 | orr \tmp, \tmp, #TTB_EAE |
135 | ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP) | 134 | ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP) |
136 | ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP) | 135 | ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP) |
@@ -143,13 +142,10 @@ ENDPROC(cpu_v7_set_pte_ext) | |||
143 | */ | 142 | */ |
144 | orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ | 143 | orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ |
145 | mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR | 144 | mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR |
146 | mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits | 145 | mov \tmp, \ttbr1, lsr #20 |
147 | mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits | 146 | mov \ttbr1, \ttbr1, lsl #12 |
148 | addls \ttbr1, \ttbr1, #TTBR1_OFFSET | 147 | addls \ttbr1, \ttbr1, #TTBR1_OFFSET |
149 | mcrr p15, 1, \ttbr1, \tmp, c2 @ load TTBR1 | 148 | mcrr p15, 1, \ttbr1, \tmp, c2 @ load TTBR1 |
150 | mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits | ||
151 | mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits | ||
152 | mcrr p15, 0, \ttbr0, \tmp, c2 @ load TTBR0 | ||
153 | .endm | 149 | .endm |
154 | 150 | ||
155 | /* | 151 | /* |
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 75ae72160099..0716bbe19872 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S | |||
@@ -252,6 +252,12 @@ ENDPROC(cpu_pj4b_do_resume) | |||
252 | * Initialise TLB, Caches, and MMU state ready to switch the MMU | 252 | * Initialise TLB, Caches, and MMU state ready to switch the MMU |
253 | * on. Return in r0 the new CP15 C1 control register setting. | 253 | * on. Return in r0 the new CP15 C1 control register setting. |
254 | * | 254 | * |
255 | * r1, r2, r4, r5, r9, r13 must be preserved - r13 is not a stack | ||
256 | * r4: TTBR0 (low word) | ||
257 | * r5: TTBR0 (high word if LPAE) | ||
258 | * r8: TTBR1 | ||
259 | * r9: Main ID register | ||
260 | * | ||
255 | * This should be able to cover all ARMv7 cores. | 261 | * This should be able to cover all ARMv7 cores. |
256 | * | 262 | * |
257 | * It is assumed that: | 263 | * It is assumed that: |
@@ -279,6 +285,78 @@ __v7_ca17mp_setup: | |||
279 | #endif | 285 | #endif |
280 | b __v7_setup | 286 | b __v7_setup |
281 | 287 | ||
288 | /* | ||
289 | * Errata: | ||
290 | * r0, r10 available for use | ||
291 | * r1, r2, r4, r5, r9, r13: must be preserved | ||
292 | * r3: contains MIDR rX number in bits 23-20 | ||
293 | * r6: contains MIDR rXpY as 8-bit XY number | ||
294 | * r9: MIDR | ||
295 | */ | ||
296 | __ca8_errata: | ||
297 | #if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM) | ||
298 | teq r3, #0x00100000 @ only present in r1p* | ||
299 | mrceq p15, 0, r0, c1, c0, 1 @ read aux control register | ||
300 | orreq r0, r0, #(1 << 6) @ set IBE to 1 | ||
301 | mcreq p15, 0, r0, c1, c0, 1 @ write aux control register | ||
302 | #endif | ||
303 | #ifdef CONFIG_ARM_ERRATA_458693 | ||
304 | teq r6, #0x20 @ only present in r2p0 | ||
305 | mrceq p15, 0, r0, c1, c0, 1 @ read aux control register | ||
306 | orreq r0, r0, #(1 << 5) @ set L1NEON to 1 | ||
307 | orreq r0, r0, #(1 << 9) @ set PLDNOP to 1 | ||
308 | mcreq p15, 0, r0, c1, c0, 1 @ write aux control register | ||
309 | #endif | ||
310 | #ifdef CONFIG_ARM_ERRATA_460075 | ||
311 | teq r6, #0x20 @ only present in r2p0 | ||
312 | mrceq p15, 1, r0, c9, c0, 2 @ read L2 cache aux ctrl register | ||
313 | tsteq r0, #1 << 22 | ||
314 | orreq r0, r0, #(1 << 22) @ set the Write Allocate disable bit | ||
315 | mcreq p15, 1, r0, c9, c0, 2 @ write the L2 cache aux ctrl register | ||
316 | #endif | ||
317 | b __errata_finish | ||
318 | |||
319 | __ca9_errata: | ||
320 | #ifdef CONFIG_ARM_ERRATA_742230 | ||
321 | cmp r6, #0x22 @ only present up to r2p2 | ||
322 | mrcle p15, 0, r0, c15, c0, 1 @ read diagnostic register | ||
323 | orrle r0, r0, #1 << 4 @ set bit #4 | ||
324 | mcrle p15, 0, r0, c15, c0, 1 @ write diagnostic register | ||
325 | #endif | ||
326 | #ifdef CONFIG_ARM_ERRATA_742231 | ||
327 | teq r6, #0x20 @ present in r2p0 | ||
328 | teqne r6, #0x21 @ present in r2p1 | ||
329 | teqne r6, #0x22 @ present in r2p2 | ||
330 | mrceq p15, 0, r0, c15, c0, 1 @ read diagnostic register | ||
331 | orreq r0, r0, #1 << 12 @ set bit #12 | ||
332 | orreq r0, r0, #1 << 22 @ set bit #22 | ||
333 | mcreq p15, 0, r0, c15, c0, 1 @ write diagnostic register | ||
334 | #endif | ||
335 | #ifdef CONFIG_ARM_ERRATA_743622 | ||
336 | teq r3, #0x00200000 @ only present in r2p* | ||
337 | mrceq p15, 0, r0, c15, c0, 1 @ read diagnostic register | ||
338 | orreq r0, r0, #1 << 6 @ set bit #6 | ||
339 | mcreq p15, 0, r0, c15, c0, 1 @ write diagnostic register | ||
340 | #endif | ||
341 | #if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP) | ||
342 | ALT_SMP(cmp r6, #0x30) @ present prior to r3p0 | ||
343 | ALT_UP_B(1f) | ||
344 | mrclt p15, 0, r0, c15, c0, 1 @ read diagnostic register | ||
345 | orrlt r0, r0, #1 << 11 @ set bit #11 | ||
346 | mcrlt p15, 0, r0, c15, c0, 1 @ write diagnostic register | ||
347 | 1: | ||
348 | #endif | ||
349 | b __errata_finish | ||
350 | |||
351 | __ca15_errata: | ||
352 | #ifdef CONFIG_ARM_ERRATA_773022 | ||
353 | cmp r6, #0x4 @ only present up to r0p4 | ||
354 | mrcle p15, 0, r0, c1, c0, 1 @ read aux control register | ||
355 | orrle r0, r0, #1 << 1 @ disable loop buffer | ||
356 | mcrle p15, 0, r0, c1, c0, 1 @ write aux control register | ||
357 | #endif | ||
358 | b __errata_finish | ||
359 | |||
282 | __v7_pj4b_setup: | 360 | __v7_pj4b_setup: |
283 | #ifdef CONFIG_CPU_PJ4B | 361 | #ifdef CONFIG_CPU_PJ4B |
284 | 362 | ||
@@ -339,96 +417,38 @@ __v7_setup: | |||
339 | bl v7_invalidate_l1 | 417 | bl v7_invalidate_l1 |
340 | ldmia r12, {r0-r5, r7, r9, r11, lr} | 418 | ldmia r12, {r0-r5, r7, r9, r11, lr} |
341 | 419 | ||
342 | mrc p15, 0, r0, c0, c0, 0 @ read main ID register | 420 | and r0, r9, #0xff000000 @ ARM? |
343 | and r10, r0, #0xff000000 @ ARM? | 421 | teq r0, #0x41000000 |
344 | teq r10, #0x41000000 | 422 | bne __errata_finish |
345 | bne 3f | 423 | and r3, r9, #0x00f00000 @ variant |
346 | and r5, r0, #0x00f00000 @ variant | 424 | and r6, r9, #0x0000000f @ revision |
347 | and r6, r0, #0x0000000f @ revision | 425 | orr r6, r6, r3, lsr #20-4 @ combine variant and revision |
348 | orr r6, r6, r5, lsr #20-4 @ combine variant and revision | 426 | ubfx r0, r9, #4, #12 @ primary part number |
349 | ubfx r0, r0, #4, #12 @ primary part number | ||
350 | 427 | ||
351 | /* Cortex-A8 Errata */ | 428 | /* Cortex-A8 Errata */ |
352 | ldr r10, =0x00000c08 @ Cortex-A8 primary part number | 429 | ldr r10, =0x00000c08 @ Cortex-A8 primary part number |
353 | teq r0, r10 | 430 | teq r0, r10 |
354 | bne 2f | 431 | beq __ca8_errata |
355 | #if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM) | ||
356 | |||
357 | teq r5, #0x00100000 @ only present in r1p* | ||
358 | mrceq p15, 0, r10, c1, c0, 1 @ read aux control register | ||
359 | orreq r10, r10, #(1 << 6) @ set IBE to 1 | ||
360 | mcreq p15, 0, r10, c1, c0, 1 @ write aux control register | ||
361 | #endif | ||
362 | #ifdef CONFIG_ARM_ERRATA_458693 | ||
363 | teq r6, #0x20 @ only present in r2p0 | ||
364 | mrceq p15, 0, r10, c1, c0, 1 @ read aux control register | ||
365 | orreq r10, r10, #(1 << 5) @ set L1NEON to 1 | ||
366 | orreq r10, r10, #(1 << 9) @ set PLDNOP to 1 | ||
367 | mcreq p15, 0, r10, c1, c0, 1 @ write aux control register | ||
368 | #endif | ||
369 | #ifdef CONFIG_ARM_ERRATA_460075 | ||
370 | teq r6, #0x20 @ only present in r2p0 | ||
371 | mrceq p15, 1, r10, c9, c0, 2 @ read L2 cache aux ctrl register | ||
372 | tsteq r10, #1 << 22 | ||
373 | orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit | ||
374 | mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register | ||
375 | #endif | ||
376 | b 3f | ||
377 | 432 | ||
378 | /* Cortex-A9 Errata */ | 433 | /* Cortex-A9 Errata */ |
379 | 2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number | 434 | ldr r10, =0x00000c09 @ Cortex-A9 primary part number |
380 | teq r0, r10 | 435 | teq r0, r10 |
381 | bne 3f | 436 | beq __ca9_errata |
382 | #ifdef CONFIG_ARM_ERRATA_742230 | ||
383 | cmp r6, #0x22 @ only present up to r2p2 | ||
384 | mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register | ||
385 | orrle r10, r10, #1 << 4 @ set bit #4 | ||
386 | mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register | ||
387 | #endif | ||
388 | #ifdef CONFIG_ARM_ERRATA_742231 | ||
389 | teq r6, #0x20 @ present in r2p0 | ||
390 | teqne r6, #0x21 @ present in r2p1 | ||
391 | teqne r6, #0x22 @ present in r2p2 | ||
392 | mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register | ||
393 | orreq r10, r10, #1 << 12 @ set bit #12 | ||
394 | orreq r10, r10, #1 << 22 @ set bit #22 | ||
395 | mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register | ||
396 | #endif | ||
397 | #ifdef CONFIG_ARM_ERRATA_743622 | ||
398 | teq r5, #0x00200000 @ only present in r2p* | ||
399 | mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register | ||
400 | orreq r10, r10, #1 << 6 @ set bit #6 | ||
401 | mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register | ||
402 | #endif | ||
403 | #if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP) | ||
404 | ALT_SMP(cmp r6, #0x30) @ present prior to r3p0 | ||
405 | ALT_UP_B(1f) | ||
406 | mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register | ||
407 | orrlt r10, r10, #1 << 11 @ set bit #11 | ||
408 | mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register | ||
409 | 1: | ||
410 | #endif | ||
411 | 437 | ||
412 | /* Cortex-A15 Errata */ | 438 | /* Cortex-A15 Errata */ |
413 | 3: ldr r10, =0x00000c0f @ Cortex-A15 primary part number | 439 | ldr r10, =0x00000c0f @ Cortex-A15 primary part number |
414 | teq r0, r10 | 440 | teq r0, r10 |
415 | bne 4f | 441 | beq __ca15_errata |
416 | 442 | ||
417 | #ifdef CONFIG_ARM_ERRATA_773022 | 443 | __errata_finish: |
418 | cmp r6, #0x4 @ only present up to r0p4 | 444 | mov r10, #0 |
419 | mrcle p15, 0, r10, c1, c0, 1 @ read aux control register | ||
420 | orrle r10, r10, #1 << 1 @ disable loop buffer | ||
421 | mcrle p15, 0, r10, c1, c0, 1 @ write aux control register | ||
422 | #endif | ||
423 | |||
424 | 4: mov r10, #0 | ||
425 | mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate | 445 | mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate |
426 | #ifdef CONFIG_MMU | 446 | #ifdef CONFIG_MMU |
427 | mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs | 447 | mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs |
428 | v7_ttb_setup r10, r4, r8, r5 @ TTBCR, TTBRx setup | 448 | v7_ttb_setup r10, r4, r5, r8, r3 @ TTBCR, TTBRx setup |
429 | ldr r5, =PRRR @ PRRR | 449 | ldr r3, =PRRR @ PRRR |
430 | ldr r6, =NMRR @ NMRR | 450 | ldr r6, =NMRR @ NMRR |
431 | mcr p15, 0, r5, c10, c2, 0 @ write PRRR | 451 | mcr p15, 0, r3, c10, c2, 0 @ write PRRR |
432 | mcr p15, 0, r6, c10, c2, 1 @ write NMRR | 452 | mcr p15, 0, r6, c10, c2, 1 @ write NMRR |
433 | #endif | 453 | #endif |
434 | dsb @ Complete invalidations | 454 | dsb @ Complete invalidations |
@@ -437,22 +457,22 @@ __v7_setup: | |||
437 | and r0, r0, #(0xf << 12) @ ThumbEE enabled field | 457 | and r0, r0, #(0xf << 12) @ ThumbEE enabled field |
438 | teq r0, #(1 << 12) @ check if ThumbEE is present | 458 | teq r0, #(1 << 12) @ check if ThumbEE is present |
439 | bne 1f | 459 | bne 1f |
440 | mov r5, #0 | 460 | mov r3, #0 |
441 | mcr p14, 6, r5, c1, c0, 0 @ Initialize TEEHBR to 0 | 461 | mcr p14, 6, r3, c1, c0, 0 @ Initialize TEEHBR to 0 |
442 | mrc p14, 6, r0, c0, c0, 0 @ load TEECR | 462 | mrc p14, 6, r0, c0, c0, 0 @ load TEECR |
443 | orr r0, r0, #1 @ set the 1st bit in order to | 463 | orr r0, r0, #1 @ set the 1st bit in order to |
444 | mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access | 464 | mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access |
445 | 1: | 465 | 1: |
446 | #endif | 466 | #endif |
447 | adr r5, v7_crval | 467 | adr r3, v7_crval |
448 | ldmia r5, {r5, r6} | 468 | ldmia r3, {r3, r6} |
449 | ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables | 469 | ARM_BE8(orr r6, r6, #1 << 25) @ big-endian page tables |
450 | #ifdef CONFIG_SWP_EMULATE | 470 | #ifdef CONFIG_SWP_EMULATE |
451 | orr r5, r5, #(1 << 10) @ set SW bit in "clear" | 471 | orr r3, r3, #(1 << 10) @ set SW bit in "clear" |
452 | bic r6, r6, #(1 << 10) @ clear it in "mmuset" | 472 | bic r6, r6, #(1 << 10) @ clear it in "mmuset" |
453 | #endif | 473 | #endif |
454 | mrc p15, 0, r0, c1, c0, 0 @ read control register | 474 | mrc p15, 0, r0, c1, c0, 0 @ read control register |
455 | bic r0, r0, r5 @ clear bits them | 475 | bic r0, r0, r3 @ clear bits them |
456 | orr r0, r0, r6 @ set them | 476 | orr r0, r0, r6 @ set them |
457 | THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions | 477 | THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions |
458 | ret lr @ return to head.S:__ret | 478 | ret lr @ return to head.S:__ret |
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S index e08e1f2bab76..67d9209077c6 100644 --- a/arch/arm/mm/proc-v7m.S +++ b/arch/arm/mm/proc-v7m.S | |||
@@ -98,7 +98,7 @@ __v7m_setup: | |||
98 | str r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority | 98 | str r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority |
99 | 99 | ||
100 | @ SVC to run the kernel in this mode | 100 | @ SVC to run the kernel in this mode |
101 | adr r1, BSYM(1f) | 101 | badr r1, 1f |
102 | ldr r5, [r12, #11 * 4] @ read the SVC vector entry | 102 | ldr r5, [r12, #11 * 4] @ read the SVC vector entry |
103 | str r1, [r12, #11 * 4] @ write the temporary SVC vector entry | 103 | str r1, [r12, #11 * 4] @ write the temporary SVC vector entry |
104 | mov r6, lr @ save LR | 104 | mov r6, lr @ save LR |
diff --git a/arch/arm/mm/pv-fixup-asm.S b/arch/arm/mm/pv-fixup-asm.S new file mode 100644 index 000000000000..1867f3e43016 --- /dev/null +++ b/arch/arm/mm/pv-fixup-asm.S | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Russell King | ||
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 assembly is required to safely remap the physical address space | ||
9 | * for Keystone 2 | ||
10 | */ | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/asm-offsets.h> | ||
13 | #include <asm/cp15.h> | ||
14 | #include <asm/memory.h> | ||
15 | #include <asm/pgtable.h> | ||
16 | |||
17 | .section ".idmap.text", "ax" | ||
18 | |||
19 | #define L1_ORDER 3 | ||
20 | #define L2_ORDER 3 | ||
21 | |||
22 | ENTRY(lpae_pgtables_remap_asm) | ||
23 | stmfd sp!, {r4-r8, lr} | ||
24 | |||
25 | mrc p15, 0, r8, c1, c0, 0 @ read control reg | ||
26 | bic ip, r8, #CR_M @ disable caches and MMU | ||
27 | mcr p15, 0, ip, c1, c0, 0 | ||
28 | dsb | ||
29 | isb | ||
30 | |||
31 | /* Update level 2 entries covering the kernel */ | ||
32 | ldr r6, =(_end - 1) | ||
33 | add r7, r2, #0x1000 | ||
34 | add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER | ||
35 | add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER) | ||
36 | 1: ldrd r4, [r7] | ||
37 | adds r4, r4, r0 | ||
38 | adc r5, r5, r1 | ||
39 | strd r4, [r7], #1 << L2_ORDER | ||
40 | cmp r7, r6 | ||
41 | bls 1b | ||
42 | |||
43 | /* Update level 2 entries for the boot data */ | ||
44 | add r7, r2, #0x1000 | ||
45 | add r7, r7, r3, lsr #SECTION_SHIFT - L2_ORDER | ||
46 | bic r7, r7, #(1 << L2_ORDER) - 1 | ||
47 | ldrd r4, [r7] | ||
48 | adds r4, r4, r0 | ||
49 | adc r5, r5, r1 | ||
50 | strd r4, [r7], #1 << L2_ORDER | ||
51 | ldrd r4, [r7] | ||
52 | adds r4, r4, r0 | ||
53 | adc r5, r5, r1 | ||
54 | strd r4, [r7] | ||
55 | |||
56 | /* Update level 1 entries */ | ||
57 | mov r6, #4 | ||
58 | mov r7, r2 | ||
59 | 2: ldrd r4, [r7] | ||
60 | adds r4, r4, r0 | ||
61 | adc r5, r5, r1 | ||
62 | strd r4, [r7], #1 << L1_ORDER | ||
63 | subs r6, r6, #1 | ||
64 | bne 2b | ||
65 | |||
66 | mrrc p15, 0, r4, r5, c2 @ read TTBR0 | ||
67 | adds r4, r4, r0 @ update physical address | ||
68 | adc r5, r5, r1 | ||
69 | mcrr p15, 0, r4, r5, c2 @ write back TTBR0 | ||
70 | mrrc p15, 1, r4, r5, c2 @ read TTBR1 | ||
71 | adds r4, r4, r0 @ update physical address | ||
72 | adc r5, r5, r1 | ||
73 | mcrr p15, 1, r4, r5, c2 @ write back TTBR1 | ||
74 | |||
75 | dsb | ||
76 | |||
77 | mov ip, #0 | ||
78 | mcr p15, 0, ip, c7, c5, 0 @ I+BTB cache invalidate | ||
79 | mcr p15, 0, ip, c8, c7, 0 @ local_flush_tlb_all() | ||
80 | dsb | ||
81 | isb | ||
82 | |||
83 | mcr p15, 0, r8, c1, c0, 0 @ re-enable MMU | ||
84 | dsb | ||
85 | isb | ||
86 | |||
87 | ldmfd sp!, {r4-r8, pc} | ||
88 | ENDPROC(lpae_pgtables_remap_asm) | ||
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile index 8aa791051029..9d259d94e429 100644 --- a/arch/arm/vdso/Makefile +++ b/arch/arm/vdso/Makefile | |||
@@ -6,9 +6,15 @@ obj-vdso := vgettimeofday.o datapage.o | |||
6 | targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds | 6 | targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds |
7 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | 7 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) |
8 | 8 | ||
9 | ccflags-y := -shared -fPIC -fno-common -fno-builtin -fno-stack-protector | 9 | ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector |
10 | ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 -DDISABLE_BRANCH_PROFILING | 10 | ccflags-y += -DDISABLE_BRANCH_PROFILING |
11 | ccflags-y += -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | 11 | |
12 | VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 | ||
13 | VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 | ||
14 | VDSO_LDFLAGS += -nostdlib -shared | ||
15 | VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
16 | VDSO_LDFLAGS += $(call cc-ldoption, -Wl$(comma)--build-id) | ||
17 | VDSO_LDFLAGS += $(call cc-option, -fuse-ld=bfd) | ||
12 | 18 | ||
13 | obj-$(CONFIG_VDSO) += vdso.o | 19 | obj-$(CONFIG_VDSO) += vdso.o |
14 | extra-$(CONFIG_VDSO) += vdso.lds | 20 | extra-$(CONFIG_VDSO) += vdso.lds |
@@ -40,10 +46,8 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE | |||
40 | 46 | ||
41 | # Actual build commands | 47 | # Actual build commands |
42 | quiet_cmd_vdsold = VDSO $@ | 48 | quiet_cmd_vdsold = VDSO $@ |
43 | cmd_vdsold = $(CC) $(c_flags) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) \ | 49 | cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \ |
44 | $(call cc-ldoption, -Wl$(comma)--build-id) \ | 50 | -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@ |
45 | -Wl,-Bsymbolic -Wl,-z,max-page-size=4096 \ | ||
46 | -Wl,-z,common-page-size=4096 -o $@ | ||
47 | 51 | ||
48 | quiet_cmd_vdsomunge = MUNGE $@ | 52 | quiet_cmd_vdsomunge = MUNGE $@ |
49 | cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@ | 53 | cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@ |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 352b6a29910f..4e57730e0be4 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -142,6 +142,12 @@ config ARM_GLOBAL_TIMER | |||
142 | help | 142 | help |
143 | This options enables support for the ARM global timer unit | 143 | This options enables support for the ARM global timer unit |
144 | 144 | ||
145 | config ARM_TIMER_SP804 | ||
146 | bool "Support for Dual Timer SP804 module" | ||
147 | depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP | ||
148 | select CLKSRC_MMIO | ||
149 | select CLKSRC_OF if OF | ||
150 | |||
145 | config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK | 151 | config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK |
146 | bool | 152 | bool |
147 | depends on ARM_GLOBAL_TIMER | 153 | depends on ARM_GLOBAL_TIMER |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index e268b5e1901c..f228354961ca 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -48,6 +48,7 @@ obj-$(CONFIG_MTK_TIMER) += mtk_timer.o | |||
48 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 48 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
49 | obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o | 49 | obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o |
50 | obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o | 50 | obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o |
51 | obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o | ||
51 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 52 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
52 | obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o | 53 | obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o |
53 | obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o | 54 | obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o |
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index c97d1980c0f8..a68866e0ecd4 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c | |||
@@ -26,7 +26,8 @@ | |||
26 | #include <linux/clockchips.h> | 26 | #include <linux/clockchips.h> |
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/sched_clock.h> | 28 | #include <linux/sched_clock.h> |
29 | #include <asm/hardware/arm_timer.h> | 29 | |
30 | #include "timer-sp.h" | ||
30 | 31 | ||
31 | static void __iomem * sched_clk_base; | 32 | static void __iomem * sched_clk_base; |
32 | 33 | ||
diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/drivers/clocksource/timer-sp.h index d6030ff599db..050d88561e9c 100644 --- a/arch/arm/include/asm/hardware/arm_timer.h +++ b/drivers/clocksource/timer-sp.h | |||
@@ -1,6 +1,3 @@ | |||
1 | #ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H | ||
2 | #define __ASM_ARM_HARDWARE_ARM_TIMER_H | ||
3 | |||
4 | /* | 1 | /* |
5 | * ARM timer implementation, found in Integrator, Versatile and Realview | 2 | * ARM timer implementation, found in Integrator, Versatile and Realview |
6 | * platforms. Not all platforms support all registers and bits in these | 3 | * platforms. Not all platforms support all registers and bits in these |
@@ -31,5 +28,3 @@ | |||
31 | #define TIMER_RIS 0x10 /* CVR ro */ | 28 | #define TIMER_RIS 0x10 /* CVR ro */ |
32 | #define TIMER_MIS 0x14 /* CVR ro */ | 29 | #define TIMER_MIS 0x14 /* CVR ro */ |
33 | #define TIMER_BGLOAD 0x18 /* CVR rw */ | 30 | #define TIMER_BGLOAD 0x18 /* CVR rw */ |
34 | |||
35 | #endif | ||
diff --git a/arch/arm/common/timer-sp.c b/drivers/clocksource/timer-sp804.c index 19211324772f..ca02503f17d1 100644 --- a/arch/arm/common/timer-sp.c +++ b/drivers/clocksource/timer-sp804.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/common/timer-sp.c | 2 | * linux/drivers/clocksource/timer-sp.c |
3 | * | 3 | * |
4 | * Copyright (C) 1999 - 2003 ARM Limited | 4 | * Copyright (C) 1999 - 2003 ARM Limited |
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd |
@@ -30,8 +30,9 @@ | |||
30 | #include <linux/of_irq.h> | 30 | #include <linux/of_irq.h> |
31 | #include <linux/sched_clock.h> | 31 | #include <linux/sched_clock.h> |
32 | 32 | ||
33 | #include <asm/hardware/arm_timer.h> | 33 | #include <clocksource/timer-sp804.h> |
34 | #include <asm/hardware/timer-sp.h> | 34 | |
35 | #include "timer-sp.h" | ||
35 | 36 | ||
36 | static long __init sp804_get_clock_rate(struct clk *clk) | 37 | static long __init sp804_get_clock_rate(struct clk *clk) |
37 | { | 38 | { |
@@ -71,6 +72,11 @@ static u64 notrace sp804_read(void) | |||
71 | return ~readl_relaxed(sched_clock_base + TIMER_VALUE); | 72 | return ~readl_relaxed(sched_clock_base + TIMER_VALUE); |
72 | } | 73 | } |
73 | 74 | ||
75 | void __init sp804_timer_disable(void __iomem *base) | ||
76 | { | ||
77 | writel(0, base + TIMER_CTRL); | ||
78 | } | ||
79 | |||
74 | void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, | 80 | void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, |
75 | const char *name, | 81 | const char *name, |
76 | struct clk *clk, | 82 | struct clk *clk, |
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index 40c34faffe59..db2ede565f1a 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c | |||
@@ -108,13 +108,7 @@ static int notrace bl_powerdown_finisher(unsigned long arg) | |||
108 | unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | 108 | unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); |
109 | 109 | ||
110 | mcpm_set_entry_vector(cpu, cluster, cpu_resume); | 110 | mcpm_set_entry_vector(cpu, cluster, cpu_resume); |
111 | 111 | mcpm_cpu_suspend(); | |
112 | /* | ||
113 | * Residency value passed to mcpm_cpu_suspend back-end | ||
114 | * has to be given clear semantics. Set to 0 as a | ||
115 | * temporary value. | ||
116 | */ | ||
117 | mcpm_cpu_suspend(0); | ||
118 | 112 | ||
119 | /* return value != 0 means failure */ | 113 | /* return value != 0 means failure */ |
120 | return 1; | 114 | return 1; |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index f8efb7087760..5c9adf1f554d 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -49,3 +49,4 @@ obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o | |||
49 | obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o | 49 | obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o |
50 | obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o | 50 | obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o |
51 | obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o | 51 | obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o |
52 | obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o | ||
diff --git a/arch/arm/mach-sa1100/irq.c b/drivers/irqchip/irq-sa11x0.c index 65aebfa66fe5..46df2875dc1c 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/drivers/irqchip/irq-sa11x0.c | |||
@@ -1,9 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/mach-sa1100/irq.c | 2 | * Copyright (C) 2015 Dmitry Eremin-Solenikov |
3 | * | ||
4 | * Copyright (C) 1999-2001 Nicolas Pitre | 3 | * Copyright (C) 1999-2001 Nicolas Pitre |
5 | * | 4 | * |
6 | * Generic IRQ handling for the SA11x0, GPIO 11-27 IRQ demultiplexing. | 5 | * Generic IRQ handling for the SA11x0. |
7 | * | 6 | * |
8 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -15,16 +14,21 @@ | |||
15 | #include <linux/io.h> | 14 | #include <linux/io.h> |
16 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
17 | #include <linux/irqdomain.h> | 16 | #include <linux/irqdomain.h> |
18 | #include <linux/ioport.h> | ||
19 | #include <linux/syscore_ops.h> | 17 | #include <linux/syscore_ops.h> |
18 | #include <linux/irqchip/irq-sa11x0.h> | ||
19 | |||
20 | #include <soc/sa1100/pwer.h> | ||
20 | 21 | ||
21 | #include <mach/hardware.h> | ||
22 | #include <mach/irqs.h> | ||
23 | #include <asm/mach/irq.h> | ||
24 | #include <asm/exception.h> | 22 | #include <asm/exception.h> |
25 | 23 | ||
26 | #include "generic.h" | 24 | #define ICIP 0x00 /* IC IRQ Pending reg. */ |
25 | #define ICMR 0x04 /* IC Mask Reg. */ | ||
26 | #define ICLR 0x08 /* IC Level Reg. */ | ||
27 | #define ICCR 0x0C /* IC Control Reg. */ | ||
28 | #define ICFP 0x10 /* IC FIQ Pending reg. */ | ||
29 | #define ICPR 0x20 /* IC Pending Reg. */ | ||
27 | 30 | ||
31 | static void __iomem *iobase; | ||
28 | 32 | ||
29 | /* | 33 | /* |
30 | * We don't need to ACK IRQs on the SA1100 unless they're GPIOs | 34 | * We don't need to ACK IRQs on the SA1100 unless they're GPIOs |
@@ -32,27 +36,25 @@ | |||
32 | */ | 36 | */ |
33 | static void sa1100_mask_irq(struct irq_data *d) | 37 | static void sa1100_mask_irq(struct irq_data *d) |
34 | { | 38 | { |
35 | ICMR &= ~BIT(d->hwirq); | 39 | u32 reg; |
40 | |||
41 | reg = readl_relaxed(iobase + ICMR); | ||
42 | reg &= ~BIT(d->hwirq); | ||
43 | writel_relaxed(reg, iobase + ICMR); | ||
36 | } | 44 | } |
37 | 45 | ||
38 | static void sa1100_unmask_irq(struct irq_data *d) | 46 | static void sa1100_unmask_irq(struct irq_data *d) |
39 | { | 47 | { |
40 | ICMR |= BIT(d->hwirq); | 48 | u32 reg; |
49 | |||
50 | reg = readl_relaxed(iobase + ICMR); | ||
51 | reg |= BIT(d->hwirq); | ||
52 | writel_relaxed(reg, iobase + ICMR); | ||
41 | } | 53 | } |
42 | 54 | ||
43 | /* | ||
44 | * Apart form GPIOs, only the RTC alarm can be a wakeup event. | ||
45 | */ | ||
46 | static int sa1100_set_wake(struct irq_data *d, unsigned int on) | 55 | static int sa1100_set_wake(struct irq_data *d, unsigned int on) |
47 | { | 56 | { |
48 | if (BIT(d->hwirq) == IC_RTCAlrm) { | 57 | return sa11x0_sc_set_wake(d->hwirq, on); |
49 | if (on) | ||
50 | PWER |= PWER_RTC; | ||
51 | else | ||
52 | PWER &= ~PWER_RTC; | ||
53 | return 0; | ||
54 | } | ||
55 | return -EINVAL; | ||
56 | } | 58 | } |
57 | 59 | ||
58 | static struct irq_chip sa1100_normal_chip = { | 60 | static struct irq_chip sa1100_normal_chip = { |
@@ -73,16 +75,13 @@ static int sa1100_normal_irqdomain_map(struct irq_domain *d, | |||
73 | return 0; | 75 | return 0; |
74 | } | 76 | } |
75 | 77 | ||
76 | static struct irq_domain_ops sa1100_normal_irqdomain_ops = { | 78 | static const struct irq_domain_ops sa1100_normal_irqdomain_ops = { |
77 | .map = sa1100_normal_irqdomain_map, | 79 | .map = sa1100_normal_irqdomain_map, |
78 | .xlate = irq_domain_xlate_onetwocell, | 80 | .xlate = irq_domain_xlate_onetwocell, |
79 | }; | 81 | }; |
80 | 82 | ||
81 | static struct irq_domain *sa1100_normal_irqdomain; | 83 | static struct irq_domain *sa1100_normal_irqdomain; |
82 | 84 | ||
83 | static struct resource irq_resource = | ||
84 | DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); | ||
85 | |||
86 | static struct sa1100irq_state { | 85 | static struct sa1100irq_state { |
87 | unsigned int saved; | 86 | unsigned int saved; |
88 | unsigned int icmr; | 87 | unsigned int icmr; |
@@ -95,16 +94,14 @@ static int sa1100irq_suspend(void) | |||
95 | struct sa1100irq_state *st = &sa1100irq_state; | 94 | struct sa1100irq_state *st = &sa1100irq_state; |
96 | 95 | ||
97 | st->saved = 1; | 96 | st->saved = 1; |
98 | st->icmr = ICMR; | 97 | st->icmr = readl_relaxed(iobase + ICMR); |
99 | st->iclr = ICLR; | 98 | st->iclr = readl_relaxed(iobase + ICLR); |
100 | st->iccr = ICCR; | 99 | st->iccr = readl_relaxed(iobase + ICCR); |
101 | 100 | ||
102 | /* | 101 | /* |
103 | * Disable all GPIO-based interrupts. | 102 | * Disable all GPIO-based interrupts. |
104 | */ | 103 | */ |
105 | ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7| | 104 | writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR); |
106 | IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2| | ||
107 | IC_GPIO1|IC_GPIO0); | ||
108 | 105 | ||
109 | return 0; | 106 | return 0; |
110 | } | 107 | } |
@@ -114,10 +111,10 @@ static void sa1100irq_resume(void) | |||
114 | struct sa1100irq_state *st = &sa1100irq_state; | 111 | struct sa1100irq_state *st = &sa1100irq_state; |
115 | 112 | ||
116 | if (st->saved) { | 113 | if (st->saved) { |
117 | ICCR = st->iccr; | 114 | writel_relaxed(st->iccr, iobase + ICCR); |
118 | ICLR = st->iclr; | 115 | writel_relaxed(st->iclr, iobase + ICLR); |
119 | 116 | ||
120 | ICMR = st->icmr; | 117 | writel_relaxed(st->icmr, iobase + ICMR); |
121 | } | 118 | } |
122 | } | 119 | } |
123 | 120 | ||
@@ -140,8 +137,8 @@ sa1100_handle_irq(struct pt_regs *regs) | |||
140 | uint32_t icip, icmr, mask; | 137 | uint32_t icip, icmr, mask; |
141 | 138 | ||
142 | do { | 139 | do { |
143 | icip = (ICIP); | 140 | icip = readl_relaxed(iobase + ICIP); |
144 | icmr = (ICMR); | 141 | icmr = readl_relaxed(iobase + ICMR); |
145 | mask = icip & icmr; | 142 | mask = icip & icmr; |
146 | 143 | ||
147 | if (mask == 0) | 144 | if (mask == 0) |
@@ -152,27 +149,27 @@ sa1100_handle_irq(struct pt_regs *regs) | |||
152 | } while (1); | 149 | } while (1); |
153 | } | 150 | } |
154 | 151 | ||
155 | void __init sa1100_init_irq(void) | 152 | void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start) |
156 | { | 153 | { |
157 | request_resource(&iomem_resource, &irq_resource); | 154 | iobase = ioremap(io_start, SZ_64K); |
155 | if (WARN_ON(!iobase)) | ||
156 | return; | ||
158 | 157 | ||
159 | /* disable all IRQs */ | 158 | /* disable all IRQs */ |
160 | ICMR = 0; | 159 | writel_relaxed(0, iobase + ICMR); |
161 | 160 | ||
162 | /* all IRQs are IRQ, not FIQ */ | 161 | /* all IRQs are IRQ, not FIQ */ |
163 | ICLR = 0; | 162 | writel_relaxed(0, iobase + ICLR); |
164 | 163 | ||
165 | /* | 164 | /* |
166 | * Whatever the doc says, this has to be set for the wait-on-irq | 165 | * Whatever the doc says, this has to be set for the wait-on-irq |
167 | * instruction to work... on a SA1100 rev 9 at least. | 166 | * instruction to work... on a SA1100 rev 9 at least. |
168 | */ | 167 | */ |
169 | ICCR = 1; | 168 | writel_relaxed(1, iobase + ICCR); |
170 | 169 | ||
171 | sa1100_normal_irqdomain = irq_domain_add_simple(NULL, | 170 | sa1100_normal_irqdomain = irq_domain_add_simple(NULL, |
172 | 32, IRQ_GPIO0_SC, | 171 | 32, irq_start, |
173 | &sa1100_normal_irqdomain_ops, NULL); | 172 | &sa1100_normal_irqdomain_ops, NULL); |
174 | 173 | ||
175 | set_handle_irq(sa1100_handle_irq); | 174 | set_handle_irq(sa1100_handle_irq); |
176 | |||
177 | sa1100_init_gpio(); | ||
178 | } | 175 | } |
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/include/clocksource/timer-sp804.h index bb28af7c32de..1f8a1caa7cb4 100644 --- a/arch/arm/include/asm/hardware/timer-sp.h +++ b/include/clocksource/timer-sp804.h | |||
@@ -1,9 +1,13 @@ | |||
1 | #ifndef __CLKSOURCE_TIMER_SP804_H | ||
2 | #define __CLKSOURCE_TIMER_SP804_H | ||
3 | |||
1 | struct clk; | 4 | struct clk; |
2 | 5 | ||
3 | void __sp804_clocksource_and_sched_clock_init(void __iomem *, | 6 | void __sp804_clocksource_and_sched_clock_init(void __iomem *, |
4 | const char *, struct clk *, int); | 7 | const char *, struct clk *, int); |
5 | void __sp804_clockevents_init(void __iomem *, unsigned int, | 8 | void __sp804_clockevents_init(void __iomem *, unsigned int, |
6 | struct clk *, const char *); | 9 | struct clk *, const char *); |
10 | void sp804_timer_disable(void __iomem *); | ||
7 | 11 | ||
8 | static inline void sp804_clocksource_init(void __iomem *base, const char *name) | 12 | static inline void sp804_clocksource_init(void __iomem *base, const char *name) |
9 | { | 13 | { |
@@ -21,3 +25,4 @@ static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, | |||
21 | __sp804_clockevents_init(base, irq, NULL, name); | 25 | __sp804_clockevents_init(base, irq, NULL, name); |
22 | 26 | ||
23 | } | 27 | } |
28 | #endif | ||
diff --git a/include/linux/irqchip/irq-sa11x0.h b/include/linux/irqchip/irq-sa11x0.h new file mode 100644 index 000000000000..15db6829c1e4 --- /dev/null +++ b/include/linux/irqchip/irq-sa11x0.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Generic IRQ handling for the SA11x0. | ||
3 | * | ||
4 | * Copyright (C) 2015 Dmitry Eremin-Solenikov | ||
5 | * Copyright (C) 1999-2001 Nicolas Pitre | ||
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 | |||
12 | #ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_SA11x0_H | ||
13 | #define __INCLUDE_LINUX_IRQCHIP_IRQ_SA11x0_H | ||
14 | |||
15 | void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start); | ||
16 | |||
17 | #endif | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 1b82d44b0a02..3d80c432ede7 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -300,6 +300,11 @@ struct pmu { | |||
300 | * Free pmu-private AUX data structures | 300 | * Free pmu-private AUX data structures |
301 | */ | 301 | */ |
302 | void (*free_aux) (void *aux); /* optional */ | 302 | void (*free_aux) (void *aux); /* optional */ |
303 | |||
304 | /* | ||
305 | * Filter events for PMU-specific reasons. | ||
306 | */ | ||
307 | int (*filter_match) (struct perf_event *event); /* optional */ | ||
303 | }; | 308 | }; |
304 | 309 | ||
305 | /** | 310 | /** |
diff --git a/include/soc/sa1100/pwer.h b/include/soc/sa1100/pwer.h new file mode 100644 index 000000000000..15a545b5a1f6 --- /dev/null +++ b/include/soc/sa1100/pwer.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef SOC_SA1100_PWER_H | ||
2 | #define SOC_SA1100_PWER_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 2015, Dmitry Eremin-Solenikov | ||
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 | |||
12 | int sa11x0_gpio_set_wake(unsigned int gpio, unsigned int on); | ||
13 | int sa11x0_sc_set_wake(unsigned int irq, unsigned int on); | ||
14 | |||
15 | #endif | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index 8e13f3e54ec3..bc95b6a6220b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -1502,11 +1502,17 @@ static int __init perf_workqueue_init(void) | |||
1502 | 1502 | ||
1503 | core_initcall(perf_workqueue_init); | 1503 | core_initcall(perf_workqueue_init); |
1504 | 1504 | ||
1505 | static inline int pmu_filter_match(struct perf_event *event) | ||
1506 | { | ||
1507 | struct pmu *pmu = event->pmu; | ||
1508 | return pmu->filter_match ? pmu->filter_match(event) : 1; | ||
1509 | } | ||
1510 | |||
1505 | static inline int | 1511 | static inline int |
1506 | event_filter_match(struct perf_event *event) | 1512 | event_filter_match(struct perf_event *event) |
1507 | { | 1513 | { |
1508 | return (event->cpu == -1 || event->cpu == smp_processor_id()) | 1514 | return (event->cpu == -1 || event->cpu == smp_processor_id()) |
1509 | && perf_cgroup_match(event); | 1515 | && perf_cgroup_match(event) && pmu_filter_match(event); |
1510 | } | 1516 | } |
1511 | 1517 | ||
1512 | static void | 1518 | static void |