2005-04-17 02:20:36 +04:00
/*
* Ported from IRIX to Linux by Kanoj Sarcar , 06 / 08 / 00.
* Copyright 2000 - 2001 Silicon Graphics , Inc .
* Copyright 2000 - 2001 Kanoj Sarcar ( kanoj @ sgi . com )
*/
# include <linux/init.h>
# include <linux/mmzone.h>
# include <linux/kernel.h>
# include <linux/nodemask.h>
# include <linux/string.h>
# include <asm/page.h>
# include <asm/sections.h>
# include <asm/smp.h>
# include <asm/sn/types.h>
# include <asm/sn/arch.h>
# include <asm/sn/gda.h>
# include <asm/sn/hub.h>
# include <asm/sn/mapped_kernel.h>
# include <asm/sn/sn_private.h>
static cpumask_t ktext_repmask ;
/*
* XXX - This needs to be much smarter about where it puts copies of the
* kernel . For example , we should never put a copy on a headless node ,
* and we should respect the topology of the machine .
*/
2006-10-11 21:35:33 +04:00
void __init setup_replication_mask ( void )
2005-04-17 02:20:36 +04:00
{
cnodeid_t cnode ;
/* Set only the master cnode's bit. The master cnode is always 0. */
cpus_clear ( ktext_repmask ) ;
cpu_set ( 0 , ktext_repmask ) ;
# ifdef CONFIG_REPLICATE_KTEXT
# ifndef CONFIG_MAPPED_KERNEL
# error Kernel replication works with mapped kernel support. No calias support.
# endif
for_each_online_node ( cnode ) {
if ( cnode = = 0 )
continue ;
/* Advertise that we have a copy of the kernel */
cpu_set ( cnode , ktext_repmask ) ;
}
# endif
/* Set up a GDA pointer to the replication mask. */
GDA - > g_ktext_repmask = & ktext_repmask ;
}
static __init void set_ktext_source ( nasid_t client_nasid , nasid_t server_nasid )
{
cnodeid_t client_cnode ;
kern_vars_t * kvp ;
client_cnode = NASID_TO_COMPACT_NODEID ( client_nasid ) ;
kvp = & hub_data ( client_nasid ) - > kern_vars ;
KERN_VARS_ADDR ( client_nasid ) = ( unsigned long ) kvp ;
kvp - > kv_magic = KV_MAGIC ;
kvp - > kv_ro_nasid = server_nasid ;
kvp - > kv_rw_nasid = master_nasid ;
kvp - > kv_ro_baseaddr = NODE_CAC_BASE ( server_nasid ) ;
kvp - > kv_rw_baseaddr = NODE_CAC_BASE ( master_nasid ) ;
printk ( " REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d \n " , client_nasid , server_nasid , master_nasid ) ;
}
/* XXX - When the BTE works, we should use it instead of this. */
static __init void copy_kernel ( nasid_t dest_nasid )
{
unsigned long dest_kern_start , source_start , source_end , kern_size ;
source_start = ( unsigned long ) _stext ;
source_end = ( unsigned long ) _etext ;
kern_size = source_end - source_start ;
dest_kern_start = CHANGE_ADDR_NASID ( MAPPED_KERN_RO_TO_K0 ( source_start ) ,
dest_nasid ) ;
memcpy ( ( void * ) dest_kern_start , ( void * ) source_start , kern_size ) ;
}
void __init replicate_kernel_text ( )
{
cnodeid_t cnode ;
nasid_t client_nasid ;
nasid_t server_nasid ;
server_nasid = master_nasid ;
/* Record where the master node should get its kernel text */
set_ktext_source ( master_nasid , master_nasid ) ;
for_each_online_node ( cnode ) {
if ( cnode = = 0 )
continue ;
client_nasid = COMPACT_TO_NASID_NODEID ( cnode ) ;
/* Check if this node should get a copy of the kernel */
if ( cpu_isset ( cnode , ktext_repmask ) ) {
server_nasid = client_nasid ;
copy_kernel ( server_nasid ) ;
}
/* Record where this node should get its kernel text */
set_ktext_source ( client_nasid , server_nasid ) ;
}
}
/*
* Return pfn of first free page of memory on a node . PROM may allocate
* data structures on the first couple of pages of the first slot of each
* node . If this is the case , getfirstfree ( node ) > getslotstart ( node , 0 ) .
*/
pfn_t node_getfirstfree ( cnodeid_t cnode )
{
unsigned long loadbase = REP_BASE ;
nasid_t nasid = COMPACT_TO_NASID_NODEID ( cnode ) ;
unsigned long offset ;
# ifdef CONFIG_MAPPED_KERNEL
loadbase + = 16777216 ;
# endif
offset = PAGE_ALIGN ( ( unsigned long ) ( & _end ) ) - loadbase ;
if ( ( cnode = = 0 ) | | ( cpu_isset ( cnode , ktext_repmask ) ) )
return ( TO_NODE ( nasid , offset ) > > PAGE_SHIFT ) ;
else
return ( KDM_TO_PHYS ( PAGE_ALIGN ( SYMMON_STK_ADDR ( nasid , 0 ) ) ) > >
PAGE_SHIFT ) ;
}