2005-09-26 10:04:21 +04:00
/*
* PowerPC version
* Copyright ( C ) 1995 - 1996 Gary Thomas ( gdt @ linuxppc . org )
*
* Modifications by Paul Mackerras ( PowerMac ) ( paulus @ cs . anu . edu . au )
* and Cort Dougan ( PReP ) ( cort @ cs . nmt . edu )
* Copyright ( C ) 1996 Paul Mackerras
* PPC44x / 36 - bit changes by Matt Porter ( mporter @ mvista . com )
*
* Derived from " arch/i386/mm/init.c "
* Copyright ( C ) 1991 , 1992 , 1993 , 1994 Linus Torvalds
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/types.h>
# include <linux/mm.h>
# include <linux/stddef.h>
# include <linux/init.h>
# include <linux/bootmem.h>
# include <linux/highmem.h>
# include <linux/initrd.h>
# include <linux/pagemap.h>
2008-02-14 03:56:49 +03:00
# include <linux/lmb.h>
2005-09-26 10:04:21 +04:00
# include <asm/pgalloc.h>
# include <asm/prom.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/mmu.h>
# include <asm/smp.h>
# include <asm/machdep.h>
# include <asm/btext.h>
# include <asm/tlb.h>
2005-10-06 06:23:33 +04:00
# include <asm/sections.h>
2008-05-08 08:27:07 +04:00
# include <asm/system.h>
2005-09-26 10:04:21 +04:00
# include "mmu_decl.h"
# if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL)
2010-01-20 19:02:24 +03:00
/* The amount of lowmem must be within 0xF0000000 - KERNELBASE. */
2008-12-17 13:09:13 +03:00
# if (CONFIG_LOWMEM_SIZE > (0xF0000000 - PAGE_OFFSET))
2005-09-26 10:04:21 +04:00
# error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL"
# endif
# endif
# define MAX_LOW_MEM CONFIG_LOWMEM_SIZE
2008-07-09 19:09:23 +04:00
phys_addr_t total_memory ;
phys_addr_t total_lowmem ;
2005-09-26 10:04:21 +04:00
2008-04-21 22:22:34 +04:00
phys_addr_t memstart_addr = ( phys_addr_t ) ~ 0ull ;
EXPORT_SYMBOL ( memstart_addr ) ;
phys_addr_t kernstart_addr ;
EXPORT_SYMBOL ( kernstart_addr ) ;
2008-04-15 23:52:21 +04:00
phys_addr_t lowmem_end_addr ;
2005-09-26 10:04:21 +04:00
int boot_mapsize ;
# ifdef CONFIG_PPC_PMAC
unsigned long agp_special_page ;
2005-10-22 08:42:51 +04:00
EXPORT_SYMBOL ( agp_special_page ) ;
2005-09-26 10:04:21 +04:00
# endif
void MMU_init ( void ) ;
/* XXX should be in current.h -- paulus */
extern struct task_struct * current_set [ NR_CPUS ] ;
/*
* this tells the system to map all of ram with the segregs
* ( i . e . page tables ) instead of the bats .
* - - Cort
*/
int __map_without_bats ;
int __map_without_ltlbs ;
2009-12-12 09:31:54 +03:00
/*
* This tells the system to allow ioremapping memory marked as reserved .
*/
int __allow_ioremap_reserved ;
2005-09-26 10:04:21 +04:00
/* max amount of low RAM to map in */
unsigned long __max_low_memory = MAX_LOW_MEM ;
/*
2008-04-15 23:52:25 +04:00
* address of the limit of what is accessible with initial MMU setup -
2005-10-06 06:23:33 +04:00
* 256 MB usually , but only 16 MB on 601.
2005-09-26 10:04:21 +04:00
*/
2008-04-15 23:52:25 +04:00
phys_addr_t __initial_memory_limit_addr = ( phys_addr_t ) 0x10000000 ;
2005-09-26 10:04:21 +04:00
/*
* Check for command - line options that affect what MMU_init will do .
*/
void MMU_setup ( void )
{
/* Check for nobats option (used in mapin_ram). */
if ( strstr ( cmd_line , " nobats " ) ) {
__map_without_bats = 1 ;
}
if ( strstr ( cmd_line , " noltlbs " ) ) {
__map_without_ltlbs = 1 ;
}
2007-04-12 09:30:22 +04:00
# ifdef CONFIG_DEBUG_PAGEALLOC
__map_without_bats = 1 ;
__map_without_ltlbs = 1 ;
# endif
2005-09-26 10:04:21 +04:00
}
/*
* MMU_init sets up the basic memory mappings for the kernel ,
* including both RAM and possibly some I / O regions ,
* and sets up the page tables and the MMU hardware ready to go .
*/
void __init MMU_init ( void )
{
if ( ppc_md . progress )
ppc_md . progress ( " MMU:enter " , 0x111 ) ;
2005-10-06 06:23:33 +04:00
/* 601 can only access 16MB at the moment */
if ( PVR_VER ( mfspr ( SPRN_PVR ) ) = = 1 )
2008-04-15 23:52:25 +04:00
__initial_memory_limit_addr = 0x01000000 ;
2007-07-17 05:17:23 +04:00
/* 8xx can only access 8MB at the moment */
if ( PVR_VER ( mfspr ( SPRN_PVR ) ) = = 0x50 )
2008-04-15 23:52:25 +04:00
__initial_memory_limit_addr = 0x00800000 ;
2005-10-06 06:23:33 +04:00
2005-09-26 10:04:21 +04:00
/* parse args from command line */
MMU_setup ( ) ;
2005-10-06 06:23:33 +04:00
if ( lmb . memory . cnt > 1 ) {
2009-12-12 09:31:53 +03:00
# ifndef CONFIG_WII
2005-10-06 06:23:33 +04:00
lmb . memory . cnt = 1 ;
lmb_analyze ( ) ;
printk ( KERN_WARNING " Only using first contiguous memory region " ) ;
2009-12-12 09:31:53 +03:00
# else
wii_memory_fixups ( ) ;
# endif
2005-10-06 06:23:33 +04:00
}
2008-04-15 23:52:21 +04:00
total_lowmem = total_memory = lmb_end_of_DRAM ( ) - memstart_addr ;
2008-04-15 23:52:22 +04:00
lowmem_end_addr = memstart_addr + total_lowmem ;
2005-10-06 06:23:33 +04:00
2005-09-26 10:04:21 +04:00
# ifdef CONFIG_FSL_BOOKE
/* Freescale Book-E parts expect lowmem to be mapped by fixed TLB
* entries , so we need to adjust lowmem to match the amount we can map
* in the fixed entries */
adjust_total_lowmem ( ) ;
# endif /* CONFIG_FSL_BOOKE */
2005-10-26 15:54:21 +04:00
2005-09-26 10:04:21 +04:00
if ( total_lowmem > __max_low_memory ) {
total_lowmem = __max_low_memory ;
2008-04-15 23:52:22 +04:00
lowmem_end_addr = memstart_addr + total_lowmem ;
2005-09-26 10:04:21 +04:00
# ifndef CONFIG_HIGHMEM
total_memory = total_lowmem ;
2008-04-15 23:52:22 +04:00
lmb_enforce_memory_limit ( lowmem_end_addr ) ;
2005-10-26 15:54:21 +04:00
lmb_analyze ( ) ;
2005-09-26 10:04:21 +04:00
# endif /* CONFIG_HIGHMEM */
}
/* Initialize the MMU hardware */
if ( ppc_md . progress )
ppc_md . progress ( " MMU:hw init " , 0x300 ) ;
MMU_init_hw ( ) ;
/* Map in all of RAM starting at KERNELBASE */
if ( ppc_md . progress )
ppc_md . progress ( " MMU:mapin " , 0x301 ) ;
mapin_ram ( ) ;
2009-05-27 07:44:50 +04:00
/* Initialize early top-down ioremap allocator */
ioremap_bot = IOREMAP_TOP ;
2005-09-26 10:04:21 +04:00
/* Map in I/O resources */
if ( ppc_md . progress )
ppc_md . progress ( " MMU:setio " , 0x302 ) ;
if ( ppc_md . progress )
ppc_md . progress ( " MMU:exit " , 0x211 ) ;
2005-11-23 09:57:25 +03:00
/* From now on, btext is no longer BAT mapped if it was at all */
# ifdef CONFIG_BOOTX_TEXT
btext_unmap ( ) ;
# endif
2005-09-26 10:04:21 +04:00
}
/* This is only called until mem_init is done. */
void __init * early_get_page ( void )
{
void * p ;
if ( init_bootmem_done ) {
p = alloc_bootmem_pages ( PAGE_SIZE ) ;
} else {
2005-10-06 06:23:33 +04:00
p = __va ( lmb_alloc_base ( PAGE_SIZE , PAGE_SIZE ,
2008-04-15 23:52:25 +04:00
__initial_memory_limit_addr ) ) ;
2005-09-26 10:04:21 +04:00
}
return p ;
}
/* Free up now-unused memory */
static void free_sec ( unsigned long start , unsigned long end , const char * name )
{
unsigned long cnt = 0 ;
while ( start < end ) {
ClearPageReserved ( virt_to_page ( start ) ) ;
2006-03-22 11:08:40 +03:00
init_page_count ( virt_to_page ( start ) ) ;
2005-09-26 10:04:21 +04:00
free_page ( start ) ;
cnt + + ;
start + = PAGE_SIZE ;
}
if ( cnt ) {
printk ( " %ldk %s " , cnt < < ( PAGE_SHIFT - 10 ) , name ) ;
totalram_pages + = cnt ;
}
}
void free_initmem ( void )
{
# define FREESEC(TYPE) \
free_sec ( ( unsigned long ) ( & __ # # TYPE # # _begin ) , \
( unsigned long ) ( & __ # # TYPE # # _end ) , \
# TYPE);
printk ( " Freeing unused kernel memory: " ) ;
FREESEC ( init ) ;
printk ( " \n " ) ;
ppc_md . progress = NULL ;
# undef FREESEC
}
# ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem ( unsigned long start , unsigned long end )
{
if ( start < end )
printk ( " Freeing initrd memory: %ldk freed \n " , ( end - start ) > > 10 ) ;
for ( ; start < end ; start + = PAGE_SIZE ) {
ClearPageReserved ( virt_to_page ( start ) ) ;
2006-03-22 11:08:40 +03:00
init_page_count ( virt_to_page ( start ) ) ;
2005-09-26 10:04:21 +04:00
free_page ( start ) ;
totalram_pages + + ;
}
}
# endif
2007-09-21 06:53:02 +04:00