Commit 0b39db28 authored by Graf Yang's avatar Graf Yang Committed by Mike Frysinger

Blackfin: SMP: add PM/CPU hotplug support

Signed-off-by: default avatarGraf Yang <graf.yang@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
parent 0d152c27
...@@ -250,6 +250,11 @@ config NR_CPUS ...@@ -250,6 +250,11 @@ config NR_CPUS
depends on SMP depends on SMP
default 2 if BF561 default 2 if BF561
config HOTPLUG_CPU
bool "Support for hot-pluggable CPUs"
depends on SMP && HOTPLUG
default y
config IRQ_PER_CPU config IRQ_PER_CPU
bool bool
depends on SMP depends on SMP
...@@ -1130,7 +1135,6 @@ source "fs/Kconfig.binfmt" ...@@ -1130,7 +1135,6 @@ source "fs/Kconfig.binfmt"
endmenu endmenu
menu "Power management options" menu "Power management options"
depends on !SMP
source "kernel/power/Kconfig" source "kernel/power/Kconfig"
......
...@@ -25,5 +25,12 @@ struct corelock_slot { ...@@ -25,5 +25,12 @@ struct corelock_slot {
void smp_icache_flush_range_others(unsigned long start, void smp_icache_flush_range_others(unsigned long start,
unsigned long end); unsigned long end);
#ifdef CONFIG_HOTPLUG_CPU
void coreb_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
void cpu_die(void);
void platform_cpu_die(void);
int __cpu_disable(void);
int __cpu_die(unsigned int cpu);
#endif
#endif /* !__ASM_BLACKFIN_SMP_H */ #endif /* !__ASM_BLACKFIN_SMP_H */
...@@ -6,3 +6,4 @@ obj-y := ints-priority.o dma.o ...@@ -6,3 +6,4 @@ obj-y := ints-priority.o dma.o
obj-$(CONFIG_BF561_COREB) += coreb.o obj-$(CONFIG_BF561_COREB) += coreb.o
obj-$(CONFIG_SMP) += smp.o secondary.o atomic.o obj-$(CONFIG_SMP) += smp.o secondary.o atomic.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
/*
* Copyright 2007-2009 Analog Devices Inc.
* Graff Yang <graf.yang@analog.com>
*
* Licensed under the GPL-2 or later.
*/
#include <asm/blackfin.h>
#include <asm/smp.h>
#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
int hotplug_coreb;
void platform_cpu_die(void)
{
unsigned long iwr[2] = {0, 0};
unsigned long bank = SIC_SYSIRQ(IRQ_SUPPLE_0) / 32;
unsigned long bit = 1 << (SIC_SYSIRQ(IRQ_SUPPLE_0) % 32);
hotplug_coreb = 1;
iwr[bank] = bit;
/* disable core timer */
bfin_write_TCNTL(0);
/* clear ipi interrupt IRQ_SUPPLE_0 */
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + 1)));
SSYNC();
coreb_sleep(iwr[0], iwr[1], 0);
}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/blackfin.h> #include <asm/blackfin.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/trace.h>
__INIT __INIT
...@@ -62,6 +63,8 @@ ENTRY(_coreb_trampoline_start) ...@@ -62,6 +63,8 @@ ENTRY(_coreb_trampoline_start)
M2 = r0; M2 = r0;
M3 = r0; M3 = r0;
trace_buffer_init(p0,r0);
/* Turn off the icache */ /* Turn off the icache */
p0.l = LO(IMEM_CONTROL); p0.l = LO(IMEM_CONTROL);
p0.h = HI(IMEM_CONTROL); p0.h = HI(IMEM_CONTROL);
...@@ -159,6 +162,41 @@ ENTRY(_coreb_trampoline_start) ...@@ -159,6 +162,41 @@ ENTRY(_coreb_trampoline_start)
ENDPROC(_coreb_trampoline_start) ENDPROC(_coreb_trampoline_start)
ENTRY(_coreb_trampoline_end) ENTRY(_coreb_trampoline_end)
.section ".text"
ENTRY(_set_sicb_iwr)
P0.H = hi(SICB_IWR0);
P0.L = lo(SICB_IWR0);
P1.H = hi(SICB_IWR1);
P1.L = lo(SICB_IWR1);
[P0] = R0;
[P1] = R1;
SSYNC;
RTS;
ENDPROC(_set_sicb_iwr)
ENTRY(_coreb_sleep)
sp.l = lo(INITIAL_STACK);
sp.h = hi(INITIAL_STACK);
fp = sp;
usp = sp;
call _set_sicb_iwr;
CLI R2;
SSYNC;
IDLE;
STI R2;
R0 = IWR_DISABLE_ALL;
R1 = IWR_DISABLE_ALL;
call _set_sicb_iwr;
p0.h = hi(COREB_L1_CODE_START);
p0.l = lo(COREB_L1_CODE_START);
jump (p0);
ENDPROC(_coreb_sleep)
__CPUINIT
ENTRY(_coreb_start) ENTRY(_coreb_start)
[--sp] = reti; [--sp] = reti;
...@@ -176,12 +214,20 @@ ENTRY(_coreb_start) ...@@ -176,12 +214,20 @@ ENTRY(_coreb_start)
sp = [p0]; sp = [p0];
usp = sp; usp = sp;
fp = sp; fp = sp;
#ifdef CONFIG_HOTPLUG_CPU
p0.l = _hotplug_coreb;
p0.h = _hotplug_coreb;
r0 = [p0];
cc = BITTST(r0, 0);
if cc jump 3f;
#endif
sp += -12; sp += -12;
call _init_pda call _init_pda
sp += 12; sp += 12;
#ifdef CONFIG_HOTPLUG_CPU
3:
#endif
call _secondary_start_kernel; call _secondary_start_kernel;
.L_exit: .L_exit:
jump.s .L_exit; jump.s .L_exit;
ENDPROC(_coreb_start) ENDPROC(_coreb_start)
__FINIT
...@@ -65,6 +65,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu) ...@@ -65,6 +65,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
bfin_write_SICB_IAR5(bfin_read_SICA_IAR5()); bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
bfin_write_SICB_IAR6(bfin_read_SICA_IAR6()); bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
bfin_write_SICB_IAR7(bfin_read_SICA_IAR7()); bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
bfin_write_SICB_IWR0(IWR_DISABLE_ALL);
bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
SSYNC(); SSYNC();
/* Store CPU-private information to the cpu_data array. */ /* 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,17 +82,18 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
{ {
unsigned long timeout; unsigned long timeout;
/* CoreB already running?! */
BUG_ON((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0);
printk(KERN_INFO "Booting Core B.\n"); printk(KERN_INFO "Booting Core B.\n");
spin_lock(&boot_lock); spin_lock(&boot_lock);
/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */ if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0) {
SSYNC(); /* CoreB already running, sending ipi to wakeup it */
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT); platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
SSYNC(); } else {
/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
SSYNC();
}
timeout = jiffies + 1 * HZ; timeout = jiffies + 1 * HZ;
while (time_before(jiffies, timeout)) { while (time_before(jiffies, timeout)) {
......
...@@ -344,8 +344,11 @@ void smp_send_stop(void) ...@@ -344,8 +344,11 @@ void smp_send_stop(void)
int __cpuinit __cpu_up(unsigned int cpu) int __cpuinit __cpu_up(unsigned int cpu)
{ {
struct task_struct *idle;
int ret; int ret;
static struct task_struct *idle;
if (idle)
free_task(idle);
idle = fork_idle(cpu); idle = fork_idle(cpu);
if (IS_ERR(idle)) { if (IS_ERR(idle)) {
...@@ -354,7 +357,6 @@ int __cpuinit __cpu_up(unsigned int cpu) ...@@ -354,7 +357,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
} }
secondary_stack = task_stack_page(idle) + THREAD_SIZE; secondary_stack = task_stack_page(idle) + THREAD_SIZE;
smp_wmb();
ret = platform_boot_secondary(cpu, idle); ret = platform_boot_secondary(cpu, idle);
...@@ -413,7 +415,6 @@ void __cpuinit secondary_start_kernel(void) ...@@ -413,7 +415,6 @@ void __cpuinit secondary_start_kernel(void)
atomic_inc(&mm->mm_users); atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count); atomic_inc(&mm->mm_count);
current->active_mm = mm; current->active_mm = mm;
BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */
preempt_disable(); preempt_disable();
...@@ -495,3 +496,34 @@ void resync_core_dcache(void) ...@@ -495,3 +496,34 @@ void resync_core_dcache(void)
} }
EXPORT_SYMBOL(resync_core_dcache); EXPORT_SYMBOL(resync_core_dcache);
#endif #endif
#ifdef CONFIG_HOTPLUG_CPU
int __cpuexit __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
if (cpu == 0)
return -EPERM;
set_cpu_online(cpu, false);
return 0;
}
static DECLARE_COMPLETION(cpu_killed);
int __cpuexit __cpu_die(unsigned int cpu)
{
return wait_for_completion_timeout(&cpu_killed, 5000);
}
void cpu_die(void)
{
complete(&cpu_killed);
atomic_dec(&init_mm.mm_users);
atomic_dec(&init_mm.mm_count);
local_irq_disable();
platform_cpu_die();
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment