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
depends on SMP
default 2 if BF561
config HOTPLUG_CPU
bool "Support for hot-pluggable CPUs"
depends on SMP && HOTPLUG
default y
config IRQ_PER_CPU
bool
depends on SMP
......@@ -1130,7 +1135,6 @@ source "fs/Kconfig.binfmt"
endmenu
menu "Power management options"
depends on !SMP
source "kernel/power/Kconfig"
......
......@@ -25,5 +25,12 @@ struct corelock_slot {
void smp_icache_flush_range_others(unsigned long start,
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 */
......@@ -6,3 +6,4 @@ obj-y := ints-priority.o dma.o
obj-$(CONFIG_BF561_COREB) += coreb.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 @@
#include <linux/init.h>
#include <asm/blackfin.h>
#include <asm/asm-offsets.h>
#include <asm/trace.h>
__INIT
......@@ -62,6 +63,8 @@ ENTRY(_coreb_trampoline_start)
M2 = r0;
M3 = r0;
trace_buffer_init(p0,r0);
/* Turn off the icache */
p0.l = LO(IMEM_CONTROL);
p0.h = HI(IMEM_CONTROL);
......@@ -159,6 +162,41 @@ ENTRY(_coreb_trampoline_start)
ENDPROC(_coreb_trampoline_start)
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)
[--sp] = reti;
......@@ -176,12 +214,20 @@ ENTRY(_coreb_start)
sp = [p0];
usp = 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;
call _init_pda
sp += 12;
#ifdef CONFIG_HOTPLUG_CPU
3:
#endif
call _secondary_start_kernel;
.L_exit:
jump.s .L_exit;
ENDPROC(_coreb_start)
__FINIT
......@@ -65,6 +65,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
bfin_write_SICB_IWR0(IWR_DISABLE_ALL);
bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
SSYNC();
/* 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
{
unsigned long timeout;
/* CoreB already running?! */
BUG_ON((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0);
printk(KERN_INFO "Booting Core B.\n");
spin_lock(&boot_lock);
/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
SSYNC();
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
SSYNC();
if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0) {
/* CoreB already running, sending ipi to wakeup it */
platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
} 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;
while (time_before(jiffies, timeout)) {
......
......@@ -344,8 +344,11 @@ void smp_send_stop(void)
int __cpuinit __cpu_up(unsigned int cpu)
{
struct task_struct *idle;
int ret;
static struct task_struct *idle;
if (idle)
free_task(idle);
idle = fork_idle(cpu);
if (IS_ERR(idle)) {
......@@ -354,7 +357,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
}
secondary_stack = task_stack_page(idle) + THREAD_SIZE;
smp_wmb();
ret = platform_boot_secondary(cpu, idle);
......@@ -413,7 +415,6 @@ void __cpuinit secondary_start_kernel(void)
atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count);
current->active_mm = mm;
BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */
preempt_disable();
......@@ -495,3 +496,34 @@ void resync_core_dcache(void)
}
EXPORT_SYMBOL(resync_core_dcache);
#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