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:18 -0400
commit95b0f9ea66661681f6ae081ea28416744d622c07 (patch)
treec4d387b9e4a5add47945be3036c7e5682ea5330c /arch/microblaze
parent3a1d26769f61fe8a1f517a66dfcee935a76fd61c (diff)
microblaze: Improve TLB calculation for small systems
Systems with small amount of memory need to be handled differently. Linux can't allocate the whole 32MB with two TLBs because then there is no MMU protection. Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r--arch/microblaze/Kconfig4
-rw-r--r--arch/microblaze/include/asm/setup.h3
-rw-r--r--arch/microblaze/include/asm/system.h1
-rw-r--r--arch/microblaze/kernel/head.S98
-rw-r--r--arch/microblaze/kernel/setup.c11
-rw-r--r--arch/microblaze/mm/init.c14
6 files changed, 120 insertions, 11 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 86ae27871f41..d64c10093b40 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -259,6 +259,10 @@ config MICROBLAZE_32K_PAGES
259 259
260endchoice 260endchoice
261 261
262config KERNEL_PAD
263 hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
264 default "0x80000" if MMU
265
262endmenu 266endmenu
263 267
264source "mm/Kconfig" 268source "mm/Kconfig"
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 6c72ed7eba98..9f195c094731 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -39,7 +39,8 @@ extern void of_platform_reset_gpio_probe(void);
39void time_init(void); 39void time_init(void);
40void init_IRQ(void); 40void init_IRQ(void);
41void machine_early_init(const char *cmdline, unsigned int ram, 41void machine_early_init(const char *cmdline, unsigned int ram,
42 unsigned int fdt, unsigned int msr); 42 unsigned int fdt, unsigned int msr, unsigned int tlb0,
43 unsigned int tlb1);
43 44
44void machine_restart(char *cmd); 45void machine_restart(char *cmd);
45void machine_shutdown(void); 46void machine_shutdown(void);
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
index 5a433cbaafb3..01228d2b1351 100644
--- a/arch/microblaze/include/asm/system.h
+++ b/arch/microblaze/include/asm/system.h
@@ -83,6 +83,7 @@ void default_idle(void);
83void free_init_pages(char *what, unsigned long begin, unsigned long end); 83void free_init_pages(char *what, unsigned long begin, unsigned long end);
84void free_initmem(void); 84void free_initmem(void);
85extern char *klimit; 85extern char *klimit;
86extern unsigned long kernel_tlb;
86extern void ret_from_fork(void); 87extern void ret_from_fork(void);
87 88
88extern void *alloc_maybe_bootmem(size_t size, gfp_t mask); 89extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 441dad80558c..49dd48f9e6ec 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -168,6 +168,53 @@ _invalidate:
168 addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */ 168 addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
169 tophys(r4,r3) /* Load the kernel physical address */ 169 tophys(r4,r3) /* Load the kernel physical address */
170 170
171 /* start to do TLB calculation */
172 addik r12, r0, _end
173 rsub r12, r3, r12
174 addik r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
175
176 or r9, r0, r0 /* TLB0 = 0 */
177 or r10, r0, r0 /* TLB1 = 0 */
178
179 addik r11, r12, -0x1000000
180 bgei r11, GT16 /* size is greater than 16MB */
181 addik r11, r12, -0x0800000
182 bgei r11, GT8 /* size is greater than 8MB */
183 addik r11, r12, -0x0400000
184 bgei r11, GT4 /* size is greater than 4MB */
185 /* size is less than 4MB */
186 addik r11, r12, -0x0200000
187 bgei r11, GT2 /* size is greater than 2MB */
188 addik r9, r0, 0x0100000 /* TLB0 must be 1MB */
189 addik r11, r12, -0x0100000
190 bgei r11, GT1 /* size is greater than 1MB */
191 /* TLB1 is 0 which is setup above */
192 bri tlb_end
193GT4: /* r11 contains the rest - will be either 1 or 4 */
194 ori r9, r0, 0x400000 /* TLB0 is 4MB */
195 bri TLB1
196GT16: /* TLB0 is 16MB */
197 addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
198TLB1:
199 /* must be used r2 because of substract if failed */
200 addik r2, r11, -0x0400000
201 bgei r2, GT20 /* size is greater than 16MB */
202 /* size is >16MB and <20MB */
203 addik r11, r11, -0x0100000
204 bgei r11, GT17 /* size is greater than 17MB */
205 /* kernel is >16MB and < 17MB */
206GT1:
207 addik r10, r0, 0x0100000 /* means TLB1 is 1MB */
208 bri tlb_end
209GT2: /* TLB0 is 0 and TLB1 will be 4MB */
210GT17: /* TLB1 is 4MB - kernel size <20MB */
211 addik r10, r0, 0x0400000 /* means TLB1 is 4MB */
212 bri tlb_end
213GT8: /* TLB0 is still zero that's why I can use only TLB1 */
214GT20: /* TLB1 is 16MB - kernel size >20MB */
215 addik r10, r0, 0x1000000 /* means TLB1 is 16MB */
216tlb_end:
217
171 /* 218 /*
172 * Configure and load two entries into TLB slots 0 and 1. 219 * Configure and load two entries into TLB slots 0 and 1.
173 * In case we are pinning TLBs, these are reserved in by the 220 * In case we are pinning TLBs, these are reserved in by the
@@ -177,16 +224,56 @@ _invalidate:
177 andi r4,r4,0xfffffc00 /* Mask off the real page number */ 224 andi r4,r4,0xfffffc00 /* Mask off the real page number */
178 ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ 225 ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
179 226
227 /* TLB0 can be zeroes that's why we not setup it */
228 beqi r9, jump_over
229
230 /* look at the code below */
231 ori r30, r0, 0x200
232 andi r29, r9, 0x100000
233 bneid r29, 1f
234 addik r30, r30, 0x80
235 andi r29, r9, 0x400000
236 bneid r29, 1f
237 addik r30, r30, 0x80
238 andi r29, r9, 0x1000000
239 bneid r29, 1f
240 addik r30, r30, 0x80
2411:
242 ori r11, r30, 0
243
180 andi r3,r3,0xfffffc00 /* Mask off the effective page number */ 244 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
181 ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) 245 ori r3,r3,(TLB_VALID)
246 or r3, r3, r11
182 247
183 mts rtlbx,r0 /* TLB slow 0 */ 248 mts rtlbx,r0 /* TLB slow 0 */
184 249
185 mts rtlblo,r4 /* Load the data portion of the entry */ 250 mts rtlblo,r4 /* Load the data portion of the entry */
186 mts rtlbhi,r3 /* Load the tag portion of the entry */ 251 mts rtlbhi,r3 /* Load the tag portion of the entry */
187 252
188 addik r4, r4, 0x01000000 /* Map next 16 M entries */ 253jump_over:
189 addik r3, r3, 0x01000000 254 /* TLB1 can be zeroes that's why we not setup it */
255 beqi r10, jump_over2
256
257 /* look at the code below */
258 ori r30, r0, 0x200
259 andi r29, r10, 0x100000
260 bneid r29, 1f
261 addik r30, r30, 0x80
262 andi r29, r10, 0x400000
263 bneid r29, 1f
264 addik r30, r30, 0x80
265 andi r29, r10, 0x1000000
266 bneid r29, 1f
267 addik r30, r30, 0x80
2681:
269 ori r12, r30, 0
270
271 addk r4, r4, r9 /* previous addr + TLB0 size */
272 addk r3, r3, r9
273
274 andi r3,r3,0xfffffc00 /* Mask off the effective page number */
275 ori r3,r3,(TLB_VALID)
276 or r3, r3, r12
190 277
191 ori r6,r0,1 /* TLB slot 1 */ 278 ori r6,r0,1 /* TLB slot 1 */
192 mts rtlbx,r6 279 mts rtlbx,r6
@@ -194,6 +281,7 @@ _invalidate:
194 mts rtlblo,r4 /* Load the data portion of the entry */ 281 mts rtlblo,r4 /* Load the data portion of the entry */
195 mts rtlbhi,r3 /* Load the tag portion of the entry */ 282 mts rtlbhi,r3 /* Load the tag portion of the entry */
196 283
284jump_over2:
197 /* 285 /*
198 * Load a TLB entry for LMB, since we need access to 286 * Load a TLB entry for LMB, since we need access to
199 * the exception vectors, using a 4k real==virtual mapping. 287 * the exception vectors, using a 4k real==virtual mapping.
@@ -237,8 +325,8 @@ start_here:
237 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for 325 * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
238 * the function. 326 * the function.
239 */ 327 */
240 addik r9, r0, machine_early_init 328 addik r11, r0, machine_early_init
241 brald r15, r9 329 brald r15, r11
242 nop 330 nop
243 331
244#ifndef CONFIG_MMU 332#ifndef CONFIG_MMU
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 604cd9dd1333..a1fa2a5813bf 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -97,8 +97,11 @@ inline unsigned get_romfs_len(unsigned *addr)
97} 97}
98#endif /* CONFIG_MTD_UCLINUX_EBSS */ 98#endif /* CONFIG_MTD_UCLINUX_EBSS */
99 99
100unsigned long kernel_tlb;
101
100void __init machine_early_init(const char *cmdline, unsigned int ram, 102void __init machine_early_init(const char *cmdline, unsigned int ram,
101 unsigned int fdt, unsigned int msr) 103 unsigned int fdt, unsigned int msr, unsigned int tlb0,
104 unsigned int tlb1)
102{ 105{
103 unsigned long *src, *dst; 106 unsigned long *src, *dst;
104 unsigned int offset = 0; 107 unsigned int offset = 0;
@@ -145,6 +148,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
145 setup_early_printk(NULL); 148 setup_early_printk(NULL);
146#endif 149#endif
147 150
151 /* setup kernel_tlb after BSS cleaning
152 * Maybe worth to move to asm code */
153 kernel_tlb = tlb0 + tlb1;
154 /* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0,
155 tlb1, kernel_tlb); */
156
148 printk("Ramdisk addr 0x%08x, ", ram); 157 printk("Ramdisk addr 0x%08x, ", ram);
149 if (fdt) 158 if (fdt)
150 printk("FDT at 0x%08x\n", fdt); 159 printk("FDT at 0x%08x\n", fdt);
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 95297b13dd9e..ce80823051ba 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -398,10 +398,16 @@ asmlinkage void __init mmu_init(void)
398 machine_restart(NULL); 398 machine_restart(NULL);
399 } 399 }
400 400
401 if ((u32) memblock.memory.regions[0].size < 0x1000000) { 401 if ((u32) memblock.memory.regions[0].size < 0x400000) {
402 printk(KERN_EMERG "Memory must be greater than 16MB\n"); 402 printk(KERN_EMERG "Memory must be greater than 4MB\n");
403 machine_restart(NULL); 403 machine_restart(NULL);
404 } 404 }
405
406 if ((u32) memblock.memory.regions[0].size < kernel_tlb) {
407 printk(KERN_EMERG "Kernel size is greater than memory node\n");
408 machine_restart(NULL);
409 }
410
405 /* Find main memory where the kernel is */ 411 /* Find main memory where the kernel is */
406 memory_start = (u32) memblock.memory.regions[0].base; 412 memory_start = (u32) memblock.memory.regions[0].base;
407 lowmem_size = memory_size = (u32) memblock.memory.regions[0].size; 413 lowmem_size = memory_size = (u32) memblock.memory.regions[0].size;
@@ -462,11 +468,11 @@ void __init *early_get_page(void)
462 p = alloc_bootmem_pages(PAGE_SIZE); 468 p = alloc_bootmem_pages(PAGE_SIZE);
463 } else { 469 } else {
464 /* 470 /*
465 * Mem start + 32MB -> here is limit 471 * Mem start + kernel_tlb -> here is limit
466 * because of mem mapping from head.S 472 * because of mem mapping from head.S
467 */ 473 */
468 p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, 474 p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
469 memory_start + 0x2000000)); 475 memory_start + kernel_tlb));
470 } 476 }
471 return p; 477 return p;
472} 478}