Merge branch 'next' of git://git.monstr.eu/linux-2.6-microblaze
Pull arch/microblaze fixes from Michal Simek * 'next' of git://git.monstr.eu/linux-2.6-microblaze: 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
This commit is contained in:
commit
30eebb54b1
23 changed files with 711 additions and 96 deletions
|
@ -1,6 +1,7 @@
|
||||||
config MICROBLAZE
|
config MICROBLAZE
|
||||||
def_bool y
|
def_bool y
|
||||||
select HAVE_MEMBLOCK
|
select HAVE_MEMBLOCK
|
||||||
|
select HAVE_MEMBLOCK_NODE_MAP
|
||||||
select HAVE_FUNCTION_TRACER
|
select HAVE_FUNCTION_TRACER
|
||||||
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
|
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
|
||||||
select HAVE_FUNCTION_GRAPH_TRACER
|
select HAVE_FUNCTION_GRAPH_TRACER
|
||||||
|
@ -28,6 +29,12 @@ config SWAP
|
||||||
config RWSEM_GENERIC_SPINLOCK
|
config RWSEM_GENERIC_SPINLOCK
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
config ZONE_DMA
|
||||||
|
def_bool y
|
||||||
|
|
||||||
|
config ARCH_POPULATES_NODE_MAP
|
||||||
|
def_bool y
|
||||||
|
|
||||||
config RWSEM_XCHGADD_ALGORITHM
|
config RWSEM_XCHGADD_ALGORITHM
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
@ -153,20 +160,18 @@ config XILINX_UNCACHED_SHADOW
|
||||||
The feature requires the design to define the RAM memory controller
|
The feature requires the design to define the RAM memory controller
|
||||||
window to be twice as large as the actual physical memory.
|
window to be twice as large as the actual physical memory.
|
||||||
|
|
||||||
config HIGHMEM_START_BOOL
|
config HIGHMEM
|
||||||
bool "Set high memory pool address"
|
bool "High memory support"
|
||||||
depends on ADVANCED_OPTIONS && HIGHMEM
|
|
||||||
help
|
|
||||||
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.
|
|
||||||
|
|
||||||
Say N here unless you know what you are doing.
|
|
||||||
|
|
||||||
config HIGHMEM_START
|
|
||||||
hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
|
|
||||||
depends on MMU
|
depends on MMU
|
||||||
default "0xfe000000"
|
help
|
||||||
|
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".
|
||||||
|
|
||||||
|
If unsure, say n.
|
||||||
|
|
||||||
config LOWMEM_SIZE_BOOL
|
config LOWMEM_SIZE_BOOL
|
||||||
bool "Set maximum low memory"
|
bool "Set maximum low memory"
|
||||||
|
@ -255,6 +260,10 @@ config MICROBLAZE_32K_PAGES
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
config KERNEL_PAD
|
||||||
|
hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
|
||||||
|
default "0x80000" if MMU
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
source "mm/Kconfig"
|
source "mm/Kconfig"
|
||||||
|
|
|
@ -8,7 +8,7 @@ obj-y += linked_dtb.o
|
||||||
|
|
||||||
targets := linux.bin linux.bin.gz simpleImage.%
|
targets := linux.bin linux.bin.gz simpleImage.%
|
||||||
|
|
||||||
OBJCOPYFLAGS := -O binary
|
OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary
|
||||||
|
|
||||||
# Ensure system.dtb exists
|
# Ensure system.dtb exists
|
||||||
$(obj)/linked_dtb.o: $(obj)/system.dtb
|
$(obj)/linked_dtb.o: $(obj)/system.dtb
|
||||||
|
|
109
arch/microblaze/include/asm/fixmap.h
Normal file
109
arch/microblaze/include/asm/fixmap.h
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* 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 <monstr@monstr.eu>
|
||||||
|
* 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>
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
#include <linux/threads.h>
|
||||||
|
#include <asm/kmap_types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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_HOLE,
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
|
||||||
|
FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1,
|
||||||
|
#endif
|
||||||
|
__end_of_fixed_addresses
|
||||||
|
};
|
||||||
|
|
||||||
|
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 FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
|
||||||
|
|
||||||
|
#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)
|
||||||
|
__this_fixmap_does_not_exist();
|
||||||
|
|
||||||
|
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__ */
|
||||||
|
#endif
|
96
arch/microblaze/include/asm/highmem.h
Normal file
96
arch/microblaze/include/asm/highmem.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* Gerhard.Wichert@pdb.siemens.de
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 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 <mingo@redhat.com>
|
||||||
|
*/
|
||||||
|
#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_ORDER PTE_SHIFT
|
||||||
|
#define LAST_PKMAP (1 << PKMAP_ORDER)
|
||||||
|
|
||||||
|
#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
|
||||||
|
& PMD_MASK)
|
||||||
|
|
||||||
|
#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
if (!PageHighMem(page))
|
||||||
|
return page_address(page);
|
||||||
|
return kmap_high(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void kunmap(struct page *page)
|
||||||
|
{
|
||||||
|
BUG_ON(in_interrupt());
|
||||||
|
if (!PageHighMem(page))
|
||||||
|
return;
|
||||||
|
kunmap_high(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 _tlbie(unsigned long va); /* invalidate a TLB entry */
|
||||||
extern void _tlbia(void); /* invalidate all TLB entries */
|
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__ */
|
# endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -69,6 +75,12 @@ extern void _tlbia(void); /* invalidate all TLB entries */
|
||||||
|
|
||||||
# define MICROBLAZE_TLB_SIZE 64
|
# define MICROBLAZE_TLB_SIZE 64
|
||||||
|
|
||||||
|
/* For cases when you want to skip some TLB entries */
|
||||||
|
# define MICROBLAZE_TLB_SKIP 0
|
||||||
|
|
||||||
|
/* Use the last TLB for temporary access to LMB */
|
||||||
|
# define MICROBLAZE_LMB_TLB_ID 63
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TLB entries are defined by a "high" tag portion and a "low" data
|
* TLB entries are defined by a "high" tag portion and a "low" data
|
||||||
* portion. The data portion is 32-bits.
|
* 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 max_pfn;
|
||||||
|
|
||||||
extern unsigned long memory_start;
|
extern unsigned long memory_start;
|
||||||
extern unsigned long memory_end;
|
|
||||||
extern unsigned long memory_size;
|
extern unsigned long memory_size;
|
||||||
|
extern unsigned long lowmem_size;
|
||||||
|
|
||||||
extern int page_is_ram(unsigned long pfn);
|
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. */
|
/* Start and end of the vmalloc area. */
|
||||||
/* Make sure to map the vmalloc area above the pinned kernel memory area
|
/* Make sure to map the vmalloc area above the pinned kernel memory area
|
||||||
of 32Mb. */
|
of 32Mb. */
|
||||||
#define VMALLOC_START (CONFIG_KERNEL_START + \
|
#define VMALLOC_START (CONFIG_KERNEL_START + CONFIG_LOWMEM_SIZE)
|
||||||
max(32 * 1024 * 1024UL, memory_size))
|
|
||||||
#define VMALLOC_END ioremap_bot
|
#define VMALLOC_END ioremap_bot
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
|
@ -39,7 +39,8 @@ extern void of_platform_reset_gpio_probe(void);
|
||||||
void time_init(void);
|
void time_init(void);
|
||||||
void init_IRQ(void);
|
void init_IRQ(void);
|
||||||
void machine_early_init(const char *cmdline, unsigned int ram,
|
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_restart(char *cmd);
|
||||||
void machine_shutdown(void);
|
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_init_pages(char *what, unsigned long begin, unsigned long end);
|
||||||
void free_initmem(void);
|
void free_initmem(void);
|
||||||
extern char *klimit;
|
extern char *klimit;
|
||||||
|
extern unsigned long kernel_tlb;
|
||||||
extern void ret_from_fork(void);
|
extern void ret_from_fork(void);
|
||||||
|
|
||||||
extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
|
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)
|
static inline int ___range_ok(unsigned long addr, unsigned long size)
|
||||||
{
|
{
|
||||||
return ((addr < memory_start) ||
|
return ((addr < memory_start) ||
|
||||||
((addr + size) > memory_end));
|
((addr + size - 1) > (memory_start + memory_size - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __range_ok(addr, size) \
|
#define __range_ok(addr, size) \
|
||||||
|
|
|
@ -35,6 +35,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
|
||||||
{"8.00.b", 0x13},
|
{"8.00.b", 0x13},
|
||||||
{"8.10.a", 0x14},
|
{"8.10.a", 0x14},
|
||||||
{"8.20.a", 0x15},
|
{"8.20.a", 0x15},
|
||||||
|
{"8.20.b", 0x16},
|
||||||
|
{"8.30.a", 0x17},
|
||||||
{NULL, 0},
|
{NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -171,10 +171,24 @@ void __init remap_early_printk(void)
|
||||||
{
|
{
|
||||||
if (!early_console_initialized || !early_console)
|
if (!early_console_initialized || !early_console)
|
||||||
return;
|
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);
|
||||||
base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
|
base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
|
||||||
printk(KERN_CONT "0x%x\n", base_addr);
|
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)
|
void __init disable_early_printk(void)
|
||||||
|
|
|
@ -63,9 +63,7 @@ ENTRY(_start)
|
||||||
real_start:
|
real_start:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mfs r1, rmsr
|
mts rmsr, r0
|
||||||
andi r1, r1, ~2
|
|
||||||
mts rmsr, r1
|
|
||||||
/*
|
/*
|
||||||
* According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
|
* According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
|
||||||
* if the msrclr instruction is not enabled. We use this to detect
|
* 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 implemented
|
||||||
* r8 != 0 - msr instructions are not implemented
|
* r8 != 0 - msr instructions are not implemented
|
||||||
*/
|
*/
|
||||||
|
mfs r1, rmsr
|
||||||
msrclr r8, 0 /* clear nothing - just read msr for test */
|
msrclr r8, 0 /* clear nothing - just read msr for test */
|
||||||
cmpu r8, r8, r1 /* r1 must contain msr reg content */
|
cmpu r8, r8, r1 /* r1 must contain msr reg content */
|
||||||
|
|
||||||
|
@ -96,7 +95,7 @@ big_endian:
|
||||||
_prepare_copy_fdt:
|
_prepare_copy_fdt:
|
||||||
or r11, r0, r0 /* incremment */
|
or r11, r0, r0 /* incremment */
|
||||||
ori r4, r0, TOPHYS(_fdt_start)
|
ori r4, r0, TOPHYS(_fdt_start)
|
||||||
ori r3, r0, (0x4000 - 4)
|
ori r3, r0, (0x8000 - 4)
|
||||||
_copy_fdt:
|
_copy_fdt:
|
||||||
lw r12, r7, r11 /* r12 = r7 + r11 */
|
lw r12, r7, r11 /* r12 = r7 + r11 */
|
||||||
sw r12, r4, r11 /* addr[r4 + r11] = r12 */
|
sw r12, r4, r11 /* addr[r4 + r11] = r12 */
|
||||||
|
@ -150,6 +149,7 @@ _copy_bram:
|
||||||
_invalidate:
|
_invalidate:
|
||||||
mts rtlbx, r3
|
mts rtlbx, r3
|
||||||
mts rtlbhi, r0 /* flush: ensure V is clear */
|
mts rtlbhi, r0 /* flush: ensure V is clear */
|
||||||
|
mts rtlblo, r0
|
||||||
bgtid r3, _invalidate /* loop for all entries */
|
bgtid r3, _invalidate /* loop for all entries */
|
||||||
addik r3, r3, -1
|
addik r3, r3, -1
|
||||||
/* sync */
|
/* sync */
|
||||||
|
@ -169,6 +169,53 @@ _invalidate:
|
||||||
addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
|
addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
|
||||||
tophys(r4,r3) /* Load the kernel physical 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.
|
* Configure and load two entries into TLB slots 0 and 1.
|
||||||
* In case we are pinning TLBs, these are reserved in by the
|
* 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 */
|
andi r4,r4,0xfffffc00 /* Mask off the real page number */
|
||||||
ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
|
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 */
|
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 rtlblo,r4 /* Load the data portion of the entry */
|
||||||
mts rtlbhi,r3 /* Load the tag portion of the entry */
|
mts rtlbhi,r3 /* Load the tag portion of the entry */
|
||||||
|
|
||||||
addik r4, r4, 0x01000000 /* Map next 16 M entries */
|
/* Increase tlb_skip size */
|
||||||
addik r3, r3, 0x01000000
|
addik r11, r11, 1
|
||||||
|
swi r11, r0, TOPHYS(tlb_skip)
|
||||||
|
|
||||||
ori r6,r0,1 /* TLB slot 1 */
|
/* TLB1 can be zeroes that's why we not setup it */
|
||||||
mts rtlbx,r6
|
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
|
||||||
|
|
||||||
|
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 rtlblo,r4 /* Load the data portion of the entry */
|
||||||
mts rtlbhi,r3 /* Load the tag 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
|
* Load a TLB entry for LMB, since we need access to
|
||||||
* the exception vectors, using a 4k real==virtual mapping.
|
* 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
|
mts rtlbx,r6
|
||||||
|
|
||||||
ori r4,r0,(TLB_WR | TLB_EX)
|
ori r4,r0,(TLB_WR | TLB_EX)
|
||||||
|
@ -238,8 +338,8 @@ start_here:
|
||||||
* Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
|
* Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
|
||||||
* the function.
|
* the function.
|
||||||
*/
|
*/
|
||||||
addik r9, r0, machine_early_init
|
addik r11, r0, machine_early_init
|
||||||
brald r15, r9
|
brald r15, r11
|
||||||
nop
|
nop
|
||||||
|
|
||||||
#ifndef CONFIG_MMU
|
#ifndef CONFIG_MMU
|
||||||
|
@ -268,8 +368,7 @@ start_here:
|
||||||
|
|
||||||
/* Load up the kernel context */
|
/* Load up the kernel context */
|
||||||
kernel_load_context:
|
kernel_load_context:
|
||||||
# Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
|
ori r5, r0, MICROBLAZE_LMB_TLB_ID
|
||||||
ori r5,r0,3
|
|
||||||
mts rtlbx,r5
|
mts rtlbx,r5
|
||||||
nop
|
nop
|
||||||
mts rtlbhi,r0
|
mts rtlbhi,r0
|
||||||
|
|
|
@ -820,19 +820,26 @@ ex_handler_done:
|
||||||
* Upon exit, we reload everything and RFI.
|
* Upon exit, we reload everything and RFI.
|
||||||
* A common place to load the TLB.
|
* A common place to load the TLB.
|
||||||
*/
|
*/
|
||||||
|
.section .data
|
||||||
|
.align 4
|
||||||
|
.global tlb_skip
|
||||||
|
tlb_skip:
|
||||||
|
.long MICROBLAZE_TLB_SKIP
|
||||||
tlb_index:
|
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:
|
finish_tlb_load:
|
||||||
/* MS: load the last used TLB index. */
|
/* MS: load the last used TLB index. */
|
||||||
lwi r5, r0, TOPHYS(tlb_index)
|
lwi r5, r0, TOPHYS(tlb_index)
|
||||||
addik r5, r5, 1 /* MS: inc tlb_index -> use next one */
|
addik r5, r5, 1 /* MS: inc tlb_index -> use next one */
|
||||||
|
|
||||||
/* MS: FIXME this is potential fault, because this is mask not count */
|
/* 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
|
ori r6, r0, 1
|
||||||
cmp r31, r5, r6
|
cmp r31, r5, r6
|
||||||
blti r31, ex12
|
blti r31, ex12
|
||||||
addik r5, r6, 1
|
lwi r5, r0, TOPHYS(tlb_skip)
|
||||||
ex12:
|
ex12:
|
||||||
/* MS: save back current TLB index */
|
/* MS: save back current TLB index */
|
||||||
swi r5, r0, TOPHYS(tlb_index)
|
swi r5, r0, TOPHYS(tlb_index)
|
||||||
|
|
|
@ -151,8 +151,8 @@ void __init init_IRQ(void)
|
||||||
#ifdef CONFIG_SELFMOD_INTC
|
#ifdef CONFIG_SELFMOD_INTC
|
||||||
selfmod_function((int *) arr_func, intc_baseaddr);
|
selfmod_function((int *) arr_func, intc_baseaddr);
|
||||||
#endif
|
#endif
|
||||||
printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
|
printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
|
||||||
intc_baseaddr, nr_irq, intr_mask);
|
intc->name, intc_baseaddr, nr_irq, intr_mask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable all external interrupts until they are
|
* Disable all external interrupts until they are
|
||||||
|
|
|
@ -29,16 +29,16 @@
|
||||||
.type _tlbia, @function
|
.type _tlbia, @function
|
||||||
.align 4;
|
.align 4;
|
||||||
_tlbia:
|
_tlbia:
|
||||||
addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */
|
lwi r12, r0, tlb_skip;
|
||||||
/* isync */
|
/* isync */
|
||||||
_tlbia_1:
|
_tlbia_1:
|
||||||
mts rtlbx, r12
|
mts rtlbx, r12
|
||||||
nop
|
nop
|
||||||
mts rtlbhi, r0 /* flush: ensure V is clear */
|
mts rtlbhi, r0 /* flush: ensure V is clear */
|
||||||
nop
|
nop
|
||||||
addik r11, r12, -2
|
rsubi r11, r12, MICROBLAZE_TLB_SIZE - 1
|
||||||
bneid r11, _tlbia_1 /* loop for all entries */
|
bneid r11, _tlbia_1 /* loop for all entries */
|
||||||
addik r12, r12, -1
|
addik r12, r12, 1
|
||||||
/* sync */
|
/* sync */
|
||||||
rtsd r15, 8
|
rtsd r15, 8
|
||||||
nop
|
nop
|
||||||
|
@ -75,7 +75,7 @@ early_console_reg_tlb_alloc:
|
||||||
* Load a TLB entry for the UART, so that microblaze_progress() can use
|
* 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.
|
* 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 */
|
mts rtlbx, r4 /* TLB slot 63 */
|
||||||
|
|
||||||
or r4,r5,r0
|
or r4,r5,r0
|
||||||
|
@ -89,6 +89,11 @@ early_console_reg_tlb_alloc:
|
||||||
nop
|
nop
|
||||||
mts rtlbhi,r5 /* Load the tag portion of the entry */
|
mts rtlbhi,r5 /* Load the tag portion of the entry */
|
||||||
nop
|
nop
|
||||||
|
|
||||||
|
lwi r5, r0, tlb_skip
|
||||||
|
addik r5, r5, 1
|
||||||
|
swi r5, r0, tlb_skip
|
||||||
|
|
||||||
rtsd r15, 8
|
rtsd r15, 8
|
||||||
nop
|
nop
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,11 @@ inline unsigned get_romfs_len(unsigned *addr)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MTD_UCLINUX_EBSS */
|
#endif /* CONFIG_MTD_UCLINUX_EBSS */
|
||||||
|
|
||||||
|
unsigned long kernel_tlb;
|
||||||
|
|
||||||
void __init machine_early_init(const char *cmdline, unsigned int ram,
|
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 long *src, *dst;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
|
@ -143,6 +146,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
|
||||||
setup_early_printk(NULL);
|
setup_early_printk(NULL);
|
||||||
#endif
|
#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);
|
printk("Ramdisk addr 0x%08x, ", ram);
|
||||||
if (fdt)
|
if (fdt)
|
||||||
printk("FDT at 0x%08x\n", fdt);
|
printk("FDT at 0x%08x\n", fdt);
|
||||||
|
@ -197,6 +206,19 @@ static int microblaze_debugfs_init(void)
|
||||||
return of_debugfs_root == NULL;
|
return of_debugfs_root == NULL;
|
||||||
}
|
}
|
||||||
arch_initcall(microblaze_debugfs_init);
|
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
|
#endif
|
||||||
|
|
||||||
static int dflt_bus_notify(struct notifier_block *nb,
|
static int dflt_bus_notify(struct notifier_block *nb,
|
||||||
|
|
|
@ -79,7 +79,7 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)
|
||||||
* !PWMA - disable pwm
|
* !PWMA - disable pwm
|
||||||
* TINT - clear interrupt status
|
* TINT - clear interrupt status
|
||||||
* ENT- enable timer itself
|
* ENT- enable timer itself
|
||||||
* EINT - enable interrupt
|
* ENIT - enable interrupt
|
||||||
* !LOAD - clear the bit to let go
|
* !LOAD - clear the bit to let go
|
||||||
* ARHT - auto reload
|
* ARHT - auto reload
|
||||||
* !CAPT - no external trigger
|
* !CAPT - no external trigger
|
||||||
|
@ -274,8 +274,8 @@ void __init time_init(void)
|
||||||
#ifdef CONFIG_SELFMOD_TIMER
|
#ifdef CONFIG_SELFMOD_TIMER
|
||||||
selfmod_function((int *) arr_func, timer_baseaddr);
|
selfmod_function((int *) arr_func, timer_baseaddr);
|
||||||
#endif
|
#endif
|
||||||
printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n",
|
printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
|
||||||
timer_baseaddr, irq);
|
timer->name, timer_baseaddr, irq);
|
||||||
|
|
||||||
/* If there is clock-frequency property than use it */
|
/* If there is clock-frequency property than use it */
|
||||||
prop = of_get_property(timer, "clock-frequency", NULL);
|
prop = of_get_property(timer, "clock-frequency", NULL);
|
||||||
|
|
|
@ -44,7 +44,7 @@ SECTIONS {
|
||||||
__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
|
__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
|
||||||
_fdt_start = . ; /* place for fdt blob */
|
_fdt_start = . ; /* place for fdt blob */
|
||||||
*(__fdt_blob) ; /* Any link-placed DTB */
|
*(__fdt_blob) ; /* Any link-placed DTB */
|
||||||
. = _fdt_start + 0x4000; /* Pad up to 16kbyte */
|
. = _fdt_start + 0x8000; /* Pad up to 32kbyte */
|
||||||
_fdt_end = . ;
|
_fdt_end = . ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
obj-y := consistent.o init.o
|
obj-y := consistent.o init.o
|
||||||
|
|
||||||
obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
|
obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
|
||||||
|
obj-$(CONFIG_HIGHMEM) += highmem.o
|
||||||
|
|
88
arch/microblaze/mm/highmem.c
Normal file
88
arch/microblaze/mm/highmem.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* highmem.c: virtual kernel memory mappings for high memory
|
||||||
|
*
|
||||||
|
* PowerPC version, stolen from the i386 version.
|
||||||
|
*
|
||||||
|
* Used in CONFIG_HIGHMEM systems for memory pages which
|
||||||
|
* are not addressable by direct kernel virtual addresses.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Gerhard Wichert, Siemens AG
|
||||||
|
* Gerhard.Wichert@pdb.siemens.de
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Redesigned the x86 32-bit VM architecture to deal with
|
||||||
|
* up to 16 Terrabyte physical memory. With current x86 CPUs
|
||||||
|
* we now support up to 64 Gigabytes physical RAM.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
|
||||||
|
*
|
||||||
|
* Reworked for PowerPC by various contributors. Moved from
|
||||||
|
* highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
|
||||||
|
* gives a more generic (and caching) interface. But kmap_atomic can
|
||||||
|
* be used in IRQ contexts, so in some (very limited) cases we need
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
#include <asm/tlbflush.h>
|
||||||
|
|
||||||
|
void *kmap_atomic_prot(struct page *page, pgprot_t prot)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned long vaddr;
|
||||||
|
int idx, type;
|
||||||
|
|
||||||
|
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
|
||||||
|
pagefault_disable();
|
||||||
|
if (!PageHighMem(page))
|
||||||
|
return page_address(page);
|
||||||
|
|
||||||
|
|
||||||
|
type = kmap_atomic_idx_push();
|
||||||
|
idx = type + KM_TYPE_NR*smp_processor_id();
|
||||||
|
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
|
||||||
|
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||||
|
BUG_ON(!pte_none(*(kmap_pte-idx)));
|
||||||
|
#endif
|
||||||
|
set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
|
||||||
|
local_flush_tlb_page(NULL, vaddr);
|
||||||
|
|
||||||
|
return (void *) vaddr;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(kmap_atomic_prot);
|
||||||
|
|
||||||
|
void __kunmap_atomic(void *kvaddr)
|
||||||
|
{
|
||||||
|
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
|
||||||
|
pagefault_enable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = kmap_atomic_idx();
|
||||||
|
#ifdef CONFIG_DEBUG_HIGHMEM
|
||||||
|
{
|
||||||
|
unsigned int idx;
|
||||||
|
|
||||||
|
idx = type + KM_TYPE_NR * smp_processor_id();
|
||||||
|
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* force other mappings to Oops if they'll try to access
|
||||||
|
* this pte without first remap it
|
||||||
|
*/
|
||||||
|
pte_clear(&init_mm, vaddr, kmap_pte-idx);
|
||||||
|
local_flush_tlb_page(NULL, vaddr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
kmap_atomic_idx_pop();
|
||||||
|
pagefault_enable();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(__kunmap_atomic);
|
|
@ -24,6 +24,7 @@
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
#include <asm/tlb.h>
|
#include <asm/tlb.h>
|
||||||
|
#include <asm/fixmap.h>
|
||||||
|
|
||||||
/* Use for MMU and noMMU because of PCI generic code */
|
/* Use for MMU and noMMU because of PCI generic code */
|
||||||
int mem_init_done;
|
int mem_init_done;
|
||||||
|
@ -44,9 +45,56 @@ char *klimit = _end;
|
||||||
*/
|
*/
|
||||||
unsigned long memory_start;
|
unsigned long memory_start;
|
||||||
EXPORT_SYMBOL(memory_start);
|
EXPORT_SYMBOL(memory_start);
|
||||||
unsigned long memory_end; /* due to mm/nommu.c */
|
|
||||||
unsigned long memory_size;
|
unsigned long memory_size;
|
||||||
EXPORT_SYMBOL(memory_size);
|
EXPORT_SYMBOL(memory_size);
|
||||||
|
unsigned long lowmem_size;
|
||||||
|
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
pte_t *kmap_pte;
|
||||||
|
EXPORT_SYMBOL(kmap_pte);
|
||||||
|
pgprot_t kmap_prot;
|
||||||
|
EXPORT_SYMBOL(kmap_prot);
|
||||||
|
|
||||||
|
static inline pte_t *virt_to_kpte(unsigned long vaddr)
|
||||||
|
{
|
||||||
|
return pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr),
|
||||||
|
vaddr), vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init highmem_init(void)
|
||||||
|
{
|
||||||
|
pr_debug("%x\n", (u32)PKMAP_BASE);
|
||||||
|
map_page(PKMAP_BASE, 0, 0); /* XXX gross */
|
||||||
|
pkmap_page_table = virt_to_kpte(PKMAP_BASE);
|
||||||
|
|
||||||
|
kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
|
||||||
|
kmap_prot = PAGE_KERNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long highmem_setup(void)
|
||||||
|
{
|
||||||
|
unsigned long pfn;
|
||||||
|
unsigned long reservedpages = 0;
|
||||||
|
|
||||||
|
for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
|
||||||
|
struct page *page = pfn_to_page(pfn);
|
||||||
|
|
||||||
|
/* FIXME not sure about */
|
||||||
|
if (memblock_is_reserved(pfn << PAGE_SHIFT))
|
||||||
|
continue;
|
||||||
|
ClearPageReserved(page);
|
||||||
|
init_page_count(page);
|
||||||
|
__free_page(page);
|
||||||
|
totalhigh_pages++;
|
||||||
|
reservedpages++;
|
||||||
|
}
|
||||||
|
totalram_pages += totalhigh_pages;
|
||||||
|
printk(KERN_INFO "High memory: %luk\n",
|
||||||
|
totalhigh_pages << (PAGE_SHIFT-10));
|
||||||
|
|
||||||
|
return reservedpages;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HIGHMEM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* paging_init() sets up the page tables - in fact we've already done this.
|
* paging_init() sets up the page tables - in fact we've already done this.
|
||||||
|
@ -54,17 +102,28 @@ EXPORT_SYMBOL(memory_size);
|
||||||
static void __init paging_init(void)
|
static void __init paging_init(void)
|
||||||
{
|
{
|
||||||
unsigned long zones_size[MAX_NR_ZONES];
|
unsigned long zones_size[MAX_NR_ZONES];
|
||||||
|
#ifdef CONFIG_MMU
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
/* Setup fixmaps */
|
||||||
|
for (idx = 0; idx < __end_of_fixed_addresses; idx++)
|
||||||
|
clear_fixmap(idx);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Clean every zones */
|
/* Clean every zones */
|
||||||
memset(zones_size, 0, sizeof(zones_size));
|
memset(zones_size, 0, sizeof(zones_size));
|
||||||
|
|
||||||
/*
|
#ifdef CONFIG_HIGHMEM
|
||||||
* old: we can DMA to/from any address.put all page into ZONE_DMA
|
highmem_init();
|
||||||
* We use only ZONE_NORMAL
|
|
||||||
*/
|
|
||||||
zones_size[ZONE_NORMAL] = max_mapnr;
|
|
||||||
|
|
||||||
free_area_init(zones_size);
|
zones_size[ZONE_DMA] = max_low_pfn;
|
||||||
|
zones_size[ZONE_HIGHMEM] = max_pfn;
|
||||||
|
#else
|
||||||
|
zones_size[ZONE_DMA] = max_pfn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* We don't have holes in memory map */
|
||||||
|
free_area_init_nodes(zones_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __init setup_memory(void)
|
void __init setup_memory(void)
|
||||||
|
@ -78,32 +137,31 @@ void __init setup_memory(void)
|
||||||
/* Find main memory where is the kernel */
|
/* Find main memory where is the kernel */
|
||||||
for_each_memblock(memory, reg) {
|
for_each_memblock(memory, reg) {
|
||||||
memory_start = (u32)reg->base;
|
memory_start = (u32)reg->base;
|
||||||
memory_end = (u32) reg->base + reg->size;
|
lowmem_size = reg->size;
|
||||||
if ((memory_start <= (u32)_text) &&
|
if ((memory_start <= (u32)_text) &&
|
||||||
((u32)_text <= memory_end)) {
|
((u32)_text <= (memory_start + lowmem_size - 1))) {
|
||||||
memory_size = memory_end - memory_start;
|
memory_size = lowmem_size;
|
||||||
PAGE_OFFSET = memory_start;
|
PAGE_OFFSET = memory_start;
|
||||||
printk(KERN_INFO "%s: Main mem: 0x%x-0x%x, "
|
printk(KERN_INFO "%s: Main mem: 0x%x, "
|
||||||
"size 0x%08x\n", __func__, (u32) memory_start,
|
"size 0x%08x\n", __func__, (u32) memory_start,
|
||||||
(u32) memory_end, (u32) memory_size);
|
(u32) memory_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!memory_start || !memory_end) {
|
if (!memory_start || !memory_size) {
|
||||||
panic("%s: Missing memory setting 0x%08x-0x%08x\n",
|
panic("%s: Missing memory setting 0x%08x, size=0x%08x\n",
|
||||||
__func__, (u32) memory_start, (u32) memory_end);
|
__func__, (u32) memory_start, (u32) memory_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reservation of region where is the kernel */
|
/* reservation of region where is the kernel */
|
||||||
kernel_align_start = PAGE_DOWN((u32)_text);
|
kernel_align_start = PAGE_DOWN((u32)_text);
|
||||||
/* ALIGN can be remove because _end in vmlinux.lds.S is align */
|
/* ALIGN can be remove because _end in vmlinux.lds.S is align */
|
||||||
kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start;
|
kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start;
|
||||||
memblock_reserve(kernel_align_start, kernel_align_size);
|
printk(KERN_INFO "%s: kernel addr:0x%08x-0x%08x size=0x%08x\n",
|
||||||
printk(KERN_INFO "%s: kernel addr=0x%08x-0x%08x size=0x%08x\n",
|
|
||||||
__func__, kernel_align_start, kernel_align_start
|
__func__, kernel_align_start, kernel_align_start
|
||||||
+ kernel_align_size, kernel_align_size);
|
+ kernel_align_size, kernel_align_size);
|
||||||
|
memblock_reserve(kernel_align_start, kernel_align_size);
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* Kernel:
|
* Kernel:
|
||||||
|
@ -120,11 +178,13 @@ void __init setup_memory(void)
|
||||||
min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
|
min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
|
||||||
/* RAM is assumed contiguous */
|
/* RAM is assumed contiguous */
|
||||||
num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
|
num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
|
||||||
max_pfn = max_low_pfn = memory_end >> PAGE_SHIFT;
|
max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
|
||||||
|
max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
|
||||||
|
|
||||||
printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr);
|
printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr);
|
||||||
printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn);
|
printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn);
|
||||||
printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
|
printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
|
||||||
|
printk(KERN_INFO "%s: max_pfn: %#lx\n", __func__, max_pfn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find an area to use for the bootmem bitmap.
|
* Find an area to use for the bootmem bitmap.
|
||||||
|
@ -137,15 +197,39 @@ void __init setup_memory(void)
|
||||||
PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
|
PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
|
||||||
memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
|
memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
|
||||||
|
|
||||||
|
/* Add active regions with valid PFNs */
|
||||||
|
for_each_memblock(memory, reg) {
|
||||||
|
unsigned long start_pfn, end_pfn;
|
||||||
|
|
||||||
|
start_pfn = memblock_region_memory_base_pfn(reg);
|
||||||
|
end_pfn = memblock_region_memory_end_pfn(reg);
|
||||||
|
memblock_set_node(start_pfn << PAGE_SHIFT,
|
||||||
|
(end_pfn - start_pfn) << PAGE_SHIFT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* free bootmem is whole main memory */
|
/* free bootmem is whole main memory */
|
||||||
free_bootmem(memory_start, memory_size);
|
free_bootmem_with_active_regions(0, max_low_pfn);
|
||||||
|
|
||||||
/* reserve allocate blocks */
|
/* reserve allocate blocks */
|
||||||
for_each_memblock(reserved, reg) {
|
for_each_memblock(reserved, reg) {
|
||||||
pr_debug("reserved - 0x%08x-0x%08x\n",
|
unsigned long top = reg->base + reg->size - 1;
|
||||||
(u32) reg->base, (u32) reg->size);
|
|
||||||
reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
|
pr_debug("reserved - 0x%08x-0x%08x, %lx, %lx\n",
|
||||||
|
(u32) reg->base, (u32) reg->size, top,
|
||||||
|
memory_start + lowmem_size - 1);
|
||||||
|
|
||||||
|
if (top <= (memory_start + lowmem_size - 1)) {
|
||||||
|
reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
|
||||||
|
} else if (reg->base < (memory_start + lowmem_size - 1)) {
|
||||||
|
unsigned long trunc_size = memory_start + lowmem_size -
|
||||||
|
reg->base;
|
||||||
|
reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX need to clip this if using highmem? */
|
||||||
|
sparse_memory_present_with_active_regions(0);
|
||||||
|
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
init_bootmem_done = 1;
|
init_bootmem_done = 1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -190,13 +274,58 @@ void free_initmem(void)
|
||||||
|
|
||||||
void __init mem_init(void)
|
void __init mem_init(void)
|
||||||
{
|
{
|
||||||
high_memory = (void *)__va(memory_end);
|
pg_data_t *pgdat;
|
||||||
|
unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
|
||||||
|
|
||||||
|
high_memory = (void *)__va(memory_start + lowmem_size - 1);
|
||||||
|
|
||||||
/* this will put all memory onto the freelists */
|
/* this will put all memory onto the freelists */
|
||||||
totalram_pages += free_all_bootmem();
|
totalram_pages += free_all_bootmem();
|
||||||
|
|
||||||
printk(KERN_INFO "Memory: %luk/%luk available\n",
|
for_each_online_pgdat(pgdat) {
|
||||||
nr_free_pages() << (PAGE_SHIFT-10),
|
unsigned long i;
|
||||||
num_physpages << (PAGE_SHIFT-10));
|
struct page *page;
|
||||||
|
|
||||||
|
for (i = 0; i < pgdat->node_spanned_pages; i++) {
|
||||||
|
if (!pfn_valid(pgdat->node_start_pfn + i))
|
||||||
|
continue;
|
||||||
|
page = pgdat_page_nr(pgdat, i);
|
||||||
|
if (PageReserved(page))
|
||||||
|
reservedpages++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
reservedpages -= highmem_setup();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
|
||||||
|
datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
|
||||||
|
initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
|
||||||
|
bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
|
||||||
|
|
||||||
|
pr_info("Memory: %luk/%luk available (%luk kernel code, "
|
||||||
|
"%luk reserved, %luk data, %luk bss, %luk init)\n",
|
||||||
|
nr_free_pages() << (PAGE_SHIFT-10),
|
||||||
|
num_physpages << (PAGE_SHIFT-10),
|
||||||
|
codesize >> 10,
|
||||||
|
reservedpages << (PAGE_SHIFT-10),
|
||||||
|
datasize >> 10,
|
||||||
|
bsssize >> 10,
|
||||||
|
initsize >> 10);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MMU
|
||||||
|
pr_info("Kernel virtual memory layout:\n");
|
||||||
|
pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP);
|
||||||
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n",
|
||||||
|
PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
|
||||||
|
#endif /* CONFIG_HIGHMEM */
|
||||||
|
pr_info(" * 0x%08lx..0x%08lx : early ioremap\n",
|
||||||
|
ioremap_bot, ioremap_base);
|
||||||
|
pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n",
|
||||||
|
(unsigned long)VMALLOC_START, VMALLOC_END);
|
||||||
|
#endif
|
||||||
mem_init_done = 1;
|
mem_init_done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +355,6 @@ static void mm_cmdline_setup(void)
|
||||||
maxmem = memparse(p, &p);
|
maxmem = memparse(p, &p);
|
||||||
if (maxmem && memory_size > maxmem) {
|
if (maxmem && memory_size > maxmem) {
|
||||||
memory_size = maxmem;
|
memory_size = maxmem;
|
||||||
memory_end = memory_start + memory_size;
|
|
||||||
memblock.memory.regions[0].size = memory_size;
|
memblock.memory.regions[0].size = memory_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,15 +398,26 @@ asmlinkage void __init mmu_init(void)
|
||||||
machine_restart(NULL);
|
machine_restart(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((u32) memblock.memory.regions[0].size < 0x1000000) {
|
if ((u32) memblock.memory.regions[0].size < 0x400000) {
|
||||||
printk(KERN_EMERG "Memory must be greater than 16MB\n");
|
printk(KERN_EMERG "Memory must be greater than 4MB\n");
|
||||||
machine_restart(NULL);
|
machine_restart(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((u32) memblock.memory.regions[0].size < kernel_tlb) {
|
||||||
|
printk(KERN_EMERG "Kernel size is greater than memory node\n");
|
||||||
|
machine_restart(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Find main memory where the kernel is */
|
/* Find main memory where the kernel is */
|
||||||
memory_start = (u32) memblock.memory.regions[0].base;
|
memory_start = (u32) memblock.memory.regions[0].base;
|
||||||
memory_end = (u32) memblock.memory.regions[0].base +
|
lowmem_size = memory_size = (u32) memblock.memory.regions[0].size;
|
||||||
(u32) memblock.memory.regions[0].size;
|
|
||||||
memory_size = memory_end - memory_start;
|
if (lowmem_size > CONFIG_LOWMEM_SIZE) {
|
||||||
|
lowmem_size = CONFIG_LOWMEM_SIZE;
|
||||||
|
#ifndef CONFIG_HIGHMEM
|
||||||
|
memory_size = lowmem_size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
mm_cmdline_setup(); /* FIXME parse args from command line - not used */
|
mm_cmdline_setup(); /* FIXME parse args from command line - not used */
|
||||||
|
|
||||||
|
@ -305,15 +444,20 @@ asmlinkage void __init mmu_init(void)
|
||||||
/* Map in all of RAM starting at CONFIG_KERNEL_START */
|
/* Map in all of RAM starting at CONFIG_KERNEL_START */
|
||||||
mapin_ram();
|
mapin_ram();
|
||||||
|
|
||||||
#ifdef CONFIG_HIGHMEM_START_BOOL
|
/* Extend vmalloc and ioremap area as big as possible */
|
||||||
ioremap_base = CONFIG_HIGHMEM_START;
|
#ifdef CONFIG_HIGHMEM
|
||||||
|
ioremap_base = ioremap_bot = PKMAP_BASE;
|
||||||
#else
|
#else
|
||||||
ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */
|
ioremap_base = ioremap_bot = FIXADDR_START;
|
||||||
#endif /* CONFIG_HIGHMEM_START_BOOL */
|
#endif
|
||||||
ioremap_bot = ioremap_base;
|
|
||||||
|
|
||||||
/* Initialize the context management stuff */
|
/* Initialize the context management stuff */
|
||||||
mmu_context_init();
|
mmu_context_init();
|
||||||
|
|
||||||
|
/* Shortly after that, the entire linear mapping will be available */
|
||||||
|
/* This will also cause that unflatten device tree will be allocated
|
||||||
|
* inside 768MB limit */
|
||||||
|
memblock_set_current_limit(memory_start + lowmem_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is only called until mem_init is done. */
|
/* This is only called until mem_init is done. */
|
||||||
|
@ -324,11 +468,11 @@ void __init *early_get_page(void)
|
||||||
p = alloc_bootmem_pages(PAGE_SIZE);
|
p = alloc_bootmem_pages(PAGE_SIZE);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Mem start + 32MB -> here is limit
|
* Mem start + kernel_tlb -> here is limit
|
||||||
* because of mem mapping from head.S
|
* because of mem mapping from head.S
|
||||||
*/
|
*/
|
||||||
p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
|
p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
|
||||||
memory_start + 0x2000000));
|
memory_start + kernel_tlb));
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <asm/mmu.h>
|
#include <asm/mmu.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
|
#include <asm/fixmap.h>
|
||||||
|
|
||||||
#define flush_HPTE(X, va, pg) _tlbie(va)
|
#define flush_HPTE(X, va, pg) _tlbie(va)
|
||||||
|
|
||||||
|
@ -44,11 +45,6 @@ unsigned long ioremap_base;
|
||||||
unsigned long ioremap_bot;
|
unsigned long ioremap_bot;
|
||||||
EXPORT_SYMBOL(ioremap_bot);
|
EXPORT_SYMBOL(ioremap_bot);
|
||||||
|
|
||||||
/* The maximum lowmem defaults to 768Mb, but this can be configured to
|
|
||||||
* another value.
|
|
||||||
*/
|
|
||||||
#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE
|
|
||||||
|
|
||||||
#ifndef CONFIG_SMP
|
#ifndef CONFIG_SMP
|
||||||
struct pgtable_cache_struct quicklists;
|
struct pgtable_cache_struct quicklists;
|
||||||
#endif
|
#endif
|
||||||
|
@ -80,7 +76,7 @@ static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
|
||||||
!(p >= virt_to_phys((unsigned long)&__bss_stop) &&
|
!(p >= virt_to_phys((unsigned long)&__bss_stop) &&
|
||||||
p < virt_to_phys((unsigned long)__bss_stop))) {
|
p < virt_to_phys((unsigned long)__bss_stop))) {
|
||||||
printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
|
printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
|
||||||
" is RAM lr %p\n", (unsigned long)p,
|
" is RAM lr %pf\n", (unsigned long)p,
|
||||||
__builtin_return_address(0));
|
__builtin_return_address(0));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +167,7 @@ void __init mapin_ram(void)
|
||||||
|
|
||||||
v = CONFIG_KERNEL_START;
|
v = CONFIG_KERNEL_START;
|
||||||
p = memory_start;
|
p = memory_start;
|
||||||
for (s = 0; s < memory_size; s += PAGE_SIZE) {
|
for (s = 0; s < lowmem_size; s += PAGE_SIZE) {
|
||||||
f = _PAGE_PRESENT | _PAGE_ACCESSED |
|
f = _PAGE_PRESENT | _PAGE_ACCESSED |
|
||||||
_PAGE_SHARED | _PAGE_HWEXEC;
|
_PAGE_SHARED | _PAGE_HWEXEC;
|
||||||
if ((char *) v < _stext || (char *) v >= _etext)
|
if ((char *) v < _stext || (char *) v >= _etext)
|
||||||
|
@ -254,3 +250,13 @@ __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
|
||||||
}
|
}
|
||||||
return pte;
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
|
||||||
|
{
|
||||||
|
unsigned long address = __fix_to_virt(idx);
|
||||||
|
|
||||||
|
if (idx >= __end_of_fixed_addresses)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
map_page(address, phys, pgprot_val(flags));
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue