aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2014-06-24 13:32:51 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-07-18 06:58:00 -0400
commit3721924c81541d828d73d0e36dcbae8fd93f0885 (patch)
treeab7e046674055bd4fb0f0c1b321e792201c1f0b2 /arch/arm/common
parent731542ef44a3dea7726a03f906111700847cf777 (diff)
ARM: 8081/1: MCPM: provide infrastructure to allow for MCPM loopback
The kernel already has the responsibility to handle resources such as the CCI when hotplugging CPUs, during the booting of secondary CPUs, and when resuming from suspend/idle. It would be more coherent and less confusing if the CCI for the boot CPU (or cluster) was also initialized by the kernel rather than expecting the firmware/bootloader to do it and only in that case. After all, the kernel has all the necessary code already and the bootloader shouldn't have to care at all. The CCI may be turned on only when the cache is off. Leveraging the CPU suspend code to loop back through the low-level MCPM entry point is all that is needed to properly turn on the CCI from the kernel by using the same code as during secondary boot. Let's provide a generic MCPM loopback function that can be invoked by backend initialization code to set things (CCI or similar) on the boot CPU just as it is done for the other CPUs. Signed-off-by: Nicolas Pitre <nico@linaro.org> Reviewed-by: Kevin Hilman <khilman@linaro.org> Tested-by: Kevin Hilman <khilman@linaro.org> Tested-by: Doug Anderson <dianders@chromium.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/mcpm_entry.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c
index f91136ab447e..3c165fc2dce2 100644
--- a/arch/arm/common/mcpm_entry.c
+++ b/arch/arm/common/mcpm_entry.c
@@ -12,11 +12,13 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/irqflags.h> 14#include <linux/irqflags.h>
15#include <linux/cpu_pm.h>
15 16
16#include <asm/mcpm.h> 17#include <asm/mcpm.h>
17#include <asm/cacheflush.h> 18#include <asm/cacheflush.h>
18#include <asm/idmap.h> 19#include <asm/idmap.h>
19#include <asm/cputype.h> 20#include <asm/cputype.h>
21#include <asm/suspend.h>
20 22
21extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER]; 23extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER];
22 24
@@ -146,6 +148,56 @@ int mcpm_cpu_powered_up(void)
146 return 0; 148 return 0;
147} 149}
148 150
151#ifdef CONFIG_ARM_CPU_SUSPEND
152
153static int __init nocache_trampoline(unsigned long _arg)
154{
155 void (*cache_disable)(void) = (void *)_arg;
156 unsigned int mpidr = read_cpuid_mpidr();
157 unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
158 unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
159 phys_reset_t phys_reset;
160
161 mcpm_set_entry_vector(cpu, cluster, cpu_resume);
162 setup_mm_for_reboot();
163
164 __mcpm_cpu_going_down(cpu, cluster);
165 BUG_ON(!__mcpm_outbound_enter_critical(cpu, cluster));
166 cache_disable();
167 __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
168 __mcpm_cpu_down(cpu, cluster);
169
170 phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
171 phys_reset(virt_to_phys(mcpm_entry_point));
172 BUG();
173}
174
175int __init mcpm_loopback(void (*cache_disable)(void))
176{
177 int ret;
178
179 /*
180 * We're going to soft-restart the current CPU through the
181 * low-level MCPM code by leveraging the suspend/resume
182 * infrastructure. Let's play it safe by using cpu_pm_enter()
183 * in case the CPU init code path resets the VFP or similar.
184 */
185 local_irq_disable();
186 local_fiq_disable();
187 ret = cpu_pm_enter();
188 if (!ret) {
189 ret = cpu_suspend((unsigned long)cache_disable, nocache_trampoline);
190 cpu_pm_exit();
191 }
192 local_fiq_enable();
193 local_irq_enable();
194 if (ret)
195 pr_err("%s returned %d\n", __func__, ret);
196 return ret;
197}
198
199#endif
200
149struct sync_struct mcpm_sync; 201struct sync_struct mcpm_sync;
150 202
151/* 203/*