blob: 0f45af137ac98e320d3e8ddafd1de68028a8508f [file] [log] [blame]
/****************************************************************************/
/* ZEPTOOS:zepto-info */
/* This file is part of ZeptoOS: The Small Linux for Big Computers.
* See www.mcs.anl.gov/zeptoos for more information.
*/
/* ZEPTOOS:zepto-info */
/* */
/* ZEPTOOS:zepto-fillin */
/* $Id: $
* ZeptoOS_Version: 2.0
* ZeptoOS_Heredity: FOSS_ORIG
* ZeptoOS_License: GPL
*/
/* ZEPTOOS:zepto-fillin */
/* */
/* ZEPTOOS:zepto-gpl */
/* Copyright: Argonne National Laboratory, Department of Energy,
* and UChicago Argonne, LLC. 2004, 2005, 2006, 2007, 2008
* ZeptoOS License: GPL
*
* This software is free. See the file ZeptoOS/misc/license.GPL
* for complete details on your rights to copy, modify, and use this
* software.
*/
/* ZEPTOOS:zepto-gpl */
/****************************************************************************/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/zepto_debug.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/bgcns.h>
#include <asm/bgp_personality.h>
#define __ZCL_KERNEL__
#define __ZCL__ /* we need MMIO address definition for linux*/
#include <bpcore/bgp_collective_inlines.h>
#include <common/bgp_personality_inlines.h>
#include <bpcore/ppc450_inlines.h>
#include <bpcore/bgp_global_ints.h>
#include <bpcore/collective.h>
#define __INLINE__ extern inline
#include <spi/GlobInt.h>
#include <linux/zepto_task.h>
int bigmem_nprocs_per_node = 1;
#ifdef CONFIG_ZEPTO_COMPUTENODE
extern BGCNS_Descriptor bgcnsd; /* defined in platforms/44x/bgp_cns.c */
extern int bluegene_getPersonality(void *buff, unsigned buffSize); /* defined in platforms/44x/bgp_cns.c */
static void _do_global_barrier(void)
{
zepto_debug(3,"entering globalBarrier()...\n");
local_irq_disable();
bgcnsd.services->globalBarrier();
local_irq_enable();
zepto_debug(3,"globalBarrier() out\n");
}
static uint16_t _get_port_masks(int i)
{
uint16_t masks;
switch(i) {
case 0: masks = _BGP_TREE_RDR_SRC0|_BGP_TREE_RDR_TGT0; break;
case 1: masks = _BGP_TREE_RDR_SRC1|_BGP_TREE_RDR_TGT1; break;
case 2: masks = _BGP_TREE_RDR_SRC2|_BGP_TREE_RDR_TGT2; break;
case 3: masks = _BGP_TREE_RDR_SRCL|_BGP_TREE_RDR_TGTL; /* local node */
}
return masks;
}
static void _write_classroute3_to_rdr1(uint16_t classroute3)
{
uint32_t rdr1;
_bgp_mbar();
rdr1 = _bgp_mfdcrx(_BGP_DCR_TR_CLASS_RDR1);
_bgp_mbar();
_bgp_mtdcrx(_BGP_DCR_TR_CLASS_RDR1, (rdr1 & 0xFFFF0000) | classroute3);
_bgp_mbar();
}
static uint32_t _get_target_port(_BGP_TreePayload status)
{
return status.u32[0];
}
static uint32_t _get_subtree_status(_BGP_TreePayload status)
{
return status.u32[1];
}
static _BGP_TreePayload _set_target_port(_BGP_TreePayload status,uint32_t port)
{
status.u32[0]=port;
return status;
}
static _BGP_TreePayload _set_subtree_status(_BGP_TreePayload status,uint32_t subtree_status)
{
status.u32[1]=subtree_status;
return status;
}
static void set_MSR_FP(int val)
{
unsigned long msr;
__asm__ __volatile__ ("mfmsr %0" : "=r" (msr));
if( val ) {
msr |= MSR_FP;
} else {
msr &= (~MSR_FP);
}
__asm__ __volatile__ ("mtmsr %0" : : "r" (msr));
}
static void setup_treeroute(int active, int job_size)
{
BGP_Personality_t bgpers;
uint16_t classroute3=0;
uint16_t port_masks[4];
unsigned n_children = 0;
int child_status = 0;
int rc, tsize, n_nodes, i;
int parent_port = -1;
set_MSR_FP(1); /* Enable FPU. XXX: this is a bit brute-force. clean it up later */
/* enable barrier ch0 for usermode */
local_irq_disable();
rc = bgcnsd.services->enableBarrier(0, 1);
local_irq_enable();
zepto_debug(2,"enableBarrier(0,1) rc=%d cpu=%d\n",rc,smp_processor_id() );
zepto_debug(3,"setup_treeroute(active=%d)\n",active);
_bgp_mtdcrx(_BGP_DCR_GLOBINT_ASSERT_CH(0),active);
_do_global_barrier();
zepto_debug(3,"Set class3 route. cpu=%d\n",smp_processor_id() );
bluegene_getPersonality(&bgpers, sizeof(bgpers));
classroute3 = bgpers.Network_Config.TreeRoutes[1];
zepto_debug(3,"classroute3=%08x\n", classroute3);
/* calculate the number of nodes */
switch( bgpers.Kernel_Config.ProcessConfig ) {
case _BGP_PERS_PROCESSCONFIG_2x2 : tsize = 2; break;
case _BGP_PERS_PROCESSCONFIG_VNM : tsize = 4; break;
default:
tsize = 1;
}
zepto_debug(3,"tsize=%d\n", tsize);
n_nodes =
bgpers.Network_Config.Xnodes *
bgpers.Network_Config.Ynodes *
bgpers.Network_Config.Znodes * tsize;
zepto_debug(3,"n_nodes=%d job_size=%d\n", n_nodes, job_size);
if( n_nodes == job_size ) { /* fully occupied */
_write_classroute3_to_rdr1(classroute3);
zepto_debug(3,"configured as a fully occupied partition.\n");
return ;
}
/* count up the number of children */
n_children=0;
for(i=0; i<3; i++) {
if ( !BGP_Personality_treeInfo_isRedundant(&bgpers,i) ) {
if( BGP_Personality_treeInfo_commWorld(&bgpers,i)==_BGP_PERS_TREEINFO_COMMWORLD_CHILD ) {
n_children++;
}
}
}
zepto_debug(3,"n_children=%d\n", n_children);
/* disable all nodes if not active */
if( !active ) classroute3 &= (~ _get_port_masks(3));
zepto_debug(3,"classroute3=%08x\n", classroute3);
/* wait a msg from children */
for( i=0; i<n_children; ++i ) {
_BGP_TreeHwHdr hdr;
_BGP_TreePayload status;
/* check see if VC0 contains a header and payload */
//zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
while(!_bgp_TreeReadyToReceiveVC0() );
//zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
_bgp_TreeRawReceivePacketVC0(&hdr, &status);
zepto_debug(3,"SUBTREE_STATUS=%d TARGET_PORT=%d\n",
_get_subtree_status(status),
_get_target_port(status) );
if( _get_subtree_status(status) ) {
child_status = 1;
} else {
uint32_t target_port = _get_target_port(status);
classroute3 &= (~ _get_port_masks(target_port) );
zepto_debug(3,"classroute3=%08x target_port=%08x\n", classroute3,target_port);
}
}
//zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
/* send information to the parent */
parent_port = -1;
for(i=0; i< 3; i++) {
if( BGP_Personality_treeInfo_commWorld(&bgpers,i)==_BGP_PERS_TREEINFO_COMMWORLD_PARENT) {
parent_port=i;
break;
}
}
zepto_debug(3,"parent_port=%d\n",parent_port);
if(parent_port>=0) {
_BGP_TreeHwHdr hdr;
int ptptarget;
_BGP_TreePayload status;
//zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
ptptarget = BGP_Personality_treeInfo_destP2Paddr(&bgpers,parent_port);
zepto_debug(3,"ptptarget=%d\n", ptptarget);
_bgp_TreeMakePtpHdr(&hdr,
1, /* class route? */
false, /* interrupt? */
ptptarget,
_BGP_TREE_CSUM_SOME );
// zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
status = _set_target_port(status,
BGP_Personality_treeInfo_destPort(&bgpers, parent_port) );
// zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
status = _set_subtree_status(status,
(active|child_status));
// zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
_bgp_TreeRawSendPacket(0, &hdr, &status);
}
// zepto_debug(3,"setup_treeroute.c(%d)\n",__LINE__);
_write_classroute3_to_rdr1(classroute3);
_do_global_barrier();
set_MSR_FP(0); /* Disable FPU */
zepto_debug(3,"configured as a partially occupied partition.\n");
}
static int setup_treeroute_write(struct file *file, const char *buffer,
unsigned long len, void *data)
{
char tmp[20];
if( bigmem_process_active_count() > 0 ) {
printk("[Z] bigmem is in use, so unable to reset treeroute!\n");
return 1;
}
printk("[Z] Reset treeroute\n");
bigmem_nprocs_per_node=1;
if( len > 20 ) len = 20;
if(copy_from_user(tmp, buffer,len) == 0 ) {
extern void bluegene_set_Kernel_Config_ProcessConfig(int nprocs); /* defined in arch/powerpc/platforms/44x/bgp_cns.c */
int active = 0;
int job_size;
char* p;
if( tmp[0] == (char)'1' ) active = 1;
p = tmp+2;
switch( *p ) {
case '4': bigmem_nprocs_per_node=4; break;
case '2': bigmem_nprocs_per_node=2; break;
default:
bigmem_nprocs_per_node=1;
}
bluegene_set_Kernel_Config_ProcessConfig(bigmem_nprocs_per_node);
p = tmp+4;
job_size = simple_strtol(p,&p,0);
setup_treeroute(active,job_size);
zepto_debug(2, "setup_treeroute: active=%d nprocs=%d job_size=%d\n",active, bigmem_nprocs_per_node, job_size);
} else {
return -EFAULT;
}
init_bigmem_pa();
return len;
}
static int __init zeptorc_init(void)
{
struct proc_dir_entry *p_setup_treeroute;
bigmem_nprocs_per_node=1; /* SMP is default */
init_bigmem_pa();
p_setup_treeroute = create_proc_entry("setup_treeroute", S_IFREG|S_IRUGO|S_IWUGO, NULL );
if( p_setup_treeroute ) {
p_setup_treeroute->nlink = 1;
p_setup_treeroute->write_proc = setup_treeroute_write;
} else {
panic("Failed to register /proc/setup_treeroute\n");
}
return 0;
}
#else /* for ION */
static int __init zeptorc_init(void)
{
bigmem_nprocs_per_node=1; /* SMP is default */
init_bigmem_pa();
return 0;
}
#endif
__initcall(zeptorc_init);