aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2009-12-28 06:13:51 -0500
committerMike Frysinger <vapier@gentoo.org>2010-03-09 00:30:48 -0500
commit0b39db28b953945232719e7ff6fb802aa8a2be5f (patch)
treec35193b07e9413ed6b5436aa79e24b0f22627082
parent0d152c27e336b5fd777da7dd3e814617e7305afd (diff)
Blackfin: SMP: add PM/CPU hotplug support
Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--arch/blackfin/Kconfig6
-rw-r--r--arch/blackfin/include/asm/smp.h7
-rw-r--r--arch/blackfin/mach-bf561/Makefile1
-rw-r--r--arch/blackfin/mach-bf561/hotplug.c32
-rw-r--r--arch/blackfin/mach-bf561/secondary.S50
-rw-r--r--arch/blackfin/mach-bf561/smp.c17
-rw-r--r--arch/blackfin/mach-common/smp.c38
7 files changed, 138 insertions, 13 deletions
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 0bd26dbca09f..c0d6d966adec 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -250,6 +250,11 @@ config NR_CPUS
250 depends on SMP 250 depends on SMP
251 default 2 if BF561 251 default 2 if BF561
252 252
253config HOTPLUG_CPU
254 bool "Support for hot-pluggable CPUs"
255 depends on SMP && HOTPLUG
256 default y
257
253config IRQ_PER_CPU 258config IRQ_PER_CPU
254 bool 259 bool
255 depends on SMP 260 depends on SMP
@@ -1130,7 +1135,6 @@ source "fs/Kconfig.binfmt"
1130endmenu 1135endmenu
1131 1136
1132menu "Power management options" 1137menu "Power management options"
1133 depends on !SMP
1134 1138
1135source "kernel/power/Kconfig" 1139source "kernel/power/Kconfig"
1136 1140
diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h
index 6a0fe94b84a6..29fb88219470 100644
--- a/arch/blackfin/include/asm/smp.h
+++ b/arch/blackfin/include/asm/smp.h
@@ -25,5 +25,12 @@ struct corelock_slot {
25 25
26void smp_icache_flush_range_others(unsigned long start, 26void smp_icache_flush_range_others(unsigned long start,
27 unsigned long end); 27 unsigned long end);
28#ifdef CONFIG_HOTPLUG_CPU
29void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
30void cpu_die(void);
31void platform_cpu_die(void);
32int __cpu_disable(void);
33int __cpu_die(unsigned int cpu);
34#endif
28 35
29#endif /* !__ASM_BLACKFIN_SMP_H */ 36#endif /* !__ASM_BLACKFIN_SMP_H */
diff --git a/arch/blackfin/mach-bf561/Makefile b/arch/blackfin/mach-bf561/Makefile
index 59e18afe28c6..b34029718318 100644
--- a/arch/blackfin/mach-bf561/Makefile
+++ b/arch/blackfin/mach-bf561/Makefile
@@ -6,3 +6,4 @@ obj-y := ints-priority.o dma.o
6 6
7obj-$(CONFIG_BF561_COREB) += coreb.o 7obj-$(CONFIG_BF561_COREB) += coreb.o
8obj-$(CONFIG_SMP) += smp.o secondary.o atomic.o 8obj-$(CONFIG_SMP) += smp.o secondary.o atomic.o
9obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/blackfin/mach-bf561/hotplug.c b/arch/blackfin/mach-bf561/hotplug.c
new file mode 100644
index 000000000000..c95169b612dc
--- /dev/null
+++ b/arch/blackfin/mach-bf561/hotplug.c
@@ -0,0 +1,32 @@
1/*
2 * Copyright 2007-2009 Analog Devices Inc.
3 * Graff Yang <graf.yang@analog.com>
4 *
5 * Licensed under the GPL-2 or later.
6 */
7
8#include <asm/blackfin.h>
9#include <asm/smp.h>
10#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
11
12int hotplug_coreb;
13
14void platform_cpu_die(void)
15{
16 unsigned long iwr[2] = {0, 0};
17 unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
18 unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
19
20 hotplug_coreb = 1;
21
22 iwr[bank] = bit;
23
24 /* disable core timer */
25 bfin_write_TCNTL(0);
26
27 /* clear ipi interrupt IRQ_SUPPLE_0 */
28 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
29 SSYNC();
30
31 coreb_sleep(iwr[0], iwr[1], 0);
32}
diff --git a/arch/blackfin/mach-bf561/secondary.S b/arch/blackfin/mach-bf561/secondary.S
index 8e6050369c06..4624eebbf9c4 100644
--- a/arch/blackfin/mach-bf561/secondary.S
+++ b/arch/blackfin/mach-bf561/secondary.S
@@ -11,6 +11,7 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <asm/blackfin.h> 12#include <asm/blackfin.h>
13#include <asm/asm-offsets.h> 13#include <asm/asm-offsets.h>
14#include <asm/trace.h>
14 15
15__INIT 16__INIT
16 17
@@ -62,6 +63,8 @@ ENTRY(_coreb_trampoline_start)
62 M2 = r0; 63 M2 = r0;
63 M3 = r0; 64 M3 = r0;
64 65
66 trace_buffer_init(p0,r0);
67
65 /* Turn off the icache */ 68 /* Turn off the icache */
66 p0.l = LO(IMEM_CONTROL); 69 p0.l = LO(IMEM_CONTROL);
67 p0.h = HI(IMEM_CONTROL); 70 p0.h = HI(IMEM_CONTROL);
@@ -159,6 +162,41 @@ ENTRY(_coreb_trampoline_start)
159ENDPROC(_coreb_trampoline_start) 162ENDPROC(_coreb_trampoline_start)
160ENTRY(_coreb_trampoline_end) 163ENTRY(_coreb_trampoline_end)
161 164
165.section ".text"
166ENTRY(_set_sicb_iwr)
167 P0.H = hi(SICB_IWR0);
168 P0.L = lo(SICB_IWR0);
169 P1.H = hi(SICB_IWR1);
170 P1.L = lo(SICB_IWR1);
171 [P0] = R0;
172 [P1] = R1;
173 SSYNC;
174 RTS;
175ENDPROC(_set_sicb_iwr)
176
177ENTRY(_coreb_sleep)
178 sp.l = lo(INITIAL_STACK);
179 sp.h = hi(INITIAL_STACK);
180 fp = sp;
181 usp = sp;
182
183 call _set_sicb_iwr;
184
185 CLI R2;
186 SSYNC;
187 IDLE;
188 STI R2;
189
190 R0 = IWR_DISABLE_ALL;
191 R1 = IWR_DISABLE_ALL;
192 call _set_sicb_iwr;
193
194 p0.h = hi(COREB_L1_CODE_START);
195 p0.l = lo(COREB_L1_CODE_START);
196 jump (p0);
197ENDPROC(_coreb_sleep)
198
199__CPUINIT
162ENTRY(_coreb_start) 200ENTRY(_coreb_start)
163 [--sp] = reti; 201 [--sp] = reti;
164 202
@@ -176,12 +214,20 @@ ENTRY(_coreb_start)
176 sp = [p0]; 214 sp = [p0];
177 usp = sp; 215 usp = sp;
178 fp = sp; 216 fp = sp;
217#ifdef CONFIG_HOTPLUG_CPU
218 p0.l = _hotplug_coreb;
219 p0.h = _hotplug_coreb;
220 r0 = [p0];
221 cc = BITTST(r0, 0);
222 if cc jump 3f;
223#endif
179 sp += -12; 224 sp += -12;
180 call _init_pda 225 call _init_pda
181 sp += 12; 226 sp += 12;
227#ifdef CONFIG_HOTPLUG_CPU
2283:
229#endif
182 call _secondary_start_kernel; 230 call _secondary_start_kernel;
183.L_exit: 231.L_exit:
184 jump.s .L_exit; 232 jump.s .L_exit;
185ENDPROC(_coreb_start) 233ENDPROC(_coreb_start)
186
187__FINIT
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 90369429ee66..3b9a4bf7dacc 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -65,6 +65,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
65 bfin_write_SICB_IAR5(bfin_read_SICA_IAR5()); 65 bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
66 bfin_write_SICB_IAR6(bfin_read_SICA_IAR6()); 66 bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
67 bfin_write_SICB_IAR7(bfin_read_SICA_IAR7()); 67 bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
68 bfin_write_SICB_IWR0(IWR_DISABLE_ALL);
69 bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
68 SSYNC(); 70 SSYNC();
69 71
70 /* Store CPU-private information to the cpu_data array. */ 72 /* Store CPU-private information to the cpu_data array. */
@@ -80,17 +82,18 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
80{ 82{
81 unsigned long timeout; 83 unsigned long timeout;
82 84
83 /* CoreB already running?! */
84 BUG_ON((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0);
85
86 printk(KERN_INFO "Booting Core B.\n"); 85 printk(KERN_INFO "Booting Core B.\n");
87 86
88 spin_lock(&boot_lock); 87 spin_lock(&boot_lock);
89 88
90 /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */ 89 if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0) {
91 SSYNC(); 90 /* CoreB already running, sending ipi to wakeup it */
92 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT); 91 platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
93 SSYNC(); 92 } else {
93 /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
94 bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
95 SSYNC();
96 }
94 97
95 timeout = jiffies + 1 * HZ; 98 timeout = jiffies + 1 * HZ;
96 while (time_before(jiffies, timeout)) { 99 while (time_before(jiffies, timeout)) {
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index b343ab3764a1..efc47ffd066d 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -344,8 +344,11 @@ void smp_send_stop(void)
344 344
345int __cpuinit __cpu_up(unsigned int cpu) 345int __cpuinit __cpu_up(unsigned int cpu)
346{ 346{
347 struct task_struct *idle;
348 int ret; 347 int ret;
348 static struct task_struct *idle;
349
350 if (idle)
351 free_task(idle);
349 352
350 idle = fork_idle(cpu); 353 idle = fork_idle(cpu);
351 if (IS_ERR(idle)) { 354 if (IS_ERR(idle)) {
@@ -354,7 +357,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
354 } 357 }
355 358
356 secondary_stack = task_stack_page(idle) + THREAD_SIZE; 359 secondary_stack = task_stack_page(idle) + THREAD_SIZE;
357 smp_wmb();
358 360
359 ret = platform_boot_secondary(cpu, idle); 361 ret = platform_boot_secondary(cpu, idle);
360 362
@@ -413,7 +415,6 @@ void __cpuinit secondary_start_kernel(void)
413 atomic_inc(&mm->mm_users); 415 atomic_inc(&mm->mm_users);
414 atomic_inc(&mm->mm_count); 416 atomic_inc(&mm->mm_count);
415 current->active_mm = mm; 417 current->active_mm = mm;
416 BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */
417 418
418 preempt_disable(); 419 preempt_disable();
419 420
@@ -495,3 +496,34 @@ void resync_core_dcache(void)
495} 496}
496EXPORT_SYMBOL(resync_core_dcache); 497EXPORT_SYMBOL(resync_core_dcache);
497#endif 498#endif
499
500#ifdef CONFIG_HOTPLUG_CPU
501int __cpuexit __cpu_disable(void)
502{
503 unsigned int cpu = smp_processor_id();
504
505 if (cpu == 0)
506 return -EPERM;
507
508 set_cpu_online(cpu, false);
509 return 0;
510}
511
512static DECLARE_COMPLETION(cpu_killed);
513
514int __cpuexit __cpu_die(unsigned int cpu)
515{
516 return wait_for_completion_timeout(&cpu_killed, 5000);
517}
518
519void cpu_die(void)
520{
521 complete(&cpu_killed);
522
523 atomic_dec(&init_mm.mm_users);
524 atomic_dec(&init_mm.mm_count);
525
526 local_irq_disable();
527 platform_cpu_die();
528}
529#endif