diff options
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r-- | arch/microblaze/kernel/cpu/cpuinfo.c | 2 | ||||
-rw-r--r-- | arch/microblaze/kernel/early_printk.c | 16 | ||||
-rw-r--r-- | arch/microblaze/kernel/head.S | 129 | ||||
-rw-r--r-- | arch/microblaze/kernel/hw_exception_handler.S | 13 | ||||
-rw-r--r-- | arch/microblaze/kernel/intc.c | 4 | ||||
-rw-r--r-- | arch/microblaze/kernel/misc.S | 13 | ||||
-rw-r--r-- | arch/microblaze/kernel/setup.c | 24 | ||||
-rw-r--r-- | arch/microblaze/kernel/timer.c | 6 | ||||
-rw-r--r-- | arch/microblaze/kernel/vmlinux.lds.S | 2 |
9 files changed, 179 insertions, 30 deletions
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index 54194b2..eab6abf 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -35,6 +35,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"8.00.b", 0x13}, {"8.10.a", 0x14}, {"8.20.a", 0x15}, + {"8.20.b", 0x16}, + {"8.30.a", 0x17}, {NULL, 0}, }; diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c index 8356e47..ec48587 100644 --- a/arch/microblaze/kernel/early_printk.c +++ b/arch/microblaze/kernel/early_printk.c @@ -171,10 +171,24 @@ void __init remap_early_printk(void) { if (!early_console_initialized || !early_console) return; - printk(KERN_INFO "early_printk_console remaping from 0x%x to ", + printk(KERN_INFO "early_printk_console remapping from 0x%x to ", base_addr); base_addr = (u32) ioremap(base_addr, PAGE_SIZE); printk(KERN_CONT "0x%x\n", base_addr); + + /* + * Early console is on the top of skipped TLB entries + * decrease tlb_skip size ensure that hardcoded TLB entry will be + * used by generic algorithm + * FIXME check if early console mapping is on the top by rereading + * TLB entry and compare baseaddr + * mts rtlbx, (tlb_skip - 1) + * nop + * mfs rX, rtlblo + * nop + * cmp rX, orig_base_addr + */ + tlb_skip -= 1; } void __init disable_early_printk(void) diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 77320b8..98b17f9 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -63,9 +63,7 @@ ENTRY(_start) real_start: #endif - mfs r1, rmsr - andi r1, r1, ~2 - mts rmsr, r1 + mts rmsr, r0 /* * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc' * if the msrclr instruction is not enabled. We use this to detect @@ -73,6 +71,7 @@ real_start: * r8 == 0 - msr instructions are implemented * r8 != 0 - msr instructions are not implemented */ + mfs r1, rmsr msrclr r8, 0 /* clear nothing - just read msr for test */ cmpu r8, r8, r1 /* r1 must contain msr reg content */ @@ -96,7 +95,7 @@ big_endian: _prepare_copy_fdt: or r11, r0, r0 /* incremment */ ori r4, r0, TOPHYS(_fdt_start) - ori r3, r0, (0x4000 - 4) + ori r3, r0, (0x8000 - 4) _copy_fdt: lw r12, r7, r11 /* r12 = r7 + r11 */ sw r12, r4, r11 /* addr[r4 + r11] = r12 */ @@ -150,6 +149,7 @@ _copy_bram: _invalidate: mts rtlbx, r3 mts rtlbhi, r0 /* flush: ensure V is clear */ + mts rtlblo, r0 bgtid r3, _invalidate /* loop for all entries */ addik r3, r3, -1 /* sync */ @@ -169,6 +169,53 @@ _invalidate: addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */ tophys(r4,r3) /* Load the kernel physical address */ + /* start to do TLB calculation */ + addik r12, r0, _end + rsub r12, r3, r12 + addik r12, r12, CONFIG_KERNEL_PAD /* that's the pad */ + + or r9, r0, r0 /* TLB0 = 0 */ + or r10, r0, r0 /* TLB1 = 0 */ + + addik r11, r12, -0x1000000 + bgei r11, GT16 /* size is greater than 16MB */ + addik r11, r12, -0x0800000 + bgei r11, GT8 /* size is greater than 8MB */ + addik r11, r12, -0x0400000 + bgei r11, GT4 /* size is greater than 4MB */ + /* size is less than 4MB */ + addik r11, r12, -0x0200000 + bgei r11, GT2 /* size is greater than 2MB */ + addik r9, r0, 0x0100000 /* TLB0 must be 1MB */ + addik r11, r12, -0x0100000 + bgei r11, GT1 /* size is greater than 1MB */ + /* TLB1 is 0 which is setup above */ + bri tlb_end +GT4: /* r11 contains the rest - will be either 1 or 4 */ + ori r9, r0, 0x400000 /* TLB0 is 4MB */ + bri TLB1 +GT16: /* TLB0 is 16MB */ + addik r9, r0, 0x1000000 /* means TLB0 is 16MB */ +TLB1: + /* must be used r2 because of substract if failed */ + addik r2, r11, -0x0400000 + bgei r2, GT20 /* size is greater than 16MB */ + /* size is >16MB and <20MB */ + addik r11, r11, -0x0100000 + bgei r11, GT17 /* size is greater than 17MB */ + /* kernel is >16MB and < 17MB */ +GT1: + addik r10, r0, 0x0100000 /* means TLB1 is 1MB */ + bri tlb_end +GT2: /* TLB0 is 0 and TLB1 will be 4MB */ +GT17: /* TLB1 is 4MB - kernel size <20MB */ + addik r10, r0, 0x0400000 /* means TLB1 is 4MB */ + bri tlb_end +GT8: /* TLB0 is still zero that's why I can use only TLB1 */ +GT20: /* TLB1 is 16MB - kernel size >20MB */ + addik r10, r0, 0x1000000 /* means TLB1 is 16MB */ +tlb_end: + /* * Configure and load two entries into TLB slots 0 and 1. * In case we are pinning TLBs, these are reserved in by the @@ -178,28 +225,81 @@ _invalidate: andi r4,r4,0xfffffc00 /* Mask off the real page number */ ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ + /* + * TLB0 is always used - check if is not zero (r9 stores TLB0 value) + * if is use TLB1 value and clear it (r10 stores TLB1 value) + */ + bnei r9, tlb0_not_zero + add r9, r10, r0 + add r10, r0, r0 +tlb0_not_zero: + + /* look at the code below */ + ori r30, r0, 0x200 + andi r29, r9, 0x100000 + bneid r29, 1f + addik r30, r30, 0x80 + andi r29, r9, 0x400000 + bneid r29, 1f + addik r30, r30, 0x80 + andi r29, r9, 0x1000000 + bneid r29, 1f + addik r30, r30, 0x80 +1: andi r3,r3,0xfffffc00 /* Mask off the effective page number */ - ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) + ori r3,r3,(TLB_VALID) + or r3, r3, r30 - mts rtlbx,r0 /* TLB slow 0 */ + /* Load tlb_skip size value which is index to first unused TLB entry */ + lwi r11, r0, TOPHYS(tlb_skip) + mts rtlbx,r11 /* TLB slow 0 */ mts rtlblo,r4 /* Load the data portion of the entry */ mts rtlbhi,r3 /* Load the tag portion of the entry */ - addik r4, r4, 0x01000000 /* Map next 16 M entries */ - addik r3, r3, 0x01000000 + /* Increase tlb_skip size */ + addik r11, r11, 1 + swi r11, r0, TOPHYS(tlb_skip) + + /* TLB1 can be zeroes that's why we not setup it */ + beqi r10, jump_over2 + + /* look at the code below */ + ori r30, r0, 0x200 + andi r29, r10, 0x100000 + bneid r29, 1f + addik r30, r30, 0x80 + andi r29, r10, 0x400000 + bneid r29, 1f + addik r30, r30, 0x80 + andi r29, r10, 0x1000000 + bneid r29, 1f + addik r30, r30, 0x80 +1: + addk r4, r4, r9 /* previous addr + TLB0 size */ + addk r3, r3, r9 - ori r6,r0,1 /* TLB slot 1 */ - mts rtlbx,r6 + andi r3,r3,0xfffffc00 /* Mask off the effective page number */ + ori r3,r3,(TLB_VALID) + or r3, r3, r30 + + lwi r11, r0, TOPHYS(tlb_skip) + mts rtlbx, r11 /* r11 is used from TLB0 */ mts rtlblo,r4 /* Load the data portion of the entry */ mts rtlbhi,r3 /* Load the tag portion of the entry */ + /* Increase tlb_skip size */ + addik r11, r11, 1 + swi r11, r0, TOPHYS(tlb_skip) + +jump_over2: /* * Load a TLB entry for LMB, since we need access to * the exception vectors, using a 4k real==virtual mapping. */ - ori r6,r0,3 /* TLB slot 3 */ + /* Use temporary TLB_ID for LMB - clear this temporary mapping later */ + ori r6, r0, MICROBLAZE_LMB_TLB_ID mts rtlbx,r6 ori r4,r0,(TLB_WR | TLB_EX) @@ -238,8 +338,8 @@ start_here: * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for * the function. */ - addik r9, r0, machine_early_init - brald r15, r9 + addik r11, r0, machine_early_init + brald r15, r11 nop #ifndef CONFIG_MMU @@ -268,8 +368,7 @@ start_here: /* Load up the kernel context */ kernel_load_context: - # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away. - ori r5,r0,3 + ori r5, r0, MICROBLAZE_LMB_TLB_ID mts rtlbx,r5 nop mts rtlbhi,r0 diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index e62be83..aa510f4 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -820,19 +820,26 @@ ex_handler_done: * Upon exit, we reload everything and RFI. * A common place to load the TLB. */ +.section .data +.align 4 +.global tlb_skip + tlb_skip: + .long MICROBLAZE_TLB_SKIP tlb_index: - .long 1 /* MS: storing last used tlb index */ + /* MS: storing last used tlb index */ + .long MICROBLAZE_TLB_SIZE/2 +.previous finish_tlb_load: /* MS: load the last used TLB index. */ lwi r5, r0, TOPHYS(tlb_index) addik r5, r5, 1 /* MS: inc tlb_index -> use next one */ /* MS: FIXME this is potential fault, because this is mask not count */ - andi r5, r5, (MICROBLAZE_TLB_SIZE-1) + andi r5, r5, MICROBLAZE_TLB_SIZE - 1 ori r6, r0, 1 cmp r31, r5, r6 blti r31, ex12 - addik r5, r6, 1 + lwi r5, r0, TOPHYS(tlb_skip) ex12: /* MS: save back current TLB index */ swi r5, r0, TOPHYS(tlb_index) diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index ad12067..6c54d4d 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -151,8 +151,8 @@ void __init init_IRQ(void) #ifdef CONFIG_SELFMOD_INTC selfmod_function((int *) arr_func, intc_baseaddr); #endif - printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n", - intc_baseaddr, nr_irq, intr_mask); + printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n", + intc->name, intc_baseaddr, nr_irq, intr_mask); /* * Disable all external interrupts until they are diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index 206da3d..1dafdde 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -29,16 +29,16 @@ .type _tlbia, @function .align 4; _tlbia: - addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */ + lwi r12, r0, tlb_skip; /* isync */ _tlbia_1: mts rtlbx, r12 nop mts rtlbhi, r0 /* flush: ensure V is clear */ nop - addik r11, r12, -2 + rsubi r11, r12, MICROBLAZE_TLB_SIZE - 1 bneid r11, _tlbia_1 /* loop for all entries */ - addik r12, r12, -1 + addik r12, r12, 1 /* sync */ rtsd r15, 8 nop @@ -75,7 +75,7 @@ early_console_reg_tlb_alloc: * Load a TLB entry for the UART, so that microblaze_progress() can use * the UARTs nice and early. We use a 4k real==virtual mapping. */ - ori r4, r0, MICROBLAZE_TLB_SIZE - 1 + lwi r4, r0, tlb_skip mts rtlbx, r4 /* TLB slot 63 */ or r4,r5,r0 @@ -89,6 +89,11 @@ early_console_reg_tlb_alloc: nop mts rtlbhi,r5 /* Load the tag portion of the entry */ nop + + lwi r5, r0, tlb_skip + addik r5, r5, 1 + swi r5, r0, tlb_skip + rtsd r15, 8 nop diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 70e6d0b..9f79fb3 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -95,8 +95,11 @@ inline unsigned get_romfs_len(unsigned *addr) } #endif /* CONFIG_MTD_UCLINUX_EBSS */ +unsigned long kernel_tlb; + void __init machine_early_init(const char *cmdline, unsigned int ram, - unsigned int fdt, unsigned int msr) + unsigned int fdt, unsigned int msr, unsigned int tlb0, + unsigned int tlb1) { unsigned long *src, *dst; unsigned int offset = 0; @@ -143,6 +146,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, setup_early_printk(NULL); #endif + /* setup kernel_tlb after BSS cleaning + * Maybe worth to move to asm code */ + kernel_tlb = tlb0 + tlb1; + /* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0, + tlb1, kernel_tlb); */ + printk("Ramdisk addr 0x%08x, ", ram); if (fdt) printk("FDT at 0x%08x\n", fdt); @@ -197,6 +206,19 @@ static int microblaze_debugfs_init(void) return of_debugfs_root == NULL; } arch_initcall(microblaze_debugfs_init); + +static int __init debugfs_tlb(void) +{ + struct dentry *d; + + if (!of_debugfs_root) + return -ENODEV; + + d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip); + if (!d) + return -ENOMEM; +} +device_initcall(debugfs_tlb); #endif static int dflt_bus_notify(struct notifier_block *nb, diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 3cb0bf6..cadfd56 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -79,7 +79,7 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val) * !PWMA - disable pwm * TINT - clear interrupt status * ENT- enable timer itself - * EINT - enable interrupt + * ENIT - enable interrupt * !LOAD - clear the bit to let go * ARHT - auto reload * !CAPT - no external trigger @@ -274,8 +274,8 @@ void __init time_init(void) #ifdef CONFIG_SELFMOD_TIMER selfmod_function((int *) arr_func, timer_baseaddr); #endif - printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n", - timer_baseaddr, irq); + printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n", + timer->name, timer_baseaddr, irq); /* If there is clock-frequency property than use it */ prop = of_get_property(timer, "clock-frequency", NULL); diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index ac0e1a5..109e9d8 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -44,7 +44,7 @@ SECTIONS { __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) { _fdt_start = . ; /* place for fdt blob */ *(__fdt_blob) ; /* Any link-placed DTB */ - . = _fdt_start + 0x4000; /* Pad up to 16kbyte */ + . = _fdt_start + 0x8000; /* Pad up to 32kbyte */ _fdt_end = . ; } |