mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
Blackfin: SMP: add PM/CPU hotplug support
Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
parent
0d152c27e3
commit
0b39db28b9
7 changed files with 138 additions and 13 deletions
|
@ -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
|
||||
|
|
32
arch/blackfin/mach-bf561/hotplug.c
Normal file
32
arch/blackfin/mach-bf561/hotplug.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
Loading…
Reference in a new issue