summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhang Zhuoyu <Zhuoyu.Zhang@freescale.com>2014-10-10 16:02:36 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:39:02 (GMT)
commit563356332542fed0435f511d68eb592f9c3f1d0d (patch)
treefb0980b1c24afebaef8e179d0302c0c0a7ae69c0
parentbcfc0b3673656149bc26d120ff774bfdacba952e (diff)
downloadlinux-fsl-qoriq-563356332542fed0435f511d68eb592f9c3f1d0d.tar.xz
Fix e6500-based platform CPU hotplug issue
Fix thread 1 of core 0 online issue. Besides, put offline thread into PW10 state, give it a chance to enter PW20 state when threads of the same core are in PW10 state. Signed-off-by: Zhang Zhuoyu <Zhuoyu.Zhang@freescale.com> Change-Id: I9018c4499f02b79f2ec684798c54bf3cfe6723de Reviewed-on: http://git.am.freescale.net:8181/21206 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Yang Li <LeoLi@freescale.com>
-rw-r--r--arch/powerpc/include/asm/fsl_pm.h7
-rw-r--r--arch/powerpc/include/asm/machdep.h1
-rw-r--r--arch/powerpc/kernel/idle_book3e.S6
-rw-r--r--arch/powerpc/platforms/85xx/smp.c57
-rw-r--r--arch/powerpc/platforms/85xx/smp.h2
-rw-r--r--arch/powerpc/sysdev/fsl_rcpm.c27
6 files changed, 75 insertions, 25 deletions
diff --git a/arch/powerpc/include/asm/fsl_pm.h b/arch/powerpc/include/asm/fsl_pm.h
index 9811cb2..4e6fd0e 100644
--- a/arch/powerpc/include/asm/fsl_pm.h
+++ b/arch/powerpc/include/asm/fsl_pm.h
@@ -16,9 +16,10 @@
#include <linux/suspend.h>
#define E500_PM_PH10 1
-#define E500_PM_PH15 2
-#define E500_PM_PH20 3
-#define E500_PM_PH30 4
+#define E500_PM_PW10 2
+#define E500_PM_PH15 3
+#define E500_PM_PH20 4
+#define E500_PM_PH30 5
#define E500_PM_DOZE E500_PM_PH10
#define E500_PM_NAP E500_PM_PH15
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index eb9dec0..bb96a21 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -278,6 +278,7 @@ extern void power4_idle(void);
extern void power7_idle(void);
extern void ppc6xx_idle(void);
extern void book3e_idle(void);
+extern void book3e_die(void);
/*
* ppc_md contains a copy of the machine description structure for the
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S
index bfb73cc..e7d8ab3 100644
--- a/arch/powerpc/kernel/idle_book3e.S
+++ b/arch/powerpc/kernel/idle_book3e.S
@@ -79,6 +79,12 @@ _GLOBAL(\name)
b 1b
.endm
+_GLOBAL(book3e_die)
+ wrteei 1
+ PPC_WAIT(0)
+1:
+ b 1b
+
/* epapr_ev_idle_start below is patched with the proper hcall
opcodes during kernel initialization */
.macro EPAPR_EV_IDLE_LOOP
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index a65c5d3..5b12f4b 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -48,8 +48,6 @@ static int tb_req;
static int tb_valid;
static u32 cur_booting_core;
-extern void fsl_enable_threads(void);
-
/* specify the cpu PM state when cpu dies, PH15/NAP is the default */
int qoriq_cpu_die_state = E500_PM_PH15;
@@ -212,11 +210,8 @@ static void __cpuinit smp_85xx_mach_cpu_die(void)
if (cur_cpu_spec && cur_cpu_spec->cpu_flush_caches)
cur_cpu_spec->cpu_flush_caches();
- if (is_core_down(cpu))
+ if (qoriq_pm_ops->cpu_enter_state)
qoriq_pm_ops->cpu_enter_state(cpu, qoriq_cpu_die_state);
-
- while (1)
- ;
}
#else
@@ -291,15 +286,33 @@ static int smp_85xx_kick_cpu(int nr)
if (cpu_online(cpu_first_thread_sibling(nr))) {
local_irq_save(flags);
- /*
- * In cpu hotplug case, Thread 1 of Core 0 must
- * start by calling fsl_enable_threads(). Thread 1
- * of other cores can be started by Thread 0
- * after reset.
- */
- if (nr == 1 && system_state == SYSTEM_RUNNING)
- fsl_enable_threads();
-
+#ifdef CONFIG_PPC_E500MC
+ if (system_state == SYSTEM_RUNNING) {
+ /*
+ * In cpu hotplug case, Thread 1 of Core0
+ * must start by Thread0 of Core0 calling
+ * fsl_enable_threads().
+ */
+ if (nr == 1) {
+ if (get_cpu() == boot_cpuid)
+ fsl_enable_threads(&ret);
+ else
+ work_on_cpu(boot_cpuid,
+ fsl_enable_threads, NULL);
+ }
+
+ /*
+ * Thread 1 of other cores can be waken up from
+ * low-power state when Thread 0 is online,
+ * or restart by Thread 0 after core reset.
+ */
+ if (!strcmp(cur_cpu_spec->cpu_name, "e6500"))
+ arch_send_call_function_single_ipi(nr);
+
+ if (qoriq_pm_ops->irq_unmask)
+ qoriq_pm_ops->irq_unmask(nr);
+ }
+#endif
smp_generic_kick_cpu(nr);
generic_set_cpu_up(nr);
@@ -365,6 +378,13 @@ static int smp_85xx_kick_cpu(int nr)
#ifdef CONFIG_PPC_E500MC
/*
+ * For e6500-based platform, wake up core from
+ * low-power state before reset core.
+ */
+ if (!strcmp(cur_cpu_spec->cpu_name, "e6500"))
+ arch_send_call_function_single_ipi(nr);
+
+ /*
* Errata-A-006568. If SOC-rcpm is V1, we need enable
* cpu first, T4240rev2 and later Soc has been fixed.
* But before this errata is still needed.
@@ -606,8 +626,13 @@ void __init mpc85xx_smp_init(void)
#ifdef CONFIG_HOTPLUG_CPU
ppc_md.cpu_die = smp_85xx_mach_cpu_die;
#endif
+ /*
+ * For e6500-based platform, put thread into PW10 state gives
+ * it a chance to enter PW20 state when threads of the same
+ * core are in PW10 state.
+ */
if (!strcmp(cur_cpu_spec->cpu_name, "e6500"))
- qoriq_cpu_die_state = E500_PM_PH20;
+ qoriq_cpu_die_state = E500_PM_PW10;
}
smp_ops = &smp_85xx_ops;
diff --git a/arch/powerpc/platforms/85xx/smp.h b/arch/powerpc/platforms/85xx/smp.h
index e2b4493..8983009 100644
--- a/arch/powerpc/platforms/85xx/smp.h
+++ b/arch/powerpc/platforms/85xx/smp.h
@@ -12,4 +12,6 @@ static inline void mpc85xx_smp_init(void)
}
#endif
+extern long fsl_enable_threads(void *);
+
#endif /* not POWERPC_85XX_SMP_H_ */
diff --git a/arch/powerpc/sysdev/fsl_rcpm.c b/arch/powerpc/sysdev/fsl_rcpm.c
index a21235c..6b26678 100644
--- a/arch/powerpc/sysdev/fsl_rcpm.c
+++ b/arch/powerpc/sysdev/fsl_rcpm.c
@@ -19,6 +19,7 @@
#include <asm/fsl_guts.h>
#include <asm/cputhreads.h>
#include <asm/fsl_pm.h>
+#include <asm/machdep.h>
const struct fsl_pm_ops *qoriq_pm_ops;
@@ -152,7 +153,9 @@ static void rcpm_v2_irq_mask(int cpu)
int hw_cpu = get_hard_smp_processor_id(cpu);
unsigned int mask = 1 << hw_cpu;
- setbits32(&rcpm_v2_regs->tpmimr0, mask);
+ if (strcmp(cur_cpu_spec->cpu_name, "e6500"))
+ setbits32(&rcpm_v2_regs->tpmimr0, mask);
+
setbits32(&rcpm_v2_regs->tpmcimr0, mask);
setbits32(&rcpm_v2_regs->tpmmcmr0, mask);
setbits32(&rcpm_v2_regs->tpmnmimr0, mask);
@@ -163,7 +166,9 @@ static void rcpm_v2_irq_unmask(int cpu)
int hw_cpu = get_hard_smp_processor_id(cpu);
unsigned int mask = 1 << hw_cpu;
- clrbits32(&rcpm_v2_regs->tpmimr0, mask);
+ if (strcmp(cur_cpu_spec->cpu_name, "e6500"))
+ clrbits32(&rcpm_v2_regs->tpmimr0, mask);
+
clrbits32(&rcpm_v2_regs->tpmcimr0, mask);
clrbits32(&rcpm_v2_regs->tpmmcmr0, mask);
clrbits32(&rcpm_v2_regs->tpmnmimr0, mask);
@@ -188,6 +193,12 @@ static void rcpm_v2_cpu_enter_state(int cpu, int state)
/* one bit corresponds to one thread for PH10 of 6500 */
setbits32(&rcpm_v2_regs->tph10setr0, 1 << hw_cpu);
break;
+#ifdef CONFIG_PPC_BOOK3E_64
+ case E500_PM_PW10:
+ /* one bit corresponds to one thread for PW10 of 6500 */
+ book3e_die();
+ break;
+#endif
case E500_PM_PH15:
setbits32(&rcpm_v2_regs->pcph15setr, mask);
break;
@@ -207,18 +218,22 @@ static void rcpm_v2_cpu_exit_state(int cpu, int state)
unsigned int hw_cpu = get_hard_smp_processor_id(cpu);
u32 mask = 1 << cpu_core_index_of_thread(hw_cpu);
+ /*
+ * The true value read from these registers only means
+ * there is a pending request.
+ */
switch (state) {
case E500_PM_PH10:
- setbits32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
+ out_be32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
break;
case E500_PM_PH15:
- setbits32(&rcpm_v2_regs->pcph15clrr, mask);
+ out_be32(&rcpm_v2_regs->pcph15clrr, mask);
break;
case E500_PM_PH20:
- setbits32(&rcpm_v2_regs->pcph20clrr, mask);
+ out_be32(&rcpm_v2_regs->pcph20clrr, mask);
break;
case E500_PM_PH30:
- setbits32(&rcpm_v2_regs->pcph30clrr, mask);
+ out_be32(&rcpm_v2_regs->pcph30clrr, mask);
break;
default:
pr_err("%s: Unknown cpu PM state (%d)\n", __func__, state);