diff options
author | Paul Burton <paul.burton@imgtec.com> | 2014-01-15 05:31:53 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-03-26 18:00:12 -0400 |
commit | 0ee958e102b62b418c2fb46c3439d4262067a5fc (patch) | |
tree | e69192dc3112657cdde015ea8a43594a41a24d89 | |
parent | b86c2247a20f5d8b6f2b3bd0dfd2c9c8c6908b5e (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/Kconfig | 21 | ||||
-rw-r--r-- | arch/mips/include/asm/smp-cps.h | 33 | ||||
-rw-r--r-- | arch/mips/include/asm/smp-ops.h | 9 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/kernel/asm-offsets.c | 13 | ||||
-rw-r--r-- | arch/mips/kernel/cps-vec.S | 191 | ||||
-rw-r--r-- | arch/mips/kernel/cpu-probe.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/smp-cps.c | 335 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 2 |
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 | ||
2007 | config 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 | |||
2006 | config MIPS_GIC_IPI | 2024 | config MIPS_GIC_IPI |
2007 | bool | 2025 | bool |
2008 | 2026 | ||
@@ -2191,6 +2209,9 @@ config SMP_UP | |||
2191 | config SYS_SUPPORTS_MIPS_CMP | 2209 | config SYS_SUPPORTS_MIPS_CMP |
2192 | bool | 2210 | bool |
2193 | 2211 | ||
2212 | config SYS_SUPPORTS_MIPS_CPS | ||
2213 | bool | ||
2214 | |||
2194 | config SYS_SUPPORTS_SMP | 2215 | config 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 | |||
16 | struct boot_config { | ||
17 | unsigned int core; | ||
18 | unsigned int vpe; | ||
19 | unsigned long pc; | ||
20 | unsigned long sp; | ||
21 | unsigned long gp; | ||
22 | }; | ||
23 | |||
24 | extern struct boot_config mips_cps_bootcfg; | ||
25 | |||
26 | extern 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 | ||
104 | extern int register_cps_smp_ops(void); | ||
105 | #else | ||
106 | static 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 | |||
53 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o | 53 | obj-$(CONFIG_MIPS_MT_SMTC) += smtc.o smtc-asm.o smtc-proc.o |
54 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o | 54 | obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o |
55 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o | 55 | obj-$(CONFIG_MIPS_CMP) += smp-cmp.o |
56 | obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o | ||
56 | obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o | 57 | obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o |
57 | obj-$(CONFIG_CPU_MIPSR2) += spram.o | 58 | obj-$(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 | ||
403 | void 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 | |||
24 | LEAF(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 | |||
42 | not_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 | ||
79 | 1: /* 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 | ||
87 | 1: cache Index_Store_Tag_I, 0(a0) | ||
88 | add a0, a0, t0 | ||
89 | bne a0, a1, 1b | ||
90 | nop | ||
91 | icache_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 | ||
106 | 1: /* 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 | ||
115 | 1: cache Index_Store_Tag_D, 0(a0) | ||
116 | bne a0, a1, 1b | ||
117 | add a0, a0, t0 | ||
118 | dcache_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 | |||
137 | 1: /* 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 | ||
157 | LEAF(excep_tlbfill) | ||
158 | b . | ||
159 | nop | ||
160 | END(excep_tlbfill) | ||
161 | |||
162 | .org 0x280 | ||
163 | LEAF(excep_xtlbfill) | ||
164 | b . | ||
165 | nop | ||
166 | END(excep_xtlbfill) | ||
167 | |||
168 | .org 0x300 | ||
169 | LEAF(excep_cache) | ||
170 | b . | ||
171 | nop | ||
172 | END(excep_cache) | ||
173 | |||
174 | .org 0x380 | ||
175 | LEAF(excep_genex) | ||
176 | b . | ||
177 | nop | ||
178 | END(excep_genex) | ||
179 | |||
180 | .org 0x400 | ||
181 | LEAF(excep_intex) | ||
182 | b . | ||
183 | nop | ||
184 | END(excep_intex) | ||
185 | |||
186 | .org 0x480 | ||
187 | LEAF(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 | |||
27 | static DECLARE_BITMAP(core_power, NR_CPUS); | ||
28 | |||
29 | struct boot_config mips_cps_bootcfg; | ||
30 | |||
31 | static 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 | |||
100 | static 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 | |||
158 | static void __init cps_prepare_cpus(unsigned int max_cpus) | ||
159 | { | ||
160 | mips_mt_set_cpuoptions(); | ||
161 | } | ||
162 | |||
163 | static 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 | |||
199 | static 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 | |||
238 | static 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 | |||
278 | static 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(¤t_cpu_data) == 0) | ||
286 | init_core(); | ||
287 | |||
288 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | | ||
289 | STATUSF_IP6 | STATUSF_IP7); | ||
290 | } | ||
291 | |||
292 | static 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 | |||
305 | static void cps_cpus_done(void) | ||
306 | { | ||
307 | } | ||
308 | |||
309 | static 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 | |||
320 | int 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 |