mirror of https://gitee.com/openkylin/linux.git
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
|
||||
#define _ASM_POWERPC_CPUTHREADS_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
/*
|
||||
|
@ -103,7 +104,12 @@ static inline u32 get_tensr(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void book3e_start_thread(int thread, unsigned long addr);
|
||||
void book3e_stop_thread(int thread);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#define INVALID_THREAD_HWID 0x0fff
|
||||
|
||||
#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_acknowledge;
|
||||
extern char __secondary_hold;
|
||||
extern unsigned int booting_thread_hwid;
|
||||
|
||||
extern void __early_start(void);
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <asm/kvm_book3s_asm.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/cputhreads.h>
|
||||
|
||||
/* The physical memory is laid out such that the secondary processor
|
||||
* spin code sits at 0x0000...0x00ff. On server, the vectors follow
|
||||
|
@ -181,6 +182,45 @@ exception_marker:
|
|||
#endif
|
||||
|
||||
#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
|
||||
* input parameter:
|
||||
|
@ -280,6 +320,44 @@ _GLOBAL(generic_secondary_smp_init)
|
|||
mr r3,r24
|
||||
mr r4,r25
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
void fsl_secondary_thread_init(void);
|
||||
unsigned long imsr, inia;
|
||||
int nr = *(const int *)info;
|
||||
unsigned long inia;
|
||||
int cpu = *(const int *)info;
|
||||
|
||||
imsr = MSR_KERNEL;
|
||||
inia = *(unsigned long *)fsl_secondary_thread_init;
|
||||
|
||||
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);
|
||||
book3e_start_thread(cpu_thread_in_core(cpu), inia);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -292,33 +279,54 @@ static int smp_85xx_kick_cpu(int nr)
|
|||
pr_debug("kick CPU #%d\n", nr);
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
/* Threads don't use the spin table */
|
||||
if (cpu_thread_in_core(nr) != 0) {
|
||||
int primary = cpu_first_thread_sibling(nr);
|
||||
|
||||
if (threads_per_core == 2) {
|
||||
if (WARN_ON_ONCE(!cpu_has_feature(CPU_FTR_SMT)))
|
||||
return -ENOENT;
|
||||
|
||||
if (cpu_thread_in_core(nr) != 1) {
|
||||
pr_err("%s: cpu %d: invalid hw thread %d\n",
|
||||
__func__, nr, cpu_thread_in_core(nr));
|
||||
return -ENOENT;
|
||||
booting_thread_hwid = cpu_thread_in_core(nr);
|
||||
primary = cpu_first_thread_sibling(nr);
|
||||
|
||||
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",
|
||||
__func__, nr, primary);
|
||||
return -ENOENT;
|
||||
}
|
||||
/*
|
||||
* If getting here, it means both threads in the core are
|
||||
* offline. So start the primary thread, then it will start
|
||||
* the thread specified in booting_thread_hwid, the one
|
||||
* corresponding to nr.
|
||||
*/
|
||||
|
||||
smp_call_function_single(primary, wake_hw_thread, &nr, 0);
|
||||
return 0;
|
||||
} else if (threads_per_core == 1) {
|
||||
/*
|
||||
* 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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
done:
|
||||
paca[nr].cpu_start = 1;
|
||||
generic_set_cpu_up(nr);
|
||||
|
||||
|
|
Loading…
Reference in New Issue