2008-05-20 03:53:02 +04:00
/*
2005-04-17 02:20:36 +04:00
* linux / arch / sparc / kernel / setup . c
*
* Copyright ( C ) 1995 David S . Miller ( davem @ caip . rutgers . edu )
* Copyright ( C ) 2000 Anton Blanchard ( anton @ samba . org )
*/
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/stddef.h>
# include <linux/unistd.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/initrd.h>
# include <asm/smp.h>
# include <linux/user.h>
2006-07-10 15:44:13 +04:00
# include <linux/screen_info.h>
2005-04-17 02:20:36 +04:00
# include <linux/delay.h>
# include <linux/fs.h>
# include <linux/seq_file.h>
# include <linux/syscalls.h>
# include <linux/kdev_t.h>
# include <linux/major.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/console.h>
# include <linux/spinlock.h>
# include <linux/root_dev.h>
2006-06-20 11:28:33 +04:00
# include <linux/cpu.h>
2007-05-08 11:27:03 +04:00
# include <linux/kdebug.h>
2011-07-18 23:57:46 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/processor.h>
# include <asm/oplib.h>
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/traps.h>
# include <asm/vaddrs.h>
# include <asm/mbus.h>
# include <asm/idprom.h>
# include <asm/machines.h>
# include <asm/cpudata.h>
# include <asm/setup.h>
2012-03-28 21:30:03 +04:00
# include <asm/cacheflush.h>
2005-04-17 02:20:36 +04:00
2008-12-07 11:02:08 +03:00
# include "kernel.h"
2005-04-17 02:20:36 +04:00
struct screen_info screen_info = {
0 , 0 , /* orig-x, orig-y */
0 , /* unused */
0 , /* orig-video-page */
0 , /* orig-video-mode */
128 , /* orig-video-cols */
0 , 0 , 0 , /* ega_ax, ega_bx, ega_cx */
54 , /* orig-video-lines */
0 , /* orig-video-isVGA */
16 /* orig-video-points */
} ;
/* Typing sync at the prom prompt calls the function pointed to by
* romvec - > pv_synchook which I set to the following function .
* This should sync all filesystems and return , for now it just
* prints out pretty messages and returns .
*/
extern unsigned long trapbase ;
/* Pretty sick eh? */
2008-06-05 22:40:58 +04:00
static void prom_sync_me ( void )
2005-04-17 02:20:36 +04:00
{
unsigned long prom_tbr , flags ;
/* XXX Badly broken. FIX! - Anton */
local_irq_save ( flags ) ;
__asm__ __volatile__ ( " rd %%tbr, %0 \n \t " : " =r " ( prom_tbr ) ) ;
__asm__ __volatile__ ( " wr %0, 0x0, %%tbr \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " : : " r " ( & trapbase ) ) ;
prom_printf ( " PROM SYNC COMMAND... \n " ) ;
2011-05-25 04:11:16 +04:00
show_free_areas ( 0 ) ;
2011-11-11 03:56:46 +04:00
if ( ! is_idle_task ( current ) ) {
2005-04-17 02:20:36 +04:00
local_irq_enable ( ) ;
sys_sync ( ) ;
local_irq_disable ( ) ;
}
prom_printf ( " Returning to prom \n " ) ;
__asm__ __volatile__ ( " wr %0, 0x0, %%tbr \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " : : " r " ( prom_tbr ) ) ;
local_irq_restore ( flags ) ;
}
2008-06-05 22:40:58 +04:00
static unsigned int boot_flags __initdata = 0 ;
2005-04-17 02:20:36 +04:00
# define BOOTME_DEBUG 0x1
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size __initdata = 0 ;
2011-04-21 08:20:23 +04:00
/* which CPU booted us (0xff = not set) */
unsigned char boot_cpu_id = 0xff ; /* 0xff will make it into DATA section... */
unsigned char boot_cpu_id4 ; /* boot_cpu_id << 2 */
2005-04-17 02:20:36 +04:00
static void
prom_console_write ( struct console * con , const char * s , unsigned n )
{
prom_write ( s , n ) ;
}
2011-04-22 02:47:35 +04:00
static struct console prom_early_console = {
. name = " earlyprom " ,
2005-04-17 02:20:36 +04:00
. write = prom_console_write ,
2011-04-22 02:47:35 +04:00
. flags = CON_PRINTBUFFER | CON_BOOT ,
2005-04-17 02:20:36 +04:00
. index = - 1 ,
} ;
/*
* Process kernel command line switches that are specific to the
* SPARC or that require special low - level processing .
*/
static void __init process_switch ( char c )
{
switch ( c ) {
case ' d ' :
boot_flags | = BOOTME_DEBUG ;
break ;
case ' s ' :
break ;
case ' h ' :
prom_printf ( " boot_flags_init: Halt! \n " ) ;
prom_halt ( ) ;
break ;
case ' p ' :
2011-09-21 23:48:06 +04:00
prom_early_console . flags & = ~ CON_BOOT ;
2005-04-17 02:20:36 +04:00
break ;
default :
printk ( " Unknown boot switch (-%c) \n " , c ) ;
break ;
}
}
static void __init boot_flags_init ( char * commands )
{
while ( * commands ) {
/* Move to the start of the next "argument". */
while ( * commands & & * commands = = ' ' )
commands + + ;
/* Process any command switches, otherwise skip it. */
if ( * commands = = ' \0 ' )
break ;
if ( * commands = = ' - ' ) {
commands + + ;
while ( * commands & & * commands ! = ' ' )
process_switch ( * commands + + ) ;
continue ;
}
2007-07-21 03:59:26 +04:00
if ( ! strncmp ( commands , " mem= " , 4 ) ) {
2005-04-17 02:20:36 +04:00
/*
* " mem=XXX[kKmM] overrides the PROM-reported
* memory size .
*/
cmdline_memory_size = simple_strtoul ( commands + 4 ,
& commands , 0 ) ;
if ( * commands = = ' K ' | | * commands = = ' k ' ) {
cmdline_memory_size < < = 10 ;
commands + + ;
} else if ( * commands = = ' M ' | | * commands = = ' m ' ) {
cmdline_memory_size < < = 20 ;
commands + + ;
}
}
while ( * commands & & * commands ! = ' ' )
commands + + ;
}
}
extern unsigned short root_flags ;
extern unsigned short root_dev ;
extern unsigned short ram_flags ;
# define RAMDISK_IMAGE_START_MASK 0x07FF
# define RAMDISK_PROMPT_FLAG 0x8000
# define RAMDISK_LOAD_FLAG 0x4000
extern int root_mountflags ;
char reboot_command [ COMMAND_LINE_SIZE ] ;
2009-01-09 03:58:05 +03:00
2005-04-17 02:20:36 +04:00
enum sparc_cpu sparc_cpu_model ;
2009-01-09 03:58:05 +03:00
EXPORT_SYMBOL ( sparc_cpu_model ) ;
2005-04-17 02:20:36 +04:00
struct tt_entry * sparc_ttable ;
struct pt_regs fake_swapper_regs ;
void __init setup_arch ( char * * cmdline_p )
{
int i ;
unsigned long highest_paddr ;
2011-01-04 14:39:11 +03:00
sparc_ttable = ( struct tt_entry * ) & trapbase ;
2005-04-17 02:20:36 +04:00
/* Initialize PROM console and command line. */
* cmdline_p = prom_getbootargs ( ) ;
2007-02-12 11:54:21 +03:00
strcpy ( boot_command_line , * cmdline_p ) ;
2008-09-11 10:40:32 +04:00
parse_early_param ( ) ;
2005-04-17 02:20:36 +04:00
2011-04-22 02:47:35 +04:00
boot_flags_init ( * cmdline_p ) ;
register_console ( & prom_early_console ) ;
2005-04-17 02:20:36 +04:00
/* Set sparc_cpu_model */
sparc_cpu_model = sun_unknown ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4 " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4 ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4c " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4c ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4m " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4m ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4s " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4m ; /* CP-1200 with PROM 2.30 -E */
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4d " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4d ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4e " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4e ;
2011-01-29 01:08:18 +03:00
if ( ! strcmp ( & cputypval [ 0 ] , " sun4u " ) )
2008-09-02 12:13:31 +04:00
sparc_cpu_model = sun4u ;
2011-01-29 01:08:18 +03:00
if ( ! strncmp ( & cputypval [ 0 ] , " leon " , 4 ) )
2009-08-17 04:13:31 +04:00
sparc_cpu_model = sparc_leon ;
2005-04-17 02:20:36 +04:00
printk ( " ARCH: " ) ;
switch ( sparc_cpu_model ) {
case sun4 :
printk ( " SUN4 \n " ) ;
break ;
case sun4c :
printk ( " SUN4C \n " ) ;
break ;
case sun4m :
printk ( " SUN4M \n " ) ;
break ;
case sun4d :
printk ( " SUN4D \n " ) ;
break ;
case sun4e :
printk ( " SUN4E \n " ) ;
break ;
case sun4u :
printk ( " SUN4U \n " ) ;
break ;
2009-08-17 04:13:31 +04:00
case sparc_leon :
printk ( " LEON \n " ) ;
break ;
2005-04-17 02:20:36 +04:00
default :
printk ( " UNKNOWN! \n " ) ;
break ;
2011-06-03 18:45:23 +04:00
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_DUMMY_CONSOLE
conswitchp = & dummy_con ;
# endif
idprom_init ( ) ;
load_mmu ( ) ;
phys_base = 0xffffffffUL ;
highest_paddr = 0UL ;
for ( i = 0 ; sp_banks [ i ] . num_bytes ! = 0 ; i + + ) {
unsigned long top ;
if ( sp_banks [ i ] . base_addr < phys_base )
phys_base = sp_banks [ i ] . base_addr ;
top = sp_banks [ i ] . base_addr +
sp_banks [ i ] . num_bytes ;
if ( highest_paddr < top )
highest_paddr = top ;
}
pfn_base = phys_base > > PAGE_SHIFT ;
if ( ! root_flags )
root_mountflags & = ~ MS_RDONLY ;
ROOT_DEV = old_decode_dev ( root_dev ) ;
2006-06-23 01:47:14 +04:00
# ifdef CONFIG_BLK_DEV_RAM
2005-04-17 02:20:36 +04:00
rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK ;
rd_prompt = ( ( ram_flags & RAMDISK_PROMPT_FLAG ) ! = 0 ) ;
rd_doload = ( ( ram_flags & RAMDISK_LOAD_FLAG ) ! = 0 ) ;
# endif
prom_setsync ( prom_sync_me ) ;
if ( ( boot_flags & BOOTME_DEBUG ) & & ( linux_dbvec ! = 0 ) & &
( ( * ( short * ) linux_dbvec ) ! = - 1 ) ) {
printk ( " Booted under KADB. Syncing trap table. \n " ) ;
( * ( linux_dbvec - > teach_debugger ) ) ( ) ;
}
init_mm . context = ( unsigned long ) NO_CONTEXT ;
init_task . thread . kregs = & fake_swapper_regs ;
paging_init ( ) ;
2006-08-25 11:46:02 +04:00
smp_setup_cpu_possible_map ( ) ;
2005-04-17 02:20:36 +04:00
}
extern int stop_a_enabled ;
void sun_do_break ( void )
{
if ( ! stop_a_enabled )
return ;
printk ( " \n " ) ;
flush_user_windows ( ) ;
prom_cmdline ( ) ;
}
2009-01-09 03:58:05 +03:00
EXPORT_SYMBOL ( sun_do_break ) ;
2005-04-17 02:20:36 +04:00
int stop_a_enabled = 1 ;
2006-06-20 11:28:33 +04:00
static int __init topology_init ( void )
{
int i , ncpus , err ;
/* Count the number of physically present processors in
* the machine , even on uniprocessor , so that / proc / cpuinfo
* output is consistent with 2.4 . x
*/
ncpus = 0 ;
while ( ! cpu_find_by_instance ( ncpus , NULL , NULL ) )
ncpus + + ;
ncpus_probed = ncpus ;
err = 0 ;
for_each_online_cpu ( i ) {
struct cpu * p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
if ( ! p )
err = - ENOMEM ;
else
2006-06-29 13:24:27 +04:00
register_cpu ( p , i ) ;
2006-06-20 11:28:33 +04:00
}
return err ;
}
subsys_initcall ( topology_init ) ;