diff --git a/arch/x86/scc/iRCCE_mailbox.c b/arch/x86/scc/iRCCE_mailbox.c new file mode 100644 index 00000000..107b56a6 --- /dev/null +++ b/arch/x86/scc/iRCCE_mailbox.c @@ -0,0 +1,360 @@ +//****************************************************************************** +// Mailbox system. +//****************************************************************************** +// +// Author: Rob F. Van der Wijngaart +// Intel Corporation +// Date: 008/30/2010 +// +//****************************************************************************** +// +// Copyright 2010 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// [2011-05-08] implemented mailbox send/recv routines +// by Simon Pickartz, Chair for Operating Systems, +// RWTH Aachen University +// +#include "iRCCE_lib.h" +#include +#include + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mailbox_print_header +//------------------------------------------------------------------------------ +// routine for printing given header (debugging purpose) +//------------------------------------------------------------------------------ +void iRCCE_mailbox_print_header(iRCCE_MAIL_HEADER* header) { + + printf( "\n" + "-------------------------\n" + "| RCK%d\n" + "-------------------------\n" + "| Sender\t: %d\t\n" + "| Size\t\t: %d\t\n" + "| Tag\t\t: %d\t\n" + "| Prio\t\t: %d\t\n" + "| Payload\t: %s\n" + "-------------------------\n\n", + RCCE_IAM, header->source, + header->size, header->tag, + header->prio, header->payload); +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mailbox_enqueue_header +//------------------------------------------------------------------------------ +// routine to put push received header into iRCCE_mailbox_recv_queue +//------------------------------------------------------------------------------ +static int iRCCE_mail_fetch( + int rank // rank from whom to empty mailbox + ) { + + iRCCE_MAIL_HEADER* header; + + // check for memory in garbage collection or allocate new + if( iRCCE_mail_garbage.first ) { + header = iRCCE_mail_garbage.first; + iRCCE_mail_garbage.first = + iRCCE_mail_garbage.first->next; + + header->next = NULL; + if( iRCCE_mail_garbage.first == NULL ) { + iRCCE_mail_garbage.last = NULL; + } + } + else { + header = (iRCCE_MAIL_HEADER*)kmalloc(sizeof(iRCCE_MAIL_HEADER)); + } + + + // copy header to allocated memory + RC_cache_invalidate(); + iRCCE_memcpy_get( (void*)header, (void*)iRCCE_mailbox_recv[rank], + RCCE_LINE_SIZE ); + + // check if received a last-mail + if( header->tag == iRCCE_LAST_MAIL ) { + iRCCE_last_mail[rank] = 1; + iRCCE_mailbox_close( rank ); // we can close respective mailbox + free( header ); + } + else { + // check mail priority + int prio = header->prio; + + // enqueue accordingly + if( iRCCE_mailbox_recv_queue[prio] == NULL ) { + iRCCE_mailbox_recv_queue[prio] = header; + } + else { + iRCCE_MAIL_HEADER* run = iRCCE_mailbox_recv_queue[prio]; + while( run->next != NULL ) run = run->next; + run->next = header; + } + } + + + return iRCCE_SUCCESS; +} + + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mailbox_check +//------------------------------------------------------------------------------ +// routine to check for new mail in mailboxes +//------------------------------------------------------------------------------ +static int iRCCE_mailbox_check() { + int i, j; + int tmp; + + for( i=0; isent ) { + iRCCE_mail_fetch(i); + + // reset senders flag + RC_cache_invalidate(); + iRCCE_mailbox_recv[i]->sent = RCCE_FLAG_UNSET; + *(int *)RCCE_fool_write_combine_buffer = 1; + } + } + } + + return iRCCE_SUCCESS; +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mail_recv +//------------------------------------------------------------------------------ +// routine for fetching received headers out of iRCCE_mailbox_recv_queue +//------------------------------------------------------------------------------ +int iRCCE_mail_recv( + iRCCE_MAIL_HEADER** header // pointer to incoming header + ) { // (memory allocated by iRCCE) + + int i; + + // if there is no mail, check for incoming + if ( !iRCCE_mailbox_recv_queue[0] ) { + iRCCE_mailbox_check(); + } + + // check priority queues + for( i=0; inext; + help_header->next = NULL; + + + *header = help_header; + return iRCCE_SUCCESS; + } + } + + // no mail queued + *header = NULL; + return iRCCE_MAILBOX_EMPTY; + +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mail_release +//------------------------------------------------------------------------------ +// routine to free memory for given header +//------------------------------------------------------------------------------ +int iRCCE_mail_release( + iRCCE_MAIL_HEADER** header + ) { + + // put header in garbage collection + if( (iRCCE_mail_garbage.first == NULL) + && (iRCCE_mail_garbage.last == NULL ) ) { + + iRCCE_mail_garbage.first = *header; + iRCCE_mail_garbage.last = *header; + } + else { + iRCCE_mail_garbage.last->next = *header; + iRCCE_mail_garbage.last = *header; + } + iRCCE_mail_garbage.last->next = NULL; + + // reset header + *header = NULL; + return iRCCE_SUCCESS; +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mail_send +//------------------------------------------------------------------------------ +// routine for sending headers into receivers mailbox (blocking) +//------------------------------------------------------------------------------ +int iRCCE_mail_send( + size_t size, // size of following message expected to be send/received + int tag, // tag to indicate message type + char prio, // mail priority + char* payload, // pointer to buffer for header payload + int dest // UE that will receive the header + ) { + + // if dest mailbox is full, check for incoming mail + RC_cache_invalidate(); + while( iRCCE_mailbox_send[dest]->sent ) { + iRCCE_mailbox_check(); + RC_cache_invalidate(); + } + + // check if mailbox is closed + RCCE_acquire_lock( dest ); + RC_cache_invalidate(); + if( iRCCE_mailbox_send[dest]->closed ) { + RCCE_release_lock( dest ); + return iRCCE_MAILBOX_CLOSED; + } + + // prepare header + iRCCE_MAIL_HEADER header = { RCCE_IAM, size, tag, NULL, prio, + RCCE_FLAG_UNSET, RCCE_FLAG_UNSET, + {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} }; + + // payload within the header? + if( payload ) { + memcpy( header.payload, payload, iRCCE_MAIL_HEADER_PAYLOAD ); + } + + // do the actual copy to MPB + RC_cache_invalidate(); + iRCCE_memcpy_put( (void*)iRCCE_mailbox_send[dest], + (void*)&header, RCCE_LINE_SIZE ); + + // set senders flag + RC_cache_invalidate(); + iRCCE_mailbox_send[dest]->sent = RCCE_FLAG_SET; + *(int *)RCCE_fool_write_combine_buffer = 1; + RC_cache_invalidate(); + + RCCE_release_lock( dest ); + + return iRCCE_SUCCESS; +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_last_mail_recv +//------------------------------------------------------------------------------ +// check if all final headers are received from all UEs +//------------------------------------------------------------------------------ +int iRCCE_last_mail_recv(void) { + int i; + int res = iRCCE_SUCCESS; + + for( i=0; inext; + free( erase_header ); + erase_header = iRCCE_mailbox_recv_queue[i]; + } + } + return iRCCE_SUCCESS; +} + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mailbox_close_one +//------------------------------------------------------------------------------ +// routine to close one mailbox +//------------------------------------------------------------------------------ +static int iRCCE_mailbox_close_one(int rank) { + RCCE_acquire_lock( RCCE_IAM ); + + // check if it contains new mail + RC_cache_invalidate(); + if( iRCCE_mailbox_recv[rank]->sent ) { + iRCCE_mail_fetch(rank); + + } + + // close mailbox + iRCCE_MAIL_HEADER help_header = { 0, 0, 0, NULL, 0, RCCE_FLAG_UNSET, + RCCE_FLAG_SET, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} }; + + RC_cache_invalidate(); + iRCCE_memcpy_put( (void*)iRCCE_mailbox_recv[rank], + &help_header, RCCE_LINE_SIZE ); + + RCCE_release_lock( RCCE_IAM ); + + iRCCE_mailbox_status[rank] = iRCCE_MAILBOX_CLOSED; + + return iRCCE_SUCCESS; +} + + +//------------------------------------------------------------------------------ +// FUNCTION: iRCCE_mailbox_close() +//------------------------------------------------------------------------------ +// routine to close one or all mailboxes +//------------------------------------------------------------------------------ +int iRCCE_mailbox_close(int rank) { + if( rank == iRCCE_MAILBOX_ALL ) { + int i; + for( i=0; i