aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze
diff options
context:
space:
mode:
authorMichal Simek <monstr@monstr.eu>2010-02-08 10:41:38 -0500
committerMichal Simek <monstr@monstr.eu>2012-03-23 04:28:19 -0400
commite02db0aa3e1976ae4e23a66077d252a2f3ba74c7 (patch)
treeed16439c89abca6be4770f654c7c458ff0f6512f /arch/microblaze
parent1451d1d88b9aa32ac9ee54180239e9b34b6f9e86 (diff)
microblaze: Handle TLB skip size dynamically
This patch fix the problem with rootfs on JFFS2 with early printk console turned on. The origin version used TLB63 for temporary early printk mapping. The code expect that kernel is not able to use all 64 TLB entries till early printk console is remapped by ioremap. After that temporary mapping on TLB63 is silently lost. This expectation give the opportunity to have early console pretty early. Microblaze systems with JFFS2 rootfs with early printk console turned on used more than 64 TLB entries before kernel can remap early console. Based on that kernel does access to bad area because early printk mapping is rewritten. This patch introduces tlb_skip variable which dynamically stores number of skipped TLB entries from the TLB0. skip_tlb=2 means that TLB0 and TLB1 should be skipped. MICROBLAZE_TLB_SKIP defines how many TLB is skipped at the kernel start. They can be used for user purpose. TLB 63 is used for temporary LMB mapping (MICROBLAZE_LMB_TLB_ID). Also clean TLBLO when kernel starts. For specific kernel sizes kernel can use just one TLB. Detect this case and use the second TLB for general purpose. Change _tlbia function to flush TLB entries from tlb_skip to TLB_SIZE. Export tlb_skip size through debugfs. Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r--arch/microblaze/include/asm/mmu.h13
-rw-r--r--arch/microblaze/kernel/early_printk.c14
-rw-r--r--arch/microblaze/kernel/head.S42
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S10
-rw-r--r--arch/microblaze/kernel/misc.S13
-rw-r--r--arch/microblaze/kernel/setup.c13
6 files changed, 83 insertions, 22 deletions
diff --git a/arch/microblaze/include/asm/mmu.h b/arch/microblaze/include/asm/mmu.h
index 5198de8b1224..1f9edddf7f4b 100644
--- a/arch/microblaze/include/asm/mmu.h
+++ b/arch/microblaze/include/asm/mmu.h
@@ -56,6 +56,12 @@ typedef struct _SEGREG {
56 56
57extern void _tlbie(unsigned long va); /* invalidate a TLB entry */ 57extern void _tlbie(unsigned long va); /* invalidate a TLB entry */
58extern void _tlbia(void); /* invalidate all TLB entries */ 58extern void _tlbia(void); /* invalidate all TLB entries */
59
60/*
61 * tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB
62 * mapping has to increase tlb_skip size.
63 */
64extern u32 tlb_skip;
59# endif /* __ASSEMBLY__ */ 65# endif /* __ASSEMBLY__ */
60 66
61/* 67/*
@@ -68,7 +74,12 @@ extern void _tlbia(void); /* invalidate all TLB entries */
68 */ 74 */
69 75
70# define MICROBLAZE_TLB_SIZE 64 76# define MICROBLAZE_TLB_SIZE 64
71# define MICROBLAZE_TLB_SKIP 2 77
78/* For cases when you want to skip some TLB entries */
79# define MICROBLAZE_TLB_SKIP 0
80
81/* Use the last TLB for temporary access to LMB */
82# define MICROBLAZE_LMB_TLB_ID 63
72 83
73/* 84/*
74 * TLB entries are defined by a "high" tag portion and a "low" data 85 * TLB entries are defined by a "high" tag portion and a "low" data
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 742c247792ce..ec485876d0d0 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -175,6 +175,20 @@ void __init remap_early_printk(void)
175 base_addr); 175 base_addr);
176 base_addr = (u32) ioremap(base_addr, PAGE_SIZE); 176 base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
177 printk(KERN_CONT "0x%x\n", base_addr); 177 printk(KERN_CONT "0x%x\n", base_addr);
178
179 /*
180 * Early console is on the top of skipped TLB entries
181 * decrease tlb_skip size ensure that hardcoded TLB entry will be
182 * used by generic algorithm
183 * FIXME check if early console mapping is on the top by rereading
184 * TLB entry and compare baseaddr
185 * mts rtlbx, (tlb_skip - 1)
186 * nop
187 * mfs rX, rtlblo
188 * nop
189 * cmp rX, orig_base_addr
190 */
191 tlb_skip -= 1;
178} 192}
179 193
180void __init disable_early_printk(void) 194void __init disable_early_printk(void)
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 49dd48f9e6ec..98b17f9f904b 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -149,6 +149,7 @@ _copy_bram:
149_invalidate: 149_invalidate:
150 mts rtlbx, r3 150 mts rtlbx, r3
151 mts rtlbhi, r0 /* flush: ensure V is clear */ 151 mts rtlbhi, r0 /* flush: ensure V is clear */
152 mts rtlblo, r0
152 bgtid r3, _invalidate /* loop for all entries */ 153 bgtid r3, _invalidate /* loop for all entries */
153 addik r3, r3, -1 154 addik r3, r3, -1
154 /* sync */ 155 /* sync */
@@ -224,8 +225,14 @@ tlb_end:
224 andi r4,r4,0xfffffc00 /* Mask off the real page number */ 225 andi r4,r4,0xfffffc00 /* Mask off the real page number */
225 ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ 226 ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
226 227
227 /* TLB0 can be zeroes that's why we not setup it */ 228 /*
228 beqi r9, jump_over 229 * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
230 * if is use TLB1 value and clear it (r10 stores TLB1 value)
231 */
232 bnei r9, tlb0_not_zero
233 add r9, r10, r0
234 add r10, r0, r0
235tlb0_not_zero:
229 236
230 /* look at the code below */ 237 /* look at the code below */
231 ori r30, r0, 0x200 238 ori r30, r0, 0x200
@@ -239,18 +246,21 @@ tlb_end:
239 bneid r29, 1f 246 bneid r29, 1f
240 addik r30, r30, 0x80 247 addik r30, r30, 0x80
2411: 2481:
242 ori r11, r30, 0
243
244 andi r3,r3,0xfffffc00 /* Mask off the effective page number */ 249 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
245 ori r3,r3,(TLB_VALID) 250 ori r3,r3,(TLB_VALID)
246 or r3, r3, r11 251 or r3, r3, r30
247 252
248 mts rtlbx,r0 /* TLB slow 0 */ 253 /* Load tlb_skip size value which is index to first unused TLB entry */
254 lwi r11, r0, TOPHYS(tlb_skip)
255 mts rtlbx,r11 /* TLB slow 0 */
249 256
250 mts rtlblo,r4 /* Load the data portion of the entry */ 257 mts rtlblo,r4 /* Load the data portion of the entry */
251 mts rtlbhi,r3 /* Load the tag portion of the entry */ 258 mts rtlbhi,r3 /* Load the tag portion of the entry */
252 259
253jump_over: 260 /* Increase tlb_skip size */
261 addik r11, r11, 1
262 swi r11, r0, TOPHYS(tlb_skip)
263
254 /* TLB1 can be zeroes that's why we not setup it */ 264 /* TLB1 can be zeroes that's why we not setup it */
255 beqi r10, jump_over2 265 beqi r10, jump_over2
256 266
@@ -266,27 +276,30 @@ jump_over:
266 bneid r29, 1f 276 bneid r29, 1f
267 addik r30, r30, 0x80 277 addik r30, r30, 0x80
2681: 2781:
269 ori r12, r30, 0
270
271 addk r4, r4, r9 /* previous addr + TLB0 size */ 279 addk r4, r4, r9 /* previous addr + TLB0 size */
272 addk r3, r3, r9 280 addk r3, r3, r9
273 281
274 andi r3,r3,0xfffffc00 /* Mask off the effective page number */ 282 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
275 ori r3,r3,(TLB_VALID) 283 ori r3,r3,(TLB_VALID)
276 or r3, r3, r12 284 or r3, r3, r30
277 285
278 ori r6,r0,1 /* TLB slot 1 */ 286 lwi r11, r0, TOPHYS(tlb_skip)
279 mts rtlbx,r6 287 mts rtlbx, r11 /* r11 is used from TLB0 */
280 288
281 mts rtlblo,r4 /* Load the data portion of the entry */ 289 mts rtlblo,r4 /* Load the data portion of the entry */
282 mts rtlbhi,r3 /* Load the tag portion of the entry */ 290 mts rtlbhi,r3 /* Load the tag portion of the entry */
283 291
292 /* Increase tlb_skip size */
293 addik r11, r11, 1
294 swi r11, r0, TOPHYS(tlb_skip)
295
284jump_over2: 296jump_over2:
285 /* 297 /*
286 * Load a TLB entry for LMB, since we need access to 298 * Load a TLB entry for LMB, since we need access to
287 * the exception vectors, using a 4k real==virtual mapping. 299 * the exception vectors, using a 4k real==virtual mapping.
288 */ 300 */
289 ori r6,r0,3 /* TLB slot 3 */ 301 /* Use temporary TLB_ID for LMB - clear this temporary mapping later */
302 ori r6, r0, MICROBLAZE_LMB_TLB_ID
290 mts rtlbx,r6 303 mts rtlbx,r6
291 304
292 ori r4,r0,(TLB_WR | TLB_EX) 305 ori r4,r0,(TLB_WR | TLB_EX)
@@ -355,8 +368,7 @@ start_here:
355 368
356 /* Load up the kernel context */ 369 /* Load up the kernel context */
357kernel_load_context: 370kernel_load_context:
358 # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away. 371 ori r5, r0, MICROBLAZE_LMB_TLB_ID
359 ori r5,r0,3
360 mts rtlbx,r5 372 mts rtlbx,r5
361 nop 373 nop
362 mts rtlbhi,r0 374 mts rtlbhi,r0
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index b7249f4215a2..aa510f450ac6 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -820,9 +820,15 @@ ex_handler_done:
820 * Upon exit, we reload everything and RFI. 820 * Upon exit, we reload everything and RFI.
821 * A common place to load the TLB. 821 * A common place to load the TLB.
822 */ 822 */
823.section .data
824.align 4
825.global tlb_skip
826 tlb_skip:
827 .long MICROBLAZE_TLB_SKIP
823 tlb_index: 828 tlb_index:
824 /* MS: storing last used tlb index */ 829 /* MS: storing last used tlb index */
825 .long (MICROBLAZE_TLB_SKIP - 1) 830 .long MICROBLAZE_TLB_SIZE/2
831.previous
826 finish_tlb_load: 832 finish_tlb_load:
827 /* MS: load the last used TLB index. */ 833 /* MS: load the last used TLB index. */
828 lwi r5, r0, TOPHYS(tlb_index) 834 lwi r5, r0, TOPHYS(tlb_index)
@@ -833,7 +839,7 @@ ex_handler_done:
833 ori r6, r0, 1 839 ori r6, r0, 1
834 cmp r31, r5, r6 840 cmp r31, r5, r6
835 blti r31, ex12 841 blti r31, ex12
836 addik r5, r6, MICROBLAZE_TLB_SKIP - 1 842 lwi r5, r0, TOPHYS(tlb_skip)
837 ex12: 843 ex12:
838 /* MS: save back current TLB index */ 844 /* MS: save back current TLB index */
839 swi r5, r0, TOPHYS(tlb_index) 845 swi r5, r0, TOPHYS(tlb_index)
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
index c9090d7973f6..1dafddeb8a0b 100644
--- a/arch/microblaze/kernel/misc.S
+++ b/arch/microblaze/kernel/misc.S
@@ -29,16 +29,16 @@
29.type _tlbia, @function 29.type _tlbia, @function
30.align 4; 30.align 4;
31_tlbia: 31_tlbia:
32 addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */ 32 lwi r12, r0, tlb_skip;
33 /* isync */ 33 /* isync */
34_tlbia_1: 34_tlbia_1:
35 mts rtlbx, r12 35 mts rtlbx, r12
36 nop 36 nop
37 mts rtlbhi, r0 /* flush: ensure V is clear */ 37 mts rtlbhi, r0 /* flush: ensure V is clear */
38 nop 38 nop
39 addik r11, r12, -MICROBLAZE_TLB_SKIP 39 rsubi r11, r12, MICROBLAZE_TLB_SIZE - 1
40 bneid r11, _tlbia_1 /* loop for all entries */ 40 bneid r11, _tlbia_1 /* loop for all entries */
41 addik r12, r12, -1 41 addik r12, r12, 1
42 /* sync */ 42 /* sync */
43 rtsd r15, 8 43 rtsd r15, 8
44 nop 44 nop
@@ -75,7 +75,7 @@ early_console_reg_tlb_alloc:
75 * Load a TLB entry for the UART, so that microblaze_progress() can use 75 * Load a TLB entry for the UART, so that microblaze_progress() can use
76 * the UARTs nice and early. We use a 4k real==virtual mapping. 76 * the UARTs nice and early. We use a 4k real==virtual mapping.
77 */ 77 */
78 ori r4, r0, 63 78 lwi r4, r0, tlb_skip
79 mts rtlbx, r4 /* TLB slot 63 */ 79 mts rtlbx, r4 /* TLB slot 63 */
80 80
81 or r4,r5,r0 81 or r4,r5,r0
@@ -89,6 +89,11 @@ early_console_reg_tlb_alloc:
89 nop 89 nop
90 mts rtlbhi,r5 /* Load the tag portion of the entry */ 90 mts rtlbhi,r5 /* Load the tag portion of the entry */
91 nop 91 nop
92
93 lwi r5, r0, tlb_skip
94 addik r5, r5, 1
95 swi r5, r0, tlb_skip
96
92 rtsd r15, 8 97 rtsd r15, 8
93 nop 98 nop
94 99
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index a1fa2a5813bf..e4f5956ee13c 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -208,6 +208,19 @@ static int microblaze_debugfs_init(void)
208 return of_debugfs_root == NULL; 208 return of_debugfs_root == NULL;
209} 209}
210arch_initcall(microblaze_debugfs_init); 210arch_initcall(microblaze_debugfs_init);
211
212static int __init debugfs_tlb(void)
213{
214 struct dentry *d;
215
216 if (!of_debugfs_root)
217 return -ENODEV;
218
219 d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip);
220 if (!d)
221 return -ENOMEM;
222}
223device_initcall(debugfs_tlb);
211#endif 224#endif
212 225
213static int dflt_bus_notify(struct notifier_block *nb, 226static int dflt_bus_notify(struct notifier_block *nb,