aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/metag/include/asm/metag_mem.h3
-rw-r--r--arch/metag/kernel/head.S8
-rw-r--r--arch/metag/kernel/smp.c115
3 files changed, 126 insertions, 0 deletions
diff --git a/arch/metag/include/asm/metag_mem.h b/arch/metag/include/asm/metag_mem.h
index 3f7b54d8ccac..aa5a076df439 100644
--- a/arch/metag/include/asm/metag_mem.h
+++ b/arch/metag/include/asm/metag_mem.h
@@ -700,6 +700,9 @@
700#define SYSC_xCPARTG_AND_S 8 700#define SYSC_xCPARTG_AND_S 8
701#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */ 701#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */
702#define SYSC_xCPARTL_OR_S 16 702#define SYSC_xCPARTL_OR_S 16
703#ifdef METAC_2_1
704#define SYSC_DCPART_GCON_BIT 0x00100000 /* Coherent shared local */
705#endif /* METAC_2_1 */
703#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */ 706#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */
704#define SYSC_xCPARTG_OR_S 24 707#define SYSC_xCPARTG_OR_S 24
705#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */ 708#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */
diff --git a/arch/metag/kernel/head.S b/arch/metag/kernel/head.S
index 969dffabc03a..713f71d1bdfe 100644
--- a/arch/metag/kernel/head.S
+++ b/arch/metag/kernel/head.S
@@ -1,6 +1,7 @@
1 ! Copyright 2005,2006,2007,2009 Imagination Technologies 1 ! Copyright 2005,2006,2007,2009 Imagination Technologies
2 2
3#include <linux/init.h> 3#include <linux/init.h>
4#include <asm/metag_mem.h>
4#include <generated/asm-offsets.h> 5#include <generated/asm-offsets.h>
5#undef __exit 6#undef __exit
6 7
@@ -48,6 +49,13 @@ __exit:
48 .global _secondary_startup 49 .global _secondary_startup
49 .type _secondary_startup,function 50 .type _secondary_startup,function
50_secondary_startup: 51_secondary_startup:
52#if CONFIG_PAGE_OFFSET < LINGLOBAL_BASE
53 ! In case GCOn has just been turned on we need to fence any writes that
54 ! the boot thread might have performed prior to coherency taking effect.
55 MOVT D0Re0,#HI(LINSYSEVENT_WR_ATOMIC_UNLOCK)
56 MOV D1Re0,#0
57 SETD [D0Re0], D1Re0
58#endif
51 MOVT A0StP,#HI(_secondary_data_stack) 59 MOVT A0StP,#HI(_secondary_data_stack)
52 ADD A0StP,A0StP,#LO(_secondary_data_stack) 60 ADD A0StP,A0StP,#LO(_secondary_data_stack)
53 GETD A0StP,[A0StP] 61 GETD A0StP,[A0StP]
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index 4b6d1f14df32..4e7751ac75d2 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -28,6 +28,8 @@
28#include <asm/cachepart.h> 28#include <asm/cachepart.h>
29#include <asm/core_reg.h> 29#include <asm/core_reg.h>
30#include <asm/cpu.h> 30#include <asm/cpu.h>
31#include <asm/global_lock.h>
32#include <asm/metag_mem.h>
31#include <asm/mmu_context.h> 33#include <asm/mmu_context.h>
32#include <asm/pgtable.h> 34#include <asm/pgtable.h>
33#include <asm/pgalloc.h> 35#include <asm/pgalloc.h>
@@ -37,6 +39,9 @@
37#include <asm/hwthread.h> 39#include <asm/hwthread.h>
38#include <asm/traps.h> 40#include <asm/traps.h>
39 41
42#define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
43#define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
44
40DECLARE_PER_CPU(PTBI, pTBI); 45DECLARE_PER_CPU(PTBI, pTBI);
41 46
42void *secondary_data_stack; 47void *secondary_data_stack;
@@ -99,6 +104,114 @@ int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
99 return 0; 104 return 0;
100} 105}
101 106
107/**
108 * describe_cachepart_change: describe a change to cache partitions.
109 * @thread: Hardware thread number.
110 * @label: Label of cache type, e.g. "dcache" or "icache".
111 * @sz: Total size of the cache.
112 * @old: Old cache partition configuration (*CPART* register).
113 * @new: New cache partition configuration (*CPART* register).
114 *
115 * If the cache partition has changed, prints a message to the log describing
116 * those changes.
117 */
118static __cpuinit void describe_cachepart_change(unsigned int thread,
119 const char *label,
120 unsigned int sz,
121 unsigned int old,
122 unsigned int new)
123{
124 unsigned int lor1, land1, gor1, gand1;
125 unsigned int lor2, land2, gor2, gand2;
126 unsigned int diff = old ^ new;
127
128 if (!diff)
129 return;
130
131 pr_info("Thread %d: %s partition changed:", thread, label);
132 if (diff & (SYSC_xCPARTL_OR_BITS | SYSC_xCPARTL_AND_BITS)) {
133 lor1 = (old & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
134 lor2 = (new & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
135 land1 = (old & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
136 land2 = (new & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
137 pr_cont(" L:%#x+%#x->%#x+%#x",
138 (lor1 * sz) >> 4,
139 ((land1 + 1) * sz) >> 4,
140 (lor2 * sz) >> 4,
141 ((land2 + 1) * sz) >> 4);
142 }
143 if (diff & (SYSC_xCPARTG_OR_BITS | SYSC_xCPARTG_AND_BITS)) {
144 gor1 = (old & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
145 gor2 = (new & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
146 gand1 = (old & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
147 gand2 = (new & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
148 pr_cont(" G:%#x+%#x->%#x+%#x",
149 (gor1 * sz) >> 4,
150 ((gand1 + 1) * sz) >> 4,
151 (gor2 * sz) >> 4,
152 ((gand2 + 1) * sz) >> 4);
153 }
154 if (diff & SYSC_CWRMODE_BIT)
155 pr_cont(" %sWR",
156 (new & SYSC_CWRMODE_BIT) ? "+" : "-");
157 if (diff & SYSC_DCPART_GCON_BIT)
158 pr_cont(" %sGCOn",
159 (new & SYSC_DCPART_GCON_BIT) ? "+" : "-");
160 pr_cont("\n");
161}
162
163/**
164 * setup_smp_cache: ensure cache coherency for new SMP thread.
165 * @thread: New hardware thread number.
166 *
167 * Ensures that coherency is enabled and that the threads share the same cache
168 * partitions.
169 */
170static __cpuinit void setup_smp_cache(unsigned int thread)
171{
172 unsigned int this_thread, lflags;
173 unsigned int dcsz, dcpart_this, dcpart_old, dcpart_new;
174 unsigned int icsz, icpart_old, icpart_new;
175
176 /*
177 * Copy over the current thread's cache partition configuration to the
178 * new thread so that they share cache partitions.
179 */
180 __global_lock2(lflags);
181 this_thread = hard_processor_id();
182 /* Share dcache partition */
183 dcpart_this = metag_in32(SYSC_DCPART(this_thread));
184 dcpart_old = metag_in32(SYSC_DCPART(thread));
185 dcpart_new = dcpart_this;
186#if PAGE_OFFSET < LINGLOBAL_BASE
187 /*
188 * For the local data cache to be coherent the threads must also have
189 * GCOn enabled.
190 */
191 dcpart_new |= SYSC_DCPART_GCON_BIT;
192 metag_out32(dcpart_new, SYSC_DCPART(this_thread));
193#endif
194 metag_out32(dcpart_new, SYSC_DCPART(thread));
195 /* Share icache partition too */
196 icpart_new = metag_in32(SYSC_ICPART(this_thread));
197 icpart_old = metag_in32(SYSC_ICPART(thread));
198 metag_out32(icpart_new, SYSC_ICPART(thread));
199 __global_unlock2(lflags);
200
201 /*
202 * Log if the cache partitions were altered so the user is aware of any
203 * potential unintentional cache wastage.
204 */
205 dcsz = get_dcache_size();
206 icsz = get_dcache_size();
207 describe_cachepart_change(this_thread, "dcache", dcsz,
208 dcpart_this, dcpart_new);
209 describe_cachepart_change(thread, "dcache", dcsz,
210 dcpart_old, dcpart_new);
211 describe_cachepart_change(thread, "icache", icsz,
212 icpart_old, icpart_new);
213}
214
102int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) 215int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
103{ 216{
104 unsigned int thread = cpu_2_hwthread_id[cpu]; 217 unsigned int thread = cpu_2_hwthread_id[cpu];
@@ -108,6 +221,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
108 221
109 flush_tlb_all(); 222 flush_tlb_all();
110 223
224 setup_smp_cache(thread);
225
111 /* 226 /*
112 * Tell the secondary CPU where to find its idle thread's stack. 227 * Tell the secondary CPU where to find its idle thread's stack.
113 */ 228 */