aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2011-12-08 02:20:27 -0500
committerScott Wood <scottwood@freescale.com>2014-07-29 20:26:20 -0400
commite16c8765533a155ebd3d7c36fc80440a03bbf46a (patch)
tree8e4c3ab9fd85d3a852889c13012017b5cf8770b7
parent7251a24e4d3acf2d7826e1c42fe84258c312a742 (diff)
powerpc/e6500: Add support for hardware threads
The general idea is that each core will release all of its threads into the secondary thread startup code, which will eventually wait in the secondary core holding area, for the appropriate bit in the PACA to be set. The kick_cpu function pointer will set that bit in the PACA, and thus "release" the core/thread to boot. We also need to do a few things that U-Boot normally does for CPUs (like enable branch prediction). Signed-off-by: Andy Fleming <afleming@freescale.com> [scottwood@freescale.com: various changes, including only enabling threads if Linux wants to kick them] Signed-off-by: Scott Wood <scottwood@freescale.com>
-rw-r--r--arch/powerpc/include/asm/cputable.h2
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h9
-rw-r--r--arch/powerpc/include/asm/reg_booke.h27
-rw-r--r--arch/powerpc/kernel/head_64.S22
-rw-r--r--arch/powerpc/kernel/prom.c10
-rw-r--r--arch/powerpc/kernel/setup-common.c6
-rw-r--r--arch/powerpc/kernel/setup_64.c6
-rw-r--r--arch/powerpc/platforms/85xx/smp.c44
8 files changed, 116 insertions, 10 deletions
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index bc2347774f0a..e91dec89644a 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -396,7 +396,7 @@ extern const char *powerpc_base_platform;
396 CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ 396 CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
397 CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ 397 CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
398 CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_ALTIVEC_COMP | \ 398 CPU_FTR_DEBUG_LVL_EXC | CPU_FTR_EMB_HV | CPU_FTR_ALTIVEC_COMP | \
399 CPU_FTR_CELL_TB_BUG) 399 CPU_FTR_CELL_TB_BUG | CPU_FTR_SMT)
400#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) 400#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
401 401
402/* 64-bit CPUs */ 402/* 64-bit CPUs */
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 3132bb9365f3..e316dad6ba76 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -150,8 +150,10 @@
150#define PPC_INST_MCRXR_MASK 0xfc0007fe 150#define PPC_INST_MCRXR_MASK 0xfc0007fe
151#define PPC_INST_MFSPR_PVR 0x7c1f42a6 151#define PPC_INST_MFSPR_PVR 0x7c1f42a6
152#define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff 152#define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff
153#define PPC_INST_MFTMR 0x7c0002dc
153#define PPC_INST_MSGSND 0x7c00019c 154#define PPC_INST_MSGSND 0x7c00019c
154#define PPC_INST_MSGSNDP 0x7c00011c 155#define PPC_INST_MSGSNDP 0x7c00011c
156#define PPC_INST_MTTMR 0x7c0003dc
155#define PPC_INST_NOP 0x60000000 157#define PPC_INST_NOP 0x60000000
156#define PPC_INST_POPCNTB 0x7c0000f4 158#define PPC_INST_POPCNTB 0x7c0000f4
157#define PPC_INST_POPCNTB_MASK 0xfc0007fe 159#define PPC_INST_POPCNTB_MASK 0xfc0007fe
@@ -369,4 +371,11 @@
369#define TABORT(r) stringify_in_c(.long PPC_INST_TABORT \ 371#define TABORT(r) stringify_in_c(.long PPC_INST_TABORT \
370 | __PPC_RA(r)) 372 | __PPC_RA(r))
371 373
374/* book3e thread control instructions */
375#define TMRN(x) ((((x) & 0x1f) << 16) | (((x) & 0x3e0) << 6))
376#define MTTMR(tmr, r) stringify_in_c(.long PPC_INST_MTTMR | \
377 TMRN(tmr) | ___PPC_RS(r))
378#define MFTMR(tmr, r) stringify_in_c(.long PPC_INST_MFTMR | \
379 TMRN(tmr) | ___PPC_RT(r))
380
372#endif /* _ASM_POWERPC_PPC_OPCODE_H */ 381#endif /* _ASM_POWERPC_PPC_OPCODE_H */
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index da429822b186..1d653308a33c 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -15,6 +15,8 @@
15#ifndef __ASM_POWERPC_REG_BOOKE_H__ 15#ifndef __ASM_POWERPC_REG_BOOKE_H__
16#define __ASM_POWERPC_REG_BOOKE_H__ 16#define __ASM_POWERPC_REG_BOOKE_H__
17 17
18#include <asm/ppc-opcode.h>
19
18/* Machine State Register (MSR) Fields */ 20/* Machine State Register (MSR) Fields */
19#define MSR_GS_LG 28 /* Guest state */ 21#define MSR_GS_LG 28 /* Guest state */
20#define MSR_UCLE_LG 26 /* User-mode cache lock enable */ 22#define MSR_UCLE_LG 26 /* User-mode cache lock enable */
@@ -608,6 +610,13 @@
608/* Bit definitions for L1CSR2. */ 610/* Bit definitions for L1CSR2. */
609#define L1CSR2_DCWS 0x40000000 /* Data Cache write shadow */ 611#define L1CSR2_DCWS 0x40000000 /* Data Cache write shadow */
610 612
613/* Bit definitions for BUCSR. */
614#define BUCSR_STAC_EN 0x01000000 /* Segment Target Address Cache */
615#define BUCSR_LS_EN 0x00400000 /* Link Stack */
616#define BUCSR_BBFI 0x00000200 /* Branch Buffer flash invalidate */
617#define BUCSR_BPEN 0x00000001 /* Branch prediction enable */
618#define BUCSR_INIT (BUCSR_STAC_EN | BUCSR_LS_EN | BUCSR_BBFI | BUCSR_BPEN)
619
611/* Bit definitions for L2CSR0. */ 620/* Bit definitions for L2CSR0. */
612#define L2CSR0_L2E 0x80000000 /* L2 Cache Enable */ 621#define L2CSR0_L2E 0x80000000 /* L2 Cache Enable */
613#define L2CSR0_L2PE 0x40000000 /* L2 Cache Parity/ECC Enable */ 622#define L2CSR0_L2PE 0x40000000 /* L2 Cache Parity/ECC Enable */
@@ -731,5 +740,23 @@
731#define MMUBE1_VBE4 0x00000002 740#define MMUBE1_VBE4 0x00000002
732#define MMUBE1_VBE5 0x00000001 741#define MMUBE1_VBE5 0x00000001
733 742
743#define TMRN_IMSR0 0x120 /* Initial MSR Register 0 (e6500) */
744#define TMRN_IMSR1 0x121 /* Initial MSR Register 1 (e6500) */
745#define TMRN_INIA0 0x140 /* Next Instruction Address Register 0 */
746#define TMRN_INIA1 0x141 /* Next Instruction Address Register 1 */
747#define SPRN_TENSR 0x1b5 /* Thread Enable Status Register */
748#define SPRN_TENS 0x1b6 /* Thread Enable Set Register */
749#define SPRN_TENC 0x1b7 /* Thread Enable Clear Register */
750
751#define TEN_THREAD(x) (1 << (x))
752
753#ifndef __ASSEMBLY__
754#define mftmr(rn) ({unsigned long rval; \
755 asm volatile(MFTMR(rn, %0) : "=r" (rval)); rval;})
756#define mttmr(rn, v) asm volatile(MTTMR(rn, %0) : \
757 : "r" ((unsigned long)(v)) \
758 : "memory")
759#endif /* !__ASSEMBLY__ */
760
734#endif /* __ASM_POWERPC_REG_BOOKE_H__ */ 761#endif /* __ASM_POWERPC_REG_BOOKE_H__ */
735#endif /* __KERNEL__ */ 762#endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index a95145d7f61b..36ff6f03f903 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -180,6 +180,28 @@ exception_marker:
180#include "exceptions-64s.S" 180#include "exceptions-64s.S"
181#endif 181#endif
182 182
183#ifdef CONFIG_PPC_BOOK3E
184_GLOBAL(fsl_secondary_thread_init)
185 /* Enable branch prediction */
186 lis r3,BUCSR_INIT@h
187 ori r3,r3,BUCSR_INIT@l
188 mtspr SPRN_BUCSR,r3
189 isync
190
191 /*
192 * Fix PIR to match the linear numbering in the device tree.
193 *
194 * On e6500, the reset value of PIR uses the low three bits for
195 * the thread within a core, and the upper bits for the core
196 * number. There are two threads per core, so shift everything
197 * but the low bit right by two bits so that the cpu numbering is
198 * continuous.
199 */
200 mfspr r3, SPRN_PIR
201 rlwimi r3, r3, 30, 2, 30
202 mtspr SPRN_PIR, r3
203#endif
204
183_GLOBAL(generic_secondary_thread_init) 205_GLOBAL(generic_secondary_thread_init)
184 mr r24,r3 206 mr r24,r3
185 207
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 613a860a203c..0448b1e9c0ae 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -309,12 +309,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
309 309
310 /* Get physical cpuid */ 310 /* Get physical cpuid */
311 intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len); 311 intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len);
312 if (intserv) { 312 if (!intserv)
313 nthreads = len / sizeof(int); 313 intserv = of_get_flat_dt_prop(node, "reg", &len);
314 } else { 314
315 intserv = of_get_flat_dt_prop(node, "reg", NULL); 315 nthreads = len / sizeof(int);
316 nthreads = 1;
317 }
318 316
319 /* 317 /*
320 * Now see if any of these threads match our boot cpu. 318 * Now see if any of these threads match our boot cpu.
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index e239df3768ac..1bb4dcde0dcc 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -456,18 +456,20 @@ void __init smp_setup_cpu_maps(void)
456 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", 456 intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
457 &len); 457 &len);
458 if (intserv) { 458 if (intserv) {
459 nthreads = len / sizeof(int);
460 DBG(" ibm,ppc-interrupt-server#s -> %d threads\n", 459 DBG(" ibm,ppc-interrupt-server#s -> %d threads\n",
461 nthreads); 460 nthreads);
462 } else { 461 } else {
463 DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n"); 462 DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n");
464 intserv = of_get_property(dn, "reg", NULL); 463 intserv = of_get_property(dn, "reg", &len);
465 if (!intserv) { 464 if (!intserv) {
466 cpu_be = cpu_to_be32(cpu); 465 cpu_be = cpu_to_be32(cpu);
467 intserv = &cpu_be; /* assume logical == phys */ 466 intserv = &cpu_be; /* assume logical == phys */
467 len = 4;
468 } 468 }
469 } 469 }
470 470
471 nthreads = len / sizeof(int);
472
471 for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { 473 for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
472 DBG(" thread %d -> cpu %d (hard id %d)\n", 474 DBG(" thread %d -> cpu %d (hard id %d)\n",
473 j, cpu, be32_to_cpu(intserv[j])); 475 j, cpu, be32_to_cpu(intserv[j]));
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index ee082d771178..6d06947e7d21 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -507,7 +507,11 @@ void __init setup_system(void)
507 check_smt_enabled(); 507 check_smt_enabled();
508 setup_tlb_core_data(); 508 setup_tlb_core_data();
509 509
510#ifdef CONFIG_SMP 510 /*
511 * Freescale Book3e parts spin in a loop provided by firmware,
512 * so smp_release_cpus() does nothing for them
513 */
514#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_FSL_BOOK3E)
511 /* Release secondary cpus out of their spinloops at 0x60 now that 515 /* Release secondary cpus out of their spinloops at 0x60 now that
512 * we can map physical -> logical CPU ids 516 * we can map physical -> logical CPU ids
513 */ 517 */
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ba093f553678..d7c1e69f3070 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -28,6 +28,7 @@
28#include <asm/dbell.h> 28#include <asm/dbell.h>
29#include <asm/fsl_guts.h> 29#include <asm/fsl_guts.h>
30#include <asm/code-patching.h> 30#include <asm/code-patching.h>
31#include <asm/cputhreads.h>
31 32
32#include <sysdev/fsl_soc.h> 33#include <sysdev/fsl_soc.h>
33#include <sysdev/mpic.h> 34#include <sysdev/mpic.h>
@@ -168,6 +169,24 @@ static inline u32 read_spin_table_addr_l(void *spin_table)
168 return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l); 169 return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l);
169} 170}
170 171
172#ifdef CONFIG_PPC64
173static void wake_hw_thread(void *info)
174{
175 void fsl_secondary_thread_init(void);
176 unsigned long imsr1, inia1;
177 int nr = *(const int *)info;
178
179 imsr1 = MSR_KERNEL;
180 inia1 = *(unsigned long *)fsl_secondary_thread_init;
181
182 mttmr(TMRN_IMSR1, imsr1);
183 mttmr(TMRN_INIA1, inia1);
184 mtspr(SPRN_TENS, TEN_THREAD(1));
185
186 smp_generic_kick_cpu(nr);
187}
188#endif
189
171static int smp_85xx_kick_cpu(int nr) 190static int smp_85xx_kick_cpu(int nr)
172{ 191{
173 unsigned long flags; 192 unsigned long flags;
@@ -183,6 +202,31 @@ static int smp_85xx_kick_cpu(int nr)
183 202
184 pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr); 203 pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
185 204
205#ifdef CONFIG_PPC64
206 /* Threads don't use the spin table */
207 if (cpu_thread_in_core(nr) != 0) {
208 int primary = cpu_first_thread_sibling(nr);
209
210 if (WARN_ON_ONCE(!cpu_has_feature(CPU_FTR_SMT)))
211 return -ENOENT;
212
213 if (cpu_thread_in_core(nr) != 1) {
214 pr_err("%s: cpu %d: invalid hw thread %d\n",
215 __func__, nr, cpu_thread_in_core(nr));
216 return -ENOENT;
217 }
218
219 if (!cpu_online(primary)) {
220 pr_err("%s: cpu %d: primary %d not online\n",
221 __func__, nr, primary);
222 return -ENOENT;
223 }
224
225 smp_call_function_single(primary, wake_hw_thread, &nr, 0);
226 return 0;
227 }
228#endif
229
186 np = of_get_cpu_node(nr, NULL); 230 np = of_get_cpu_node(nr, NULL);
187 cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL); 231 cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
188 232