aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorZhao Chenhui <chenhui.zhao@freescale.com>2012-07-20 08:42:36 -0400
committerKumar Gala <galak@kernel.crashing.org>2012-09-12 15:57:08 -0400
commitd0832a75075b1119635e0f48549e378040cf5e67 (patch)
tree9d835dba5b7663517ea08cbde0b9b694614ba704 /arch/powerpc
parentbf34526374a334ddfafaed73b0d8bf7eb4dea833 (diff)
powerpc/85xx: add HOTPLUG_CPU support
Add support to disable and re-enable individual cores at runtime on MPC85xx/QorIQ SMP machines. Currently support e500v1/e500v2 core. MPC85xx machines use ePAPR spin-table in boot page for CPU kick-off. This patch uses the boot page from bootloader to boot core at runtime. It supports 32-bit and 36-bit physical address. Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Jin Qing <b24347@freescale.com> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig6
-rw-r--r--arch/powerpc/include/asm/cacheflush.h2
-rw-r--r--arch/powerpc/include/asm/smp.h1
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S28
-rw-r--r--arch/powerpc/platforms/85xx/smp.c90
5 files changed, 112 insertions, 15 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 98e513b62709..b8bab10bd0f1 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -215,7 +215,8 @@ config ARCH_HIBERNATION_POSSIBLE
215config ARCH_SUSPEND_POSSIBLE 215config ARCH_SUSPEND_POSSIBLE
216 def_bool y 216 def_bool y
217 depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ 217 depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
218 (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x 218 (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
219 || 44x || 40x
219 220
220config PPC_DCR_NATIVE 221config PPC_DCR_NATIVE
221 bool 222 bool
@@ -328,7 +329,8 @@ config SWIOTLB
328 329
329config HOTPLUG_CPU 330config HOTPLUG_CPU
330 bool "Support for enabling/disabling CPUs" 331 bool "Support for enabling/disabling CPUs"
331 depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV) 332 depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
333 PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
332 ---help--- 334 ---help---
333 Say Y here to be able to disable and re-enable individual 335 Say Y here to be able to disable and re-enable individual
334 CPUs at runtime on SMP machines. 336 CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402518e8..b843e35122e8 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,6 +30,8 @@ extern void flush_dcache_page(struct page *page);
30#define flush_dcache_mmap_lock(mapping) do { } while (0) 30#define flush_dcache_mmap_lock(mapping) do { } while (0)
31#define flush_dcache_mmap_unlock(mapping) do { } while (0) 31#define flush_dcache_mmap_unlock(mapping) do { } while (0)
32 32
33extern void __flush_disable_L1(void);
34
33extern void __flush_icache_range(unsigned long, unsigned long); 35extern void __flush_icache_range(unsigned long, unsigned long);
34static inline void flush_icache_range(unsigned long start, unsigned long stop) 36static inline void flush_icache_range(unsigned long start, unsigned long stop)
35{ 37{
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ce8e2bdf84ed..e807e9d8e3f7 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -191,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
191extern unsigned long __secondary_hold_acknowledge; 191extern unsigned long __secondary_hold_acknowledge;
192extern char __secondary_hold; 192extern char __secondary_hold;
193 193
194extern void __early_start(void);
194#endif /* __ASSEMBLY__ */ 195#endif /* __ASSEMBLY__ */
195 196
196#endif /* __KERNEL__ */ 197#endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 0f59863c3ade..b221541d9861 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -1043,6 +1043,34 @@ _GLOBAL(flush_dcache_L1)
1043 1043
1044 blr 1044 blr
1045 1045
1046/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
1047_GLOBAL(__flush_disable_L1)
1048 mflr r10
1049 bl flush_dcache_L1 /* Flush L1 d-cache */
1050 mtlr r10
1051
1052 mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
1053 li r5, 2
1054 rlwimi r4, r5, 0, 3
1055
1056 msync
1057 isync
1058 mtspr SPRN_L1CSR0, r4
1059 isync
1060
10611: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
1062 andi. r4, r4, 2
1063 bne 1b
1064
1065 mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
1066 li r5, 2
1067 rlwimi r4, r5, 0, 3
1068
1069 mtspr SPRN_L1CSR1, r4
1070 isync
1071
1072 blr
1073
1046#ifdef CONFIG_SMP 1074#ifdef CONFIG_SMP
1047/* When we get here, r24 needs to hold the CPU # */ 1075/* When we get here, r24 needs to hold the CPU # */
1048 .globl __secondary_start 1076 .globl __secondary_start
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 7ed52a604a13..6fcfa12e5c56 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -31,8 +31,6 @@
31#include <sysdev/mpic.h> 31#include <sysdev/mpic.h>
32#include "smp.h" 32#include "smp.h"
33 33
34extern void __early_start(void);
35
36struct epapr_spin_table { 34struct epapr_spin_table {
37 u32 addr_h; 35 u32 addr_h;
38 u32 addr_l; 36 u32 addr_l;
@@ -100,15 +98,45 @@ static void mpc85xx_take_timebase(void)
100 local_irq_restore(flags); 98 local_irq_restore(flags);
101} 99}
102 100
103static int __init 101#ifdef CONFIG_HOTPLUG_CPU
104smp_85xx_kick_cpu(int nr) 102static void __cpuinit smp_85xx_mach_cpu_die(void)
103{
104 unsigned int cpu = smp_processor_id();
105 u32 tmp;
106
107 local_irq_disable();
108 idle_task_exit();
109 generic_set_cpu_dead(cpu);
110 mb();
111
112 mtspr(SPRN_TCR, 0);
113
114 __flush_disable_L1();
115 tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
116 mtspr(SPRN_HID0, tmp);
117 isync();
118
119 /* Enter NAP mode. */
120 tmp = mfmsr();
121 tmp |= MSR_WE;
122 mb();
123 mtmsr(tmp);
124 isync();
125
126 while (1)
127 ;
128}
129#endif
130
131static int __cpuinit smp_85xx_kick_cpu(int nr)
105{ 132{
106 unsigned long flags; 133 unsigned long flags;
107 const u64 *cpu_rel_addr; 134 const u64 *cpu_rel_addr;
108 __iomem struct epapr_spin_table *spin_table; 135 __iomem struct epapr_spin_table *spin_table;
109 struct device_node *np; 136 struct device_node *np;
110 int n = 0, hw_cpu = get_hard_smp_processor_id(nr); 137 int hw_cpu = get_hard_smp_processor_id(nr);
111 int ioremappable; 138 int ioremappable;
139 int ret = 0;
112 140
113 WARN_ON(nr < 0 || nr >= NR_CPUS); 141 WARN_ON(nr < 0 || nr >= NR_CPUS);
114 WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS); 142 WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -139,9 +167,34 @@ smp_85xx_kick_cpu(int nr)
139 spin_table = phys_to_virt(*cpu_rel_addr); 167 spin_table = phys_to_virt(*cpu_rel_addr);
140 168
141 local_irq_save(flags); 169 local_irq_save(flags);
170#ifdef CONFIG_PPC32
171#ifdef CONFIG_HOTPLUG_CPU
172 /* Corresponding to generic_set_cpu_dead() */
173 generic_set_cpu_up(nr);
174
175 if (system_state == SYSTEM_RUNNING) {
176 out_be32(&spin_table->addr_l, 0);
142 177
178 /*
179 * We don't set the BPTR register here since it already points
180 * to the boot page properly.
181 */
182 mpic_reset_core(hw_cpu);
183
184 /* wait until core is ready... */
185 if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
186 10000, 100)) {
187 pr_err("%s: timeout waiting for core %d to reset\n",
188 __func__, hw_cpu);
189 ret = -ENOENT;
190 goto out;
191 }
192
193 /* clear the acknowledge status */
194 __secondary_hold_acknowledge = -1;
195 }
196#endif
143 out_be32(&spin_table->pir, hw_cpu); 197 out_be32(&spin_table->pir, hw_cpu);
144#ifdef CONFIG_PPC32
145 out_be32(&spin_table->addr_l, __pa(__early_start)); 198 out_be32(&spin_table->addr_l, __pa(__early_start));
146 199
147 if (!ioremappable) 200 if (!ioremappable)
@@ -149,11 +202,18 @@ smp_85xx_kick_cpu(int nr)
149 (ulong)spin_table + sizeof(struct epapr_spin_table)); 202 (ulong)spin_table + sizeof(struct epapr_spin_table));
150 203
151 /* Wait a bit for the CPU to ack. */ 204 /* Wait a bit for the CPU to ack. */
152 while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000)) 205 if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
153 mdelay(1); 206 10000, 100)) {
207 pr_err("%s: timeout waiting for core %d to ack\n",
208 __func__, hw_cpu);
209 ret = -ENOENT;
210 goto out;
211 }
212out:
154#else 213#else
155 smp_generic_kick_cpu(nr); 214 smp_generic_kick_cpu(nr);
156 215
216 out_be32(&spin_table->pir, hw_cpu);
157 out_be64((u64 *)(&spin_table->addr_h), 217 out_be64((u64 *)(&spin_table->addr_h),
158 __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); 218 __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
159 219
@@ -167,13 +227,15 @@ smp_85xx_kick_cpu(int nr)
167 if (ioremappable) 227 if (ioremappable)
168 iounmap(spin_table); 228 iounmap(spin_table);
169 229
170 pr_debug("waited %d msecs for CPU #%d.\n", n, nr); 230 return ret;
171
172 return 0;
173} 231}
174 232
175struct smp_ops_t smp_85xx_ops = { 233struct smp_ops_t smp_85xx_ops = {
176 .kick_cpu = smp_85xx_kick_cpu, 234 .kick_cpu = smp_85xx_kick_cpu,
235#ifdef CONFIG_HOTPLUG_CPU
236 .cpu_disable = generic_cpu_disable,
237 .cpu_die = generic_cpu_die,
238#endif
177#ifdef CONFIG_KEXEC 239#ifdef CONFIG_KEXEC
178 .give_timebase = smp_generic_give_timebase, 240 .give_timebase = smp_generic_give_timebase,
179 .take_timebase = smp_generic_take_timebase, 241 .take_timebase = smp_generic_take_timebase,
@@ -277,8 +339,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
277} 339}
278#endif /* CONFIG_KEXEC */ 340#endif /* CONFIG_KEXEC */
279 341
280static void __init 342static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
281smp_85xx_setup_cpu(int cpu_nr)
282{ 343{
283 if (smp_85xx_ops.probe == smp_mpic_probe) 344 if (smp_85xx_ops.probe == smp_mpic_probe)
284 mpic_setup_this_cpu(); 345 mpic_setup_this_cpu();
@@ -329,6 +390,9 @@ void __init mpc85xx_smp_init(void)
329 } 390 }
330 smp_85xx_ops.give_timebase = mpc85xx_give_timebase; 391 smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
331 smp_85xx_ops.take_timebase = mpc85xx_take_timebase; 392 smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
393#ifdef CONFIG_HOTPLUG_CPU
394 ppc_md.cpu_die = smp_85xx_mach_cpu_die;
395#endif
332 } 396 }
333 397
334 smp_ops = &smp_85xx_ops; 398 smp_ops = &smp_85xx_ops;