2005-04-16 15:20:36 -07:00
/*
* S390 version
2012-07-20 11:15:04 +02:00
* Copyright 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>
2013-01-07 13:56:17 +01:00
# include <linux/export.h>
2005-04-16 15:20:36 -07:00
# 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>
2014-08-11 12:20:58 +02:00
# include <linux/random.h>
2005-04-16 15:20:36 -07:00
# 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>
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>
2012-03-30 09:40:55 +02:00
# include <asm/facility.h>
2005-04-16 15:20:36 -07:00
# 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:34 -04:00
# include <asm/os_info.h>
2012-06-11 16:06:59 +02:00
# include <asm/sclp.h>
2014-08-11 12:20:58 +02:00
# include <asm/sysinfo.h>
2014-03-06 18:25:13 +01:00
# include <asm/numa.h>
2012-03-11 11:59:26 -04:00
# include "entry.h"
2007-02-05 21:18:17 +01: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 ) ;
2015-02-19 12:22:02 +01:00
unsigned long elf_hwcap __read_mostly = 0 ;
2007-05-04 18:48:28 +02:00
char elf_platform [ ELF_PLATFORM_SIZE ] ;
2006-12-04 15:40:38 +01:00
2015-02-24 15:54:47 +01:00
unsigned long int_hwcap = 0 ;
2009-02-19 15:19:01 +01:00
int __initdata memory_end_set ;
unsigned long __initdata memory_end ;
2014-01-29 18:16:01 +01:00
unsigned long __initdata max_physmem_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 ) ;
2012-10-05 16:52:18 +02:00
unsigned long MODULES_VADDR ;
unsigned long MODULES_END ;
2009-03-26 15:23:43 +01:00
/* An array with a pointer to the lowcore of every CPU. */
2015-12-31 10:29:00 +01:00
struct lowcore * lowcore_ptr [ NR_CPUS ] ;
2009-03-26 15:23:43 +01:00
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 )
{
2012-06-11 16:06:59 +02:00
if ( MACHINE_IS_KVM ) {
2015-05-06 13:18:59 +02:00
if ( sclp . has_vt220 )
2012-06-11 16:06:59 +02:00
add_preferred_console ( " ttyS " , 1 , NULL ) ;
2015-05-06 13:18:59 +02:00
else if ( sclp . has_linemode )
2012-06-11 16:06:59 +02:00
add_preferred_console ( " ttyS " , 0 , NULL ) ;
else
add_preferred_console ( " hvc " , 0 , NULL ) ;
} 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
}
}
2014-04-14 10:38:05 +02:00
# ifdef CONFIG_CRASH_DUMP
2013-04-30 17:18:46 +02:00
static void __init setup_zfcpdump ( void )
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 ;
2013-04-30 17:18:46 +02:00
strcat ( boot_command_line , " cio_ignore=all,!ipldev,!condev " ) ;
2007-04-27 16:01:49 +02:00
console_loglevel = 2 ;
}
# else
2013-04-30 17:18:46 +02:00
static inline void setup_zfcpdump ( void ) { }
2014-04-14 10:38:05 +02:00
# endif /* CONFIG_CRASH_DUMP */
2007-04-27 16:01:49 +02:00
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 ;
2013-01-07 13:56:17 +01:00
EXPORT_SYMBOL_GPL ( pm_power_off ) ;
2006-01-14 13:21:01 -08:00
2006-03-24 03:15:15 -08:00
static int __init early_parse_mem ( char * p )
{
memory_end = memparse ( p , & p ) ;
2014-01-29 18:16:01 +01:00
memory_end & = PAGE_MASK ;
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 ) ;
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
{
2015-12-31 10:29:00 +01:00
struct lowcore * lc ;
2005-05-01 08:58:57 -07:00
/*
* Setup lowcore for boot cpu
*/
2015-12-31 10:29:00 +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 ) ;
2013-09-24 09:14:56 +02:00
lc - > restart_psw . mask = PSW_KERNEL_BITS ;
2016-01-18 12:49:44 +01:00
lc - > restart_psw . addr = ( unsigned long ) restart_int_handler ;
2013-09-24 09:14:56 +02:00
lc - > external_new_psw . mask = PSW_KERNEL_BITS |
2011-10-30 15:16:50 +01:00
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2016-01-18 12:49:44 +01:00
lc - > external_new_psw . addr = ( unsigned long ) ext_int_handler ;
2013-09-24 09:14:56 +02:00
lc - > svc_new_psw . mask = PSW_KERNEL_BITS |
2011-10-30 15:16:50 +01:00
PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK ;
2016-01-18 12:49:44 +01:00
lc - > svc_new_psw . addr = ( unsigned long ) system_call ;
2013-09-24 09:14:56 +02:00
lc - > program_new_psw . mask = PSW_KERNEL_BITS |
2011-10-30 15:16:50 +01:00
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2016-01-18 12:49:44 +01:00
lc - > program_new_psw . addr = ( unsigned long ) pgm_check_handler ;
2013-09-24 09:14:56 +02:00
lc - > mcck_new_psw . mask = PSW_KERNEL_BITS ;
2016-01-18 12:49:44 +01:00
lc - > mcck_new_psw . addr = ( unsigned long ) mcck_int_handler ;
2013-09-24 09:14:56 +02:00
lc - > io_new_psw . mask = PSW_KERNEL_BITS |
2011-10-30 15:16:50 +01:00
PSW_MASK_DAT | PSW_MASK_MCHECK ;
2016-01-18 12:49:44 +01:00
lc - > io_new_psw . addr = ( unsigned long ) io_int_handler ;
2008-04-17 07:46:25 +02:00
lc - > clock_comparator = - 1ULL ;
2013-04-24 10:20:43 +02:00
lc - > kernel_stack = ( ( unsigned long ) & init_thread_union )
+ THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof ( struct pt_regs ) ;
2005-05-01 08:58:57 -07:00
lc - > async_stack = ( unsigned long )
2013-04-24 10:20:43 +02:00
__alloc_bootmem ( ASYNC_SIZE , ASYNC_SIZE , 0 )
+ ASYNC_SIZE - STACK_FRAME_OVERHEAD - sizeof ( struct pt_regs ) ;
2005-05-01 08:58:57 -07:00
lc - > panic_stack = ( unsigned long )
2013-04-24 10:20:43 +02:00
__alloc_bootmem ( PAGE_SIZE , PAGE_SIZE , 0 )
+ PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof ( struct pt_regs ) ;
2005-05-01 08:58:57 -07:00
lc - > current_task = ( unsigned long ) init_thread_union . thread_info . task ;
lc - > thread_info = ( unsigned long ) & init_thread_union ;
2016-03-10 10:32:21 +01:00
lc - > lpp = LPP_MAGIC ;
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 ) ;
2014-10-06 17:53:53 +02:00
if ( MACHINE_HAS_VX )
lc - > vector_save_area_addr =
( unsigned long ) & lc - > vector_save_area ;
2008-12-31 15:11:42 +01:00
lc - > vdso_per_cpu_data = ( unsigned long ) & lc - > paste [ 0 ] ;
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 ;
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
2013-12-13 12:53:42 +01:00
* restart data to the absolute zero lowcore . This is necessary if
2012-03-11 11:59:26 -04:00
* 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 ;
2012-05-24 14:35:16 +02:00
/* Setup absolute zero lowcore */
2012-06-05 09:59:52 +02:00
mem_assign_absolute ( S390_lowcore . restart_stack , lc - > restart_stack ) ;
mem_assign_absolute ( S390_lowcore . restart_fn , lc - > restart_fn ) ;
mem_assign_absolute ( S390_lowcore . restart_data , lc - > restart_data ) ;
mem_assign_absolute ( S390_lowcore . restart_source , lc - > restart_source ) ;
mem_assign_absolute ( S390_lowcore . restart_psw , lc - > restart_psw ) ;
2012-03-11 11:59:26 -04:00
2014-04-07 18:25:23 +02:00
# ifdef CONFIG_SMP
lc - > spinlock_lockval = arch_spin_lockval ( 0 ) ;
# endif
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 " ,
2016-01-26 21:57:22 +01:00
. flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM ,
2011-03-23 10:15:59 +01:00
} ;
static struct resource data_resource = {
. name = " Kernel data " ,
2016-01-26 21:57:22 +01:00
. flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM ,
2011-03-23 10:15:59 +01:00
} ;
2011-03-23 10:16:00 +01:00
static struct resource bss_resource = {
. name = " Kernel bss " ,
2016-01-26 21:57:22 +01:00
. flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM ,
2011-03-23 10:16:00 +01:00
} ;
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 ;
2014-01-29 18:16:01 +01:00
struct memblock_region * reg ;
int 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
2014-01-29 18:16:01 +01:00
for_each_memblock ( memory , reg ) {
2011-03-23 10:15:59 +01:00
res = alloc_bootmem_low ( sizeof ( * res ) ) ;
2016-01-26 21:57:22 +01:00
res - > flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM ;
2014-01-29 18:16:01 +01:00
res - > name = " System RAM " ;
res - > start = reg - > base ;
res - > end = reg - > base + reg - > 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
}
}
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 ;
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. */
2012-10-05 16:52:18 +02:00
vmalloc_size = VMALLOC_END ? : ( 128UL < < 30 ) - MODULES_LEN ;
2014-01-29 18:16:01 +01:00
tmp = ( memory_end ? : max_physmem_end ) / PAGE_SIZE ;
2014-09-26 09:23:20 +02:00
tmp = tmp * ( sizeof ( struct page ) + PAGE_SIZE ) ;
if ( tmp + vmalloc_size + MODULES_LEN < = ( 1UL < < 42 ) )
2011-12-27 11:27:07 +01:00
vmax = 1UL < < 42 ; /* 3-level kernel page table */
else
vmax = 1UL < < 53 ; /* 4-level kernel page table */
2012-10-05 16:52:18 +02:00
/* module area is at the end of the kernel address space. */
MODULES_END = vmax ;
MODULES_VADDR = MODULES_END - MODULES_LEN ;
VMALLOC_END = MODULES_VADDR ;
2011-12-27 11:27:07 +01:00
VMALLOC_START = vmax - vmalloc_size ;
/* Split remaining virtual space between 1:1 mapping & vmemmap array */
tmp = VMALLOC_START / ( PAGE_SIZE + sizeof ( struct page ) ) ;
2013-02-28 11:16:26 +01:00
/* vmemmap contains a multiple of PAGES_PER_SECTION struct pages */
tmp = SECTION_ALIGN_UP ( tmp ) ;
2011-12-27 11:27:07 +01:00
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 */
2014-01-29 18:16:01 +01:00
memory_end = min ( memory_end ? : max_physmem_end , tmp ) ;
max_pfn = max_low_pfn = PFN_DOWN ( memory_end ) ;
memblock_remove ( memory_end , ULONG_MAX ) ;
2006-12-04 15:40:56 +01:00
2014-01-29 18:16:01 +01:00
pr_notice ( " Max memory size: %luMB \n " , memory_end > > 20 ) ;
2006-12-04 15:40:56 +01:00
}
2011-10-30 15:16:42 +01:00
static void __init setup_vmcoreinfo ( void )
{
2012-06-05 09:59:52 +02:00
mem_assign_absolute ( S390_lowcore . vmcore_info , paddr_vmcoreinfo_note ( ) ) ;
2011-10-30 15:16:42 +01:00
}
2011-10-30 15:16:40 +01:00
# ifdef CONFIG_CRASH_DUMP
/*
* 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 ;
2014-07-10 18:14:20 +02:00
if ( action ! = MEM_GOING_OFFLINE )
return NOTIFY_OK ;
2011-10-30 15:16:40 +01:00
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
2014-01-29 18:16:01 +01:00
/*
* Make sure that the area behind memory_end is protected
*/
static void reserve_memory_end ( void )
{
2014-04-14 10:38:05 +02:00
# ifdef CONFIG_CRASH_DUMP
2014-01-29 18:16:01 +01:00
if ( ipl_info . type = = IPL_TYPE_FCP_DUMP & &
2015-05-06 13:18:59 +02:00
! OLDMEM_BASE & & sclp . hsa_size ) {
memory_end = sclp . hsa_size ;
2014-01-29 18:16:01 +01:00
memory_end & = PAGE_MASK ;
memory_end_set = 1 ;
}
# endif
if ( ! memory_end_set )
return ;
memblock_reserve ( memory_end , ULONG_MAX ) ;
}
2011-10-30 15:16:40 +01:00
/*
* Make sure that oldmem , where the dump is stored , is protected
*/
static void reserve_oldmem ( void )
{
# ifdef CONFIG_CRASH_DUMP
2014-01-29 18:16:01 +01:00
if ( OLDMEM_BASE )
/* Forget all memory above the running kdump system */
memblock_reserve ( OLDMEM_SIZE , ( phys_addr_t ) ULONG_MAX ) ;
# endif
}
2011-10-30 15:16:40 +01:00
2014-01-29 18:16:01 +01:00
/*
* Make sure that oldmem , where the dump is stored , is protected
*/
static void remove_oldmem ( void )
{
# ifdef CONFIG_CRASH_DUMP
if ( OLDMEM_BASE )
/* Forget all memory above the running kdump system */
memblock_remove ( OLDMEM_SIZE , ( phys_addr_t ) ULONG_MAX ) ;
2011-10-30 15:16:40 +01:00
# 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 ;
2014-01-29 18:16:01 +01:00
phys_addr_t low , high ;
2011-10-30 15:16:40 +01:00
int rc ;
rc = parse_crashkernel ( boot_command_line , memory_end , & crash_size ,
& crash_base ) ;
2014-01-29 18:16:01 +01:00
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 ) ;
2014-01-29 18:16:01 +01:00
if ( rc | | crash_size = = 0 )
2011-10-30 15:16:40 +01:00
return ;
2014-01-29 18:16:01 +01:00
if ( memblock . memory . regions [ 0 ] . size < crash_size ) {
pr_info ( " crashkernel reservation failed: %s \n " ,
" first memory chunk must be at least crashkernel size " ) ;
2011-10-30 15:16:40 +01:00
return ;
}
2014-01-29 18:16:01 +01:00
low = crash_base ? : OLDMEM_BASE ;
high = low + crash_size ;
if ( low > = OLDMEM_BASE & & high < = OLDMEM_BASE + OLDMEM_SIZE ) {
/* The crashkernel fits into OLDMEM, reuse OLDMEM */
crash_base = low ;
} else {
/* Find suitable area in free memory */
2015-05-06 13:18:59 +02:00
low = max_t ( unsigned long , crash_size , sclp . hsa_size ) ;
2014-01-29 18:16:01 +01:00
high = crash_base ? crash_base + crash_size : ULONG_MAX ;
if ( crash_base & & crash_base < low ) {
pr_info ( " crashkernel reservation failed: %s \n " ,
" crash_base too low " ) ;
return ;
}
low = crash_base ? : low ;
crash_base = memblock_find_in_range ( low , high , crash_size ,
KEXEC_CRASH_MEM_ALIGN ) ;
}
if ( ! crash_base ) {
pr_info ( " crashkernel reservation failed: %s \n " ,
" no suitable area found " ) ;
2011-10-30 15:16:40 +01:00
return ;
}
2014-01-29 18:16:01 +01:00
if ( register_memory_notifier ( & kdump_mem_nb ) )
return ;
2011-10-30 15:16:40 +01:00
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 ) ;
2014-01-29 18:16:01 +01:00
memblock_remove ( crash_base , crash_size ) ;
2011-10-30 15:16:40 +01:00
pr_info ( " Reserving %lluMB of memory at %lluMB "
" for crashkernel (System RAM: %luMB) \n " ,
2014-01-29 18:16:01 +01:00
crash_size > > 20 , crash_base > > 20 ,
( unsigned long ) memblock . memory . total_size > > 20 ) ;
2012-03-11 11:59:34 -04:00
os_info_crashkernel_add ( crash_base , crash_size ) ;
2011-10-30 15:16:40 +01:00
# endif
}
2014-01-29 18:16:01 +01:00
/*
* Reserve the initrd from being used by memblock
*/
static void __init reserve_initrd ( void )
2005-05-01 08:58:57 -07:00
{
2014-01-29 18:16:01 +01:00
# ifdef CONFIG_BLK_DEV_INITRD
initrd_start = INITRD_START ;
initrd_end = initrd_start + INITRD_SIZE ;
memblock_reserve ( INITRD_START , INITRD_SIZE ) ;
# endif
}
2005-04-16 15:20:36 -07:00
2014-01-29 18:16:01 +01:00
/*
* Check for initrd being in usable memory
*/
static void __init check_initrd ( void )
{
# ifdef CONFIG_BLK_DEV_INITRD
if ( INITRD_START & & INITRD_SIZE & &
! memblock_is_region_memory ( INITRD_START , INITRD_SIZE ) ) {
pr_err ( " initrd does not fit memory. \n " ) ;
memblock_free ( INITRD_START , INITRD_SIZE ) ;
initrd_start = initrd_end = 0 ;
}
# endif
}
/*
2015-06-16 14:03:37 +02:00
* Reserve memory used for lowcore / command line / kernel image .
2014-01-29 18:16:01 +01:00
*/
static void __init reserve_kernel ( void )
{
2015-06-16 14:03:37 +02:00
unsigned long start_pfn = PFN_UP ( __pa ( & _end ) ) ;
2005-04-16 15:20:36 -07:00
2015-06-16 14:03:37 +02:00
# ifdef CONFIG_DMA_API_DEBUG
2006-09-20 15:58:41 +02:00
/*
2015-06-16 14:03:37 +02:00
* DMA_API_DEBUG code stumbles over addresses from the
* range [ _ehead , _stext ] . Mark the memory as reserved
* so it is not used for CONFIG_DMA_API_DEBUG = y .
2006-09-20 15:58:41 +02:00
*/
2015-06-16 14:03:37 +02:00
memblock_reserve ( 0 , PFN_PHYS ( start_pfn ) ) ;
# else
2014-01-29 18:16:01 +01:00
memblock_reserve ( 0 , ( unsigned long ) _ehead ) ;
memblock_reserve ( ( unsigned long ) _stext , PFN_PHYS ( start_pfn )
- ( unsigned long ) _stext ) ;
2015-06-16 14:03:37 +02:00
# endif
2014-01-29 18:16:01 +01:00
}
2006-09-20 15:58:41 +02:00
2014-01-29 18:16:01 +01:00
static void __init setup_memory ( void )
{
struct memblock_region * reg ;
2005-04-16 15:20:36 -07:00
/*
2014-01-29 18:16:01 +01:00
* Init storage key for present memory
2005-04-16 15:20:36 -07:00
*/
2014-01-29 18:16:01 +01:00
for_each_memblock ( memory , reg ) {
storage_key_init_range ( reg - > base , reg - > base + reg - > size ) ;
2005-04-16 15:20:36 -07:00
}
2005-05-01 08:58:58 -07:00
psw_set_key ( PAGE_DEFAULT_KEY ) ;
2014-01-29 18:16:01 +01:00
/* Only cosmetics */
memblock_enforce_memory_limit ( memblock_end_of_DRAM ( ) ) ;
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 .
*/
2015-08-14 13:20:28 +02:00
static int __init setup_hwcaps ( void )
2007-05-04 18:48:28 +02:00
{
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 ;
2012-07-31 11:03:04 +02:00
/*
* Transactional execution support HWCAP_S390_TE is bit 10.
*/
if ( test_facility ( 50 ) & & test_facility ( 73 ) )
elf_hwcap | = HWCAP_S390_TE ;
2014-10-06 17:53:53 +02:00
/*
2015-08-14 13:20:28 +02:00
* Vector extension HWCAP_S390_VXRS is bit 11. The Vector extension
* can be disabled with the " novx " parameter . Use MACHINE_HAS_VX
* instead of facility bit 129.
2014-10-06 17:53:53 +02:00
*/
2015-08-14 13:20:28 +02:00
if ( MACHINE_HAS_VX )
2014-10-06 17:53:53 +02:00
elf_hwcap | = HWCAP_S390_VXRS ;
2010-05-17 10:00:00 +02:00
get_cpu_id ( & cpu_id ) ;
2014-08-11 12:20:58 +02:00
add_device_randomness ( & cpu_id , sizeof ( cpu_id ) ) ;
2010-05-17 10:00:00 +02:00
switch ( cpu_id . machine ) {
2007-05-04 18:48:28 +02:00
case 0x2064 :
case 0x2066 :
default : /* Use "z900" as default for 64 bit kernels. */
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 ;
2012-11-13 10:26:37 +02:00
case 0x2827 :
2013-07-24 10:35:33 +02:00
case 0x2828 :
2012-11-13 10:26:37 +02:00
strcpy ( elf_platform , " zEC12 " ) ;
break ;
2015-01-14 17:50:19 +01:00
case 0x2964 :
2016-02-19 10:46:08 +01:00
case 0x2965 :
2015-01-14 17:50:19 +01:00
strcpy ( elf_platform , " z13 " ) ;
break ;
2007-05-04 18:48:28 +02:00
}
2015-02-24 15:54:47 +01:00
/*
* Virtualization support HWCAP_INT_SIE is bit 0.
*/
if ( sclp . has_sief2 )
int_hwcap | = HWCAP_INT_SIE ;
2015-08-14 13:20:28 +02:00
return 0 ;
2007-05-04 18:48:28 +02:00
}
2015-08-14 13:20:28 +02:00
arch_initcall ( setup_hwcaps ) ;
2007-05-04 18:48:28 +02:00
2014-08-11 12:20:58 +02:00
/*
* Add system information as device randomness
*/
static void __init setup_randomness ( void )
{
struct sysinfo_3_2_2 * vmms ;
vmms = ( struct sysinfo_3_2_2 * ) alloc_page ( GFP_KERNEL ) ;
if ( vmms & & stsi ( vmms , 3 , 2 , 2 ) = = 0 & & vmms - > count )
add_device_randomness ( & vmms , vmms - > count ) ;
free_page ( ( unsigned long ) vmms ) ;
}
2016-04-01 15:42:15 +02:00
/*
* Find the correct size for the task_struct . This depends on
* the size of the struct fpu at the end of the thread_struct
* which is embedded in the task_struct .
*/
static void __init setup_task_size ( void )
{
int task_size = sizeof ( struct task_struct ) ;
if ( ! MACHINE_HAS_VX ) {
task_size - = sizeof ( __vector128 ) * __NUM_VXRS ;
task_size + = sizeof ( freg_t ) * __NUM_FPRS ;
}
arch_task_struct_size = task_size ;
}
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
*/
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 " ) ;
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
2014-01-29 18:16:01 +01:00
/* Is init_mm really needed? */
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 ;
parse_early_param ( ) ;
2015-10-14 15:53:06 +02:00
# ifdef CONFIG_CRASH_DUMP
/* Deactivate elfcorehdr= kernel parameter */
elfcorehdr_addr = ELFCORE_ADDR_MAX ;
# endif
2012-03-11 11:59:34 -04:00
os_info_init ( ) ;
2008-01-26 14:11:11 +01:00
setup_ipl ( ) ;
2016-04-01 15:42:15 +02:00
setup_task_size ( ) ;
2014-01-29 18:16:01 +01:00
/* Do some memory reservations *before* memory is added to memblock */
reserve_memory_end ( ) ;
2013-04-30 09:36:23 +02:00
reserve_oldmem ( ) ;
2014-01-29 18:16:01 +01:00
reserve_kernel ( ) ;
reserve_initrd ( ) ;
memblock_allow_resize ( ) ;
/* Get information about *all* installed memory */
detect_memory_memblock ( ) ;
remove_oldmem ( ) ;
/*
* Make sure all chunks are MAX_ORDER aligned so we don ' t need the
* extra checks that HOLES_IN_ZONE would require .
*
* Is this still required ?
*/
memblock_trim_memory ( 1UL < < ( MAX_ORDER - 1 + PAGE_SHIFT ) ) ;
2006-12-04 15:40:56 +01:00
setup_memory_end ( ) ;
2005-05-01 08:58:57 -07:00
setup_memory ( ) ;
2014-01-29 18:16:01 +01:00
check_initrd ( ) ;
reserve_crashkernel ( ) ;
2015-10-29 10:28:26 +01:00
# ifdef CONFIG_CRASH_DUMP
2015-05-26 19:05:23 +02:00
/*
* Be aware that smp_save_dump_cpus ( ) triggers a system reset .
* Therefore CPU and device initialization should be done afterwards .
*/
smp_save_dump_cpus ( ) ;
2015-10-29 10:28:26 +01:00
# endif
2014-01-29 18:16:01 +01:00
2005-05-01 08:58:57 -07:00
setup_resources ( ) ;
2011-10-30 15:16:42 +01:00
setup_vmcoreinfo ( ) ;
2005-05-01 08:58:57 -07:00
setup_lowcore ( ) ;
2013-12-16 14:31:26 +01:00
smp_fill_possible_mask ( ) ;
2016-04-14 12:35:22 +02:00
cpu_detect_mhz_feature ( ) ;
2005-04-16 15:20:36 -07:00
cpu_init ( ) ;
2014-03-06 18:25:13 +01:00
numa_setup ( ) ;
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 */
2013-04-30 17:18:46 +02:00
setup_zfcpdump ( ) ;
2014-08-11 12:20:58 +02:00
/* Add system specific data to the random pool */
setup_randomness ( ) ;
2005-04-16 15:20:36 -07:00
}