Commit 30eebb54 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'next' of git://

Pull arch/microblaze fixes from Michal Simek

* 'next' of git://
  microblaze: Handle TLB skip size dynamically
  microblaze: Introduce TLB skip size
  microblaze: Improve TLB calculation for small systems
  microblaze: Extend space for compiled-in FDT to 32kB
  microblaze: Clear all MSR flags on the first kernel instruction
  microblaze: Use node name instead of compatible string
  microblaze: Fix mapin_ram function
  microblaze: Highmem support
  microblaze: Use active regions
  microblaze: Show more detailed information about memory
  microblaze: Introduce fixmap
  microblaze: mm: Fix lowmem max memory size limits
  microblaze: mm: Use ZONE_DMA instead of ZONE_NORMAL
  microblaze: trivial: Fix typo fault in timer.c
  microblaze: Use vsprintf extention %pf with builtin_return_address
  microblaze: Add PVR version string for MB 8.20.b and 8.30.a
  microblaze: Fix makefile to work with latest toolchain
  microblaze: Fix typo in early_printk.c
parents 9e4db1c3 e02db0aa
def_bool y
......@@ -28,6 +29,12 @@ config SWAP
def_bool y
config ZONE_DMA
def_bool y
def_bool y
......@@ -153,20 +160,18 @@ config XILINX_UNCACHED_SHADOW
The feature requires the design to define the RAM memory controller
window to be twice as large as the actual physical memory.
bool "Set high memory pool address"
config HIGHMEM
bool "High memory support"
depends on MMU
This option allows you to set the base address of the kernel virtual
area used to map high memory pages. This can be useful in
optimizing the layout of kernel virtual memory.
The address space of Microblaze processors is only 4 Gigabytes large
and it has to accommodate user address space, kernel address
space as well as some memory mapped IO. That means that, if you
have a large amount of physical memory and/or IO, not all of the
memory can be "permanently mapped" by the kernel. The physical
memory that is not permanently mapped is called "high memory".
Say N here unless you know what you are doing.
hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
depends on MMU
default "0xfe000000"
If unsure, say n.
bool "Set maximum low memory"
......@@ -255,6 +260,10 @@ config MICROBLAZE_32K_PAGES
hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
default "0x80000" if MMU
source "mm/Kconfig"
......@@ -8,7 +8,7 @@ obj-y += linked_dtb.o
targets := linux.bin linux.bin.gz simpleImage.%
OBJCOPYFLAGS := -R .note -R .comment -R -O binary
# Ensure system.dtb exists
$(obj)/linked_dtb.o: $(obj)/system.dtb
* fixmap.h: compile-time virtual memory allocation
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
* Copyright (C) 1998 Ingo Molnar
* Copyright 2008 Freescale Semiconductor Inc.
* Port to powerpc added by Kumar Gala
* Copyright 2011 Michal Simek <>
* Copyright 2011 PetaLogix Qld Pty Ltd
* Port to Microblaze
#ifndef _ASM_FIXMAP_H
#define _ASM_FIXMAP_H
#ifndef __ASSEMBLY__
#include <linux/kernel.h>
#include <asm/page.h>
#include <linux/threads.h>
#include <asm/kmap_types.h>
#define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE))
* Here we define all the compile-time 'special' virtual
* addresses. The point is to have a constant address at
* compile time, but to set the physical address only
* in the boot process. We allocate these special addresses
* from the end of virtual memory (0xfffff000) backwards.
* Also this lets us do fail-safe vmalloc(), we
* can guarantee that these special addresses and
* vmalloc()-ed addresses never overlap.
* these 'compile-time allocated' memory buffers are
* fixed-size 4k pages. (or larger if used with an increment
* highger than 1) use fixmap_set(idx,phys) to associate
* physical memory with fixmap indices.
* TLB entries of such buffers will not be flushed across
* task switches.
enum fixed_addresses {
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1,
extern void __set_fixmap(enum fixed_addresses idx,
phys_addr_t phys, pgprot_t flags);
#define set_fixmap(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL)
* Some hardware wants to get fixmapped without caching.
#define set_fixmap_nocache(idx, phys) \
__set_fixmap(idx, phys, PAGE_KERNEL_CI)
#define clear_fixmap(idx) \
__set_fixmap(idx, 0, __pgprot(0))
#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
extern void __this_fixmap_does_not_exist(void);
* 'index to address' translation. If anyone tries to use the idx
* directly without tranlation, we catch the bug with a NULL-deference
* kernel oops. Illegal ranges of incoming indices are caught too.
static __always_inline unsigned long fix_to_virt(const unsigned int idx)
* this branch gets completely eliminated after inlining,
* except when someone tries to use fixaddr indices in an
* illegal way. (such as mixing up address types or using
* out-of-range indices).
* If it doesn't get removed, the linker will complain
* loudly with a reasonably clear error message..
if (idx >= __end_of_fixed_addresses)
return __fix_to_virt(idx);
static inline unsigned long virt_to_fix(const unsigned long vaddr)
BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
return __virt_to_fix(vaddr);
#endif /* !__ASSEMBLY__ */
* highmem.h: virtual kernel memory mappings for high memory
* Used in CONFIG_HIGHMEM systems for memory pages which
* are not addressable by direct kernel virtual addresses.
* Copyright (C) 1999 Gerhard Wichert, Siemens AG
* Redesigned the x86 32-bit VM architecture to deal with
* up to 16 Terabyte physical memory. With current x86 CPUs
* we now support up to 64 Gigabytes physical RAM.
* Copyright (C) 1999 Ingo Molnar <>
#ifndef _ASM_HIGHMEM_H
#define _ASM_HIGHMEM_H
#ifdef __KERNEL__
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <asm/fixmap.h>
extern pte_t *kmap_pte;
extern pgprot_t kmap_prot;
extern pte_t *pkmap_page_table;
* Right now we initialize only a single pte table. It can be extended
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
* We use one full pte table with 4K pages. And with 16K/64K/256K pages pte
* table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP
* and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP
* in case of 16K/64K/256K page sizes.
#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
extern void __kunmap_atomic(void *kvaddr);
static inline void *kmap(struct page *page)
if (!PageHighMem(page))
return page_address(page);
return kmap_high(page);
static inline void kunmap(struct page *page)
if (!PageHighMem(page))
static inline void *__kmap_atomic(struct page *page)
return kmap_atomic_prot(page, kmap_prot);
static inline struct page *kmap_atomic_to_page(void *ptr)
unsigned long idx, vaddr = (unsigned long) ptr;
pte_t *pte;
if (vaddr < FIXADDR_START)
return virt_to_page(ptr);
idx = virt_to_fix(vaddr);
pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
return pte_page(*pte);
#define flush_cache_kmaps() { flush_icache(); flush_dcache(); }
#endif /* __KERNEL__ */
#endif /* _ASM_HIGHMEM_H */
......@@ -56,6 +56,12 @@ typedef struct _SEGREG {
extern void _tlbie(unsigned long va); /* invalidate a TLB entry */
extern void _tlbia(void); /* invalidate all TLB entries */
* tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB
* mapping has to increase tlb_skip size.
extern u32 tlb_skip;
# endif /* __ASSEMBLY__ */
......@@ -69,6 +75,12 @@ extern void _tlbia(void); /* invalidate all TLB entries */
/* For cases when you want to skip some TLB entries */
/* Use the last TLB for temporary access to LMB */
* TLB entries are defined by a "high" tag portion and a "low" data
* portion. The data portion is 32-bits.
......@@ -135,8 +135,8 @@ extern unsigned long min_low_pfn;
extern unsigned long max_pfn;
extern unsigned long memory_start;
extern unsigned long memory_end;
extern unsigned long memory_size;
extern unsigned long lowmem_size;
extern int page_is_ram(unsigned long pfn);
......@@ -94,8 +94,7 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/* Start and end of the vmalloc area. */
/* Make sure to map the vmalloc area above the pinned kernel memory area
of 32Mb. */
max(32 * 1024 * 1024UL, memory_size))
#define VMALLOC_END ioremap_bot
#endif /* __ASSEMBLY__ */
......@@ -39,7 +39,8 @@ extern void of_platform_reset_gpio_probe(void);
void time_init(void);
void init_IRQ(void);
void 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);
void machine_restart(char *cmd);
void machine_shutdown(void);
......@@ -83,6 +83,7 @@ void default_idle(void);
void free_init_pages(char *what, unsigned long begin, unsigned long end);
void free_initmem(void);
extern char *klimit;
extern unsigned long kernel_tlb;
extern void ret_from_fork(void);
extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
......@@ -80,7 +80,7 @@ extern unsigned long search_exception_table(unsigned long);
static inline int ___range_ok(unsigned long addr, unsigned long size)
return ((addr < memory_start) ||
((addr + size) > memory_end));
((addr + size - 1) > (memory_start + memory_size - 1)));
#define __range_ok(addr, size) \
......@@ -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},
......@@ -171,10 +171,24 @@ void __init remap_early_printk(void)
if (!early_console_initialized || !early_console)
printk(KERN_INFO "early_printk_console remaping from 0x%x to ",
printk(KERN_INFO "early_printk_console remapping from 0x%x to ",
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)
......@@ -63,9 +63,7 @@ ENTRY(_start)
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:
or r11, r0, r0 /* incremment */
ori r4, r0, TOPHYS(_fdt_start)
ori r3, r0, (0x4000 - 4)
ori r3, r0, (0x8000 - 4)
lw r12, r7, r11 /* r12 = r7 + r11 */
sw r12, r4, r11 /* addr[r4 + r11] = r12 */
......@@ -150,6 +149,7 @@ _copy_bram:
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 */
/* 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 */
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 */
* 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
/* 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
andi r3,r3,0xfffffc00 /* Mask off the effective page number */
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
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)
* 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 */
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
#ifndef CONFIG_MMU
......@@ -268,8 +368,7 @@ start_here:
/* Load up the kernel context */
# Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
ori r5,r0,3
mts rtlbx,r5
mts rtlbhi,r0
......@@ -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
.long 1 /* MS: storing last used tlb index */
/* MS: storing last used tlb index */
/* 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