forked from luck/tmp_suning_uos_patched
powerpc/mpc85xx: Add CPU hotplug support for E6500
Support Freescale E6500 core-based platforms, like t4240. Support disabling/enabling individual CPU thread dynamically. Signed-off-by: Chenhui Zhao <chenhui.zhao@freescale.com>
This commit is contained in:
parent
2f4f1f815b
commit
6becef7ea0
@ -1,6 +1,7 @@
|
|||||||
#ifndef _ASM_POWERPC_CPUTHREADS_H
|
#ifndef _ASM_POWERPC_CPUTHREADS_H
|
||||||
#define _ASM_POWERPC_CPUTHREADS_H
|
#define _ASM_POWERPC_CPUTHREADS_H
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -103,7 +104,12 @@ static inline u32 get_tensr(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void book3e_start_thread(int thread, unsigned long addr);
|
||||||
void book3e_stop_thread(int thread);
|
void book3e_stop_thread(int thread);
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#define INVALID_THREAD_HWID 0x0fff
|
||||||
|
|
||||||
#endif /* _ASM_POWERPC_CPUTHREADS_H */
|
#endif /* _ASM_POWERPC_CPUTHREADS_H */
|
||||||
|
|
||||||
|
@ -200,6 +200,7 @@ extern void generic_secondary_thread_init(void);
|
|||||||
extern unsigned long __secondary_hold_spinloop;
|
extern unsigned long __secondary_hold_spinloop;
|
||||||
extern unsigned long __secondary_hold_acknowledge;
|
extern unsigned long __secondary_hold_acknowledge;
|
||||||
extern char __secondary_hold;
|
extern char __secondary_hold;
|
||||||
|
extern unsigned int booting_thread_hwid;
|
||||||
|
|
||||||
extern void __early_start(void);
|
extern void __early_start(void);
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <asm/kvm_book3s_asm.h>
|
#include <asm/kvm_book3s_asm.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/hw_irq.h>
|
#include <asm/hw_irq.h>
|
||||||
|
#include <asm/cputhreads.h>
|
||||||
|
|
||||||
/* The physical memory is laid out such that the secondary processor
|
/* The physical memory is laid out such that the secondary processor
|
||||||
* spin code sits at 0x0000...0x00ff. On server, the vectors follow
|
* spin code sits at 0x0000...0x00ff. On server, the vectors follow
|
||||||
@ -181,6 +182,45 @@ exception_marker:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PPC_BOOK3E
|
#ifdef CONFIG_PPC_BOOK3E
|
||||||
|
/*
|
||||||
|
* The booting_thread_hwid holds the thread id we want to boot in cpu
|
||||||
|
* hotplug case. It is set by cpu hotplug code, and is invalid by default.
|
||||||
|
* The thread id is the same as the initial value of SPRN_PIR[THREAD_ID]
|
||||||
|
* bit field.
|
||||||
|
*/
|
||||||
|
.globl booting_thread_hwid
|
||||||
|
booting_thread_hwid:
|
||||||
|
.long INVALID_THREAD_HWID
|
||||||
|
.align 3
|
||||||
|
/*
|
||||||
|
* start a thread in the same core
|
||||||
|
* input parameters:
|
||||||
|
* r3 = the thread physical id
|
||||||
|
* r4 = the entry point where thread starts
|
||||||
|
*/
|
||||||
|
_GLOBAL(book3e_start_thread)
|
||||||
|
LOAD_REG_IMMEDIATE(r5, MSR_KERNEL)
|
||||||
|
cmpi 0, r3, 0
|
||||||
|
beq 10f
|
||||||
|
cmpi 0, r3, 1
|
||||||
|
beq 11f
|
||||||
|
/* If the thread id is invalid, just exit. */
|
||||||
|
b 13f
|
||||||
|
10:
|
||||||
|
mttmr TMRN_IMSR0, r5
|
||||||
|
mttmr TMRN_INIA0, r4
|
||||||
|
b 12f
|
||||||
|
11:
|
||||||
|
mttmr TMRN_IMSR1, r5
|
||||||
|
mttmr TMRN_INIA1, r4
|
||||||
|
12:
|
||||||
|
isync
|
||||||
|
li r6, 1
|
||||||
|
sld r6, r6, r3
|
||||||
|
mtspr SPRN_TENS, r6
|
||||||
|
13:
|
||||||
|
blr
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stop a thread in the same core
|
* stop a thread in the same core
|
||||||
* input parameter:
|
* input parameter:
|
||||||
@ -280,6 +320,44 @@ _GLOBAL(generic_secondary_smp_init)
|
|||||||
mr r3,r24
|
mr r3,r24
|
||||||
mr r4,r25
|
mr r4,r25
|
||||||
bl book3e_secondary_core_init
|
bl book3e_secondary_core_init
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After common core init has finished, check if the current thread is the
|
||||||
|
* one we wanted to boot. If not, start the specified thread and stop the
|
||||||
|
* current thread.
|
||||||
|
*/
|
||||||
|
LOAD_REG_ADDR(r4, booting_thread_hwid)
|
||||||
|
lwz r3, 0(r4)
|
||||||
|
li r5, INVALID_THREAD_HWID
|
||||||
|
cmpw r3, r5
|
||||||
|
beq 20f
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The value of booting_thread_hwid has been stored in r3,
|
||||||
|
* so make it invalid.
|
||||||
|
*/
|
||||||
|
stw r5, 0(r4)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the current thread id and check if it is the one we wanted.
|
||||||
|
* If not, start the one specified in booting_thread_hwid and stop
|
||||||
|
* the current thread.
|
||||||
|
*/
|
||||||
|
mfspr r8, SPRN_TIR
|
||||||
|
cmpw r3, r8
|
||||||
|
beq 20f
|
||||||
|
|
||||||
|
/* start the specified thread */
|
||||||
|
LOAD_REG_ADDR(r5, fsl_secondary_thread_init)
|
||||||
|
ld r4, 0(r5)
|
||||||
|
bl book3e_start_thread
|
||||||
|
|
||||||
|
/* stop the current thread */
|
||||||
|
mr r3, r8
|
||||||
|
bl book3e_stop_thread
|
||||||
|
10:
|
||||||
|
b 10b
|
||||||
|
20:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
generic_secondary_common_init:
|
generic_secondary_common_init:
|
||||||
|
@ -180,24 +180,11 @@ static inline u32 read_spin_table_addr_l(void *spin_table)
|
|||||||
static void wake_hw_thread(void *info)
|
static void wake_hw_thread(void *info)
|
||||||
{
|
{
|
||||||
void fsl_secondary_thread_init(void);
|
void fsl_secondary_thread_init(void);
|
||||||
unsigned long imsr, inia;
|
unsigned long inia;
|
||||||
int nr = *(const int *)info;
|
int cpu = *(const int *)info;
|
||||||
|
|
||||||
imsr = MSR_KERNEL;
|
|
||||||
inia = *(unsigned long *)fsl_secondary_thread_init;
|
inia = *(unsigned long *)fsl_secondary_thread_init;
|
||||||
|
book3e_start_thread(cpu_thread_in_core(cpu), inia);
|
||||||
if (cpu_thread_in_core(nr) == 0) {
|
|
||||||
/* For when we boot on a secondary thread with kdump */
|
|
||||||
mttmr(TMRN_IMSR0, imsr);
|
|
||||||
mttmr(TMRN_INIA0, inia);
|
|
||||||
mtspr(SPRN_TENS, TEN_THREAD(0));
|
|
||||||
} else {
|
|
||||||
mttmr(TMRN_IMSR1, imsr);
|
|
||||||
mttmr(TMRN_INIA1, inia);
|
|
||||||
mtspr(SPRN_TENS, TEN_THREAD(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
smp_generic_kick_cpu(nr);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -292,33 +279,54 @@ static int smp_85xx_kick_cpu(int nr)
|
|||||||
pr_debug("kick CPU #%d\n", nr);
|
pr_debug("kick CPU #%d\n", nr);
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
/* Threads don't use the spin table */
|
if (threads_per_core == 2) {
|
||||||
if (cpu_thread_in_core(nr) != 0) {
|
|
||||||
int primary = cpu_first_thread_sibling(nr);
|
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!cpu_has_feature(CPU_FTR_SMT)))
|
if (WARN_ON_ONCE(!cpu_has_feature(CPU_FTR_SMT)))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
if (cpu_thread_in_core(nr) != 1) {
|
booting_thread_hwid = cpu_thread_in_core(nr);
|
||||||
pr_err("%s: cpu %d: invalid hw thread %d\n",
|
primary = cpu_first_thread_sibling(nr);
|
||||||
__func__, nr, cpu_thread_in_core(nr));
|
|
||||||
return -ENOENT;
|
if (qoriq_pm_ops)
|
||||||
|
qoriq_pm_ops->cpu_up_prepare(nr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If either thread in the core is online, use it to start
|
||||||
|
* the other.
|
||||||
|
*/
|
||||||
|
if (cpu_online(primary)) {
|
||||||
|
smp_call_function_single(primary,
|
||||||
|
wake_hw_thread, &nr, 1);
|
||||||
|
goto done;
|
||||||
|
} else if (cpu_online(primary + 1)) {
|
||||||
|
smp_call_function_single(primary + 1,
|
||||||
|
wake_hw_thread, &nr, 1);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpu_online(primary)) {
|
/*
|
||||||
pr_err("%s: cpu %d: primary %d not online\n",
|
* If getting here, it means both threads in the core are
|
||||||
__func__, nr, primary);
|
* offline. So start the primary thread, then it will start
|
||||||
return -ENOENT;
|
* the thread specified in booting_thread_hwid, the one
|
||||||
}
|
* corresponding to nr.
|
||||||
|
*/
|
||||||
|
|
||||||
smp_call_function_single(primary, wake_hw_thread, &nr, 0);
|
} else if (threads_per_core == 1) {
|
||||||
return 0;
|
/*
|
||||||
|
* If one core has only one thread, set booting_thread_hwid to
|
||||||
|
* an invalid value.
|
||||||
|
*/
|
||||||
|
booting_thread_hwid = INVALID_THREAD_HWID;
|
||||||
|
|
||||||
|
} else if (threads_per_core > 2) {
|
||||||
|
pr_err("Do not support more than 2 threads per CPU.");
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = smp_85xx_start_cpu(primary);
|
ret = smp_85xx_start_cpu(primary);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
done:
|
||||||
paca[nr].cpu_start = 1;
|
paca[nr].cpu_start = 1;
|
||||||
generic_set_cpu_up(nr);
|
generic_set_cpu_up(nr);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user