aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorDave Kleikamp <shaggy@linux.vnet.ibm.com>2010-03-05 05:43:12 -0500
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2010-05-05 09:11:10 -0400
commite7f75ad01d590243904c2d95ab47e6b2e9ef6dad (patch)
tree454cf065417973e9c2fcd75542351c2534b9a4b9 /arch/powerpc/mm
parent795033c344d88dc6aa5106d0cc358656f29bd722 (diff)
powerpc/47x: Base ppc476 support
This patch adds the base support for the 476 processor. The code was primarily written by Ben Herrenschmidt and Torez Smith, but I've been maintaining it for a while. The goal is to have a single binary that will run on 44x and 47x, but we still have some details to work out. The biggest is that the L1 cache line size differs on the two platforms, but it's currently a compile-time option. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Torez Smith <lnxtorez@linux.vnet.ibm.com> Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/44x_mmu.c144
-rw-r--r--arch/powerpc/mm/mmu_context_nohash.c8
-rw-r--r--arch/powerpc/mm/mmu_decl.h7
-rw-r--r--arch/powerpc/mm/tlb_nohash_low.S118
4 files changed, 255 insertions, 22 deletions
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index 3986264b0993..d8c6efb32bc6 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -38,7 +38,9 @@ unsigned int tlb_44x_index; /* = 0 */
38unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS; 38unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS;
39int icache_44x_need_flush; 39int icache_44x_need_flush;
40 40
41static void __init ppc44x_update_tlb_hwater(void) 41unsigned long tlb_47x_boltmap[1024/8];
42
43static void __cpuinit ppc44x_update_tlb_hwater(void)
42{ 44{
43 extern unsigned int tlb_44x_patch_hwater_D[]; 45 extern unsigned int tlb_44x_patch_hwater_D[];
44 extern unsigned int tlb_44x_patch_hwater_I[]; 46 extern unsigned int tlb_44x_patch_hwater_I[];
@@ -59,7 +61,7 @@ static void __init ppc44x_update_tlb_hwater(void)
59} 61}
60 62
61/* 63/*
62 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem 64 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 44x type MMU
63 */ 65 */
64static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys) 66static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
65{ 67{
@@ -67,12 +69,18 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
67 69
68 ppc44x_update_tlb_hwater(); 70 ppc44x_update_tlb_hwater();
69 71
72 mtspr(SPRN_MMUCR, 0);
73
70 __asm__ __volatile__( 74 __asm__ __volatile__(
71 "tlbwe %2,%3,%4\n" 75 "tlbwe %2,%3,%4\n"
72 "tlbwe %1,%3,%5\n" 76 "tlbwe %1,%3,%5\n"
73 "tlbwe %0,%3,%6\n" 77 "tlbwe %0,%3,%6\n"
74 : 78 :
79#ifdef CONFIG_PPC47x
80 : "r" (PPC47x_TLB2_S_RWX),
81#else
75 : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G), 82 : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
83#endif
76 "r" (phys), 84 "r" (phys),
77 "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M), 85 "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M),
78 "r" (entry), 86 "r" (entry),
@@ -81,8 +89,93 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
81 "i" (PPC44x_TLB_ATTRIB)); 89 "i" (PPC44x_TLB_ATTRIB));
82} 90}
83 91
92static int __init ppc47x_find_free_bolted(void)
93{
94 unsigned int mmube0 = mfspr(SPRN_MMUBE0);
95 unsigned int mmube1 = mfspr(SPRN_MMUBE1);
96
97 if (!(mmube0 & MMUBE0_VBE0))
98 return 0;
99 if (!(mmube0 & MMUBE0_VBE1))
100 return 1;
101 if (!(mmube0 & MMUBE0_VBE2))
102 return 2;
103 if (!(mmube1 & MMUBE1_VBE3))
104 return 3;
105 if (!(mmube1 & MMUBE1_VBE4))
106 return 4;
107 if (!(mmube1 & MMUBE1_VBE5))
108 return 5;
109 return -1;
110}
111
112static void __init ppc47x_update_boltmap(void)
113{
114 unsigned int mmube0 = mfspr(SPRN_MMUBE0);
115 unsigned int mmube1 = mfspr(SPRN_MMUBE1);
116
117 if (mmube0 & MMUBE0_VBE0)
118 __set_bit((mmube0 >> MMUBE0_IBE0_SHIFT) & 0xff,
119 tlb_47x_boltmap);
120 if (mmube0 & MMUBE0_VBE1)
121 __set_bit((mmube0 >> MMUBE0_IBE1_SHIFT) & 0xff,
122 tlb_47x_boltmap);
123 if (mmube0 & MMUBE0_VBE2)
124 __set_bit((mmube0 >> MMUBE0_IBE2_SHIFT) & 0xff,
125 tlb_47x_boltmap);
126 if (mmube1 & MMUBE1_VBE3)
127 __set_bit((mmube1 >> MMUBE1_IBE3_SHIFT) & 0xff,
128 tlb_47x_boltmap);
129 if (mmube1 & MMUBE1_VBE4)
130 __set_bit((mmube1 >> MMUBE1_IBE4_SHIFT) & 0xff,
131 tlb_47x_boltmap);
132 if (mmube1 & MMUBE1_VBE5)
133 __set_bit((mmube1 >> MMUBE1_IBE5_SHIFT) & 0xff,
134 tlb_47x_boltmap);
135}
136
137/*
138 * "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 47x type MMU
139 */
140static void __cpuinit ppc47x_pin_tlb(unsigned int virt, unsigned int phys)
141{
142 unsigned int rA;
143 int bolted;
144
145 /* Base rA is HW way select, way 0, bolted bit set */
146 rA = 0x88000000;
147
148 /* Look for a bolted entry slot */
149 bolted = ppc47x_find_free_bolted();
150 BUG_ON(bolted < 0);
151
152 /* Insert bolted slot number */
153 rA |= bolted << 24;
154
155 pr_debug("256M TLB entry for 0x%08x->0x%08x in bolt slot %d\n",
156 virt, phys, bolted);
157
158 mtspr(SPRN_MMUCR, 0);
159
160 __asm__ __volatile__(
161 "tlbwe %2,%3,0\n"
162 "tlbwe %1,%3,1\n"
163 "tlbwe %0,%3,2\n"
164 :
165 : "r" (PPC47x_TLB2_SW | PPC47x_TLB2_SR |
166 PPC47x_TLB2_SX
167#ifdef CONFIG_SMP
168 | PPC47x_TLB2_M
169#endif
170 ),
171 "r" (phys),
172 "r" (virt | PPC47x_TLB0_VALID | PPC47x_TLB0_256M),
173 "r" (rA));
174}
175
84void __init MMU_init_hw(void) 176void __init MMU_init_hw(void)
85{ 177{
178 /* This is not useful on 47x but won't hurt either */
86 ppc44x_update_tlb_hwater(); 179 ppc44x_update_tlb_hwater();
87 180
88 flush_instruction_cache(); 181 flush_instruction_cache();
@@ -95,8 +188,51 @@ unsigned long __init mmu_mapin_ram(unsigned long top)
95 /* Pin in enough TLBs to cover any lowmem not covered by the 188 /* Pin in enough TLBs to cover any lowmem not covered by the
96 * initial 256M mapping established in head_44x.S */ 189 * initial 256M mapping established in head_44x.S */
97 for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; 190 for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr;
98 addr += PPC_PIN_SIZE) 191 addr += PPC_PIN_SIZE) {
99 ppc44x_pin_tlb(addr + PAGE_OFFSET, addr); 192 if (mmu_has_feature(MMU_FTR_TYPE_47x))
193 ppc47x_pin_tlb(addr + PAGE_OFFSET, addr);
194 else
195 ppc44x_pin_tlb(addr + PAGE_OFFSET, addr);
196 }
197 if (mmu_has_feature(MMU_FTR_TYPE_47x)) {
198 ppc47x_update_boltmap();
100 199
200#ifdef DEBUG
201 {
202 int i;
203
204 printk(KERN_DEBUG "bolted entries: ");
205 for (i = 0; i < 255; i++) {
206 if (test_bit(i, tlb_47x_boltmap))
207 printk("%d ", i);
208 }
209 printk("\n");
210 }
211#endif /* DEBUG */
212 }
101 return total_lowmem; 213 return total_lowmem;
102} 214}
215
216#ifdef CONFIG_SMP
217void __cpuinit mmu_init_secondary(int cpu)
218{
219 unsigned long addr;
220
221 /* Pin in enough TLBs to cover any lowmem not covered by the
222 * initial 256M mapping established in head_44x.S
223 *
224 * WARNING: This is called with only the first 256M of the
225 * linear mapping in the TLB and we can't take faults yet
226 * so beware of what this code uses. It runs off a temporary
227 * stack. current (r2) isn't initialized, smp_processor_id()
228 * will not work, current thread info isn't accessible, ...
229 */
230 for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr;
231 addr += PPC_PIN_SIZE) {
232 if (mmu_has_feature(MMU_FTR_TYPE_47x))
233 ppc47x_pin_tlb(addr + PAGE_OFFSET, addr);
234 else
235 ppc44x_pin_tlb(addr + PAGE_OFFSET, addr);
236 }
237}
238#endif /* CONFIG_SMP */
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index 1f2d9ff09895..ddfd7ad4e1d6 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -395,10 +395,18 @@ void __init mmu_context_init(void)
395 * the PID/TID comparison is disabled, so we can use a TID of zero 395 * the PID/TID comparison is disabled, so we can use a TID of zero
396 * to represent all kernel pages as shared among all contexts. 396 * to represent all kernel pages as shared among all contexts.
397 * -- Dan 397 * -- Dan
398 *
399 * The IBM 47x core supports 16-bit PIDs, thus 65535 contexts. We
400 * should normally never have to steal though the facility is
401 * present if needed.
402 * -- BenH
398 */ 403 */
399 if (mmu_has_feature(MMU_FTR_TYPE_8xx)) { 404 if (mmu_has_feature(MMU_FTR_TYPE_8xx)) {
400 first_context = 0; 405 first_context = 0;
401 last_context = 15; 406 last_context = 15;
407 } else if (mmu_has_feature(MMU_FTR_TYPE_47x)) {
408 first_context = 1;
409 last_context = 65535;
402 } else { 410 } else {
403 first_context = 1; 411 first_context = 1;
404 last_context = 255; 412 last_context = 255;
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index d49a77503e19..eb11d5d2aa94 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -69,12 +69,7 @@ static inline void _tlbil_va(unsigned long address, unsigned int pid,
69} 69}
70#endif /* CONIFG_8xx */ 70#endif /* CONIFG_8xx */
71 71
72/* 72#if defined(CONFIG_PPC_BOOK3E) || defined(CONFIG_PPC_47x)
73 * As of today, we don't support tlbivax broadcast on any
74 * implementation. When that becomes the case, this will be
75 * an extern.
76 */
77#ifdef CONFIG_PPC_BOOK3E
78extern void _tlbivax_bcast(unsigned long address, unsigned int pid, 73extern void _tlbivax_bcast(unsigned long address, unsigned int pid,
79 unsigned int tsize, unsigned int ind); 74 unsigned int tsize, unsigned int ind);
80#else 75#else
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index bbdc5b577b85..e925cb58afd9 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -10,7 +10,7 @@
10 * - tlbil_va 10 * - tlbil_va
11 * - tlbil_pid 11 * - tlbil_pid
12 * - tlbil_all 12 * - tlbil_all
13 * - tlbivax_bcast (not yet) 13 * - tlbivax_bcast
14 * 14 *
15 * Code mostly moved over from misc_32.S 15 * Code mostly moved over from misc_32.S
16 * 16 *
@@ -33,6 +33,7 @@
33#include <asm/ppc_asm.h> 33#include <asm/ppc_asm.h>
34#include <asm/asm-offsets.h> 34#include <asm/asm-offsets.h>
35#include <asm/processor.h> 35#include <asm/processor.h>
36#include <asm/bug.h>
36 37
37#if defined(CONFIG_40x) 38#if defined(CONFIG_40x)
38 39
@@ -65,7 +66,7 @@ _GLOBAL(__tlbil_va)
65 * Nothing to do for 8xx, everything is inline 66 * Nothing to do for 8xx, everything is inline
66 */ 67 */
67 68
68#elif defined(CONFIG_44x) 69#elif defined(CONFIG_44x) /* Includes 47x */
69 70
70/* 71/*
71 * 440 implementation uses tlbsx/we for tlbil_va and a full sweep 72 * 440 implementation uses tlbsx/we for tlbil_va and a full sweep
@@ -73,7 +74,13 @@ _GLOBAL(__tlbil_va)
73 */ 74 */
74_GLOBAL(__tlbil_va) 75_GLOBAL(__tlbil_va)
75 mfspr r5,SPRN_MMUCR 76 mfspr r5,SPRN_MMUCR
76 rlwimi r5,r4,0,24,31 /* Set TID */ 77 mfmsr r10
78
79 /*
80 * We write 16 bits of STID since 47x supports that much, we
81 * will never be passed out of bounds values on 440 (hopefully)
82 */
83 rlwimi r5,r4,0,16,31
77 84
78 /* We have to run the search with interrupts disabled, otherwise 85 /* We have to run the search with interrupts disabled, otherwise
79 * an interrupt which causes a TLB miss can clobber the MMUCR 86 * an interrupt which causes a TLB miss can clobber the MMUCR
@@ -83,24 +90,41 @@ _GLOBAL(__tlbil_va)
83 * and restoring MMUCR, so only normal interrupts have to be 90 * and restoring MMUCR, so only normal interrupts have to be
84 * taken care of. 91 * taken care of.
85 */ 92 */
86 mfmsr r4
87 wrteei 0 93 wrteei 0
88 mtspr SPRN_MMUCR,r5 94 mtspr SPRN_MMUCR,r5
89 tlbsx. r3, 0, r3 95 tlbsx. r6,0,r3
90 wrtee r4 96 bne 10f
91 bne 1f
92 sync 97 sync
93 /* There are only 64 TLB entries, so r3 < 64, 98BEGIN_MMU_FTR_SECTION
94 * which means bit 22, is clear. Since 22 is 99 b 2f
95 * the V bit in the TLB_PAGEID, loading this 100END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
101 /* On 440 There are only 64 TLB entries, so r3 < 64, which means bit
102 * 22, is clear. Since 22 is the V bit in the TLB_PAGEID, loading this
96 * value will invalidate the TLB entry. 103 * value will invalidate the TLB entry.
97 */ 104 */
98 tlbwe r3, r3, PPC44x_TLB_PAGEID 105 tlbwe r6,r6,PPC44x_TLB_PAGEID
99 isync 106 isync
1001: blr 10710: wrtee r10
108 blr
1092:
110#ifdef CONFIG_PPC_47x
111 oris r7,r6,0x8000 /* specify way explicitely */
112 clrrwi r4,r3,12 /* get an EPN for the hashing with V = 0 */
113 ori r4,r4,PPC47x_TLBE_SIZE
114 tlbwe r4,r7,0 /* write it */
115 isync
116 wrtee r10
117 blr
118#else /* CONFIG_PPC_47x */
1191: trap
120 EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0;
121#endif /* !CONFIG_PPC_47x */
101 122
102_GLOBAL(_tlbil_all) 123_GLOBAL(_tlbil_all)
103_GLOBAL(_tlbil_pid) 124_GLOBAL(_tlbil_pid)
125BEGIN_MMU_FTR_SECTION
126 b 2f
127END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
104 li r3,0 128 li r3,0
105 sync 129 sync
106 130
@@ -115,6 +139,76 @@ _GLOBAL(_tlbil_pid)
115 139
116 isync 140 isync
117 blr 141 blr
1422:
143#ifdef CONFIG_PPC_47x
144 /* 476 variant. There's not simple way to do this, hopefully we'll
145 * try to limit the amount of such full invalidates
146 */
147 mfmsr r11 /* Interrupts off */
148 wrteei 0
149 li r3,-1 /* Current set */
150 lis r10,tlb_47x_boltmap@h
151 ori r10,r10,tlb_47x_boltmap@l
152 lis r7,0x8000 /* Specify way explicitely */
153
154 b 9f /* For each set */
155
1561: li r9,4 /* Number of ways */
157 li r4,0 /* Current way */
158 li r6,0 /* Default entry value 0 */
159 andi. r0,r8,1 /* Check if way 0 is bolted */
160 mtctr r9 /* Load way counter */
161 bne- 3f /* Bolted, skip loading it */
162
1632: /* For each way */
164 or r5,r3,r4 /* Make way|index for tlbre */
165 rlwimi r5,r5,16,8,15 /* Copy index into position */
166 tlbre r6,r5,0 /* Read entry */
1673: addis r4,r4,0x2000 /* Next way */
168 andi. r0,r6,PPC47x_TLB0_VALID /* Valid entry ? */
169 beq 4f /* Nope, skip it */
170 rlwimi r7,r5,0,1,2 /* Insert way number */
171 rlwinm r6,r6,0,21,19 /* Clear V */
172 tlbwe r6,r7,0 /* Write it */
1734: bdnz 2b /* Loop for each way */
174 srwi r8,r8,1 /* Next boltmap bit */
1759: cmpwi cr1,r3,255 /* Last set done ? */
176 addi r3,r3,1 /* Next set */
177 beq cr1,1f /* End of loop */
178 andi. r0,r3,0x1f /* Need to load a new boltmap word ? */
179 bne 1b /* No, loop */
180 lwz r8,0(r10) /* Load boltmap entry */
181 addi r10,r10,4 /* Next word */
182 b 1b /* Then loop */
1831: isync /* Sync shadows */
184 wrtee r11
185#else /* CONFIG_PPC_47x */
1861: trap
187 EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0;
188#endif /* !CONFIG_PPC_47x */
189 blr
190
191#ifdef CONFIG_PPC_47x
192/*
193 * _tlbivax_bcast is only on 47x. We don't bother doing a runtime
194 * check though, it will blow up soon enough if we mistakenly try
195 * to use it on a 440.
196 */
197_GLOBAL(_tlbivax_bcast)
198 mfspr r5,SPRN_MMUCR
199 mfmsr r10
200 rlwimi r5,r4,0,16,31
201 wrteei 0
202 mtspr SPRN_MMUCR,r5
203/* tlbivax 0,r3 - use .long to avoid binutils deps */
204 .long 0x7c000624 | (r3 << 11)
205 isync
206 eieio
207 tlbsync
208 sync
209 wrtee r10
210 blr
211#endif /* CONFIG_PPC_47x */
118 212
119#elif defined(CONFIG_FSL_BOOKE) 213#elif defined(CONFIG_FSL_BOOKE)
120/* 214/*