aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2014-01-15 05:31:53 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-03-26 18:00:12 -0400
commit0ee958e102b62b418c2fb46c3439d4262067a5fc (patch)
treee69192dc3112657cdde015ea8a43594a41a24d89
parentb86c2247a20f5d8b6f2b3bd0dfd2c9c8c6908b5e (diff)
MIPS: Coherent Processing System SMP implementation
This patch introduces a new SMP implementation for systems implementing the MIPS Coherent Processing System architecture. The kernel will make use of the Coherence Manager, Cluster Power Controller & Global Interrupt Controller in order to detect, bring up & make use of other cores in the system. SMTC is not supported, so only a single TC per VPE in the system is used. That is, this option enables an SMVP style setup but across multiple cores. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6362/ Patchwork: https://patchwork.linux-mips.org/patch/6611/ Patchwork: https://patchwork.linux-mips.org/patch/6651/ Patchwork: https://patchwork.linux-mips.org/patch/6652/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/Kconfig21
-rw-r--r--arch/mips/include/asm/smp-cps.h33
-rw-r--r--arch/mips/include/asm/smp-ops.h9
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/asm-offsets.c13
-rw-r--r--arch/mips/kernel/cps-vec.S191
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/smp-cps.c335
-rw-r--r--arch/mips/mm/c-r4k.c2
9 files changed, 606 insertions, 1 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2a9848e0061b..a706779349a7 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1887,6 +1887,7 @@ config MIPS_MT_SMTC
1887 bool "Use all TCs on all VPEs for SMP (DEPRECATED)" 1887 bool "Use all TCs on all VPEs for SMP (DEPRECATED)"
1888 depends on CPU_MIPS32_R2 1888 depends on CPU_MIPS32_R2
1889 depends on SYS_SUPPORTS_MULTITHREADING 1889 depends on SYS_SUPPORTS_MULTITHREADING
1890 depends on !MIPS_CPS
1890 select CPU_MIPSR2_IRQ_VI 1891 select CPU_MIPSR2_IRQ_VI
1891 select CPU_MIPSR2_IRQ_EI 1892 select CPU_MIPSR2_IRQ_EI
1892 select MIPS_MT 1893 select MIPS_MT
@@ -2003,6 +2004,23 @@ config MIPS_CMP
2003 help 2004 help
2004 Enable Coherency Manager processor (CMP) support. 2005 Enable Coherency Manager processor (CMP) support.
2005 2006
2007config MIPS_CPS
2008 bool "MIPS Coherent Processing System support"
2009 depends on SYS_SUPPORTS_MIPS_CPS
2010 select MIPS_CM
2011 select MIPS_CPC
2012 select MIPS_GIC_IPI
2013 select SMP
2014 select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
2015 select SYS_SUPPORTS_SMP
2016 select WEAK_ORDERING
2017 help
2018 Select this if you wish to run an SMP kernel across multiple cores
2019 within a MIPS Coherent Processing System. When this option is
2020 enabled the kernel will probe for other cores and boot them with
2021 no external assistance. It is safe to enable this when hardware
2022 support is unavailable.
2023
2006config MIPS_GIC_IPI 2024config MIPS_GIC_IPI
2007 bool 2025 bool
2008 2026
@@ -2191,6 +2209,9 @@ config SMP_UP
2191config SYS_SUPPORTS_MIPS_CMP 2209config SYS_SUPPORTS_MIPS_CMP
2192 bool 2210 bool
2193 2211
2212config SYS_SUPPORTS_MIPS_CPS
2213 bool
2214
2194config SYS_SUPPORTS_SMP 2215config SYS_SUPPORTS_SMP
2195 bool 2216 bool
2196 2217
diff --git a/arch/mips/include/asm/smp-cps.h b/arch/mips/include/asm/smp-cps.h
new file mode 100644
index 000000000000..d60d1a2180d1
--- /dev/null
+++ b/arch/mips/include/asm/smp-cps.h
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2013 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#ifndef __MIPS_ASM_SMP_CPS_H__
12#define __MIPS_ASM_SMP_CPS_H__
13
14#ifndef __ASSEMBLY__
15
16struct boot_config {
17 unsigned int core;
18 unsigned int vpe;
19 unsigned long pc;
20 unsigned long sp;
21 unsigned long gp;
22};
23
24extern struct boot_config mips_cps_bootcfg;
25
26extern void mips_cps_core_entry(void);
27
28#else /* __ASSEMBLY__ */
29
30.extern mips_cps_bootcfg;
31
32#endif /* __ASSEMBLY__ */
33#endif /* __MIPS_ASM_SMP_CPS_H__ */
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index 51458bb004da..a02c9d4f9b55 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -100,4 +100,13 @@ static inline int register_vsmp_smp_ops(void)
100#endif 100#endif
101} 101}
102 102
103#ifdef CONFIG_MIPS_CPS
104extern int register_cps_smp_ops(void);
105#else
106static inline int register_cps_smp_ops(void)
107{
108 return -ENODEV;
109}
110#endif
111
103#endif /* __ASM_SMP_OPS_H */ 112#endif /* __ASM_SMP_OPS_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index a6a87173e17a..277dab301cea 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
53obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o 53obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o
54obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o 54obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
55obj-$(CONFIG_MIPS_CMP) += smp-cmp.o 55obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
56obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
56obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o 57obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
57obj-$(CONFIG_CPU_MIPSR2) += spram.o 58obj-$(CONFIG_CPU_MIPSR2) += spram.o
58 59
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 0c2e853c3db4..8a2a45d4b147 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -16,6 +16,7 @@
16#include <linux/suspend.h> 16#include <linux/suspend.h>
17#include <asm/ptrace.h> 17#include <asm/ptrace.h>
18#include <asm/processor.h> 18#include <asm/processor.h>
19#include <asm/smp-cps.h>
19 20
20#include <linux/kvm_host.h> 21#include <linux/kvm_host.h>
21 22
@@ -397,3 +398,15 @@ void output_kvm_defines(void)
397 OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]); 398 OFFSET(COP0_STATUS, mips_coproc, reg[MIPS_CP0_STATUS][0]);
398 BLANK(); 399 BLANK();
399} 400}
401
402#ifdef CONFIG_MIPS_CPS
403void output_cps_defines(void)
404{
405 COMMENT(" MIPS CPS offsets. ");
406 OFFSET(BOOTCFG_CORE, boot_config, core);
407 OFFSET(BOOTCFG_VPE, boot_config, vpe);
408 OFFSET(BOOTCFG_PC, boot_config, pc);
409 OFFSET(BOOTCFG_SP, boot_config, sp);
410 OFFSET(BOOTCFG_GP, boot_config, gp);
411}
412#endif
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
new file mode 100644
index 000000000000..f7a46db4b161
--- /dev/null
+++ b/arch/mips/kernel/cps-vec.S
@@ -0,0 +1,191 @@
1/*
2 * Copyright (C) 2013 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#include <asm/addrspace.h>
12#include <asm/asm.h>
13#include <asm/asm-offsets.h>
14#include <asm/asmmacro.h>
15#include <asm/cacheops.h>
16#include <asm/mipsregs.h>
17
18#define GCR_CL_COHERENCE_OFS 0x2008
19
20.section .text.cps-vec
21.balign 0x1000
22.set noreorder
23
24LEAF(mips_cps_core_entry)
25 /*
26 * These first 8 bytes will be patched by cps_smp_setup to load the
27 * base address of the CM GCRs into register v1.
28 */
29 .quad 0
30
31 /* Check whether we're here due to an NMI */
32 mfc0 k0, CP0_STATUS
33 and k0, k0, ST0_NMI
34 beqz k0, not_nmi
35 nop
36
37 /* This is an NMI */
38 la k0, nmi_handler
39 jr k0
40 nop
41
42not_nmi:
43 /* Setup Cause */
44 li t0, CAUSEF_IV
45 mtc0 t0, CP0_CAUSE
46
47 /* Setup Status */
48 li t0, ST0_CU1 | ST0_CU0
49 mtc0 t0, CP0_STATUS
50
51 /*
52 * Clear the bits used to index the caches. Note that the architecture
53 * dictates that writing to any of TagLo or TagHi selects 0 or 2 should
54 * be valid for all MIPS32 CPUs, even those for which said writes are
55 * unnecessary.
56 */
57 mtc0 zero, CP0_TAGLO, 0
58 mtc0 zero, CP0_TAGHI, 0
59 mtc0 zero, CP0_TAGLO, 2
60 mtc0 zero, CP0_TAGHI, 2
61 ehb
62
63 /* Primary cache configuration is indicated by Config1 */
64 mfc0 v0, CP0_CONFIG, 1
65
66 /* Detect I-cache line size */
67 _EXT t0, v0, MIPS_CONF1_IL_SHF, MIPS_CONF1_IL_SZ
68 beqz t0, icache_done
69 li t1, 2
70 sllv t0, t1, t0
71
72 /* Detect I-cache size */
73 _EXT t1, v0, MIPS_CONF1_IS_SHF, MIPS_CONF1_IS_SZ
74 xori t2, t1, 0x7
75 beqz t2, 1f
76 li t3, 32
77 addi t1, t1, 1
78 sllv t1, t3, t1
791: /* At this point t1 == I-cache sets per way */
80 _EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
81 addi t2, t2, 1
82 mul t1, t1, t0
83 mul t1, t1, t2
84
85 li a0, KSEG0
86 add a1, a0, t1
871: cache Index_Store_Tag_I, 0(a0)
88 add a0, a0, t0
89 bne a0, a1, 1b
90 nop
91icache_done:
92
93 /* Detect D-cache line size */
94 _EXT t0, v0, MIPS_CONF1_DL_SHF, MIPS_CONF1_DL_SZ
95 beqz t0, dcache_done
96 li t1, 2
97 sllv t0, t1, t0
98
99 /* Detect D-cache size */
100 _EXT t1, v0, MIPS_CONF1_DS_SHF, MIPS_CONF1_DS_SZ
101 xori t2, t1, 0x7
102 beqz t2, 1f
103 li t3, 32
104 addi t1, t1, 1
105 sllv t1, t3, t1
1061: /* At this point t1 == D-cache sets per way */
107 _EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
108 addi t2, t2, 1
109 mul t1, t1, t0
110 mul t1, t1, t2
111
112 li a0, KSEG0
113 addu a1, a0, t1
114 subu a1, a1, t0
1151: cache Index_Store_Tag_D, 0(a0)
116 bne a0, a1, 1b
117 add a0, a0, t0
118dcache_done:
119
120 /* Set Kseg0 cacheable, coherent, write-back, write-allocate */
121 mfc0 t0, CP0_CONFIG
122 ori t0, 0x7
123 xori t0, 0x2
124 mtc0 t0, CP0_CONFIG
125 ehb
126
127 /* Enter the coherent domain */
128 li t0, 0xff
129 sw t0, GCR_CL_COHERENCE_OFS(v1)
130 ehb
131
132 /* Jump to kseg0 */
133 la t0, 1f
134 jr t0
135 nop
136
1371: /* We're up, cached & coherent */
138
139 /*
140 * TODO: We should check the VPE number we intended to boot here, and
141 * if non-zero we should start that VPE and stop this one. For
142 * the moment this doesn't matter since CPUs are brought up
143 * sequentially and in order, but once hotplug is implemented
144 * this will need revisiting.
145 */
146
147 /* Off we go! */
148 la t0, mips_cps_bootcfg
149 lw t1, BOOTCFG_PC(t0)
150 lw gp, BOOTCFG_GP(t0)
151 lw sp, BOOTCFG_SP(t0)
152 jr t1
153 nop
154 END(mips_cps_core_entry)
155
156.org 0x200
157LEAF(excep_tlbfill)
158 b .
159 nop
160 END(excep_tlbfill)
161
162.org 0x280
163LEAF(excep_xtlbfill)
164 b .
165 nop
166 END(excep_xtlbfill)
167
168.org 0x300
169LEAF(excep_cache)
170 b .
171 nop
172 END(excep_cache)
173
174.org 0x380
175LEAF(excep_genex)
176 b .
177 nop
178 END(excep_genex)
179
180.org 0x400
181LEAF(excep_intex)
182 b .
183 nop
184 END(excep_intex)
185
186.org 0x480
187LEAF(excep_ejtag)
188 la k0, ejtag_debug_handler
189 jr k0
190 nop
191 END(excep_ejtag)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index ac09248b7468..c1ee8b4d2144 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -398,8 +398,10 @@ static void decode_configs(struct cpuinfo_mips *c)
398 398
399 mips_probe_watch_registers(c); 399 mips_probe_watch_registers(c);
400 400
401#ifndef CONFIG_MIPS_CPS
401 if (cpu_has_mips_r2) 402 if (cpu_has_mips_r2)
402 c->core = read_c0_ebase() & 0x3ff; 403 c->core = read_c0_ebase() & 0x3ff;
404#endif
403} 405}
404 406
405#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ 407#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
new file mode 100644
index 000000000000..536eec0d21b6
--- /dev/null
+++ b/arch/mips/kernel/smp-cps.c
@@ -0,0 +1,335 @@
1/*
2 * Copyright (C) 2013 Imagination Technologies
3 * Author: Paul Burton <paul.burton@imgtec.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 */
10
11#include <linux/io.h>
12#include <linux/sched.h>
13#include <linux/slab.h>
14#include <linux/smp.h>
15#include <linux/types.h>
16
17#include <asm/cacheflush.h>
18#include <asm/gic.h>
19#include <asm/mips-cm.h>
20#include <asm/mips-cpc.h>
21#include <asm/mips_mt.h>
22#include <asm/mipsregs.h>
23#include <asm/smp-cps.h>
24#include <asm/time.h>
25#include <asm/uasm.h>
26
27static DECLARE_BITMAP(core_power, NR_CPUS);
28
29struct boot_config mips_cps_bootcfg;
30
31static void init_core(void)
32{
33 unsigned int nvpes, t;
34 u32 mvpconf0, vpeconf0, vpecontrol, tcstatus, tcbind, status;
35
36 if (!cpu_has_mipsmt)
37 return;
38
39 /* Enter VPE configuration state */
40 dvpe();
41 set_c0_mvpcontrol(MVPCONTROL_VPC);
42
43 /* Retrieve the count of VPEs in this core */
44 mvpconf0 = read_c0_mvpconf0();
45 nvpes = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
46 smp_num_siblings = nvpes;
47
48 for (t = 1; t < nvpes; t++) {
49 /* Use a 1:1 mapping of TC index to VPE index */
50 settc(t);
51
52 /* Bind 1 TC to this VPE */
53 tcbind = read_tc_c0_tcbind();
54 tcbind &= ~TCBIND_CURVPE;
55 tcbind |= t << TCBIND_CURVPE_SHIFT;
56 write_tc_c0_tcbind(tcbind);
57
58 /* Set exclusive TC, non-active, master */
59 vpeconf0 = read_vpe_c0_vpeconf0();
60 vpeconf0 &= ~(VPECONF0_XTC | VPECONF0_VPA);
61 vpeconf0 |= t << VPECONF0_XTC_SHIFT;
62 vpeconf0 |= VPECONF0_MVP;
63 write_vpe_c0_vpeconf0(vpeconf0);
64
65 /* Declare TC non-active, non-allocatable & interrupt exempt */
66 tcstatus = read_tc_c0_tcstatus();
67 tcstatus &= ~(TCSTATUS_A | TCSTATUS_DA);
68 tcstatus |= TCSTATUS_IXMT;
69 write_tc_c0_tcstatus(tcstatus);
70
71 /* Halt the TC */
72 write_tc_c0_tchalt(TCHALT_H);
73
74 /* Allow only 1 TC to execute */
75 vpecontrol = read_vpe_c0_vpecontrol();
76 vpecontrol &= ~VPECONTROL_TE;
77 write_vpe_c0_vpecontrol(vpecontrol);
78
79 /* Copy (most of) Status from VPE 0 */
80 status = read_c0_status();
81 status &= ~(ST0_IM | ST0_IE | ST0_KSU);
82 status |= ST0_CU0;
83 write_vpe_c0_status(status);
84
85 /* Copy Config from VPE 0 */
86 write_vpe_c0_config(read_c0_config());
87 write_vpe_c0_config7(read_c0_config7());
88
89 /* Ensure no software interrupts are pending */
90 write_vpe_c0_cause(0);
91
92 /* Sync Count */
93 write_vpe_c0_count(read_c0_count());
94 }
95
96 /* Leave VPE configuration state */
97 clear_c0_mvpcontrol(MVPCONTROL_VPC);
98}
99
100static void __init cps_smp_setup(void)
101{
102 unsigned int ncores, nvpes, core_vpes;
103 int c, v;
104 u32 core_cfg, *entry_code;
105
106 /* Detect & record VPE topology */
107 ncores = mips_cm_numcores();
108 pr_info("VPE topology ");
109 for (c = nvpes = 0; c < ncores; c++) {
110 if (cpu_has_mipsmt && config_enabled(CONFIG_MIPS_MT_SMP)) {
111 write_gcr_cl_other(c << CM_GCR_Cx_OTHER_CORENUM_SHF);
112 core_cfg = read_gcr_co_config();
113 core_vpes = ((core_cfg & CM_GCR_Cx_CONFIG_PVPE_MSK) >>
114 CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
115 } else {
116 core_vpes = 1;
117 }
118
119 pr_cont("%c%u", c ? ',' : '{', core_vpes);
120
121 for (v = 0; v < min_t(int, core_vpes, NR_CPUS - nvpes); v++) {
122 cpu_data[nvpes + v].core = c;
123#ifdef CONFIG_MIPS_MT_SMP
124 cpu_data[nvpes + v].vpe_id = v;
125#endif
126 }
127
128 nvpes += core_vpes;
129 }
130 pr_cont("} total %u\n", nvpes);
131
132 /* Indicate present CPUs (CPU being synonymous with VPE) */
133 for (v = 0; v < min_t(unsigned, nvpes, NR_CPUS); v++) {
134 set_cpu_possible(v, true);
135 set_cpu_present(v, true);
136 __cpu_number_map[v] = v;
137 __cpu_logical_map[v] = v;
138 }
139
140 /* Core 0 is powered up (we're running on it) */
141 bitmap_set(core_power, 0, 1);
142
143 /* Disable MT - we only want to run 1 TC per VPE */
144 if (cpu_has_mipsmt)
145 dmt();
146
147 /* Initialise core 0 */
148 init_core();
149
150 /* Patch the start of mips_cps_core_entry to provide the CM base */
151 entry_code = (u32 *)&mips_cps_core_entry;
152 UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
153
154 /* Make core 0 coherent with everything */
155 write_gcr_cl_coherence(0xff);
156}
157
158static void __init cps_prepare_cpus(unsigned int max_cpus)
159{
160 mips_mt_set_cpuoptions();
161}
162
163static void boot_core(struct boot_config *cfg)
164{
165 u32 access;
166
167 /* Select the appropriate core */
168 write_gcr_cl_other(cfg->core << CM_GCR_Cx_OTHER_CORENUM_SHF);
169
170 /* Set its reset vector */
171 write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
172
173 /* Ensure its coherency is disabled */
174 write_gcr_co_coherence(0);
175
176 /* Ensure the core can access the GCRs */
177 access = read_gcr_access();
178 access |= 1 << (CM_GCR_ACCESS_ACCESSEN_SHF + cfg->core);
179 write_gcr_access(access);
180
181 /* Copy cfg */
182 mips_cps_bootcfg = *cfg;
183
184 if (mips_cpc_present()) {
185 /* Select the appropriate core */
186 write_cpc_cl_other(cfg->core << CPC_Cx_OTHER_CORENUM_SHF);
187
188 /* Reset the core */
189 write_cpc_co_cmd(CPC_Cx_CMD_RESET);
190 } else {
191 /* Take the core out of reset */
192 write_gcr_co_reset_release(0);
193 }
194
195 /* The core is now powered up */
196 bitmap_set(core_power, cfg->core, 1);
197}
198
199static void boot_vpe(void *info)
200{
201 struct boot_config *cfg = info;
202 u32 tcstatus, vpeconf0;
203
204 /* Enter VPE configuration state */
205 dvpe();
206 set_c0_mvpcontrol(MVPCONTROL_VPC);
207
208 settc(cfg->vpe);
209
210 /* Set the TC restart PC */
211 write_tc_c0_tcrestart((unsigned long)&smp_bootstrap);
212
213 /* Activate the TC, allow interrupts */
214 tcstatus = read_tc_c0_tcstatus();
215 tcstatus &= ~TCSTATUS_IXMT;
216 tcstatus |= TCSTATUS_A;
217 write_tc_c0_tcstatus(tcstatus);
218
219 /* Clear the TC halt bit */
220 write_tc_c0_tchalt(0);
221
222 /* Activate the VPE */
223 vpeconf0 = read_vpe_c0_vpeconf0();
224 vpeconf0 |= VPECONF0_VPA;
225 write_vpe_c0_vpeconf0(vpeconf0);
226
227 /* Set the stack & global pointer registers */
228 write_tc_gpr_sp(cfg->sp);
229 write_tc_gpr_gp(cfg->gp);
230
231 /* Leave VPE configuration state */
232 clear_c0_mvpcontrol(MVPCONTROL_VPC);
233
234 /* Enable other VPEs to execute */
235 evpe(EVPE_ENABLE);
236}
237
238static void cps_boot_secondary(int cpu, struct task_struct *idle)
239{
240 struct boot_config cfg;
241 unsigned int remote;
242 int err;
243
244 cfg.core = cpu_data[cpu].core;
245 cfg.vpe = cpu_vpe_id(&cpu_data[cpu]);
246 cfg.pc = (unsigned long)&smp_bootstrap;
247 cfg.sp = __KSTK_TOS(idle);
248 cfg.gp = (unsigned long)task_thread_info(idle);
249
250 if (!test_bit(cfg.core, core_power)) {
251 /* Boot a VPE on a powered down core */
252 boot_core(&cfg);
253 return;
254 }
255
256 if (cfg.core != current_cpu_data.core) {
257 /* Boot a VPE on another powered up core */
258 for (remote = 0; remote < NR_CPUS; remote++) {
259 if (cpu_data[remote].core != cfg.core)
260 continue;
261 if (cpu_online(remote))
262 break;
263 }
264 BUG_ON(remote >= NR_CPUS);
265
266 err = smp_call_function_single(remote, boot_vpe, &cfg, 1);
267 if (err)
268 panic("Failed to call remote CPU\n");
269 return;
270 }
271
272 BUG_ON(!cpu_has_mipsmt);
273
274 /* Boot a VPE on this core */
275 boot_vpe(&cfg);
276}
277
278static void cps_init_secondary(void)
279{
280 /* Disable MT - we only want to run 1 TC per VPE */
281 if (cpu_has_mipsmt)
282 dmt();
283
284 /* TODO: revisit this assumption once hotplug is implemented */
285 if (cpu_vpe_id(&current_cpu_data) == 0)
286 init_core();
287
288 change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
289 STATUSF_IP6 | STATUSF_IP7);
290}
291
292static void cps_smp_finish(void)
293{
294 write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
295
296#ifdef CONFIG_MIPS_MT_FPAFF
297 /* If we have an FPU, enroll ourselves in the FPU-full mask */
298 if (cpu_has_fpu)
299 cpu_set(smp_processor_id(), mt_fpu_cpumask);
300#endif /* CONFIG_MIPS_MT_FPAFF */
301
302 local_irq_enable();
303}
304
305static void cps_cpus_done(void)
306{
307}
308
309static struct plat_smp_ops cps_smp_ops = {
310 .smp_setup = cps_smp_setup,
311 .prepare_cpus = cps_prepare_cpus,
312 .boot_secondary = cps_boot_secondary,
313 .init_secondary = cps_init_secondary,
314 .smp_finish = cps_smp_finish,
315 .send_ipi_single = gic_send_ipi_single,
316 .send_ipi_mask = gic_send_ipi_mask,
317 .cpus_done = cps_cpus_done,
318};
319
320int register_cps_smp_ops(void)
321{
322 if (!mips_cm_present()) {
323 pr_warn("MIPS CPS SMP unable to proceed without a CM\n");
324 return -ENODEV;
325 }
326
327 /* check we have a GIC - we need one for IPIs */
328 if (!(read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX_MSK)) {
329 pr_warn("MIPS CPS SMP unable to proceed without a GIC\n");
330 return -ENODEV;
331 }
332
333 register_smp_ops(&cps_smp_ops);
334 return 0;
335}
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index ae810320875e..d72e9a16cf14 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -57,7 +57,7 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
57 preempt_enable(); 57 preempt_enable();
58} 58}
59 59
60#if defined(CONFIG_MIPS_CMP) 60#if defined(CONFIG_MIPS_CMP) || defined(CONFIG_MIPS_CPS)
61#define cpu_has_safe_index_cacheops 0 61#define cpu_has_safe_index_cacheops 0
62#else 62#else
63#define cpu_has_safe_index_cacheops 1 63#define cpu_has_safe_index_cacheops 1