2011-07-13 15:08:33 +02:00
|
|
|
//******************************************************************************
|
|
|
|
// Mailbox system.
|
|
|
|
//******************************************************************************
|
|
|
|
//
|
|
|
|
// Author: Simon Pickartz,
|
|
|
|
// Chair for Operating Systems,
|
|
|
|
// RWTH Aachen University
|
|
|
|
// Date: 005/08/2011
|
|
|
|
//
|
|
|
|
//******************************************************************************
|
|
|
|
//
|
|
|
|
// 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-06-28 23:39:40 -07:00
|
|
|
|
2011-07-13 15:08:33 +02:00
|
|
|
/**
|
|
|
|
*
|
2011-10-24 19:26:27 +02:00
|
|
|
* @file iRCCE_mailbox.c
|
|
|
|
* @brief contains implementation of the mailbox system
|
2011-07-13 15:08:33 +02:00
|
|
|
* @author Simon Pickartz
|
|
|
|
*
|
2011-06-28 23:39:40 -07:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2011-05-31 01:50:47 -07:00
|
|
|
#include <metalsvm/stdlib.h>
|
|
|
|
#include <metalsvm/string.h>
|
|
|
|
|
|
|
|
#ifdef CONFIG_ROCKCREEK
|
|
|
|
#include <asm/iRCCE_lib.h>
|
2011-07-23 12:27:08 -07:00
|
|
|
#include <asm/irqflags.h>
|
2011-05-31 10:22:26 +02:00
|
|
|
|
2011-06-06 08:32:59 -07:00
|
|
|
// forward declaration
|
2011-08-09 14:54:30 -07:00
|
|
|
static int iRCCE_mailbox_close_one(int rank, int check);
|
2011-06-06 08:32:59 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mailbox_print_header
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// routine for printing given header (debugging purpose)
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine for printing a given header
|
|
|
|
* @param header is a pointer to a given iRCCE_MAIL_HEADER structure
|
|
|
|
*/
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
void iRCCE_mailbox_print_header(iRCCE_MAIL_HEADER* header) {
|
|
|
|
|
2011-07-18 01:14:18 -07:00
|
|
|
kprintf( "\n"
|
2011-05-31 10:22:26 +02:00
|
|
|
"-------------------------\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);
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
// FUNCTION: iRCCE_mail_fetch
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine to check for new mail in a given mailbox
|
|
|
|
* @param rank is the ID of the ranks mailbox to be emptied
|
|
|
|
*
|
|
|
|
* The function checks if the mailbox has new mail for a given rank. In case of
|
|
|
|
* new mail it needs memory for the received header. Either there is memory
|
|
|
|
* in the internal garbage collection or it has to allocated. The next step is
|
|
|
|
* to check wheter a last-mail was received or a normal one. A last-mail is
|
|
|
|
* indicated by the iRCCE_LAST_MAIL tag. A last-mail entails the appropriate
|
|
|
|
* flag in the iRCCE_last_mail array to be set. Otherwise the header has to be
|
|
|
|
* enqueued in the mailbox_recv_queue accordingly to the priority field.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
static int iRCCE_mail_fetch(
|
|
|
|
int rank // rank from whom to empty mailbox
|
|
|
|
) {
|
2011-07-23 12:27:08 -07:00
|
|
|
/* interrupts should already be disabled! */
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
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;
|
|
|
|
}
|
2011-11-08 07:46:01 -08:00
|
|
|
} else {
|
2011-05-31 10:22:26 +02:00
|
|
|
header = (iRCCE_MAIL_HEADER*)kmalloc(sizeof(iRCCE_MAIL_HEADER));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// copy header to allocated memory
|
2011-08-01 13:55:29 +02:00
|
|
|
//RC_cache_invalidate();
|
2011-05-31 10:22:26 +02:00
|
|
|
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;
|
2011-06-06 08:32:59 -07:00
|
|
|
iRCCE_mailbox_close_one( rank, 0 ); // we can close respective mailbox
|
|
|
|
iRCCE_mail_release( &header );
|
2011-11-08 07:46:01 -08:00
|
|
|
} else {
|
2011-05-31 10:22:26 +02:00
|
|
|
// check mail priority
|
|
|
|
int prio = header->prio;
|
|
|
|
|
|
|
|
// enqueue accordingly
|
2011-07-13 15:08:33 +02:00
|
|
|
header->next = NULL;
|
|
|
|
|
|
|
|
if( iRCCE_mailbox_recv_queue[prio].first == NULL ) {
|
|
|
|
iRCCE_mailbox_recv_queue[prio].first = header;
|
|
|
|
iRCCE_mailbox_recv_queue[prio].last = header;
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-07-13 15:08:33 +02:00
|
|
|
iRCCE_mailbox_recv_queue[prio].last->next = header;
|
|
|
|
iRCCE_mailbox_recv_queue[prio].last = header;
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-07-13 15:08:33 +02:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-01 13:55:29 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mail_check
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
/**
|
2011-11-07 13:01:57 -08:00
|
|
|
* @brief routine to check one specific mailbox or all
|
|
|
|
* @param sender is the core ID from which the mailbox is checked use
|
|
|
|
* iRCCE_MAILBOX_ALL as wildcard to check all mailboxes
|
2011-08-01 13:55:29 +02:00
|
|
|
*
|
|
|
|
* This function may be called by the user application to check one specific
|
2011-11-07 13:01:57 -08:00
|
|
|
* mailbox. It is recommended to use it in combination with an inter-core
|
|
|
|
* interrupt. It empties one or all mailboxes of the participating cores if the
|
|
|
|
* corresponding sent-flag is set and the mailbox is not closed. After calling
|
|
|
|
* iRCCE_mail_fetch the sent-flag has to be reset. Here we have to use a little
|
|
|
|
* trick because we can only write to the MPB in cacheline granularity. We set
|
|
|
|
* the appropriate flag to zero and afterwords touch the MPB on another
|
|
|
|
* cacheline. That causes the write combine buffer to write out the data.
|
2011-08-01 13:55:29 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
2011-11-08 07:46:01 -08:00
|
|
|
const static iRCCE_MAIL_HEADER dummy_header =
|
2011-11-07 13:01:57 -08:00
|
|
|
{0, 0, 0, NULL, 0, 0, 0, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} };
|
|
|
|
|
2011-08-01 13:55:29 +02:00
|
|
|
int iRCCE_mail_check(int sender) {
|
2011-08-13 17:14:01 -07:00
|
|
|
uint32_t flags;
|
2011-11-07 13:01:57 -08:00
|
|
|
int j, i;
|
|
|
|
int found = 0;
|
2011-08-13 17:14:01 -07:00
|
|
|
|
2011-08-27 10:13:13 -07:00
|
|
|
// check all mailboxes in case of wildcard
|
|
|
|
if( sender == iRCCE_MAILBOX_ALL ) {
|
2011-11-07 13:01:57 -08:00
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
2011-08-27 10:13:13 -07:00
|
|
|
|
2011-11-07 13:01:57 -08:00
|
|
|
for( j=1; j<RCCE_NP; ++j ) {
|
|
|
|
i = (j+RCCE_IAM)%RCCE_NP;
|
|
|
|
|
|
|
|
// only check open mailboxes
|
|
|
|
if( iRCCE_mailbox_status[i] == iRCCE_MAILBOX_OPEN ) {
|
|
|
|
RC_cache_invalidate();
|
|
|
|
if( iRCCE_mailbox_recv[i]->sent ) {
|
|
|
|
if( !found ) found = 1;
|
|
|
|
|
|
|
|
iRCCE_mail_fetch(i);
|
|
|
|
// reset senders flag
|
|
|
|
RC_cache_invalidate();
|
|
|
|
*(iRCCE_mailbox_recv[i]) = dummy_header;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
|
|
|
return (found == 1)? iRCCE_SUCCESS : iRCCE_MAILBOX_EMPTY;
|
2011-08-27 10:13:13 -07:00
|
|
|
}
|
2011-08-13 17:14:01 -07:00
|
|
|
|
2011-08-01 13:55:29 +02:00
|
|
|
// verify sender's ID
|
2011-11-08 07:46:01 -08:00
|
|
|
if(BUILTIN_EXPECT((sender < 0) || (sender > RCCE_NP) || (sender == RCCE_IAM), 0)) {
|
2011-08-28 07:09:04 -07:00
|
|
|
return iRCCE_ERROR_SOURCE;
|
2011-08-01 13:55:29 +02:00
|
|
|
}
|
2011-08-27 10:13:13 -07:00
|
|
|
|
2011-08-01 13:55:29 +02:00
|
|
|
// check if mailbox is open
|
|
|
|
if( iRCCE_mailbox_status[sender] == iRCCE_MAILBOX_CLOSED ) {
|
|
|
|
return iRCCE_MAILBOX_CLOSED;
|
|
|
|
}
|
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
for(i=0; i<5; i++) {
|
|
|
|
RC_cache_invalidate();
|
|
|
|
if( iRCCE_mailbox_recv[sender]->sent ) {
|
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
2011-08-27 10:13:13 -07:00
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
iRCCE_mail_fetch(sender);
|
2011-08-01 13:55:29 +02:00
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
// reset senders flag
|
|
|
|
RC_cache_invalidate();
|
|
|
|
*(iRCCE_mailbox_recv[sender]) = dummy_header;
|
2011-08-01 13:55:29 +02:00
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
2011-08-27 10:13:13 -07:00
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NOP8;
|
2011-08-01 13:55:29 +02:00
|
|
|
}
|
2011-08-13 17:14:01 -07:00
|
|
|
|
2011-11-29 03:22:01 -08:00
|
|
|
return iRCCE_MAILBOX_EMPTY;
|
2011-08-01 13:55:29 +02:00
|
|
|
}
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mail_recv
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine for fetching received headers out of iRCCE_mailbox_recv_queue
|
|
|
|
* @param header is the address of a pointer to an iRCCE_MAIL_HEADER structure
|
|
|
|
* @return iRCCE_SUCCESS if there was new mail; iRCCE_MAILBOX_EMPTY else
|
|
|
|
* @todo implement fairer dequeue mechanism
|
|
|
|
*
|
|
|
|
* The function checks if the receive queue with highest priority (priority 0)
|
|
|
|
* contains any mail headers. In this case we pop the first element of that list
|
2011-11-07 13:01:57 -08:00
|
|
|
* in a FIFO maner. Afterwards the first element of a non-empty receive queue
|
|
|
|
* with highest priority is returned.
|
2011-07-01 12:18:15 +02:00
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_mail_recv(
|
|
|
|
iRCCE_MAIL_HEADER** header // pointer to incoming header
|
|
|
|
) { // (memory allocated by iRCCE)
|
|
|
|
|
2011-11-07 13:01:57 -08:00
|
|
|
int i, found = 0;
|
2011-07-23 12:27:08 -07:00
|
|
|
uint32_t flags;
|
2011-07-13 15:08:33 +02:00
|
|
|
iRCCE_MAIL_HEADER* help_header;
|
2011-11-07 13:01:57 -08:00
|
|
|
|
|
|
|
// if no mail queued pointer must be ZERO
|
|
|
|
*header = NULL;
|
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
2011-07-18 01:14:18 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// check priority queues
|
|
|
|
for( i=0; i<iRCCE_PRIOS; ++i ) {
|
2011-07-23 12:27:08 -07:00
|
|
|
|
2011-11-07 13:01:57 -08:00
|
|
|
if ( iRCCE_mailbox_recv_queue[i].first ) {
|
2011-07-13 15:08:33 +02:00
|
|
|
help_header = iRCCE_mailbox_recv_queue[i].first;
|
|
|
|
|
|
|
|
iRCCE_mailbox_recv_queue[i].first =
|
|
|
|
iRCCE_mailbox_recv_queue[i].first->next;
|
|
|
|
|
|
|
|
if( iRCCE_mailbox_recv_queue[i].first == NULL ) {
|
|
|
|
iRCCE_mailbox_recv_queue[i].last = NULL;
|
|
|
|
}
|
2011-11-07 13:01:57 -08:00
|
|
|
|
|
|
|
/* prepare return value */
|
2011-05-31 10:22:26 +02:00
|
|
|
help_header->next = NULL;
|
|
|
|
*header = help_header;
|
2011-11-07 13:01:57 -08:00
|
|
|
found = 1;
|
|
|
|
break;
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-11-07 13:01:57 -08:00
|
|
|
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-07-01 12:18:15 +02:00
|
|
|
|
2011-11-07 13:01:57 -08:00
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
|
|
|
return (found == 1)? iRCCE_SUCCESS : iRCCE_MAILBOX_EMPTY;
|
2011-05-31 10:22:26 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mail_release
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine to store released header by user in garbage collection
|
|
|
|
* @param header is the address of a pointer to an iRCCE_MAIL_HEADER structure
|
|
|
|
* @return iRCCE_SUCCESS in any case
|
|
|
|
*
|
|
|
|
* This function enqueus a pointer to memory for an iRCCE_MAIL_HEADER structure
|
|
|
|
* that is not used by the user program anymore. 'header' points to NULL by
|
|
|
|
* return of the function.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_mail_release(
|
|
|
|
iRCCE_MAIL_HEADER** header
|
|
|
|
) {
|
2011-07-23 12:27:08 -07:00
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// 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;
|
2011-07-23 12:27:08 -07:00
|
|
|
|
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mail_send
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine to send a mail to a given destination (blocking)
|
|
|
|
* @param size is the size of the following message. This message may be
|
|
|
|
* contained in the payload or send by an isend()-call
|
|
|
|
* @param tag is an integer value to distinguish between different mail types
|
|
|
|
* @param prio indicates the priority of the mail. 0 is the highest priority
|
|
|
|
* whereas 4 is the lowest.
|
|
|
|
* @param payload is a pointer to byte array with a size of
|
|
|
|
* iRCCE_MAIL_HEADER_PAYLOAD. If NULL is passed nothing is done, otherwise array
|
|
|
|
* pointed by payload is copied into the header.
|
|
|
|
* @param dest indicates the destination of the mail in terms of the ID of
|
|
|
|
* one of the participating ranks
|
|
|
|
* @return iRCCE_SUCCESS if send was successful. If target mailbox is closed
|
|
|
|
* iRCCE_MAILBOX_CLOESD is returned.
|
|
|
|
*
|
|
|
|
* First it has to be checked if the target mailbox still contains an unread mail.
|
|
|
|
* If this is the case there is time to empty the own mailboxes. It blocks until
|
|
|
|
* the receiver has emptied its mailbox. The next step is to acquire the lock
|
|
|
|
* for the target mailbox to be sure that the mailbox is not closed by the
|
|
|
|
* receiver while the mail is delivered. After locking the mailbox an
|
|
|
|
* iRCCE_MAIL_HEADER is generated according with the parameters (but with a
|
|
|
|
* sent-flag set to zero)and is copied into the target mailbox. After all data
|
|
|
|
* beeing written the appropropriate sent-flag has to be set with the same trick
|
|
|
|
* already used in iRCCE_mail_check(). Now the lock can be released.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
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
|
|
|
|
) {
|
2011-11-07 13:01:57 -08:00
|
|
|
uint32_t flags;
|
|
|
|
|
2011-08-28 07:09:04 -07:00
|
|
|
// verify sender's ID
|
2011-11-08 07:46:01 -08:00
|
|
|
if(BUILTIN_EXPECT((dest < 0) || (dest > RCCE_NP) || (dest == RCCE_IAM),0)) {
|
2011-08-28 07:09:04 -07:00
|
|
|
return iRCCE_ERROR_TARGET;
|
2011-07-18 01:14:18 -07:00
|
|
|
}
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// if dest mailbox is full, check for incoming mail
|
|
|
|
RC_cache_invalidate();
|
|
|
|
while( iRCCE_mailbox_send[dest]->sent ) {
|
2011-11-07 13:01:57 -08:00
|
|
|
// iRCCE_mail_check(iRCCE_MAILBOX_ALL);
|
2011-05-31 10:22:26 +02:00
|
|
|
RC_cache_invalidate();
|
2011-11-07 13:01:57 -08:00
|
|
|
NOP8;
|
|
|
|
NOP8;
|
|
|
|
NOP8;
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-11-07 13:01:57 -08:00
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// check if mailbox is closed
|
|
|
|
RCCE_acquire_lock( dest );
|
|
|
|
RC_cache_invalidate();
|
|
|
|
if( iRCCE_mailbox_send[dest]->closed ) {
|
|
|
|
RCCE_release_lock( dest );
|
2011-11-07 13:01:57 -08:00
|
|
|
|
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
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 );
|
2011-08-18 02:07:42 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// set senders flag
|
|
|
|
RC_cache_invalidate();
|
|
|
|
iRCCE_mailbox_send[dest]->sent = RCCE_FLAG_SET;
|
|
|
|
*(int *)RCCE_fool_write_combine_buffer = 1;
|
2011-07-13 15:08:33 +02:00
|
|
|
RC_cache_invalidate();
|
2011-08-18 02:23:10 -07:00
|
|
|
|
2011-08-27 23:32:04 -07:00
|
|
|
RCCE_release_lock( dest );
|
2011-08-27 11:20:18 -07:00
|
|
|
|
2011-11-07 13:01:57 -08:00
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_last_mail_recv
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief check if all final headers are received from all UEs
|
|
|
|
* @return iRCCE_SUCCES if all last-mails arrive iRCCE_LAST_MAILS_NOT_RECV
|
|
|
|
* otherwise
|
|
|
|
*
|
|
|
|
* This functions is used to determine if all last-mails arrived at the calling
|
|
|
|
* UE. Therefore it checks the iRCCE_last_mail array if all flags are set.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_last_mail_recv(void) {
|
|
|
|
int i;
|
|
|
|
int res = iRCCE_SUCCESS;
|
|
|
|
|
|
|
|
for( i=0; i<RCCE_NP; ++i ) {
|
|
|
|
if( iRCCE_last_mail[i] == 0 ) {
|
|
|
|
res = iRCCE_LAST_MAILS_NOT_RECV;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mailbox_wait
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief wait for all last-mails to be received
|
|
|
|
* @return iRCCE_SUCCESS
|
|
|
|
*
|
|
|
|
* This functions blocks in a loop calling continously iRCCE_last_mail_recv()
|
|
|
|
* until its return value is iRCCE_SUCCESS what implicates that all last-mails
|
|
|
|
* of the participating UEs arrived at the calling UE.
|
|
|
|
* This function is used to shut down the mailbox environment.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_mailbox_wait(void) {
|
|
|
|
while( iRCCE_last_mail_recv() == iRCCE_LAST_MAILS_NOT_RECV ) {
|
2011-11-07 13:01:57 -08:00
|
|
|
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mailbox_flush
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief dequeue all iRCCE_mailbox_recv_queue elements and free memory
|
|
|
|
* @return iRCCE_SUCCESS
|
|
|
|
*
|
|
|
|
* This function empties all iRCCE_mailbox_recv_queues whith no regard to their
|
|
|
|
* content. This function is used to shut down the mailbox environment.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_mailbox_flush(void) {
|
|
|
|
int i;
|
2011-07-23 12:27:08 -07:00
|
|
|
uint32_t flags;
|
2011-08-27 10:13:13 -07:00
|
|
|
|
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
|
|
|
|
|
|
|
// empty priority queues
|
2011-05-31 10:22:26 +02:00
|
|
|
for( i=0; i<iRCCE_PRIOS; ++i ) {
|
2011-07-13 15:08:33 +02:00
|
|
|
iRCCE_MAIL_HEADER* erase_header =
|
|
|
|
iRCCE_mailbox_recv_queue[i].first;
|
2011-08-27 02:43:06 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
while( erase_header != NULL ) {
|
2011-07-13 15:08:33 +02:00
|
|
|
iRCCE_mailbox_recv_queue[i].first =
|
|
|
|
iRCCE_mailbox_recv_queue[i].first->next;
|
2011-05-31 01:57:48 -07:00
|
|
|
kfree( erase_header, sizeof(iRCCE_MAIL_HEADER) );
|
2011-07-13 15:08:33 +02:00
|
|
|
erase_header = iRCCE_mailbox_recv_queue[i].first;
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-07-23 12:27:08 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
2011-08-27 10:13:13 -07:00
|
|
|
|
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mailbox_close_one
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine to close one mailbox
|
|
|
|
* @return iRCCE_SUCCESS
|
|
|
|
* @param rank is the ID of the ranks mailbox to be closed
|
|
|
|
* @param check is a flag indicating wether the mailbox has to be emptied before
|
|
|
|
* closing or not. This is required for a close-call as a result of a received
|
|
|
|
* last-mail.
|
|
|
|
*
|
|
|
|
* This function closes a mailbox of the given rank. If the check flag is set
|
2011-11-07 13:01:57 -08:00
|
|
|
* an iRCCE_mail_check()-call is performed. The close procedure has to be
|
2011-08-01 13:55:29 +02:00
|
|
|
* locked to be sure that no UE sends any mail while closing the mailbox.
|
2011-07-01 12:18:15 +02:00
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
2011-06-06 08:32:59 -07:00
|
|
|
static int iRCCE_mailbox_close_one(int rank, int check) {
|
2011-07-23 12:27:08 -07:00
|
|
|
uint32_t flags;
|
2011-05-31 10:22:26 +02:00
|
|
|
RCCE_acquire_lock( RCCE_IAM );
|
|
|
|
|
2011-07-23 12:27:08 -07:00
|
|
|
/* disable interrupts */
|
|
|
|
flags = irq_nested_disable();
|
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
// check if it contains new mail
|
|
|
|
RC_cache_invalidate();
|
2011-06-06 08:32:59 -07:00
|
|
|
if( check && iRCCE_mailbox_recv[rank]->sent ) {
|
2011-07-23 12:27:08 -07:00
|
|
|
|
2011-05-31 10:22:26 +02:00
|
|
|
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 );
|
2011-07-23 12:27:08 -07:00
|
|
|
|
|
|
|
/* enable interrupts */
|
|
|
|
irq_nested_enable(flags);
|
2011-05-31 10:22:26 +02:00
|
|
|
|
|
|
|
RCCE_release_lock( RCCE_IAM );
|
|
|
|
|
2011-08-27 02:43:06 -07:00
|
|
|
iRCCE_mailbox_status[rank] = iRCCE_MAILBOX_CLOSED;
|
2011-05-31 10:22:26 +02:00
|
|
|
|
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// FUNCTION: iRCCE_mailbox_close()
|
|
|
|
//------------------------------------------------------------------------------
|
2011-07-01 12:18:15 +02:00
|
|
|
/**
|
|
|
|
* @brief routine to close one or all mailboxes
|
|
|
|
* @param rank is the ID of the UEs mailbox to be closed if iRCCE_MAILBOX_ALL
|
|
|
|
* is passed all mailboxes are closed by the calling UE
|
|
|
|
* @return iRCCE_SUCCESS
|
|
|
|
*
|
|
|
|
* This functions closed one or all mailboxes of the calling UE. This is done by
|
|
|
|
* calling iRCCE_mailbox_close_one for one or all mailboxes.
|
|
|
|
*/
|
2011-05-31 10:22:26 +02:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int iRCCE_mailbox_close(int rank) {
|
|
|
|
if( rank == iRCCE_MAILBOX_ALL ) {
|
|
|
|
int i;
|
|
|
|
for( i=0; i<RCCE_NP; ++i ) {
|
2011-06-06 08:32:59 -07:00
|
|
|
iRCCE_mailbox_close_one( i, 1 );
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2011-06-06 08:32:59 -07:00
|
|
|
iRCCE_mailbox_close_one( rank, 1 );
|
2011-05-31 10:22:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return iRCCE_SUCCESS;
|
|
|
|
}
|
2011-05-31 01:50:47 -07:00
|
|
|
|
|
|
|
#endif
|