2005-04-16 15:20:36 -07:00
/*
* arch / s390 / kernel / setup . c
*
* S390 version
2012-03-11 11:59:26 -04:00
* Copyright ( C ) IBM Corp . 1999 , 2012
2005-04-16 15:20:36 -07:00
* Author ( s ) : Hartmut Penner ( hp @ de . ibm . com ) ,
* Martin Schwidefsky ( schwidefsky @ de . ibm . com )
*
* Derived from " arch/i386/kernel/setup.c "
* Copyright ( C ) 1995 , Linus Torvalds
*/
/*
* This file handles the architecture - dependent parts of initialization
*/
2008-12-25 13:39:40 +01:00
# define KMSG_COMPONENT "setup"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2005-04-16 15:20:36 -07:00
# include <linux/errno.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/kernel.h>
2011-12-08 10:22:09 -08:00
# include <linux/memblock.h>
2005-04-16 15:20:36 -07:00
# include <linux/mm.h>
# include <linux/stddef.h>
# include <linux/unistd.h>
# include <linux/ptrace.h>
# include <linux/user.h>
# include <linux/tty.h>
# include <linux/ioport.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/initrd.h>
# include <linux/bootmem.h>
# include <linux/root_dev.h>
# include <linux/console.h>
# include <linux/kernel_stat.h>
2005-10-30 15:00:11 -08:00
# include <linux/device.h>
2006-06-29 15:08:25 +02:00
# include <linux/notifier.h>
2006-09-20 15:58:41 +02:00
# include <linux/pfn.h>
2007-02-05 21:18:24 +01:00
# include <linux/ctype.h>
2007-02-05 21:16:47 +01:00
# include <linux/reboot.h>
2008-04-17 07:46:12 +02:00
# include <linux/topology.h>
2009-06-12 10:26:44 +02:00
# include <linux/ftrace.h>
2011-10-30 15:16:40 +01:00
# include <linux/kexec.h>
# include <linux/crash_dump.h>
# include <linux/memory.h>
2012-02-27 10:01:52 +01:00
# include <linux/compat.h>
2005-04-16 15:20:36 -07:00
2007-02-21 10:55:21 +01:00
# include <asm/ipl.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
# include <asm/system.h>
# include <asm/smp.h>
# include <asm/mmu_context.h>
# include <asm/cpcmd.h>
# include <asm/lowcore.h>
# include <asm/irq.h>
2005-05-01 08:58:58 -07:00
# include <asm/page.h>
# include <asm/ptrace.h>
2006-06-25 05:49:30 -07:00
# include <asm/sections.h>
2007-02-05 21:18:24 +01:00
# include <asm/ebcdic.h>
2008-06-20 15:24:18 +02:00
# include <asm/kvm_virtio.h>
2011-10-30 15:16:40 +01:00
# include <asm/diag.h>
2012-03-11 11:59:26 -04:00
# include "entry.h"
2007-02-05 21:18:17 +01:00
2011-10-30 15:16:50 +01:00
long psw_kernel_bits = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY |
PSW_MASK_EA | PSW_MASK_BA ;
long psw_user_bits = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT |
PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_MCHECK |
PSW_MASK_PSTATE | PSW_ASC_HOME ;
2005-04-16 15:20:36 -07:00
2006-09-20 15:59:42 +02:00
/*
* User copy operations .
*/
struct uaccess_ops uaccess ;
2007-05-04 18:47:48 +02:00
EXPORT_SYMBOL ( uaccess ) ;
2006-09-20 15:59:42 +02:00
2005-04-16 15:20:36 -07:00
/*
* Machine setup . .
*/
unsigned int console_mode = 0 ;
2009-03-26 15:24:04 +01:00
EXPORT_SYMBOL ( console_mode ) ;
2005-04-16 15:20:36 -07:00
unsigned int console_devno = - 1 ;
2009-03-26 15:24:04 +01:00
EXPORT_SYMBOL ( console_devno ) ;
2005-04-16 15:20:36 -07:00
unsigned int console_irq = - 1 ;
2009-03-26 15:24:04 +01:00
EXPORT_SYMBOL ( console_irq ) ;
2007-05-04 18:48:28 +02:00
unsigned long elf_hwcap = 0 ;
char elf_platform [ ELF_PLATFORM_SIZE ] ;
2006-12-04 15:40:38 +01:00
2008-07-14 09:59:21 +02:00
struct mem_chunk __initdata memory_chunk [ MEMORY_CHUNKS ] ;
2009-02-19 15:19:01 +01:00
int __initdata memory_end_set ;
unsigned long __initdata memory_end ;
2005-04-16 15:20:36 -07:00
2011-12-27 11:27:07 +01:00
unsigned long VMALLOC_START ;
EXPORT_SYMBOL ( VMALLOC_START ) ;
unsigned long VMALLOC_END ;
EXPORT_SYMBOL ( VMALLOC_END ) ;
struct page * vmemmap ;
EXPORT_SYMBOL ( vmemmap ) ;
2009-03-26 15:23:43 +01:00
/* An array with a pointer to the lowcore of every CPU. */
struct _lowcore * lowcore_ptr [ NR_CPUS ] ;
EXPORT_SYMBOL ( lowcore_ptr ) ;
2005-04-16 15:20:36 -07:00
/*
* This is set up by the setup - routine at boot - time
* for S390 need to find out , what we have to setup
* using address 0x10400 . . .
*/
# include <asm/setup.h>
/*
* condev = and conmode = setup parameter .
*/
static int __init condev_setup ( char * str )
{
int vdev ;
vdev = simple_strtoul ( str , & str , 0 ) ;
if ( vdev > = 0 & & vdev < 65536 ) {
console_devno = vdev ;
console_irq = - 1 ;
}
return 1 ;
}
__setup ( " condev= " , condev_setup ) ;
2009-08-23 18:09:06 +02:00
static void __init set_preferred_console ( void )
{
2009-09-11 10:28:56 +02:00
if ( MACHINE_IS_KVM )
2009-08-23 18:09:06 +02:00
add_preferred_console ( " hvc " , 0 , NULL ) ;
2009-09-11 10:28:56 +02:00
else if ( CONSOLE_IS_3215 | | CONSOLE_IS_SCLP )
2009-08-23 18:09:06 +02:00
add_preferred_console ( " ttyS " , 0 , NULL ) ;
2009-09-11 10:28:56 +02:00
else if ( CONSOLE_IS_3270 )
2009-08-23 18:09:06 +02:00
add_preferred_console ( " tty3270 " , 0 , NULL ) ;
}
2005-04-16 15:20:36 -07:00
static int __init conmode_setup ( char * str )
{
2008-02-05 16:50:41 +01:00
# if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
2005-04-16 15:20:36 -07:00
if ( strncmp ( str , " hwc " , 4 ) = = 0 | | strncmp ( str , " sclp " , 5 ) = = 0 )
SET_CONSOLE_SCLP ;
# endif
# if defined(CONFIG_TN3215_CONSOLE)
if ( strncmp ( str , " 3215 " , 5 ) = = 0 )
SET_CONSOLE_3215 ;
# endif
# if defined(CONFIG_TN3270_CONSOLE)
if ( strncmp ( str , " 3270 " , 5 ) = = 0 )
SET_CONSOLE_3270 ;
# endif
2009-08-23 18:09:06 +02:00
set_preferred_console ( ) ;
2005-04-16 15:20:36 -07:00
return 1 ;
}
__setup ( " conmode= " , conmode_setup ) ;
static void __init conmode_default ( void )
{
char query_buffer [ 1024 ] ;
char * ptr ;
if ( MACHINE_IS_VM ) {
2006-12-04 15:40:30 +01:00
cpcmd ( " QUERY CONSOLE " , query_buffer , 1024 , NULL ) ;
2005-04-16 15:20:36 -07:00
console_devno = simple_strtoul ( query_buffer + 5 , NULL , 16 ) ;
ptr = strstr ( query_buffer , " SUBCHANNEL = " ) ;
console_irq = simple_strtoul ( ptr + 13 , NULL , 16 ) ;
2006-12-04 15:40:30 +01:00
cpcmd ( " QUERY TERM " , query_buffer , 1024 , NULL ) ;
2005-04-16 15:20:36 -07:00
ptr = strstr ( query_buffer , " CONMODE " ) ;
/*
* Set the conmode to 3215 so that the device recognition
* will set the cu_type of the console to 3215. If the
* conmode is 3270 and we don ' t set it back then both
* 3215 and the 3270 driver will try to access the console
* device ( 3215 as console and 3270 as normal tty ) .
*/
2006-12-04 15:40:30 +01:00
cpcmd ( " TERM CONMODE 3215 " , NULL , 0 , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( ptr = = NULL ) {
2008-02-05 16:50:41 +01:00
# if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
2005-04-16 15:20:36 -07:00
SET_CONSOLE_SCLP ;
# endif
return ;
}
if ( strncmp ( ptr + 8 , " 3270 " , 4 ) = = 0 ) {
# if defined(CONFIG_TN3270_CONSOLE)
SET_CONSOLE_3270 ;
# elif defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215 ;
2008-02-05 16:50:41 +01:00
# elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
2005-04-16 15:20:36 -07:00
SET_CONSOLE_SCLP ;
# endif
} else if ( strncmp ( ptr + 8 , " 3215 " , 4 ) = = 0 ) {
# if defined(CONFIG_TN3215_CONSOLE)
SET_CONSOLE_3215 ;
# elif defined(CONFIG_TN3270_CONSOLE)
SET_CONSOLE_3270 ;
2008-02-05 16:50:41 +01:00
# elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
2005-04-16 15:20:36 -07:00
SET_CONSOLE_SCLP ;
# endif
}
} else {
2008-02-05 16:50:41 +01:00
# if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
2005-04-16 15:20:36 -07:00
SET_CONSOLE_SCLP ;
# endif
}
}
2009-03-26 15:24:46 +01:00
# ifdef CONFIG_ZFCPDUMP
2007-04-27 16:01:49 +02:00
static void __init setup_zfcpdump ( unsigned int console_devno )
{
2008-07-14 09:59:09 +02:00
static char str [ 41 ] ;
2007-04-27 16:01:49 +02:00
if ( ipl_info . type ! = IPL_TYPE_FCP_DUMP )
return ;
2011-11-14 11:19:05 +01:00
if ( OLDMEM_BASE )
return ;
2007-04-27 16:01:49 +02:00
if ( console_devno ! = - 1 )
2008-07-14 09:59:09 +02:00
sprintf ( str , " cio_ignore=all,!0.0.%04x,!0.0.%04x " ,
2007-04-27 16:01:49 +02:00
ipl_info . data . fcp . dev_id . devno , console_devno ) ;
else
2008-07-14 09:59:09 +02:00
sprintf ( str , " cio_ignore=all,!0.0.%04x " ,
2007-04-27 16:01:49 +02:00
ipl_info . data . fcp . dev_id . devno ) ;
2008-07-14 09:59:09 +02:00
strcat ( boot_command_line , str ) ;
2007-04-27 16:01:49 +02:00
console_loglevel = 2 ;
}
# else
static inline void setup_zfcpdump ( unsigned int console_devno ) { }
# endif /* CONFIG_ZFCPDUMP */
2005-04-16 15:20:36 -07:00
/*
* Reboot , halt and power_off stubs . They just call _machine_restart ,
* _machine_halt or _machine_power_off .
*/
void machine_restart ( char * command )
{
2007-11-20 11:13:31 +01:00
if ( ( ! in_interrupt ( ) & & ! in_atomic ( ) ) | | oops_in_progress )
2006-06-29 14:57:32 +02:00
/*
* Only unblank the console if we are called in enabled
* context or a bust_spinlocks cleared the way for us .
*/
console_unblank ( ) ;
2005-04-16 15:20:36 -07:00
_machine_restart ( command ) ;
}
void machine_halt ( void )
{
2006-06-29 14:57:32 +02:00
if ( ! in_interrupt ( ) | | oops_in_progress )
/*
* Only unblank the console if we are called in enabled
* context or a bust_spinlocks cleared the way for us .
*/
console_unblank ( ) ;
2005-04-16 15:20:36 -07:00
_machine_halt ( ) ;
}
void machine_power_off ( void )
{
2006-06-29 14:57:32 +02:00
if ( ! in_interrupt ( ) | | oops_in_progress )
/*
* Only unblank the console if we are called in enabled
* context or a bust_spinlocks cleared the way for us .
*/
console_unblank ( ) ;
2005-04-16 15:20:36 -07:00
_machine_power_off ( ) ;
}
2006-01-14 13:21:01 -08:00
/*
* Dummy power off function .
*/
void ( * pm_power_off ) ( void ) = machine_power_off ;
2006-03-24 03:15:15 -08:00
static int __init early_parse_mem ( char * p )
{
memory_end = memparse ( p , & p ) ;
2009-02-19 15:19:01 +01:00
memory_end_set = 1 ;
2006-03-24 03:15:15 -08:00
return 0 ;
}
early_param ( " mem " , early_parse_mem ) ;
2011-12-27 11:27:07 +01:00
static int __init parse_vmalloc ( char * arg )
{
if ( ! arg )
return - EINVAL ;
VMALLOC_END = ( memparse ( arg , & arg ) + PAGE_SIZE - 1 ) & PAGE_MASK ;
return 0 ;
}
early_param ( " vmalloc " , parse_vmalloc ) ;
2009-12-07 12:51:43 +01:00
unsigned int user_mode = HOME_SPACE_MODE ;
EXPORT_SYMBOL_GPL ( user_mode ) ;
2007-02-05 21:18:17 +01:00
2011-10-30 15:16:50 +01:00
static int set_amode_primary ( void )
2007-02-05 21:18:17 +01:00
{
2011-10-30 15:16:50 +01:00
psw_kernel_bits = ( psw_kernel_bits & ~ PSW_MASK_ASC ) | PSW_ASC_HOME ;
psw_user_bits = ( psw_user_bits & ~ PSW_MASK_ASC ) | PSW_ASC_PRIMARY ;
2007-02-05 21:18:17 +01:00
# ifdef CONFIG_COMPAT
2011-10-30 15:16:50 +01:00
psw32_user_bits =
( psw32_user_bits & ~ PSW32_MASK_ASC ) | PSW32_ASC_PRIMARY ;
2007-02-05 21:18:17 +01:00
# endif
if ( MACHINE_HAS_MVCOS ) {
memcpy ( & uaccess , & uaccess_mvcos_switch , sizeof ( uaccess ) ) ;
2008-12-25 13:39:40 +01:00
return 1 ;
2007-02-05 21:18:17 +01:00
} else {
memcpy ( & uaccess , & uaccess_pt , sizeof ( uaccess ) ) ;
2008-12-25 13:39:40 +01:00
return 0 ;
2007-02-05 21:18:17 +01:00
}
}
/*
* Switch kernel / user addressing modes ?
*/
static int __init early_parse_switch_amode ( char * p )
{
2011-05-23 10:24:23 +02:00
user_mode = PRIMARY_SPACE_MODE ;
2007-02-05 21:18:17 +01:00
return 0 ;
}
early_param ( " switch_amode " , early_parse_switch_amode ) ;
2009-12-07 12:51:43 +01:00
static int __init early_parse_user_mode ( char * p )
2007-02-05 21:18:17 +01:00
{
2009-12-07 12:51:43 +01:00
if ( p & & strcmp ( p , " primary " ) = = 0 )
user_mode = PRIMARY_SPACE_MODE ;
else if ( ! p | | strcmp ( p , " home " ) = = 0 )
user_mode = HOME_SPACE_MODE ;
else
return 1 ;
2008-12-25 13:39:40 +01:00
return 0 ;
2007-02-05 21:18:17 +01:00
}
2009-12-07 12:51:43 +01:00
early_param ( " user_mode " , early_parse_user_mode ) ;
2007-02-05 21:18:17 +01:00
static void setup_addressing_mode ( void )
{
2011-05-23 10:24:23 +02:00
if ( user_mode = = PRIMARY_SPACE_MODE ) {
2011-10-30 15:16:50 +01:00
if ( set_amode_primary ( ) )
2008-12-25 13:39:40 +01:00
pr_info ( " Address spaces switched, "
" mvcos available \n " ) ;
else
pr_info ( " Address spaces switched, "
" mvcos not available \n " ) ;
2007-02-05 21:18:17 +01:00
}
}
2012-03-11 11:59:26 -04:00
void * restart_stack __attribute__ ( ( __section__ ( " .data " ) ) ) ;
static void __init setup_lowcore ( void )
2005-05-01 08:58:57 -07:00
{
struct _lowcore * lc ;
/*
* Setup lowcore for boot cpu
*/
2010-02-26 22:37:43 +01:00
BUILD_BUG_ON ( sizeof ( struct _lowcore ) ! = LC_PAGES * 4096 ) ;
2010-03-24 11:49:51 +01:00
lc = __alloc_bootmem_low ( LC_PAGES * PAGE_SIZE , LC_PAGES * PAGE_SIZE , 0 ) ;
2011-10-30 15:16:50 +01:00
lc - > restart_psw . mask = psw_kernel_bits ;
2005-05-01 08:58:57 -07:00
lc - > restart_psw . addr =
2012-03-11 11:59:26 -04:00
PSW_ADDR_AMODE | ( unsigned long ) restart_int_handler ;
2011-10-30 15:16:50 +01:00
lc - > external_new_psw . mask = psw_kernel_bits |
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2005-05-01 08:58:57 -07:00
lc - > external_new_psw . addr =
PSW_ADDR_AMODE | ( unsigned long ) ext_int_handler ;
2011-10-30 15:16:50 +01:00
lc - > svc_new_psw . mask = psw_kernel_bits |
PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK ;
2005-05-01 08:58:57 -07:00
lc - > svc_new_psw . addr = PSW_ADDR_AMODE | ( unsigned long ) system_call ;
2011-10-30 15:16:50 +01:00
lc - > program_new_psw . mask = psw_kernel_bits |
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2005-05-01 08:58:57 -07:00
lc - > program_new_psw . addr =
2011-10-30 15:16:50 +01:00
PSW_ADDR_AMODE | ( unsigned long ) pgm_check_handler ;
lc - > mcck_new_psw . mask = psw_kernel_bits ;
2005-05-01 08:58:57 -07:00
lc - > mcck_new_psw . addr =
PSW_ADDR_AMODE | ( unsigned long ) mcck_int_handler ;
2011-10-30 15:16:50 +01:00
lc - > io_new_psw . mask = psw_kernel_bits |
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2005-05-01 08:58:57 -07:00
lc - > io_new_psw . addr = PSW_ADDR_AMODE | ( unsigned long ) io_int_handler ;
2008-04-17 07:46:25 +02:00
lc - > clock_comparator = - 1ULL ;
2005-05-01 08:58:57 -07:00
lc - > kernel_stack = ( ( unsigned long ) & init_thread_union ) + THREAD_SIZE ;
lc - > async_stack = ( unsigned long )
__alloc_bootmem ( ASYNC_SIZE , ASYNC_SIZE , 0 ) + ASYNC_SIZE ;
lc - > panic_stack = ( unsigned long )
__alloc_bootmem ( PAGE_SIZE , PAGE_SIZE , 0 ) + PAGE_SIZE ;
lc - > current_task = ( unsigned long ) init_thread_union . thread_info . task ;
lc - > thread_info = ( unsigned long ) & init_thread_union ;
2009-04-14 15:36:16 +02:00
lc - > machine_flags = S390_lowcore . machine_flags ;
2010-10-25 16:10:51 +02:00
lc - > stfl_fac_list = S390_lowcore . stfl_fac_list ;
memcpy ( lc - > stfle_fac_list , S390_lowcore . stfle_fac_list ,
MAX_FACILITY_BIT / 8 ) ;
2006-01-06 00:19:28 -08:00
# ifndef CONFIG_64BIT
2005-06-25 14:55:30 -07:00
if ( MACHINE_HAS_IEEE ) {
lc - > extended_save_area_addr = ( __u32 )
2010-03-24 11:49:51 +01:00
__alloc_bootmem_low ( PAGE_SIZE , PAGE_SIZE , 0 ) ;
2005-06-25 14:55:30 -07:00
/* enable extended save area */
2006-11-06 10:49:02 +01:00
__ctl_set_bit ( 14 , 29 ) ;
2005-06-25 14:55:30 -07:00
}
2008-12-31 15:11:42 +01:00
# else
lc - > vdso_per_cpu_data = ( unsigned long ) & lc - > paste [ 0 ] ;
2005-06-25 14:55:30 -07:00
# endif
2009-04-14 15:36:29 +02:00
lc - > sync_enter_timer = S390_lowcore . sync_enter_timer ;
lc - > async_enter_timer = S390_lowcore . async_enter_timer ;
lc - > exit_timer = S390_lowcore . exit_timer ;
lc - > user_timer = S390_lowcore . user_timer ;
lc - > system_timer = S390_lowcore . system_timer ;
lc - > steal_timer = S390_lowcore . steal_timer ;
lc - > last_update_timer = S390_lowcore . last_update_timer ;
lc - > last_update_clock = S390_lowcore . last_update_clock ;
2009-06-12 10:26:44 +02:00
lc - > ftrace_func = S390_lowcore . ftrace_func ;
2012-03-11 11:59:26 -04:00
restart_stack = __alloc_bootmem ( ASYNC_SIZE , ASYNC_SIZE , 0 ) ;
restart_stack + = ASYNC_SIZE ;
/*
* Set up PSW restart to call ipl . c : do_restart ( ) . Copy the relevant
* restart data to the absolute zero lowcore . This is necesary if
* PSW restart is done on an offline CPU that has lowcore zero .
*/
lc - > restart_stack = ( unsigned long ) restart_stack ;
lc - > restart_fn = ( unsigned long ) do_restart ;
lc - > restart_data = 0 ;
lc - > restart_source = - 1UL ;
memcpy ( & S390_lowcore . restart_stack , & lc - > restart_stack ,
4 * sizeof ( unsigned long ) ) ;
copy_to_absolute_zero ( & S390_lowcore . restart_psw ,
& lc - > restart_psw , sizeof ( psw_t ) ) ;
2005-05-01 08:58:57 -07:00
set_prefix ( ( u32 ) ( unsigned long ) lc ) ;
2009-03-26 15:23:43 +01:00
lowcore_ptr [ 0 ] = lc ;
2005-05-01 08:58:57 -07:00
}
2011-03-23 10:15:59 +01:00
static struct resource code_resource = {
. name = " Kernel code " ,
. flags = IORESOURCE_BUSY | IORESOURCE_MEM ,
} ;
static struct resource data_resource = {
. name = " Kernel data " ,
. flags = IORESOURCE_BUSY | IORESOURCE_MEM ,
} ;
2011-03-23 10:16:00 +01:00
static struct resource bss_resource = {
. name = " Kernel bss " ,
. flags = IORESOURCE_BUSY | IORESOURCE_MEM ,
} ;
2011-03-23 10:15:59 +01:00
static struct resource __initdata * standard_resources [ ] = {
& code_resource ,
& data_resource ,
2011-03-23 10:16:00 +01:00
& bss_resource ,
2011-03-23 10:15:59 +01:00
} ;
static void __init setup_resources ( void )
2005-05-01 08:58:57 -07:00
{
2011-03-23 10:15:59 +01:00
struct resource * res , * std_res , * sub_res ;
int i , j ;
2005-05-01 08:58:57 -07:00
2006-06-25 05:49:30 -07:00
code_resource . start = ( unsigned long ) & _text ;
code_resource . end = ( unsigned long ) & _etext - 1 ;
data_resource . start = ( unsigned long ) & _etext ;
data_resource . end = ( unsigned long ) & _edata - 1 ;
2011-03-23 10:16:00 +01:00
bss_resource . start = ( unsigned long ) & __bss_start ;
bss_resource . end = ( unsigned long ) & __bss_stop - 1 ;
2006-06-25 05:49:30 -07:00
2008-01-26 14:11:02 +01:00
for ( i = 0 ; i < MEMORY_CHUNKS ; i + + ) {
if ( ! memory_chunk [ i ] . size )
continue ;
2011-10-30 15:16:40 +01:00
if ( memory_chunk [ i ] . type = = CHUNK_OLDMEM | |
memory_chunk [ i ] . type = = CHUNK_CRASHK )
continue ;
2011-03-23 10:15:59 +01:00
res = alloc_bootmem_low ( sizeof ( * res ) ) ;
2005-05-01 08:58:57 -07:00
res - > flags = IORESOURCE_BUSY | IORESOURCE_MEM ;
switch ( memory_chunk [ i ] . type ) {
case CHUNK_READ_WRITE :
2011-10-30 15:16:44 +01:00
case CHUNK_CRASHK :
2005-05-01 08:58:57 -07:00
res - > name = " System RAM " ;
break ;
case CHUNK_READ_ONLY :
res - > name = " System ROM " ;
res - > flags | = IORESOURCE_READONLY ;
break ;
default :
res - > name = " reserved " ;
}
res - > start = memory_chunk [ i ] . addr ;
2011-03-23 10:15:59 +01:00
res - > end = res - > start + memory_chunk [ i ] . size - 1 ;
2005-05-01 08:58:57 -07:00
request_resource ( & iomem_resource , res ) ;
2007-02-05 21:18:24 +01:00
2011-03-23 10:15:59 +01:00
for ( j = 0 ; j < ARRAY_SIZE ( standard_resources ) ; j + + ) {
std_res = standard_resources [ j ] ;
if ( std_res - > start < res - > start | |
std_res - > start > res - > end )
continue ;
if ( std_res - > end > res - > end ) {
sub_res = alloc_bootmem_low ( sizeof ( * sub_res ) ) ;
* sub_res = * std_res ;
sub_res - > end = res - > end ;
std_res - > start = res - > end + 1 ;
request_resource ( res , sub_res ) ;
} else {
request_resource ( res , std_res ) ;
}
2007-02-05 21:18:24 +01:00
}
2005-05-01 08:58:57 -07:00
}
}
2007-04-27 16:01:49 +02:00
unsigned long real_memory_size ;
EXPORT_SYMBOL_GPL ( real_memory_size ) ;
2006-12-04 15:40:56 +01:00
static void __init setup_memory_end ( void )
{
2011-12-27 11:27:07 +01:00
unsigned long vmax , vmalloc_size , tmp ;
2006-12-04 15:40:56 +01:00
int i ;
2011-10-30 15:16:40 +01:00
2009-03-26 15:24:46 +01:00
# ifdef CONFIG_ZFCPDUMP
2011-11-14 11:19:05 +01:00
if ( ipl_info . type = = IPL_TYPE_FCP_DUMP & & ! OLDMEM_BASE ) {
2007-04-27 16:01:49 +02:00
memory_end = ZFCPDUMP_HSA_SIZE ;
2009-02-19 15:19:01 +01:00
memory_end_set = 1 ;
}
2007-04-27 16:01:49 +02:00
# endif
2011-12-27 11:27:07 +01:00
real_memory_size = 0 ;
2006-12-04 15:40:56 +01:00
memory_end & = PAGE_MASK ;
2008-01-26 14:11:02 +01:00
/*
* Make sure all chunks are MAX_ORDER aligned so we don ' t need the
* extra checks that HOLES_IN_ZONE would require .
*/
for ( i = 0 ; i < MEMORY_CHUNKS ; i + + ) {
unsigned long start , end ;
struct mem_chunk * chunk ;
unsigned long align ;
chunk = & memory_chunk [ i ] ;
align = 1UL < < ( MAX_ORDER + PAGE_SHIFT - 1 ) ;
start = ( chunk - > addr + align - 1 ) & ~ ( align - 1 ) ;
end = ( chunk - > addr + chunk - > size ) & ~ ( align - 1 ) ;
if ( start > = end )
memset ( chunk , 0 , sizeof ( * chunk ) ) ;
else {
chunk - > addr = start ;
chunk - > size = end - start ;
}
2011-12-27 11:27:07 +01:00
real_memory_size = max ( real_memory_size ,
chunk - > addr + chunk - > size ) ;
2008-01-26 14:11:02 +01:00
}
2011-12-27 11:27:07 +01:00
/* Choose kernel address space layout: 2, 3, or 4 levels. */
# ifdef CONFIG_64BIT
vmalloc_size = VMALLOC_END ? : 128UL < < 30 ;
tmp = ( memory_end ? : real_memory_size ) / PAGE_SIZE ;
tmp = tmp * ( sizeof ( struct page ) + PAGE_SIZE ) + vmalloc_size ;
if ( tmp < = ( 1UL < < 42 ) )
vmax = 1UL < < 42 ; /* 3-level kernel page table */
else
vmax = 1UL < < 53 ; /* 4-level kernel page table */
# else
vmalloc_size = VMALLOC_END ? : 96UL < < 20 ;
vmax = 1UL < < 31 ; /* 2-level kernel page table */
# endif
/* vmalloc area is at the end of the kernel address space. */
VMALLOC_END = vmax ;
VMALLOC_START = vmax - vmalloc_size ;
/* Split remaining virtual space between 1:1 mapping & vmemmap array */
tmp = VMALLOC_START / ( PAGE_SIZE + sizeof ( struct page ) ) ;
tmp = VMALLOC_START - tmp * sizeof ( struct page ) ;
tmp & = ~ ( ( vmax > > 11 ) - 1 ) ; /* align to page table level */
tmp = min ( tmp , 1UL < < MAX_PHYSMEM_BITS ) ;
vmemmap = ( struct page * ) tmp ;
/* Take care that memory_end is set and <= vmemmap */
memory_end = min ( memory_end ? : real_memory_size , tmp ) ;
/* Fixup memory chunk array to fit into 0..memory_end */
2006-12-04 15:40:56 +01:00
for ( i = 0 ; i < MEMORY_CHUNKS ; i + + ) {
struct mem_chunk * chunk = & memory_chunk [ i ] ;
2011-12-27 11:27:07 +01:00
if ( chunk - > addr > = memory_end ) {
2006-12-04 15:40:56 +01:00
memset ( chunk , 0 , sizeof ( * chunk ) ) ;
continue ;
}
2011-12-27 11:27:07 +01:00
if ( chunk - > addr + chunk - > size > memory_end )
chunk - > size = memory_end - chunk - > addr ;
2006-12-04 15:40:56 +01:00
}
}
2011-10-30 15:16:42 +01:00
static void __init setup_vmcoreinfo ( void )
{
# ifdef CONFIG_KEXEC
unsigned long ptr = paddr_vmcoreinfo_note ( ) ;
copy_to_absolute_zero ( & S390_lowcore . vmcore_info , & ptr , sizeof ( ptr ) ) ;
# endif
}
2011-10-30 15:16:40 +01:00
# ifdef CONFIG_CRASH_DUMP
/*
* Find suitable location for crashkernel memory
*/
static unsigned long __init find_crash_base ( unsigned long crash_size ,
char * * msg )
{
unsigned long crash_base ;
struct mem_chunk * chunk ;
int i ;
if ( memory_chunk [ 0 ] . size < crash_size ) {
* msg = " first memory chunk must be at least crashkernel size " ;
return 0 ;
}
2011-12-01 13:32:14 +01:00
if ( OLDMEM_BASE & & crash_size = = OLDMEM_SIZE )
2011-10-30 15:16:40 +01:00
return OLDMEM_BASE ;
for ( i = MEMORY_CHUNKS - 1 ; i > = 0 ; i - - ) {
chunk = & memory_chunk [ i ] ;
if ( chunk - > size = = 0 )
continue ;
if ( chunk - > type ! = CHUNK_READ_WRITE )
continue ;
if ( chunk - > size < crash_size )
continue ;
crash_base = ( chunk - > addr + chunk - > size ) - crash_size ;
if ( crash_base < crash_size )
continue ;
if ( crash_base < ZFCPDUMP_HSA_SIZE_MAX )
continue ;
if ( crash_base < ( unsigned long ) INITRD_START + INITRD_SIZE )
continue ;
return crash_base ;
}
* msg = " no suitable area found " ;
return 0 ;
}
/*
* Check if crash_base and crash_size is valid
*/
static int __init verify_crash_base ( unsigned long crash_base ,
unsigned long crash_size ,
char * * msg )
{
struct mem_chunk * chunk ;
int i ;
/*
* Because we do the swap to zero , we must have at least ' crash_size '
* bytes free space before crash_base
*/
if ( crash_size > crash_base ) {
* msg = " crashkernel offset must be greater than size " ;
return - EINVAL ;
}
/* First memory chunk must be at least crash_size */
if ( memory_chunk [ 0 ] . size < crash_size ) {
* msg = " first memory chunk must be at least crashkernel size " ;
return - EINVAL ;
}
/* Check if we fit into the respective memory chunk */
for ( i = 0 ; i < MEMORY_CHUNKS ; i + + ) {
chunk = & memory_chunk [ i ] ;
if ( chunk - > size = = 0 )
continue ;
if ( crash_base < chunk - > addr )
continue ;
if ( crash_base > = chunk - > addr + chunk - > size )
continue ;
/* we have found the memory chunk */
if ( crash_base + crash_size > chunk - > addr + chunk - > size ) {
* msg = " selected memory chunk is too small for "
" crashkernel memory " ;
return - EINVAL ;
}
return 0 ;
}
* msg = " invalid memory range specified " ;
return - EINVAL ;
}
/*
* Reserve kdump memory by creating a memory hole in the mem_chunk array
*/
static void __init reserve_kdump_bootmem ( unsigned long addr , unsigned long size ,
int type )
{
create_mem_hole ( memory_chunk , addr , size , type ) ;
}
/*
* When kdump is enabled , we have to ensure that no memory from
* the area [ 0 - crashkernel memory size ] and
* [ crashk_res . start - crashk_res . end ] is set offline .
*/
static int kdump_mem_notifier ( struct notifier_block * nb ,
unsigned long action , void * data )
{
struct memory_notify * arg = data ;
if ( arg - > start_pfn < PFN_DOWN ( resource_size ( & crashk_res ) ) )
return NOTIFY_BAD ;
if ( arg - > start_pfn > PFN_DOWN ( crashk_res . end ) )
return NOTIFY_OK ;
if ( arg - > start_pfn + arg - > nr_pages - 1 < PFN_DOWN ( crashk_res . start ) )
return NOTIFY_OK ;
return NOTIFY_BAD ;
}
static struct notifier_block kdump_mem_nb = {
. notifier_call = kdump_mem_notifier ,
} ;
# endif
/*
* Make sure that oldmem , where the dump is stored , is protected
*/
static void reserve_oldmem ( void )
{
# ifdef CONFIG_CRASH_DUMP
if ( ! OLDMEM_BASE )
return ;
reserve_kdump_bootmem ( OLDMEM_BASE , OLDMEM_SIZE , CHUNK_OLDMEM ) ;
reserve_kdump_bootmem ( OLDMEM_SIZE , memory_end - OLDMEM_SIZE ,
CHUNK_OLDMEM ) ;
if ( OLDMEM_BASE + OLDMEM_SIZE = = real_memory_size )
saved_max_pfn = PFN_DOWN ( OLDMEM_BASE ) - 1 ;
else
saved_max_pfn = PFN_DOWN ( real_memory_size ) - 1 ;
# endif
}
/*
* Reserve memory for kdump kernel to be loaded with kexec
*/
static void __init reserve_crashkernel ( void )
{
# ifdef CONFIG_CRASH_DUMP
unsigned long long crash_base , crash_size ;
2012-03-11 11:59:24 -04:00
char * msg = NULL ;
2011-10-30 15:16:40 +01:00
int rc ;
rc = parse_crashkernel ( boot_command_line , memory_end , & crash_size ,
& crash_base ) ;
if ( rc | | crash_size = = 0 )
return ;
2011-10-30 15:16:44 +01:00
crash_base = ALIGN ( crash_base , KEXEC_CRASH_MEM_ALIGN ) ;
crash_size = ALIGN ( crash_size , KEXEC_CRASH_MEM_ALIGN ) ;
2011-10-30 15:16:40 +01:00
if ( register_memory_notifier ( & kdump_mem_nb ) )
return ;
if ( ! crash_base )
crash_base = find_crash_base ( crash_size , & msg ) ;
if ( ! crash_base ) {
pr_info ( " crashkernel reservation failed: %s \n " , msg ) ;
unregister_memory_notifier ( & kdump_mem_nb ) ;
return ;
}
if ( verify_crash_base ( crash_base , crash_size , & msg ) ) {
pr_info ( " crashkernel reservation failed: %s \n " , msg ) ;
unregister_memory_notifier ( & kdump_mem_nb ) ;
return ;
}
if ( ! OLDMEM_BASE & & MACHINE_IS_VM )
diag10_range ( PFN_DOWN ( crash_base ) , PFN_DOWN ( crash_size ) ) ;
crashk_res . start = crash_base ;
crashk_res . end = crash_base + crash_size - 1 ;
insert_resource ( & iomem_resource , & crashk_res ) ;
2011-10-30 15:16:44 +01:00
reserve_kdump_bootmem ( crash_base , crash_size , CHUNK_CRASHK ) ;
2011-10-30 15:16:40 +01:00
pr_info ( " Reserving %lluMB of memory at %lluMB "
" for crashkernel (System RAM: %luMB) \n " ,
crash_size > > 20 , crash_base > > 20 , memory_end > > 20 ) ;
# endif
}
2012-03-11 11:59:26 -04:00
static void __init setup_memory ( void )
2005-05-01 08:58:57 -07:00
{
unsigned long bootmap_size ;
2007-02-05 21:18:24 +01:00
unsigned long start_pfn , end_pfn ;
2005-05-01 08:58:57 -07:00
int i ;
2005-04-16 15:20:36 -07:00
/*
* partially used pages are not usable - thus
* we are rounding upwards :
*/
2006-09-20 15:58:41 +02:00
start_pfn = PFN_UP ( __pa ( & _end ) ) ;
end_pfn = max_pfn = PFN_DOWN ( memory_end ) ;
2005-04-16 15:20:36 -07:00
2006-09-20 15:58:41 +02:00
# ifdef CONFIG_BLK_DEV_INITRD
/*
* Move the initrd in case the bitmap of the bootmem allocater
* would overwrite it .
*/
if ( INITRD_START & & INITRD_SIZE ) {
unsigned long bmap_size ;
unsigned long start ;
bmap_size = bootmem_bootmap_pages ( end_pfn - start_pfn + 1 ) ;
bmap_size = PFN_PHYS ( bmap_size ) ;
if ( PFN_PHYS ( start_pfn ) + bmap_size > INITRD_START ) {
start = PFN_PHYS ( start_pfn ) + bmap_size + PAGE_SIZE ;
2011-10-30 15:16:40 +01:00
# ifdef CONFIG_CRASH_DUMP
if ( OLDMEM_BASE ) {
/* Move initrd behind kdump oldmem */
if ( start + INITRD_SIZE > OLDMEM_BASE & &
start < OLDMEM_BASE + OLDMEM_SIZE )
start = OLDMEM_BASE + OLDMEM_SIZE ;
}
# endif
2006-09-20 15:58:41 +02:00
if ( start + INITRD_SIZE > memory_end ) {
2008-12-25 13:39:40 +01:00
pr_err ( " initrd extends beyond end of "
" memory (0x%08lx > 0x%08lx) "
2006-09-20 15:58:41 +02:00
" disabling initrd \n " ,
start + INITRD_SIZE , memory_end ) ;
INITRD_START = INITRD_SIZE = 0 ;
} else {
2008-12-25 13:39:40 +01:00
pr_info ( " Moving initrd (0x%08lx -> "
" 0x%08lx, size: %ld) \n " ,
INITRD_START , start , INITRD_SIZE ) ;
2006-09-20 15:58:41 +02:00
memmove ( ( void * ) start , ( void * ) INITRD_START ,
INITRD_SIZE ) ;
INITRD_START = start ;
}
}
}
# endif
2005-04-16 15:20:36 -07:00
/*
2006-10-04 20:02:19 +02:00
* Initialize the boot - time allocator
2005-04-16 15:20:36 -07:00
*/
bootmap_size = init_bootmem ( start_pfn , end_pfn ) ;
/*
* Register RAM areas with the bootmem allocator .
*/
2005-05-01 08:58:57 -07:00
2005-05-01 08:58:58 -07:00
for ( i = 0 ; i < MEMORY_CHUNKS & & memory_chunk [ i ] . size > 0 ; i + + ) {
2006-12-08 15:56:10 +01:00
unsigned long start_chunk , end_chunk , pfn ;
2005-04-16 15:20:36 -07:00
2011-10-30 15:16:44 +01:00
if ( memory_chunk [ i ] . type ! = CHUNK_READ_WRITE & &
memory_chunk [ i ] . type ! = CHUNK_CRASHK )
2005-04-16 15:20:36 -07:00
continue ;
2006-12-08 15:56:10 +01:00
start_chunk = PFN_DOWN ( memory_chunk [ i ] . addr ) ;
2008-11-14 18:18:00 +01:00
end_chunk = start_chunk + PFN_DOWN ( memory_chunk [ i ] . size ) ;
2006-12-08 15:56:10 +01:00
end_chunk = min ( end_chunk , end_pfn ) ;
if ( start_chunk > = end_chunk )
continue ;
2011-12-08 10:22:09 -08:00
memblock_add_node ( PFN_PHYS ( start_chunk ) ,
PFN_PHYS ( end_chunk - start_chunk ) , 0 ) ;
2006-12-08 15:56:10 +01:00
pfn = max ( start_chunk , start_pfn ) ;
2008-11-14 18:18:00 +01:00
for ( ; pfn < end_chunk ; pfn + + )
2010-10-25 16:10:14 +02:00
page_set_storage_key ( PFN_PHYS ( pfn ) ,
PAGE_DEFAULT_KEY , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2005-05-01 08:58:58 -07:00
psw_set_key ( PAGE_DEFAULT_KEY ) ;
2006-12-08 15:56:10 +01:00
free_bootmem_with_active_regions ( 0 , max_pfn ) ;
2005-05-01 08:58:57 -07:00
2007-02-21 10:55:37 +01:00
/*
* Reserve memory used for lowcore / command line / kernel image .
*/
2008-02-07 00:15:17 -08:00
reserve_bootmem ( 0 , ( unsigned long ) _ehead , BOOTMEM_DEFAULT ) ;
2007-02-21 10:55:37 +01:00
reserve_bootmem ( ( unsigned long ) _stext ,
2008-02-07 00:15:17 -08:00
PFN_PHYS ( start_pfn ) - ( unsigned long ) _stext ,
BOOTMEM_DEFAULT ) ;
2005-05-01 08:58:57 -07:00
/*
* Reserve the bootmem bitmap itself as well . We do this in two
* steps ( first step was init_bootmem ( ) ) because this catches
* the ( very unlikely ) case of us accidentally initializing the
* bootmem allocator with an invalid RAM area .
*/
2008-02-07 00:15:17 -08:00
reserve_bootmem ( start_pfn < < PAGE_SHIFT , bootmap_size ,
BOOTMEM_DEFAULT ) ;
2005-04-16 15:20:36 -07:00
2011-10-30 15:16:40 +01:00
# ifdef CONFIG_CRASH_DUMP
if ( crashk_res . start )
reserve_bootmem ( crashk_res . start ,
crashk_res . end - crashk_res . start + 1 ,
BOOTMEM_DEFAULT ) ;
if ( is_kdump_kernel ( ) )
reserve_bootmem ( elfcorehdr_addr - OLDMEM_BASE ,
PAGE_ALIGN ( elfcorehdr_size ) , BOOTMEM_DEFAULT ) ;
# endif
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_BLK_DEV_INITRD
2006-09-20 15:58:41 +02:00
if ( INITRD_START & & INITRD_SIZE ) {
2005-04-16 15:20:36 -07:00
if ( INITRD_START + INITRD_SIZE < = memory_end ) {
2008-02-07 00:15:17 -08:00
reserve_bootmem ( INITRD_START , INITRD_SIZE ,
BOOTMEM_DEFAULT ) ;
2005-04-16 15:20:36 -07:00
initrd_start = INITRD_START ;
initrd_end = initrd_start + INITRD_SIZE ;
} else {
2008-12-25 13:39:40 +01:00
pr_err ( " initrd extends beyond end of "
" memory (0x%08lx > 0x%08lx) "
" disabling initrd \n " ,
2005-05-01 08:58:57 -07:00
initrd_start + INITRD_SIZE , memory_end ) ;
initrd_start = initrd_end = 0 ;
2005-04-16 15:20:36 -07:00
}
2005-05-01 08:58:57 -07:00
}
2005-04-16 15:20:36 -07:00
# endif
2005-05-01 08:58:57 -07:00
}
2005-04-16 15:20:36 -07:00
2007-05-04 18:48:28 +02:00
/*
* Setup hardware capabilities .
*/
static void __init setup_hwcaps ( void )
{
static const int stfl_bits [ 6 ] = { 0 , 2 , 7 , 17 , 19 , 21 } ;
2010-05-17 10:00:00 +02:00
struct cpuid cpu_id ;
2007-05-04 18:48:28 +02:00
int i ;
/*
* The store facility list bits numbers as found in the principles
* of operation are numbered with bit 1UL < < 31 as number 0 to
* bit 1UL < < 0 as number 31.
* Bit 0 : instructions named N3 , " backported " to esa - mode
* Bit 2 : z / Architecture mode is active
* Bit 7 : the store - facility - list - extended facility is installed
* Bit 17 : the message - security assist is installed
* Bit 19 : the long - displacement facility is installed
* Bit 21 : the extended - immediate facility is installed
2009-03-26 15:24:56 +01:00
* Bit 22 : extended - translation facility 3 is installed
* Bit 30 : extended - translation facility 3 enhancement facility
2007-05-04 18:48:28 +02:00
* These get translated to :
* HWCAP_S390_ESAN3 bit 0 , HWCAP_S390_ZARCH bit 1 ,
* HWCAP_S390_STFLE bit 2 , HWCAP_S390_MSA bit 3 ,
2009-03-26 15:24:56 +01:00
* HWCAP_S390_LDISP bit 4 , HWCAP_S390_EIMM bit 5 and
* HWCAP_S390_ETF3EH bit 8 ( 22 & & 30 ) .
2007-05-04 18:48:28 +02:00
*/
for ( i = 0 ; i < 6 ; i + + )
2010-10-25 16:10:51 +02:00
if ( test_facility ( stfl_bits [ i ] ) )
2007-05-04 18:48:28 +02:00
elf_hwcap | = 1UL < < i ;
2010-10-25 16:10:51 +02:00
if ( test_facility ( 22 ) & & test_facility ( 30 ) )
2009-10-06 10:34:13 +02:00
elf_hwcap | = HWCAP_S390_ETF3EH ;
2009-03-26 15:24:56 +01:00
2007-05-04 18:48:28 +02:00
/*
* Check for additional facilities with store - facility - list - extended .
* stfle stores doublewords ( 8 byte ) with bit 1ULL < < 63 as bit 0
* and 1ULL < < 0 as bit 63. Bits 0 - 31 contain the same information
* as stored by stfl , bits 32 - xxx contain additional facilities .
* How many facility words are stored depends on the number of
2011-03-30 22:57:33 -03:00
* doublewords passed to the instruction . The additional facilities
2007-05-04 18:48:28 +02:00
* are :
2009-03-26 15:24:54 +01:00
* Bit 42 : decimal floating point facility is installed
* Bit 44 : perform floating point operation facility is installed
2007-05-04 18:48:28 +02:00
* translated to :
2009-03-26 15:24:56 +01:00
* HWCAP_S390_DFP bit 6 ( 42 & & 44 ) .
2007-05-04 18:48:28 +02:00
*/
2010-10-25 16:10:51 +02:00
if ( ( elf_hwcap & ( 1UL < < 2 ) ) & & test_facility ( 42 ) & & test_facility ( 44 ) )
elf_hwcap | = HWCAP_S390_DFP ;
2007-05-04 18:48:28 +02:00
2009-10-06 10:34:13 +02:00
/*
* Huge page support HWCAP_S390_HPAGE is bit 7.
*/
2008-04-30 13:38:46 +02:00
if ( MACHINE_HAS_HPAGE )
2009-10-06 10:34:13 +02:00
elf_hwcap | = HWCAP_S390_HPAGE ;
/*
* 64 - bit register support for 31 - bit processes
* HWCAP_S390_HIGH_GPRS is bit 9.
*/
elf_hwcap | = HWCAP_S390_HIGH_GPRS ;
2008-04-30 13:38:46 +02:00
2010-05-17 10:00:00 +02:00
get_cpu_id ( & cpu_id ) ;
switch ( cpu_id . machine ) {
2007-05-04 18:48:28 +02:00
case 0x9672 :
# if !defined(CONFIG_64BIT)
default : /* Use "g5" as default for 31 bit kernels. */
# endif
strcpy ( elf_platform , " g5 " ) ;
break ;
case 0x2064 :
case 0x2066 :
# if defined(CONFIG_64BIT)
default : /* Use "z900" as default for 64 bit kernels. */
# endif
strcpy ( elf_platform , " z900 " ) ;
break ;
case 0x2084 :
case 0x2086 :
strcpy ( elf_platform , " z990 " ) ;
break ;
case 0x2094 :
2008-12-25 13:39:22 +01:00
case 0x2096 :
2007-05-04 18:48:28 +02:00
strcpy ( elf_platform , " z9-109 " ) ;
break ;
2008-12-25 13:39:22 +01:00
case 0x2097 :
case 0x2098 :
strcpy ( elf_platform , " z10 " ) ;
break ;
2010-10-29 16:50:35 +02:00
case 0x2817 :
2011-08-03 16:44:24 +02:00
case 0x2818 :
2010-10-29 16:50:35 +02:00
strcpy ( elf_platform , " z196 " ) ;
break ;
2007-05-04 18:48:28 +02:00
}
}
2005-05-01 08:58:57 -07:00
/*
* Setup function called from init / main . c just after the banner
* was printed .
*/
2005-04-16 15:20:36 -07:00
2012-03-11 11:59:26 -04:00
void __init setup_arch ( char * * cmdline_p )
2005-05-01 08:58:57 -07:00
{
2005-04-16 15:20:36 -07:00
/*
2005-05-01 08:58:57 -07:00
* print what head . S has found out about the machine
2005-04-16 15:20:36 -07:00
*/
2006-01-06 00:19:28 -08:00
# ifndef CONFIG_64BIT
2008-12-25 13:39:40 +01:00
if ( MACHINE_IS_VM )
pr_info ( " Linux is running as a z/VM "
" guest operating system in 31-bit mode \n " ) ;
2010-02-26 22:37:38 +01:00
else if ( MACHINE_IS_LPAR )
2008-12-25 13:39:40 +01:00
pr_info ( " Linux is running natively in 31-bit mode \n " ) ;
if ( MACHINE_HAS_IEEE )
pr_info ( " The hardware system has IEEE compatible "
" floating point units \n " ) ;
else
pr_info ( " The hardware system has no IEEE compatible "
" floating point units \n " ) ;
2006-01-06 00:19:28 -08:00
# else /* CONFIG_64BIT */
2008-03-25 18:47:44 +01:00
if ( MACHINE_IS_VM )
2008-12-25 13:39:40 +01:00
pr_info ( " Linux is running as a z/VM "
" guest operating system in 64-bit mode \n " ) ;
2009-08-23 18:09:06 +02:00
else if ( MACHINE_IS_KVM )
2008-12-25 13:39:40 +01:00
pr_info ( " Linux is running under KVM in 64-bit mode \n " ) ;
2010-02-26 22:37:38 +01:00
else if ( MACHINE_IS_LPAR )
2008-12-25 13:39:40 +01:00
pr_info ( " Linux is running natively in 64-bit mode \n " ) ;
2006-01-06 00:19:28 -08:00
# endif /* CONFIG_64BIT */
2005-05-01 08:58:57 -07:00
2008-07-14 09:59:09 +02:00
/* Have one command line that is parsed and saved in /proc/cmdline */
/* boot_command_line has been already set up in early.c */
* cmdline_p = boot_command_line ;
2006-03-24 03:15:15 -08:00
2005-05-01 08:58:57 -07:00
ROOT_DEV = Root_RAM0 ;
2006-03-24 03:15:15 -08:00
init_mm . start_code = PAGE_OFFSET ;
init_mm . end_code = ( unsigned long ) & _etext ;
init_mm . end_data = ( unsigned long ) & _edata ;
init_mm . brk = ( unsigned long ) & _end ;
2006-09-20 15:59:44 +02:00
if ( MACHINE_HAS_MVCOS )
memcpy ( & uaccess , & uaccess_mvcos , sizeof ( uaccess ) ) ;
else
memcpy ( & uaccess , & uaccess_std , sizeof ( uaccess ) ) ;
2006-03-24 03:15:15 -08:00
parse_early_param ( ) ;
2008-01-26 14:11:11 +01:00
setup_ipl ( ) ;
2006-12-04 15:40:56 +01:00
setup_memory_end ( ) ;
2007-02-05 21:18:17 +01:00
setup_addressing_mode ( ) ;
2011-10-30 15:16:40 +01:00
reserve_oldmem ( ) ;
reserve_crashkernel ( ) ;
2005-05-01 08:58:57 -07:00
setup_memory ( ) ;
setup_resources ( ) ;
2011-10-30 15:16:42 +01:00
setup_vmcoreinfo ( ) ;
2005-05-01 08:58:57 -07:00
setup_lowcore ( ) ;
2005-04-16 15:20:36 -07:00
cpu_init ( ) ;
2008-04-17 07:46:12 +02:00
s390_init_cpu_topology ( ) ;
2005-04-16 15:20:36 -07:00
2007-05-04 18:48:28 +02:00
/*
* Setup capabilities ( ELF_HWCAP & ELF_PLATFORM ) .
*/
setup_hwcaps ( ) ;
2005-04-16 15:20:36 -07:00
/*
* Create kernel page tables and switch to virtual addressing .
*/
paging_init ( ) ;
/* Setup default console */
conmode_default ( ) ;
2009-08-23 18:09:06 +02:00
set_preferred_console ( ) ;
2007-04-27 16:01:49 +02:00
/* Setup zfcpdump support */
setup_zfcpdump ( console_devno ) ;
2005-04-16 15:20:36 -07:00
}