diff options
-rw-r--r-- | arch/metag/include/asm/metag_mem.h | 3 | ||||
-rw-r--r-- | arch/metag/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/metag/kernel/smp.c | 115 |
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 | |||
40 | DECLARE_PER_CPU(PTBI, pTBI); | 45 | DECLARE_PER_CPU(PTBI, pTBI); |
41 | 46 | ||
42 | void *secondary_data_stack; | 47 | void *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 | */ | ||
118 | static __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 | */ | ||
170 | static __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 | |||
102 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) | 215 | int __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 | */ |