#include #include #include #include #include #include "teac.h" /* Notes- * -Why is elan3_fini dropping core? It's intermittent, and seems to * depend on relative timing of multiple calls. */ #ifdef CHROMIUM #include #include #include #else #define crAlloc(sz) malloc(sz) #define crStrncpy(out,in,sz) strncpy(out,in,sz) #define crMemcpy(out,in,bytes) memcpy(out,in,bytes) #define crStrchr(instr,inchr) strchr(instr,inchr) #define crFree(ptr) free(ptr) #define crRealloc( pp, size ) { \ if (!(*pp=realloc(*pp,size))) { \ fprintf(stderr,"failed to reallocate %d bytes!\n",size); \ abort(); \ } \ } #include static void crDebug( const char* fmt, ... ) { va_list ap; va_start(ap,fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #endif #define EADDR_ALLOC_ELAN 0x200000 #define ALLOC_ELAN_SIZE 0x200000 #define EADDR_ALLOC_MAIN 0x400000 #define ALLOC_MAIN_SIZE 0x2000000 /* We need some defs to handle changes in structures between software * revisions. */ /* Capability shape is the same between KITE and pre-KITE */ #ifdef ELAN_PRE_KITE /* software level is PRE_KITE */ #define TEAC_DEVINFO_TYPE 0 #define TEAC_CAP_TYPE 0 #else #ifdef ELAN_PRE_EAGLE /* software level is KITE */ #ifdef LINUX #define TEAC_DEVINFO_TYPE 1 #define TEAC_CREATE_TYPE 1 #else #define TEAC_DEVINFO_TYPE 0 #define TEAC_CREATE_TYPE 0 #endif #define TEAC_CAP_TYPE 1 #else /* software level is EAGLE */ #define TEAC_DEVINFO_TYPE 2 #define TEAC_CAP_TYPE 2 #define TEAC_CREATE_TYPE 2 #endif #endif #if (TEAC_CAP_TYPE == 2) #define TEAC_CAP_ENTRIES(cap) ELAN_CAP_ENTRIES(cap) #else #define TEAC_CAP_ENTRIES(cap) (cap->Entries) #endif /* In the future we will use the bitwise AND of the rail masks */ #define RAIL 0 #ifndef HOST_TABLE_FILENAME #define HOST_TABLE_FILENAME "/usr/users/8/welling/elanstuff/teac/teac_host_map.t" #endif #define INITIAL_HOST_TABLE_SIZE 256 static host_t* hosts= NULL; /* this one ends up sorted by host name */ static int* hostsIndex= NULL; /* this is sorted by node ID */ static sdramaddr_t* sdramAddrBase= NULL; static E3_Addr* elanAddrBase= NULL; static int nodeTablesInitialized= 0; static int nodeTableSize= 0; static int nodeCount= 0; static int read_node_map() { FILE* f= NULL; int i; int iLine; char buf[256]; if (hosts) crFree(hosts); if (!(hosts= (host_t*)crAlloc(INITIAL_HOST_TABLE_SIZE*sizeof(host_t)))) { fprintf(stderr,"libteac: read_node_map: unable to allocate %d bytes!\n", INITIAL_HOST_TABLE_SIZE*sizeof(host_t)); abort(); } nodeTableSize= INITIAL_HOST_TABLE_SIZE; if (!(f=fopen(HOST_TABLE_FILENAME,"r"))) { fprintf(stderr,"libteac: read_node_map: cannot open <%s> for reading!\n", HOST_TABLE_FILENAME); abort(); } i= 0; iLine= 0; buf[sizeof(buf)-1]= '\0'; while (!feof(f) && !ferror(f)) { char* tmp; char* string; if (!fgets(buf, sizeof(buf)-1, f)) break; iLine++; if (buf[0]=='#' || buf[0]=='\n' || buf[0]=='\0') continue; if (i>=nodeTableSize) { /* We need to grow the table */ int newSize= 2*nodeTableSize; crRealloc((void**)&hosts,newSize*sizeof(host_t)); nodeTableSize= newSize; } if (!(string=strtok_r(buf," ,;\t\n",&tmp))) { fprintf(stderr,"libteac: read_node_map: Bad machine name at line %d of %s!\n", iLine, HOST_TABLE_FILENAME); abort(); } if (strlen(string)==0) continue; /* blank line */ hosts[i].name= strdup(string); if (!(string=strtok_r(NULL," ,;\t\n",&tmp))) { fprintf(stderr,"libteac: read_node_map: bad integer string at line %d of %s!\n", iLine, HOST_TABLE_FILENAME); abort(); } errno= 0; hosts[i].railMask= atoi(string); if (errno != 0) { fprintf(stderr,"libteac: read_node_map: bad integer %s at %s line %d!\n", string, HOST_TABLE_FILENAME, iLine); abort(); } if (!(string=strtok_r(NULL," ,;\t\n",&tmp))) { fprintf(stderr,"libteac: read_node_map: bad integer string at line %d of %s!\n", iLine, HOST_TABLE_FILENAME); abort(); } errno= 0; hosts[i].id= atoi(string); if (errno != 0) { fprintf(stderr,"libteac: read_node_map: bad integer %s at %s line %d!\n", string, HOST_TABLE_FILENAME, iLine); abort(); } if (!(string=strtok_r(NULL," ,;\t\n",&tmp))) { fprintf(stderr,"libteac: read_node_map: bad hex value at line %d of %s!\n", iLine, HOST_TABLE_FILENAME); abort(); } errno= 0; hosts[i].sdramAddrBase= (sdramaddr_t)strtol(string, (char**)NULL, 0); if (errno != 0) { fprintf(stderr,"libteac: read_node_map: bad hex address %s at %s line %d!\n", string, HOST_TABLE_FILENAME, iLine); abort(); } if (!(string=strtok_r(NULL," ,;\t\n",&tmp))) { fprintf(stderr,"libteac: read_node_map: bad hex value at line %d of %s!\n", iLine, HOST_TABLE_FILENAME); abort(); } errno= 0; hosts[i].elanAddrBase= (E3_Addr)strtol(string, (char**)NULL, 0); if (errno != 0) { fprintf(stderr,"libteac: read_node_map: bad hex address %s at %s line %d!\n", string, HOST_TABLE_FILENAME, iLine); abort(); } #if 0 crDebug("line %d: %d: got <%s> %d %d 0x%x 0x%x\n", iLine, i, hosts[i].name, hosts[i].railMask, hosts[i].id, hosts[i].sdramAddrBase, hosts[i].elanAddrBase); #endif i++; } if (ferror(f)) { perror("Error reading host table"); fprintf(stderr,"libteac: read_node_map: error reading <%s>!\n", HOST_TABLE_FILENAME); abort(); } (void)fclose(f); return i; } static int hostnameCompare(const void* h1, const void* h2) { return strcmp(((host_t*)h1)->name, ((host_t*)h2)->name); } static int hostnameLookup(const void* h1, const void* h2) { return strcmp((const char*)h1, ((host_t*)h2)->name); } static void initialize_node_tables() { if (!nodeTablesInitialized) { int nodeMin; int nodeMax; int nodeRange; int i; crDebug("Loading Quadrics network map from <%s>\n",HOST_TABLE_FILENAME); /* Load information about Quadrics network */ nodeCount= read_node_map(); if (nodeCount==0) { fprintf(stderr, "libteac: initialize_node_tables: no valid nodes in %s!\n", HOST_TABLE_FILENAME); abort(); } /* * Build the offset tables. Offsets are looked up by node ID, so we * have to avoid redundant IDs and order the tables correctly. */ nodeMin= nodeMax= hosts[0].id; for (i=1; inodeMax) nodeMax= hosts[i].id; } nodeRange= (nodeMax-nodeMin) + 1; if (!(sdramAddrBase=(sdramaddr_t*)crAlloc(nodeRange*sizeof(sdramaddr_t)))) { fprintf(stderr, "libteac: initialize_node_tables: unable to allocate %d bytes!\n", nodeRange*sizeof(sdramaddr_t)); abort(); } if (!(elanAddrBase=(E3_Addr*)crAlloc(nodeRange*sizeof(E3_Addr)))) { fprintf(stderr, "libteac: initialize_node_tables: unable to allocate %d bytes!\n", nodeRange*sizeof(E3_Addr)); abort(); } for (i=0; i got <%s> <%d> <%x> <%x>\n", hn,h->name,h->id,(int)h->sdramAddrBase,(int)h->elanAddrBase); } else fprintf(stderr,"Lookup <%s> returned NULL!\n",hn); #endif if (h) return h->id; else return -1; } /* * A version of address translation with some safety checks */ static E3_Addr teac_main2elan( ELAN3_CTX *ctx, void* main_addr ) { E3_Addr result= elan3_main2elan(ctx,main_addr); /* crDebug("mapping %0lx -> %d; addressable %d\n", main_addr,result,elan3_addressable(ctx,main_addr,64)); */ if (result==ELAN_BAD_ADDR) { fprintf(stderr,"Address translation error: %0x has no elan equivalent\n", (int)main_addr); abort(); } return result; } Tcomm *teac_Init(char *lh, char *hh, int lctx, int hctx, int myrank, const unsigned char key[TEAC_KEY_SIZE]) { #if (TEAC_DEVINFO_TYPE == 2) ELAN_DEVINFO info; ELAN_POSITION position; #else ELAN3_DEVINFO info; #endif ELAN_CAPABILITY *cap; Tcomm* result= NULL; int i; int j; int a; int b; char buf[256]; char* here; #if ( TEAC_CREATE_TYPE == 0 ) void* control; #endif if (!nodeTablesInitialized) initialize_node_tables(); if (!(result= (Tcomm*)crAlloc(sizeof(Tcomm)))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", sizeof(Tcomm)); return(NULL); } result->ctx = NULL; result->dma = NULL; result->e_dma = 0; result->s_event = 0; result->r_event = NULL; for (i=0; isbuf_pull_event[i] = 0; result->rbuf_pull_event = 0; result->m_snd = NULL; result->m_rcv = NULL; for (i=0; isbuf_ready[i]= NULL; result->rbuf_ready = NULL; result->mbuff= NULL; for (i=0; isendWrappers[i]= NULL; result->vp = -1; result->hhost = result->lhost = -1; result->hctx = result->lctx = -1; result->msgnum = 0; result->poll_shift = 0; result->totalSendBufferBytesAllocated= 0; result->totalRecvBufferBytesAllocated= 0; a = trans_host(lh); b = trans_host(hh); result->lhost = (a < b)? a : b; result->hhost = (a > b) ? a : b; result->lctx = (lctxhctx = (hctx>lctx) ? hctx : lctx; cap = &(result->cap); #if (TEAC_CAP_TYPE == 2) elan_nullcap(cap); /* Initialize the UserKey to the given value */ crMemcpy((void*)&(cap->cap_userkey.key_values),key,TEAC_KEY_SIZE); cap->cap_lowcontext = lctx; cap->cap_mycontext = lctx + (myrank%4); cap->cap_highcontext = hctx; cap->cap_lownode = result->lhost; cap->cap_highnode = result->hhost; cap->cap_type = ELAN_CAP_TYPE_BLOCK | ELAN_CAP_TYPE_NO_BITMAP | ELAN_CAP_TYPE_MULTI_RAIL; #else elan3_nullcap(cap); /* Initialize the UserKey to the given value */ crMemcpy((void*)&(cap->UserKey),key,TEAC_KEY_SIZE); cap->LowContext = lctx; cap->MyContext = lctx + (myrank%4); cap->HighContext = hctx; cap->LowNode = result->lhost; cap->HighNode = result->hhost; cap->Entries = (hctx - lctx + 1) * (cap->HighNode - cap->LowNode + 1); cap->Type = ELAN_CAP_TYPE_BLOCK | ELAN_CAP_TYPE_NO_BITMAP | ELAN_CAP_TYPE_MULTI_RAIL; #endif if ((result->ctx = elan3_init( 0, EADDR_ALLOC_MAIN, ALLOC_MAIN_SIZE, EADDR_ALLOC_ELAN, ALLOC_ELAN_SIZE)) == NULL) { fprintf(stderr, "teac_Init: elan3_init returned NULL context\n"); return(NULL); } elan3_block_inputter (result->ctx, 1); #if ( TEAC_CREATE_TYPE == 0 ) if ((control = elan3_control_open (RAIL)) != NULL) { if (elan3_create(control, &(result->cap))) { crDebug("elan3_create failed with <%s>, but that's OK!\n", strerror(errno)); errno= 0; } } else { perror("elan3_control_open failed"); teac_Close(result); return NULL; } #elif ( TEAC_CREATE_TYPE == 1 ) if (elan3_create(result->ctx, &(result->cap))) { crDebug("elan3_create failed with <%s>, but that's OK!\n", strerror(errno)); errno= 0; } #else /* I don't think we have to do anything here! */ #endif #if (TEAC_DEVINFO_TYPE == 2) (void)elan3_get_devinfo(result->ctx, &info); (void)elan3_get_position(result->ctx, &position); crDebug("Position mode %d, NodeID %d, NumNodes %d, NumLevels %d\n", position.pos_mode,position.pos_nodeid, position.pos_nodes, position.pos_levels); if (position.pos_mode != ELAN_POS_MODE_SWITCHED) crDebug("WARNING: position mode is not %d!\n",ELAN_POS_MODE_SWITCHED); crDebug("Rail %d\n",info.dev_rail); #elif (TEAC_DEVINFO_TYPE == 1) elan3_devinfo(0, &info); crDebug("NodeId: %d, NumNodes: %d, NumLevels: %d, NodeLevel: %d\n", info.Position.NodeId, info.Position.NumNodes, info.Position.NumLevels, info.Position.NodeLevel); #else elan3_devinfo(0, &info); crDebug("NodeId: %d, NumLevels: %d, NodeLevel: %d\n", info.NodeId, info.NumLevels, info.NodeLevel); #endif #if 0 { static char junkString[256]; #if (TEAC_CAP_TYPE == 2) crDebug("Capability: <%s>\n", elan_capability_string(&(result->cap),junkString)); crDebug("railmask is %d\n",result->cap.cap_railmask); crDebug("bitmap is %x\n",result->cap.cap_bitmap[0]); #else crDebug("Capability: <%s>\n", elan3_capability_string(&(result->cap),junkString)); crDebug("railmask is %d\n",result->cap.RailMask); crDebug("bitmap is %x\n",result->cap.Bitmap[0]); #endif } #endif /* Reality check. */ if (gethostname(buf,sizeof(buf)-1)) { perror("Can't get my own host name"); teac_Close(result); return NULL; } if ((here= crStrchr(buf,'.')) != NULL) *here= '\0'; #if (TEAC_DEVINFO_TYPE == 2) if (trans_host(buf) != (int)position.pos_nodeid) { fprintf(stderr, "teac_Init: Expected Quadrics port id %d does not match real value %d!\n", trans_host(buf), position.pos_nodeid); teac_Close(result); return NULL; } #elif (TEAC_DEVINFO_TYPE == 1) if (trans_host(buf) != info.Position.NodeId) { fprintf(stderr, "teac_Init: Expected Quadrics port id %d does not match real value %d!\n", trans_host(buf), info.Position.NodeId); teac_Close(result); return NULL; } #else if (trans_host(buf) != info.NodeId) { fprintf(stderr, "teac_Init: Expected Quadrics port id %d does not match real value %d!\n", trans_host(buf), info.NodeId); teac_Close(result); return NULL; } #endif if (elan3_attach(result->ctx, &(result->cap))) { fprintf(stderr, "teac_Init: elan3_attach failed\n"); teac_Close(result); return(NULL); } if (elan3_addvp(result->ctx, 0, &(result->cap))) { fprintf(stderr, "teac_Init: elan3_addvp failed\n"); teac_Close(result); return(NULL); } result->vp = elan3_process(result->ctx); if (! elan3_set_required_mappings (result->ctx)) { fprintf(stderr, "teac_Init: elan3_set_required_mappings failed\n"); teac_Close(result); return(NULL); } if (!(result->r_event= (sdramaddr_t**)crAlloc( TEAC_CAP_ENTRIES(cap)*sizeof(sdramaddr_t*) ))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", TEAC_CAP_ENTRIES(cap)*sizeof(sdramaddr_t*)); teac_Close(result); return(NULL); } if (!(result->r_event[0]= (sdramaddr_t*)crAlloc( TEAC_CAP_ENTRIES(cap)*NUM_SEND_BUFFERS * sizeof(sdramaddr_t) ))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", TEAC_CAP_ENTRIES(cap)*NUM_SEND_BUFFERS*sizeof(sdramaddr_t)); teac_Close(result); return(NULL); } if (!(result->r_event[0][0]= elan3_allocElan(result->ctx, E3_EVENT_ALIGN, TEAC_CAP_ENTRIES(cap)*NUM_SEND_BUFFERS*sizeof(E3_BlockCopyEvent)))) { perror("teac_Init: elan3_allocElan failed for r_event block"); teac_Close(result); return(NULL); } for (j=1; jr_event[j]= result->r_event[0] + j*NUM_SEND_BUFFERS; result->r_event[j][0]= result->r_event[0][0]+j*NUM_SEND_BUFFERS*sizeof(E3_BlockCopyEvent); } for (j=0; jr_event[j][i]= result->r_event[j][0] + i*sizeof(E3_BlockCopyEvent); } #if 0 crDebug("r_event[0][0] is %x\n",(int)result->r_event[0][0]); #endif if (!(result->m_rcv= (volatile E3_uint32**)crAlloc( TEAC_CAP_ENTRIES(cap)*sizeof(E3_uint32*) ))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", TEAC_CAP_ENTRIES(cap)*sizeof(E3_uint32*)); teac_Close(result); return(NULL); } if (!(result->m_rcv[0]= (volatile E3_uint32*) elan3_allocMain(result->ctx, 0, TEAC_CAP_ENTRIES(cap)*NUM_SEND_BUFFERS*sizeof(E3_uint32)))) { perror("teac_Init: elan3_allocMain failed for m_rcv block"); teac_Close(result); return(NULL); } for (i=1; im_rcv[i]= result->m_rcv[0] + i*NUM_SEND_BUFFERS; #if 0 crDebug("Base of m_rcv is %lx -> %lx\n", (long)(result->m_rcv[0]), (long)teac_main2elan(result->ctx,(void*)(result->m_rcv[0]))); #endif if (!(result->mbuff= (teacMsg**)crAlloc( TEAC_CAP_ENTRIES(cap)*sizeof(teacMsg*) ))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", TEAC_CAP_ENTRIES(cap)*sizeof(teacMsg*)); teac_Close(result); return(NULL); } if (!(result->mbuff[0]= (teacMsg*) elan3_allocMain(result->ctx, 8, TEAC_CAP_ENTRIES(cap)*NUM_SEND_BUFFERS*sizeof(teacMsg)))) { perror("teac_Init: elan3_allocMain failed for mbuff block"); teac_Close(result); return(NULL); } for (i=1; imbuff[i]= result->mbuff[0] + i*NUM_SEND_BUFFERS; #if 0 crDebug("Base of mbuff is %lx -> %lx\n", (long)(result->mbuff[0]), (long)teac_main2elan(result->ctx,result->mbuff[0])); #endif if (!(result->dma= (E3_DMA_MAIN *) elan3_allocMain(result->ctx, E3_DMA_ALIGN, sizeof(E3_DMA_MAIN)))) { perror("teac_Init: elan3_allocMain failed for dma"); teac_Close(result); return(NULL); } if (!(result->e_dma= elan3_allocElan(result->ctx, E3_DMA_ALIGN, sizeof(E3_DMA)))) { perror("teac_Init: elan3_allocElan failed for e_dma"); teac_Close(result); return(NULL); } if (!(result->s_event= elan3_allocElan(result->ctx, E3_EVENT_ALIGN, sizeof(E3_BlockCopyEvent)))) { perror("teac_Init: elan3_allocElan failed for s_event"); teac_Close(result); return(NULL); } #if 0 crDebug("s_event is %x\n",(int)result->s_event); #endif if (!(result->sbuf_pull_event[0]= elan3_allocElan(result->ctx, E3_EVENT_ALIGN, NUM_SEND_BUFFERS*sizeof(E3_BlockCopyEvent)))) { perror("teac_Init: elan3_allocElan failed for sbuf_pull_event block"); teac_Close(result); return(NULL); } for (i=1; isbuf_pull_event[i]= result->sbuf_pull_event[0]+i*sizeof(E3_BlockCopyEvent); if (!(result->rbuf_pull_event= elan3_allocElan(result->ctx, E3_EVENT_ALIGN, sizeof(E3_BlockCopyEvent)))) { perror("teac_Init: elan3_allocElan failed for rbuf_pull_event"); teac_Close(result); return(NULL); } if (!(result->m_snd= (E3_uint32 *) elan3_allocMain(result->ctx, 0, sizeof(E3_uint32)))) { perror("teac_Init: elan3_allocMain failed for m_snd"); teac_Close(result); return(NULL); } if (!(result->sbuf_ready[0]= (E3_uint32 *) elan3_allocMain(result->ctx, 0, NUM_SEND_BUFFERS*sizeof(E3_uint32)))) { perror("teac_Init: elan3_allocMain failed for sbuf_ready block"); teac_Close(result); return(NULL); } for (i=1; isbuf_ready[i]= result->sbuf_ready[0] + i; if (!(result->sendWrappers[0]= (SBuffer*)crAlloc(NUM_SEND_BUFFERS*sizeof(SBuffer)))) { fprintf(stderr,"teac_Init: unable to allocate %d bytes!\n", NUM_SEND_BUFFERS*sizeof(SBuffer)); teac_Close(result); return(NULL); } for (i=1; isendWrappers[i]= result->sendWrappers[0] + i; if (!(result->rbuf_ready= (E3_uint32 *) elan3_allocMain(result->ctx, 0, sizeof(E3_uint32)))) { perror("teac_Init: elan3_allocMain failed for rbuf_ready"); teac_Close(result); return(NULL); } for (i=0; ictx, 8, E_BUFFER_INITIAL_SIZE))) { perror("teac_Init: elan3_allocMain failed for buffer block"); teac_Close(result); return(NULL); } result->sendWrappers[i]->bufId= i; result->sendWrappers[i]->totSize= E_BUFFER_INITIAL_SIZE; result->sendWrappers[i]->validSize= 0; result->sendWrappers[i]->buf= buf; result->totalSendBufferBytesAllocated += result->sendWrappers[i]->totSize; } elan3_initevent_word (result->ctx, result->s_event, result->m_snd); elan3_initevent_word (result->ctx, result->rbuf_pull_event, result->rbuf_ready); for (i=0; ictx, result->sbuf_pull_event[i], result->sbuf_ready[i]); } for (j=0; jctx, result->r_event[j][i], &(result->m_rcv[j][i])); } /* Get the message receive events ready to fire, in case something * comes in before receive gets called. */ for (j=0; jctx, result->r_event[j][i], 1); } /* Fire the sbuffer free events, so that the buffers look free when * the first call to send happens. */ for (i=0; ictx, result->sbuf_pull_event[i], 1); elan3_setevent( result->ctx, result->sbuf_pull_event[i] ); } /* And now we're ready to face the world. */ elan3_block_inputter (result->ctx, 0); return(result); } void teac_Close(Tcomm *tcomm) { int i; if (tcomm) { /* First we have to wait until all pending messages have been * pulled (assuming they got initialized in the first place). */ if ((tcomm->sbuf_pull_event[0] != 0) && (tcomm->sbuf_ready[0] != NULL)) { for (i=0; ictx, tcomm->sbuf_pull_event[i], tcomm->sbuf_ready[i], 10); } crDebug("All TEAC messages have reported home!\n"); } elan3_block_inputter (tcomm->ctx, 1); if (tcomm->e_dma != 0) elan3_freeElan(tcomm->ctx, tcomm->e_dma); if (tcomm->s_event != 0) elan3_freeElan(tcomm->ctx, tcomm->s_event); if (tcomm->r_event != NULL) { if (tcomm->r_event[0] != NULL) { if (tcomm->r_event[0][0] != 0) elan3_freeElan(tcomm->ctx, tcomm->r_event[0][0]); crFree(tcomm->r_event[0]); } crFree(tcomm->r_event); } if (tcomm->sbuf_pull_event[0] != 0) elan3_freeElan(tcomm->ctx, tcomm->sbuf_pull_event[0]); if (tcomm->sendWrappers[0] != NULL) { for (i=0; isendWrappers[i]->buf != NULL) { elan3_free(tcomm->ctx, tcomm->sendWrappers[i]->buf); tcomm->totalSendBufferBytesAllocated -= tcomm->sendWrappers[i]->totSize; } } crFree(tcomm->sendWrappers[0]); } if (tcomm->rbuf_pull_event != 0) elan3_freeElan(tcomm->ctx, tcomm->rbuf_pull_event); if (tcomm->m_snd != NULL) elan3_free(tcomm->ctx, (E3_uint32*)tcomm->m_snd); if (tcomm->m_rcv != NULL) { if (tcomm->m_rcv[0] != NULL) elan3_free(tcomm->ctx, (E3_uint32*)tcomm->m_rcv[0]); crFree(tcomm->m_rcv); } if (tcomm->sbuf_ready[0] != NULL) elan3_free(tcomm->ctx, (E3_uint32*)tcomm->sbuf_ready[0]); if (tcomm->rbuf_ready != NULL) elan3_free(tcomm->ctx, (E3_uint32*)tcomm->rbuf_ready); if (tcomm->mbuff != NULL) { if (tcomm->mbuff[0] != NULL) elan3_free(tcomm->ctx, tcomm->mbuff[0]); crFree(tcomm->mbuff); } #if (TEAC_CREATE_TYPE==2) elan3_detach(tcomm->ctx); elan3_fini(tcomm->ctx); #else /* elan3_detach and elan3_destroy seem to crash sometimes in * these versions. */ #endif } } int teac_Select(Tcomm* tcomm, int *ids, int num_ids, int timeout) { int id; while (timeout-- > 0) { if ((id= teac_Poll(tcomm, ids, num_ids)) >= 0) return id; } return -1; } int teac_Poll(Tcomm* tcomm, int *ids, int num_ids) { int i; int j; for (j=0; jpoll_shift) % num_ids; int thisId= ids[index]; for (i=0; ictx, &(tcomm->m_rcv[thisId][i]), 1)) { #ifdef never tcomm->poll_shift= index; #endif return thisId; } } } return -1; } int teac_sendBufferAvailable(Tcomm* tcomm) { int i; for (i=0; ictx, tcomm->sbuf_ready[i], 1)) return 1; } return 0; } SBuffer* teac_getSendBuffer( Tcomm* tcomm, long size ) { /* Find a free send buffer. We'll busy wait in this poll loop * if necessary. */ int i= 0; while (1) { if (elan3_pollevent_word(tcomm->ctx, tcomm->sbuf_ready[i], 1)) break; if (++i == NUM_SEND_BUFFERS) i= 0; } /* We will use this buffer! */ #if 0 crDebug("Allocated message buffer %d\n",i); #endif *(tcomm->sbuf_ready[i])= 0; /* mark it busy */ /* If the associated chunk of memory is smaller than that requested, * replace it with something larger. */ if (tcomm->sendWrappers[i]->totSize < size) { tcomm->totalSendBufferBytesAllocated -= tcomm->sendWrappers[i]->totSize; elan3_free( tcomm->ctx, tcomm->sendWrappers[i]->buf ); if (!(tcomm->sendWrappers[i]->buf= (char*)elan3_allocMain(tcomm->ctx, 8, size))) { perror("teac_getSendBuffer: failed to grow send buffer"); exit(-1); } tcomm->totalSendBufferBytesAllocated += size; } tcomm->sendWrappers[i]->totSize= size; tcomm->sendWrappers[i]->validSize= 0; return tcomm->sendWrappers[i]; } SBuffer* teac_getUnreadySendBuffer( Tcomm* tcomm, long size ) { SBuffer* result= NULL; if (!(result= (SBuffer*)crAlloc(sizeof(SBuffer)))) { fprintf(stderr,"libteac: read_node_map: unable to allocate %d bytes!\n", sizeof(SBuffer)); abort(); } result->bufId= -1; /* this marks it unready */ #if 0 crDebug("Allocated an unready message buffer!\n"); #endif /* Allocate some DMA-able memory */ if (!(result->buf= (char*)elan3_allocMain(tcomm->ctx, 8, size))) { perror("teac_getUnreadySendBuffer: failed to allocate elan3 memory"); exit(-1); } result->totSize= size; result->validSize= 0; tcomm->totalSendBufferBytesAllocated += result->totSize; return result; } SBuffer* teac_makeSendBufferReady( Tcomm* tcomm, SBuffer* buf ) { int i= 0; /* If the input buffer is already ready, just return it */ if (buf->bufId >= 0 && buf->bufIdctx, tcomm->sbuf_ready[i], 1)) break; if (++i == NUM_SEND_BUFFERS) i= 0; } /* We will use this buffer! */ #if 0 crDebug("Allocated message buffer %d in makeSendBufferReady\n",i); #endif *(tcomm->sbuf_ready[i])= 0; /* mark it busy */ /* Substitute the unready payload for the old payload */ tcomm->totalSendBufferBytesAllocated -= tcomm->sendWrappers[i]->totSize; elan3_free( tcomm->ctx, tcomm->sendWrappers[i]->buf ); tcomm->sendWrappers[i]->buf= buf->buf; tcomm->sendWrappers[i]->totSize= buf->totSize; tcomm->sendWrappers[i]->validSize= buf->validSize; crFree(buf); return tcomm->sendWrappers[i]; } int teac_Send( Tcomm* tcomm, int* ids, int num_ids, SBuffer* buf, void *start ) { int vp = tcomm->vp; int iBuf; int iDest; teacMsg *msg; /* Complain loudly if this is an unready buffer */ if (buf->bufId==-1) { fprintf(stderr,"teac_Send: tried to send an unready buffer!\n"); return 0; } /* Reality check: is this one of my buffers? */ if (buf->bufId<0 || buf->bufId>=NUM_SEND_BUFFERS) { fprintf(stderr,"teac_Send: I don't know this buffer!\n"); return 0; } /* Reality check: did they write too much into the message? */ if (buf->validSize > buf->totSize) { fprintf(stderr,"teac_Send: message too large! (%ld vs %ld)\n", buf->validSize, buf->totSize); abort(); return 0; } iBuf= buf->bufId; msg = &(tcomm->mbuff[vp][iBuf]); msg->msgnum = tcomm->msgnum++; msg->size = buf->validSize; msg->host = vp; if ( start != NULL ) msg->mptr = teac_main2elan( tcomm->ctx, start ); else msg->mptr = teac_main2elan(tcomm->ctx, buf->buf); msg->clr_event = elan3_sdram2elan(tcomm->ctx, tcomm->ctx->sdram, tcomm->sbuf_pull_event[iBuf]); msg->new= 1; /* Set up the parts of the DMA that are not specific to destination */ tcomm->dma->dma_type = E3_DMA_TYPE(DMA_BYTE,DMA_WRITE,DMA_NORMAL,0); tcomm->dma->dma_size = sizeof(teacMsg); tcomm->dma->dma_srcEvent = elan3_sdram2elan(tcomm->ctx,tcomm->ctx->sdram,tcomm->s_event); tcomm->dma->dma_source = teac_main2elan(tcomm->ctx, msg); elan3_primeevent(tcomm->ctx, tcomm->sbuf_pull_event[buf->bufId], num_ids); /* Send this message off to each destination */ for (iDest=0; iDestdma->dma_srcCookieVProc = elan3_local_cookie(tcomm->ctx, vp, ids[iDest]); tcomm->dma->dma_destCookieVProc = ids[iDest]; tcomm->dma->dma_destEvent = elan3_sdram2elan(tcomm->ctx,tcomm->ctx->sdram, tcomm->r_event[vp][iBuf]) + sdramAddrBase[(ids[iDest]/NUM_SEND_BUFFERS) + tcomm->lhost] - sdramAddrBase[(vp/NUM_SEND_BUFFERS) + tcomm->lhost]; tcomm->dma->dma_dest = teac_main2elan(tcomm->ctx, msg) + elanAddrBase[(ids[iDest]/NUM_SEND_BUFFERS) + tcomm->lhost] - elanAddrBase[(vp/NUM_SEND_BUFFERS) + tcomm->lhost]; elan3_primeevent(tcomm->ctx, tcomm->s_event, 1); *(tcomm->m_snd)= 0; elan3_putdma_main(tcomm->ctx, tcomm->dma, tcomm->e_dma); #if 0 crDebug("DMA dest event %x, dest mem %lx\n", tcomm->dma->dma_destEvent, (long)tcomm->dma->dma_dest); crDebug("Mem shifts are %x %x based on %d %d\n", elanAddrBase[(ids[iDest]/NUM_SEND_BUFFERS) + tcomm->lhost], elanAddrBase[(vp/NUM_SEND_BUFFERS) + tcomm->lhost], ids[iDest],vp); crDebug("Send msg %d in buffer %d to %d (list index %d)...", msg->msgnum,iBuf, ids[iDest],iDest); #endif elan3_waitevent_word(tcomm->ctx, tcomm->s_event, tcomm->m_snd, ELAN_WAIT_EVENT); #if 0 crDebug("message away!\n"); #endif } return 1; } RBuffer* teac_Recv(Tcomm* tcomm, int id) { int vp = tcomm->vp; RBuffer* result= NULL; int iEvent= 0; int iBuf= 0; int i; int lowestMsgnum; /* poll until we get an incoming message from the given sender */ while (1) { if (elan3_pollevent_word(tcomm->ctx, &(tcomm->m_rcv[id][iEvent]), 1)) break; if (++iEvent == NUM_SEND_BUFFERS) iEvent= 0; } /* This may not be the earliest event, however. */ lowestMsgnum= -1; for (i=0; i %lx\n", (long)&(tcomm->mbuff[id][i]), (long)teac_main2elan(tcomm->ctx,(void*)(&tcomm->mbuff[id][i]))); #endif if (tcomm->mbuff[id][i].new) { if ((lowestMsgnum < 0) || (tcomm->mbuff[id][i].msgnum < (E3_uint32)lowestMsgnum)) { lowestMsgnum= tcomm->mbuff[id][i].msgnum; iBuf= i; } } } if (lowestMsgnum<0) { fprintf(stderr, "teac_Recv: internal error: can't find message I just got!\n"); return NULL; } tcomm->mbuff[id][iBuf].new= 0; tcomm->m_rcv[id][iBuf]= 0; elan3_primeevent(tcomm->ctx, tcomm->r_event[id][iBuf],1); #if 0 crDebug("got msg %d in buffer %d from %d!\n", tcomm->mbuff[id][iBuf].msgnum, iBuf, id); #endif /* Make some space to put the message when it arrives */ if (!(result= (RBuffer*)crAlloc(sizeof(RBuffer)))) { fprintf(stderr,"teac_Recv: unable to allocate %d bytes!\n", sizeof(RBuffer)); return NULL; } #if 0 if (!(result->buf= (void*)elan3_allocMain(tcomm->ctx, 8,E_BUFFER_SIZE))) { perror("teac_Recv: elan3_allocMain failed for buffer"); return(NULL); } result->totSize= E_BUFFER_SIZE; #endif if (!(result->buf= (void*)elan3_allocMain(tcomm->ctx, 8, tcomm->mbuff[id][iBuf].size))) { perror("teac_Recv: elan3_allocMain failed for buffer"); return(NULL); } result->totSize= tcomm->mbuff[id][iBuf].size; tcomm->totalRecvBufferBytesAllocated+= result->totSize; result->validSize= tcomm->mbuff[id][iBuf].size; result->from= tcomm->mbuff[id][iBuf].host; result->senderMsgnum= tcomm->mbuff[id][iBuf].msgnum; /* Set up the DMA to pull the message */ tcomm->dma->dma_type = E3_DMA_TYPE(DMA_BYTE,DMA_READ,DMA_NORMAL,0); tcomm->dma->dma_size = tcomm->mbuff[id][iBuf].size; tcomm->dma->dma_source = tcomm->mbuff[id][iBuf].mptr; tcomm->dma->dma_dest = teac_main2elan(tcomm->ctx,result->buf); tcomm->dma->dma_srcCookieVProc = elan3_remote_cookie(tcomm->ctx, vp, tcomm->mbuff[id][iBuf].host); tcomm->dma->dma_destCookieVProc = elan3_local_cookie(tcomm->ctx, vp, tcomm->mbuff[id][iBuf].host); tcomm->dma->dma_srcEvent = tcomm->mbuff[id][iBuf].clr_event; tcomm->dma->dma_destEvent = elan3_sdram2elan(tcomm->ctx,tcomm->ctx->sdram, tcomm->rbuf_pull_event); elan3_primeevent(tcomm->ctx, tcomm->rbuf_pull_event,1); *(tcomm->rbuf_ready)= 0; elan3_getdma_main(tcomm->ctx, tcomm->dma, tcomm->e_dma); elan3_waitevent_word(tcomm->ctx, tcomm->rbuf_pull_event, tcomm->rbuf_ready, ELAN_WAIT_EVENT); return(result); } int teac_Dispose( Tcomm* tcomm, RBuffer* buf ) { tcomm->totalRecvBufferBytesAllocated -= buf->totSize; elan3_free(tcomm->ctx, buf->buf); crFree(buf); return 0; } char* teac_getTcommString(Tcomm *c, char* buf, int buflen) { snprintf(buf,buflen-1, "", c->vp,c->lhost,c->hhost,c->lctx,c->hctx,c->msgnum); buf[buflen-1]= '\0'; return buf; } char* teac_getConnString(Tcomm *c, int id, char* buf, int buflen) { int rel_rank= id%4; int node= ((id-rel_rank)/4) + c->lhost; snprintf(buf,buflen-1,"vp %d, <%s>:%d",id, hosts[hostsIndex[node]].name,rel_rank); buf[buflen-1]= '\0'; #if 0 crDebug("getConnString: lookup id %d -> %d %d -> %s\n",id,rel_rank,node,buf); #endif return buf; } int teac_getConnId(Tcomm *c, const char* host, int rank) { int node= trans_host(host); #if 0 crDebug("getConnId: <%s> %d %d maps to %d %d\n", host, rank, c->lhost, node, (4*(node - c->lhost) + (rank%4))); #endif return (4*(node - c->lhost) + (rank%4)); } int teac_getHostInfo(Tcomm *c, char* host, const int hostLength, int* railMask, int *nodeId, long* sdramBaseAddr, long* elanBaseAddr) { #if (TEAC_DEVINFO_TYPE == 2) ELAN_DEVINFO info; ELAN_POSITION position; #else ELAN3_DEVINFO info; #endif char* here; if (gethostname(host,hostLength-1)) { perror("Can't get my own host name"); return 0; } host[hostLength-1]= '\0'; if ((here= crStrchr(host,'.')) != NULL) *here= '\0'; #if (TEAC_DEVINFO_TYPE == 2) (void)elan3_get_devinfo(c->ctx, &info); (void)elan3_get_position(c->ctx, &position); *nodeId= position.pos_nodeid; #elif (TEAC_DEVINFO_TYPE == 1) elan3_devinfo(0, &info); *nodeId= info.Position.NodeId; #else elan3_devinfo(0, &info); *nodeId= info.NodeId; #endif #if (TEAC_CAP_TYPE == 2) *railMask= c->cap.cap_railmask; #else *railMask= c->cap.RailMask; #endif *sdramBaseAddr= (int)c->r_event[0][0]; *elanBaseAddr= (long)teac_main2elan(c->ctx,(void*)c->m_rcv[0]); return 1; }