Beispiel #1
0
/*!
 * \brief This function frees a buffer previously returned by mcc_recv_nocopy().
 *
 * Once the zero-copy mechanism of receiving data is used, this function
 * has to be called to free a buffer and to make it available for the next data
 * transfer.
 *
 * \param[in] buffer Pointer to the buffer to be freed.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 *
 * \see mcc_recv_nocopy
 */
int mcc_free_buffer(void *buffer)
{
    MCC_SIGNAL affiliated_signal;
    MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};
    int return_value, i = 0;

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Enqueue the buffer into the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    mcc_queue_buffer(&bookeeping_data->free_list, (MCC_RECEIVE_BUFFER *)((unsigned int)buffer - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data))));

    /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */
    affiliated_signal.type = BUFFER_FREED;
    affiliated_signal.destination = tmp_destination;
    for (i=0; i<MCC_NUM_CORES; i++) {
        if(i != MCC_CORE_NUMBER) {
            mcc_queue_signal(i, affiliated_signal);
        }
    }
    mcc_generate_cpu_to_cpu_interrupt();

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #2
0
/*!
 * \brief This function de-initializes the Multi Core Communication subsystem for a given node.
 *
 * The function frees all resources of the node. Deletes all endpoints and frees any buffers that may have been queued there.
 *
 * \param[in] node Node number to be deinitialized.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_OSSYNC (OS synchronization module(s) deinitialization failed)
 *
 * \see mcc_initialize
 */
int mcc_destroy(MCC_NODE node)
{
    int i = 0, return_value;

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* All endpoints of the particular node have to be removed from the endpoint table */
    MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM));
    for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {
        if (bookeeping_data->endpoint_table[i].endpoint.node == node) {
            /* Remove the endpoint from the table */
            mcc_remove_endpoint(bookeeping_data->endpoint_table[i].endpoint);
        }
    }

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Deinitialize synchronization module */
    mcc_deinit_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER);

    /* De-initialize OS synchronization module(s) 
       (for unblocking tasks waiting for new data and for unblocking tasks waiting for a free buffer */
    return_value = mcc_deinit_os_sync();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #3
0
/*!
 * \brief This function de-initializes the Multi Core Communication subsystem for a given node.
 *
 * The function frees all resources of the node. Deletes all endpoints and frees any buffers that may have been queued there.
 *
 * \param[in] node Node number to be deinitialized.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 *
 * \see mcc_initialize
 */
int mcc_destroy(MCC_NODE node)
{
    int i = 0, return_value;

#if (MCC_OS_USED == MCC_MQX)
    for(i=0; i<MCC_MQX_LWEVENT_COMPONENTS_COUNT; i++) {
        _lwevent_destroy(&lwevent_buffer_queued[i]);
    }
    _lwevent_destroy(&lwevent_buffer_freed);
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* All endpoints of the particular node have to be removed from the endpoint table */
    MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM));
    for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {
        if (bookeeping_data->endpoint_table[i].endpoint.node == node) {
            /* Remove the endpoint from the table */
            mcc_remove_endpoint(bookeeping_data->endpoint_table[i].endpoint);
        }
    }

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Deinitialize synchronization module */
    mcc_deinit_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER);

    return return_value;
}
Beispiel #4
0
/*!
 * \brief This function removes an endpoint.
 *
 * Removes an endpoint with specified structure / params (core, node and port).
 *
 * \param[in] endpoint Pointer to the endpoint structure.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (invalid value for port or the endpoint doesn't exist)
 */
int mcc_remove_endpoint(MCC_ENDPOINT endpoint)
{
    int i=0;

    /* must be valid */
    if(endpoint.port == MCC_RESERVED_PORT_NUMBER)
        return MCC_ERR_ENDPOINT;

    MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM));
    for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {

        if(MCC_ENDPOINTS_EQUAL(bookeeping_data->endpoint_table[i].endpoint, endpoint)) {
            /* clear the queue */
            MCC_RECEIVE_BUFFER * buffer = mcc_dequeue_buffer((MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list);
            while(buffer) {
                mcc_queue_buffer(&bookeeping_data->free_list, buffer);
                buffer = mcc_dequeue_buffer((MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list);
            }
            /* indicate free */
            bookeeping_data->endpoint_table[i].endpoint.port = MCC_RESERVED_PORT_NUMBER;
            MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->endpoint_table[i].endpoint.port, sizeof(MCC_PORT));
            return MCC_SUCCESS;
        }
    }
    return MCC_ERR_ENDPOINT;
}
Beispiel #5
0
/*!
 * \brief This function returns the number of buffers currently queued at the endpoint.
 *
 * The function checks if messages are available on a receive endpoint. While the call only checks the
 * availability of messages, it does not dequeue them.
 *
 * \param[in] endpoint Pointer to the endpoint structure.
 * \param[out] num_msgs Pointer to an unsigned int that will contain the number of buffers queued.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 *
 * \see mcc_recv_copy
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_msgs_available(MCC_ENDPOINT *endpoint, unsigned int *num_msgs)
{
    unsigned int count = 0;
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    int return_value;

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);
    if(list == null) {
        /* The endpoint does not exists (has not been registered so far), return immediately - error */
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    buf = list->head;
    while(buf != (MCC_RECEIVE_BUFFER*)0) {
        count++;
        MCC_DCACHE_INVALIDATE_MLINES((void*)&buf->next, sizeof(MCC_RECEIVE_BUFFER*));
        buf = (MCC_RECEIVE_BUFFER*)buf->next;
    }
    *num_msgs = count;

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #6
0
/*!
 * \brief This function dequeues the buffer.
 *
 * Dequeues the buffer from the list.
 *
 * \param[in] list Pointer to the MCC_RECEIVE_LIST structure.
 *  
 * \return Pointer to MCC_RECEIVE_BUFFER
 */
MCC_RECEIVE_BUFFER * mcc_dequeue_buffer(MCC_RECEIVE_LIST *list)
{
    MCC_RECEIVE_BUFFER * next_buf, * next_buf_virt;
    MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST));

    next_buf = list->head;

    next_buf_virt = (MCC_RECEIVE_BUFFER *)MCC_MEM_PHYS_TO_VIRT(next_buf);
    if(next_buf) {
        MCC_DCACHE_INVALIDATE_MLINES((void*)&next_buf_virt->next, sizeof(MCC_RECEIVE_BUFFER*));
        list->head = next_buf_virt->next;
        if(list->tail == next_buf)
            list->tail = null;
    }
    MCC_DCACHE_FLUSH_MLINES(list, sizeof(MCC_RECEIVE_LIST));
    return next_buf_virt;
}
Beispiel #7
0
/*!
 * \brief This function sends a message to an endpoint. The data is NOT copied 
 * from the user-app. buffer but the pointer to already filled message buffer is
 * provided.  
 *
 * The application has to take the responsibility for:
 *  1. MCC buffer de-allocation
 *  2. filling the data to be sent into the pre-allocated MCC buffer
 *  3. not exceeding the buffer size when filling the data (MCC_ATTR_BUFFER_SIZE_IN_BYTES) 
 * 
 * Once the data cache is used on the target platform it is good to have MCC buffers 
 * in shared RAM aligned to the cache line size in order not to corrupt entities placed 
 * just before and just after the MCC buffer when flushing the MCC buffer content into
 * the shared RAM. It is also the application responsibility to flush the data in
 * that case. If the alignment condition is not fulfilled the application
 * has to take care about the data cache coherency. 
 * The following scenarios can happen:
 * A. Data cache is OFF:
 *    - No cache operation needs to be done, the application just 
 *     1. calls the mcc_get_buffer() function, 
 *     2. fills data into the provided MCC buffer,
 *     3. and finally issues the mcc_send_nocopy() function.
 * B. Data cache is ON, shared RAM MCC buffers ALIGNED to the cache line size:
 *    - The application has to perform following steps: 
 *     1. call the mcc_get_buffer() to get the pointer to a free message buffer 
 *     2. copy data to be sent into the message buffer
 *     3. flush all cache lines occupied by the message buffer new data
 *       (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes).
 *     4. call the mcc_send_nocopy() with the correct buffer pointer and the message size passed 
 * C. Data cache is ON, shared RAM MCC buffers NOT ALIGNED:
 *    - The application has to perform following steps: 
 *     1. call the mcc_get_buffer() to get the pointer to a free message buffer 
 *     2. grab the hw semaphore by calling the mcc_get_semaphore() low level MCC function.
 *     3. invalidate all cache lines occupied by data to be filled into the free message buffer.
 *       (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes).
 *     4. copy data to be sent into the message buffer.
 *     5. flush all cache lines occupied by the message buffer new data 
 *       (maximum of MCC_ATTR_BUFFER_SIZE_IN_BYTES bytes).
 *     6. release the hw semaphore by calling the mcc_release_semaphore() low level MCC function.
 *     7. call the mcc_send_nocopy() with the correct buffer pointer and the message size passed.
 * 
 * After the mcc_send_nocopy() function is issued the message buffer is no more owned 
 * by the sending task and must not be touched anymore unless the mcc_send_nocopy() 
 * function fails and returns an error. In that case the application should try 
 * to re-issue the mcc_send_nocopy() again and if it is still not possible to send 
 * the message and the application wants to give it up from whatever reasons 
 * (for instance the MCC_ERR_ENDPOINT error is returned meaning the endpoint 
 * has not been created yet) the mcc_free_buffer() function could be called, 
 * passing the pointer to the buffer to be freed as a parameter.     
 *
 * \param[in] src_endpoint Pointer to the local endpoint identifying the source endpoint.
 * \param[in] dest_endpoint Pointer to the destination endpoint to send the message to.
 * \param[in] buffer_p Pointer to the MCC buffer of the shared memory where the 
 *            data to be sent is stored.
 * \param[in] msg_size Size of the message to be sent in bytes.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer)
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_SQ_FULL (signal queue is full)
 *
 * \see mcc_send
 * \see mcc_get_buffer
 * \see MCC_ENDPOINT
 */
int mcc_send_nocopy(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *buffer_p, MCC_MEM_SIZE msg_size)
{
    int return_value;
    MCC_RECEIVE_BUFFER * buf;
    MCC_RECEIVE_LIST *list;
    MCC_SIGNAL affiliated_signal;

    /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */
    if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) {
        return MCC_ERR_INVAL;
    }

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*dest_endpoint);

    if(list == null) {
        /* The endpoint does not exists (has not been registered so far) */
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    /* Store the message size and the source endpoint in the MCC_RECEIVE_BUFFER structure */
    buf = (MCC_RECEIVE_BUFFER *)((unsigned int)buffer_p - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data)));
    MCC_DCACHE_INVALIDATE_MLINES((void*)&buf->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE));
    ((MCC_RECEIVE_BUFFER*)buf)->data_len = msg_size;
    mcc_memcpy((void*)src_endpoint, (void*)&buf->source, sizeof(MCC_ENDPOINT));
    MCC_DCACHE_FLUSH_MLINES((void*)(void*)&buf->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE));


    /* Write the signal type into the signal queue of the particular core */
    affiliated_signal.type = BUFFER_QUEUED;
    affiliated_signal.destination = *dest_endpoint;
    return_value = mcc_queue_signal(dest_endpoint->core, affiliated_signal);
    if(return_value != MCC_SUCCESS) {
        /* Signal queue is full - error */
        mcc_release_semaphore();
        return return_value;
    }

    /* Enqueue the buffer into the endpoint buffer list */
    mcc_queue_buffer(list, (MCC_RECEIVE_BUFFER*)buf);

    /* Semaphore-protected section end */
    mcc_release_semaphore();

    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Signal the other core by generating the CPU-to-CPU interrupt */
    return_value = mcc_generate_cpu_to_cpu_interrupt();

    return return_value;
}
Beispiel #8
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available. The data is NOT copied into the user-app. buffer.
 *
 * This is the "zero-copy receive" version of the MCC receive function. No data is copied. 
 * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
 * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
 * make the appropriate API call to free it, see mcc_free_buffer.
 *
 * \param[out] src_endpoint Pointer to the MCC_ENDPOINT structure to be filled by the endpoint identifying the message sender.
 * \param[in] dest_endpoint Pointer to the local receiving endpoint to receive from.
 * \param[out] buffer_p Pointer to the MCC buffer of the shared memory where the received data is stored.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of valid bytes in the buffer.
 * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv
 * \see MCC_ENDPOINT
 */
int mcc_recv_nocopy(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void **buffer_p, MCC_MEM_SIZE *recv_size, unsigned int timeout_ms)
{
    MCC_RECEIVE_LIST *list = null;
    int return_value;

    return_value = mcc_recv_common_part(dest_endpoint, timeout_ms, (MCC_RECEIVE_LIST**)&list);
    if(return_value != MCC_SUCCESS)
        return return_value;
    
    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        mcc_release_semaphore();
        return MCC_ERR_TIMEOUT;
    }

    /* Get the message pointer from the head of the receive buffer list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    *buffer_p = (void*)&list->head->data;
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE));
    mcc_memcpy((void*)&list->head->source, (void*)src_endpoint, sizeof(MCC_ENDPOINT));
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);

    /* Dequeue the buffer from the endpoint list */
    mcc_dequeue_buffer(list);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #9
0
/*!
 * \brief This function dequeues a signal
 * 
 * It dequeues a signal from the signal queue for the particular core.
 *    
 * \param[in] core Core number.
 * \param[in] signal Signal to be dequeued.
 *  
 * \return MCC_SUCCESS
 * \return MCC_ERR_SQ_EMPTY (signal queue is empty, nothing to dequeue)
 */
int mcc_dequeue_signal(MCC_CORE core, MCC_SIGNAL *signal)
{
    int head;

    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int));
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int));
    head = bookeeping_data->signal_queue_head[core];

    if(MCC_SIGNAL_QUEUE_EMPTY(core))
        return MCC_ERR_SQ_EMPTY;

    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signals_received[core][head], sizeof(MCC_SIGNAL));
    signal->type = bookeeping_data->signals_received[core][head].type;
    signal->destination.core = bookeeping_data->signals_received[core][head].destination.core;
    signal->destination.node = bookeeping_data->signals_received[core][head].destination.node;
    signal->destination.port = bookeeping_data->signals_received[core][head].destination.port;

    bookeeping_data->signal_queue_head[core] = head == (MCC_MAX_OUTSTANDING_SIGNALS-1) ? 0 : head+1;
    MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int));

    return MCC_SUCCESS;
}
Beispiel #10
0
/*!
 * \brief This function queues a signal
 *  
 * Signal circular queue rules:
 * 	tail points to next free slot
 * 	head points to first occupied slot
 * 	head == tail indicates empty
 * 	(tail + 1) % len = fill
 * This method costs 1 slot since you need to differentiate
 * between full and empty (if you fill the last slot it looks
 * like empty since h == t)
 *
 * \param[in] core Core number.
 * \param[in] signal Signal to be queued.
 *  
 * \return MCC_SUCCESS
 * \return MCC_ERR_SQ_FULL (signal queue is full - no more that MCC_MAX_OUTSTANDING_SIGNALS items allowed)
 */
int mcc_queue_signal(MCC_CORE core, MCC_SIGNAL signal)
{
    int tail, new_tail;

    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_head[core], sizeof(unsigned int));
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int));
    tail = bookeeping_data->signal_queue_tail[core];
    new_tail = tail == (MCC_MAX_OUTSTANDING_SIGNALS-1) ? 0 : tail+1;

    if(MCC_SIGNAL_QUEUE_FULL(core))
        return MCC_ERR_SQ_FULL;

    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->signals_received[core][tail], sizeof(MCC_SIGNAL));
    bookeeping_data->signals_received[core][tail].type = signal.type;
    bookeeping_data->signals_received[core][tail].destination.core = signal.destination.core;
    bookeeping_data->signals_received[core][tail].destination.node = signal.destination.node;
    bookeeping_data->signals_received[core][tail].destination.port = signal.destination.port;

    bookeeping_data->signal_queue_tail[core] = new_tail;
    MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signal_queue_tail[core], sizeof(unsigned int));
    MCC_DCACHE_FLUSH_MLINES((void*)&bookeeping_data->signals_received[core][tail], sizeof(MCC_SIGNAL));

    return MCC_SUCCESS;
}
Beispiel #11
0
/*!
 * \brief This function returns the endpoint list.
 *
 * Returns the MCC_RECEIVE_LIST respective to the endpoint structure provided.
 *
 * \param[in] endpoint Pointer to the MCC_ENDPOINT structure.
 *  
 * \return MCC_RECEIVE_LIST pointer 
 * \return null pointer
 */
MCC_RECEIVE_LIST * mcc_get_endpoint_list(MCC_ENDPOINT endpoint)
{
    int i=0;

    /* must be valid */
    if(endpoint.port == MCC_RESERVED_PORT_NUMBER)
        return null;

    MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM));
    for(i = 0; i<MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {

        if(MCC_ENDPOINTS_EQUAL(bookeeping_data->endpoint_table[i].endpoint, endpoint)) {
            return (MCC_RECEIVE_LIST *)&bookeeping_data->endpoint_table[i].list;
        }
    }
    return null;
}
Beispiel #12
0
/*!
 * \brief This function queues the buffer.
 *
 * Queues the buffer in the list.
 *
 * \param[in] list Pointer to the MCC_RECEIVE_LIST structure.
 * \param[in] r_buffer Pointer to MCC_RECEIVE_BUFFER.
 *  
 * \return none
 */
void mcc_queue_buffer(MCC_RECEIVE_LIST *list, MCC_RECEIVE_BUFFER * r_buffer)
{
    MCC_RECEIVE_BUFFER * last_buf;
    MCC_RECEIVE_BUFFER * r_buffer_phys;

    MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST));

    last_buf = (MCC_RECEIVE_BUFFER *)MCC_MEM_PHYS_TO_VIRT(list->tail);
    r_buffer_phys = (MCC_RECEIVE_BUFFER *)MCC_MEM_VIRT_TO_PHYS(r_buffer);
    if(last_buf) {
        last_buf->next = r_buffer_phys;
        MCC_DCACHE_FLUSH_MLINES((void*)&last_buf->next, sizeof(MCC_RECEIVE_BUFFER*));
    }
    else {
        list->head = r_buffer_phys;
    }
    r_buffer->next = null;
    list->tail = r_buffer_phys;
    MCC_DCACHE_FLUSH_MLINES(list, sizeof(MCC_RECEIVE_LIST));
    MCC_DCACHE_FLUSH_MLINES((void*)&r_buffer->next, sizeof(MCC_RECEIVE_BUFFER*));
}
Beispiel #13
0
/*!
 * \private
 *  
 * \brief This function dequeues a buffer from the free list.
 *
 * This is an internal implementation of the mcc_get_buffer() function. It is called
 * either from the mcc_send() or from mcc_get_buffer() when the non-copy-send
 * mechanism is enabled by the MCC_SEND_RECV_NOCOPY_API_ENABLED macro in mcc_config.h. 
 *
 * \param[out] buffer Pointer to the MCC buffer dequeued from the free list.
 * \param[out] buf_size Pointer to an MCC_MEM_SIZE that is used for passing the size of the dequeued MCC buffer to the application.
 * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available)
 * \return MCC_ERR_NOMEM (no free buffer available and timeout_ms set to 0)
 *
 * \see mcc_send_nocopy
 * \see mcc_send
 * \see mcc_get_buffer 
 */
static int mcc_get_buffer_internal(void **buffer, MCC_MEM_SIZE *buf_size, unsigned int timeout_ms)
{
    int return_value;
    MCC_RECEIVE_BUFFER * buf = null;

    *buffer = null;
    
    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    buf = mcc_dequeue_buffer(&bookeeping_data->free_list);

    /* Semaphore-protected section end */
    mcc_release_semaphore();

    if(buf == null) {
        /* Non-blocking call */
        if(timeout_ms == 0) {
            return MCC_ERR_NOMEM;
        } else {
            /* Wait for the buffer freed event */
            return_value = mcc_wait_for_buffer_freed((MCC_RECEIVE_BUFFER **)&buf, timeout_ms);
            if(MCC_SUCCESS != return_value) {
                return return_value;
            }
        }
    }

    /* Return the MCC buffer size and the pointer to the dequeued MCC buffer */
    *buf_size = (MCC_MEM_SIZE)sizeof(bookeeping_data->r_buffers[0].data);
    *buffer = (void*)buf->data;
    return MCC_SUCCESS;
}
Beispiel #14
0
/*!
 * \brief This function registers an endpoint.
 *
 * Register an endpoint with specified structure / params (core, node and port).
 *
 * \param[in] endpoint Pointer to the endpoint structure.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_NOMEM (maximum number of endpoints exceeded)
 * \return MCC_ERR_ENDPOINT (invalid value for port or endpoint already registered)
 */
int mcc_register_endpoint(MCC_ENDPOINT endpoint)
{
    int i;

    /* must be valid */
    if(endpoint.port == MCC_RESERVED_PORT_NUMBER)
        return MCC_ERR_ENDPOINT;

    /* check not already registered */
    if(mcc_get_endpoint_list(endpoint))
        return MCC_ERR_ENDPOINT;

    MCC_DCACHE_INVALIDATE_MLINES(&bookeeping_data->endpoint_table[0], MCC_ATTR_MAX_RECEIVE_ENDPOINTS * sizeof(MCC_ENDPOINT_MAP_ITEM));
    for(i = 0; i < MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {
        if(bookeeping_data->endpoint_table[i].endpoint.port == MCC_RESERVED_PORT_NUMBER) {
            bookeeping_data->endpoint_table[i].endpoint.core = endpoint.core;
            bookeeping_data->endpoint_table[i].endpoint.node = endpoint.node;
            bookeeping_data->endpoint_table[i].endpoint.port = endpoint.port;
            MCC_DCACHE_FLUSH_MLINES(&bookeeping_data->endpoint_table[i], sizeof(MCC_ENDPOINT_MAP_ITEM));
            return MCC_SUCCESS;
        }
    }
    return MCC_ERR_NOMEM;
}
Beispiel #15
0
/*!
 * \brief This function initializes the Multi Core Communication subsystem for a given node.
 *
 * This function should only be called once per node (once in MQX, once per a process in Linux).
 * It tries to initialize the bookkeeping structure when the init_string member of this structure
 * is not equal to MCC_INIT_STRING, i.e. when no other core had performed the initialization yet.
 * Note, that this way of bookkeeping data re-initialization protection is not powerful enough and
 * the user application should not rely on this method. Instead, the application should be designed 
 * to unambiguously assign the core that will perform the MCC initialization. 
 * Clear the shared memory before the first core is attempting to initialize the MCC 
 * (in some cases MCC_INIT_STRING remains in the shared memory after the application reset and could
 * cause that the bookkeeping data structure is not initialized correctly). 
 *
 * \param[in] node Node number that will be used in endpoints created by this process.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INT (interrupt registration error)
 * \return MCC_ERR_VERSION (incorrect MCC version used - compatibility issue)
 * \return MCC_ERR_OSSYNC (OS synchronization module(s) initialization failed)
 *
 * \see mcc_destroy
 * \see MCC_BOOKEEPING_STRUCT
 */
int mcc_initialize(MCC_NODE node)
{
    int i,j = 0;
    int return_value = MCC_SUCCESS;
    MCC_SIGNAL tmp_signals_received = {(MCC_SIGNAL_TYPE)0, {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0}};

    /* Initialize synchronization module for shared data protection */
    return_value = mcc_init_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER);
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Initialize all necessary OS synchronization module(s) 
       (for unblocking tasks waiting for new received data and for unblocking tasks waiting for a free buffer) */
    return_value = mcc_init_os_sync();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Register CPU-to-CPU interrupt for inter-core signaling */
    //mcc_register_cpu_to_cpu_isr(MCC_CORE0_CPU_TO_CPU_VECTOR);
    return_value = mcc_register_cpu_to_cpu_isr();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Initialize the bookeeping structure */
    bookeeping_data = (MCC_BOOKEEPING_STRUCT *)mcc_get_bookeeping_data();
    MCC_DCACHE_INVALIDATE_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT));
    if(strcmp(bookeeping_data->init_string, init_string) != 0) {
        /* MCC not initialized yet, do it now */
        /* Zero it all - no guarantee Linux or uboot didnt touch it before it was reserved */
        memset((void*) bookeeping_data, 0, sizeof(struct mcc_bookeeping_struct));

        /* Set init_string in case it has not been set yet by another core */
        mcc_memcpy((void*)init_string, bookeeping_data->init_string, (unsigned int)sizeof(bookeeping_data->init_string));

        /* Set version_string */
        mcc_memcpy((void*)version_string, bookeeping_data->version_string, (unsigned int)sizeof(bookeeping_data->version_string));

        /* Initialize the free list */
        bookeeping_data->free_list.head = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[0]);
        bookeeping_data->free_list.tail = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1]);

        /* Initialize receive buffers */
        for(i=0; i<MCC_ATTR_NUM_RECEIVE_BUFFERS-1; i++) {
            bookeeping_data->r_buffers[i].next = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(&bookeeping_data->r_buffers[i+1]);
        }
        bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1].next = null;

        /* Initialize signal queues */
        for(i=0; i<MCC_NUM_CORES; i++) {
            for(j=0; j<MCC_MAX_OUTSTANDING_SIGNALS; j++) {
                bookeeping_data->signals_received[i][j] = tmp_signals_received;
            }
            bookeeping_data->signal_queue_head[i] = 0;
            bookeeping_data->signal_queue_tail[i] = 0;
        }

        /* Mark all endpoint ports as free */
        for(i=0; i<MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {
            bookeeping_data->endpoint_table[i].endpoint.port = MCC_RESERVED_PORT_NUMBER;
        }
    }
    else {
        /* MCC already initialized - check the major number of the version string to ensure compatibility */
        if(strncmp(bookeeping_data->version_string, version_string, 4) != 0) {
            return_value = MCC_ERR_VERSION;
        }
    }
    
    MCC_DCACHE_FLUSH_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT));
    return return_value;
}
Beispiel #16
0
/*!
 * \brief This function initializes the Multi Core Communication subsystem for a given node.
 *
 * This function should only be called once per node (once in MQX, once per process in Linux).
 *
 * \param[in] node Node number that will be used in endpoints created by this process.
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INT (interrupt registration error)
 *
 * \see mcc_destroy
 * \see MCC_BOOKEEPING_STRUCT
 */
int mcc_initialize(MCC_NODE node)
{
    int i,j = 0;
    int return_value = MCC_SUCCESS;
    MCC_SIGNAL tmp_signals_received = {(MCC_SIGNAL_TYPE)0, (MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};

#if (MCC_OS_USED == MCC_MQX)
    for(i=0; i<MCC_MQX_LWEVENT_COMPONENTS_COUNT; i++) {
        _lwevent_create(&lwevent_buffer_queued[i],0);
    }
    _lwevent_create(&lwevent_buffer_freed,0);
#endif

    /* Initialize synchronization module */
    return_value = mcc_init_semaphore(MCC_SHMEM_SEMAPHORE_NUMBER);
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Register CPU-to-CPU interrupt for inter-core signaling */
    //mcc_register_cpu_to_cpu_isr(MCC_CORE0_CPU_TO_CPU_VECTOR);
    return_value = mcc_register_cpu_to_cpu_isr();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Initialize the bookeeping structure */
    bookeeping_data = (MCC_BOOKEEPING_STRUCT *)MCC_BASE_ADDRESS;
    MCC_DCACHE_INVALIDATE_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT));
    if(strcmp(bookeeping_data->init_string, init_string) != 0) {

        /* Zero it all - no guarantee Linux or uboot didnt touch it before it was reserved */
        _mem_zero((void*) bookeeping_data, (_mem_size) sizeof(struct mcc_bookeeping_struct));

        /* Set init_string in case it has not been set yet by another core */
        mcc_memcpy((void*)init_string, bookeeping_data->init_string, (unsigned int)sizeof(bookeeping_data->init_string));

        /* Set version_string */
        mcc_memcpy((void*)version_string, bookeeping_data->version_string, (unsigned int)sizeof(bookeeping_data->version_string));

        /* Initialize the free list */
        bookeeping_data->free_list.head = &bookeeping_data->r_buffers[0];
        bookeeping_data->free_list.tail = &bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1];

        /* Initialize receive buffers */
        for(i=0; i<MCC_ATTR_NUM_RECEIVE_BUFFERS-1; i++) {
            bookeeping_data->r_buffers[i].next = &bookeeping_data->r_buffers[i+1];
        }
        bookeeping_data->r_buffers[MCC_ATTR_NUM_RECEIVE_BUFFERS-1].next = null;

        /* Initialize signal queues */
        for(i=0; i<MCC_NUM_CORES; i++) {
            for(j=0; j<MCC_MAX_OUTSTANDING_SIGNALS; j++) {
                bookeeping_data->signals_received[i][j] = tmp_signals_received;
            }
            bookeeping_data->signal_queue_head[i] = 0;
            bookeeping_data->signal_queue_tail[i] = 0;
        }

        /* Mark all endpoint ports as free */
        for(i=0; i<MCC_ATTR_MAX_RECEIVE_ENDPOINTS; i++) {
            bookeeping_data->endpoint_table[i].endpoint.port = MCC_RESERVED_PORT_NUMBER;
        }
    }
    MCC_DCACHE_FLUSH_MLINES(bookeeping_data, sizeof(MCC_BOOKEEPING_STRUCT));
    return return_value;
}
Beispiel #17
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available. The data is NOT copied into the user-app. buffer.
 *
 * This is the "zero-copy receive" version of the MCC receive function. No data is copied. 
 * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
 * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
 * make the appropriate API call to free it.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[out] buffer_p Pointer to the MCC buffer of the shared memory where the received data is stored.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of valid bytes in the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_copy
 * \see MCC_ENDPOINT
 */
int mcc_recv_nocopy(MCC_ENDPOINT *endpoint, void **buffer_p, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    int return_value;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
	}

    /* Get the message pointer from the head of the receive buffer list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    *buffer_p = (void*)&list->head->data;
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    mcc_dequeue_buffer(list);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #18
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available.
 *        The data will be copied from the receive buffer into the user supplied buffer.
 *
 * This is the "receive with copy" version of the MCC receive function. This version is simple
 * to use but it requires copying data from shared memory into the user space buffer.
 * The user has no obligation or burden to manage the shared memory buffers.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[in] buffer Pointer to the user-app. buffer where data will be copied into.
 * \param[in] buffer_size The maximum number of bytes to copy.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_recv_copy(MCC_ENDPOINT *endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
    MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};
    int return_value, i = 0;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
    }

    /* Copy the message from the MCC receive buffer into the user-app. buffer */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    if (list->head->data_len > buffer_size) {
        list->head->data_len = buffer_size;
    }
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    mcc_memcpy((void*)list->head->data, buffer, list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    buf = mcc_dequeue_buffer(list);

    /* Enqueue the buffer into the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    mcc_queue_buffer(&bookeeping_data->free_list, buf);

    /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */
    affiliated_signal.type = BUFFER_FREED;
    affiliated_signal.destination = tmp_destination;
    for (i=0; i<MCC_NUM_CORES; i++) {
        if(i != MCC_CORE_NUMBER) {
            mcc_queue_signal(i, affiliated_signal);
        }
    }
    mcc_generate_cpu_to_cpu_interrupt();

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #19
0
/*!
 * \brief This function sends a message to an endpoint.
 *
 * The message is copied into the MCC buffer and the destination core is signaled.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to send to.
 * \param[in] msg Pointer to the message to be sent.
 * \param[in] msg_size Size of the message to be sent in bytes.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available)
 * \return MCC_ERR_NOMEM (no free buffer available and timeout_us set to 0)
 * \return MCC_ERR_SQ_FULL (signal queue is full)
 *
 * \see mcc_recv_copy
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_send(MCC_ENDPOINT *endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_us)
{
    int return_value, end_time_set_flag = 0;
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */
    if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) {
        return MCC_ERR_INVAL;
    }

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    buf = mcc_dequeue_buffer(&bookeeping_data->free_list);

    while(buf == null) {
        mcc_release_semaphore();

        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_NOMEM;
        }
        /* Blocking calls: CPU-to-CPU ISR sets the event and thus resumes tasks waiting for a free MCC buffer.
         * As the interrupt request is send to all cores when a buffer is freed it could happen that several
         * tasks from different cores/nodes are waiting for a free buffer and all of them are notified that the buffer
         * has been freed. This function has to check (after the wake up) that a buffer is really available and has not been already
         * grabbed by another "competitor task" that has been faster. If so, it has to wait again for the next notification. */
        /* wait forever */
        else if(timeout_us == 0xFFFFFFFF) {
#if (MCC_OS_USED == MCC_MQX)
            _lwevent_wait_ticks(&lwevent_buffer_freed, 1, TRUE, 0);
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        /* timeout_us > 0 */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(!end_time_set_flag) {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                end_time_set_flag = 1;
            }
            return_value = _lwevent_wait_until(&lwevent_buffer_freed, 1, TRUE, &tick_time);
            if(return_value == LWEVENT_WAIT_TIMEOUT) {
                /* Buffer not dequeued before the timeout */
                return MCC_ERR_TIMEOUT;
            }
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_get_semaphore();
        buf = mcc_dequeue_buffer(&bookeeping_data->free_list);
    }

    /* Semaphore-protected section end */
    mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Copy the message into the MCC receive buffer */
    mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size);
    MCC_DCACHE_FLUSH_MLINES((void*)buf->data, msg_size);
    buf->data_len = msg_size;
    MCC_DCACHE_FLUSH_MLINES((void*)&buf->data_len, sizeof(MCC_MEM_SIZE));

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    if(list == null) {
        /* The endpoint does not exists (has not been registered so far),
         free the buffer and return immediately - error */
        /* Enqueue the buffer back into the free list */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);
      
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    /* Write the signal type into the signal queue of the particular core */
    affiliated_signal.type = BUFFER_QUEUED;
    affiliated_signal.destination = *endpoint;
    return_value = mcc_queue_signal(endpoint->core, affiliated_signal);
    if(return_value != MCC_SUCCESS) {
        /* Signal queue is full, free the buffer and return immediately - error */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);

        mcc_release_semaphore();
        return return_value;
    }

    /* Enqueue the buffer into the endpoint buffer list */
    mcc_queue_buffer(list, buf);

    /* Semaphore-protected section end */
    mcc_release_semaphore();

    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Signal the other core by generating the CPU-to-CPU interrupt */
    return_value = mcc_generate_cpu_to_cpu_interrupt();

    return return_value;
}
Beispiel #20
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available.
 *        The data is copied from the receive buffer into the user supplied buffer.
 *
 * This is the "receive with copy" version of the MCC receive function. This version is simple
 * to use but it requires copying data from shared memory into the user space buffer.
 * The user has no obligation or burden to manage the shared memory buffers.
 *
 * \param[out] src_endpoint Pointer to the MCC_ENDPOINT structure to be filled by the endpoint identifying the message sender.
 * \param[in] dest_endpoint Pointer to the local receiving endpoint to receive from.
 * \param[in] buffer Pointer to the user-app. buffer where data will be copied into.
 * \param[in] buffer_size The maximum number of bytes to copy.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer.
 * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_recv(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_ms)
{
    MCC_RECEIVE_LIST *list = null;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
    MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};
    int return_value, i = 0;

    return_value = mcc_recv_common_part(dest_endpoint, timeout_ms, (MCC_RECEIVE_LIST**)&list);
    if(return_value != MCC_SUCCESS)
        return return_value;
    
    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        mcc_release_semaphore();
        return MCC_ERR_TIMEOUT;
    }

    /* Copy the message from the MCC receive buffer into the user-app. buffer */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->source, sizeof(MCC_ENDPOINT) + sizeof(MCC_MEM_SIZE));
    mcc_memcpy((void*)&list->head->source, (void*)src_endpoint, sizeof(MCC_ENDPOINT));
    if (list->head->data_len > buffer_size) {
        list->head->data_len = buffer_size;
    }
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    mcc_memcpy((void*)list->head->data, buffer, list->head->data_len);

    /* Dequeue the buffer from the endpoint list */
    list->head = (MCC_RECEIVE_BUFFER*)MCC_MEM_VIRT_TO_PHYS(list->head);
    buf = mcc_dequeue_buffer(list);

    /* Enqueue the buffer into the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    mcc_queue_buffer(&bookeeping_data->free_list, buf);

    /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */
    affiliated_signal.type = BUFFER_FREED;
    affiliated_signal.destination = tmp_destination;
    for (i=0; i<MCC_NUM_CORES; i++) {
        if(i != MCC_CORE_NUMBER) {
            mcc_queue_signal(i, affiliated_signal);
        }
    }

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();

    mcc_generate_cpu_to_cpu_interrupt();

    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Beispiel #21
0
/*!
 * \brief This function sends a message to an endpoint.
 *
 * The message is copied into the MCC buffer and the destination core is signaled.
 *
 * \param[in] src_endpoint Pointer to the local endpoint identifying the source endpoint.
 * \param[in] dest_endpoint Pointer to the destination endpoint to send the message to.
 * \param[in] msg Pointer to the message to be sent.
 * \param[in] msg_size Size of the message to be sent in bytes.
 * \param[in] timeout_ms Timeout, in milliseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available)
 * \return MCC_ERR_NOMEM (no free buffer available and timeout_ms set to 0)
 * \return MCC_ERR_SQ_FULL (signal queue is full)
 *
 * \see mcc_recv
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_send(MCC_ENDPOINT *src_endpoint, MCC_ENDPOINT *dest_endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_ms)
{
    int return_value;
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
    MCC_MEM_SIZE buffer_size;

    /* Reuse the mcc_get_buffer_internal() function to get the MCC buffer pointer. */
    return_value = mcc_get_buffer_internal((void**)&buf, &buffer_size, timeout_ms);
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */
    if(msg_size > buffer_size) {
        while(MCC_SUCCESS != mcc_free_buffer_internal(buf)) {};
        return MCC_ERR_INVAL;
    }

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* As the mcc_get_buffer_internal() returns the pointer to the data field, it
       is necessary to adjust the pointer to point at the MCC buffer structure beginning. */
    buf = (MCC_RECEIVE_BUFFER *)((unsigned int)buf - (unsigned int)(&(((MCC_RECEIVE_BUFFER*)0)->data)));

    /* Copy the message into the MCC receive buffer */
    MCC_DCACHE_INVALIDATE_MLINES((void*)buf, sizeof(MCC_RECEIVE_BUFFER));
    mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size);
    mcc_memcpy((void*)src_endpoint, (void*)&buf->source, sizeof(MCC_ENDPOINT));
    buf->data_len = msg_size;
    MCC_DCACHE_FLUSH_MLINES((void*)buf, sizeof(MCC_RECEIVE_BUFFER));

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*dest_endpoint);

    if(list == null) {
        /* The endpoint does not exists (has not been registered so far),
         free the buffer and return immediately - error */
        /* Enqueue the buffer back into the free list */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);
      
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    /* Write the signal type into the signal queue of the particular core */
    affiliated_signal.type = BUFFER_QUEUED;
    affiliated_signal.destination = *dest_endpoint;
    return_value = mcc_queue_signal(dest_endpoint->core, affiliated_signal);
    if(return_value != MCC_SUCCESS) {
        /* Signal queue is full, free the buffer and return immediately - error */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);

        mcc_release_semaphore();
        return return_value;
    }

    /* Enqueue the buffer into the endpoint buffer list */
    mcc_queue_buffer(list, buf);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();

    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Signal the other core by generating the CPU-to-CPU interrupt */
    return_value = mcc_generate_cpu_to_cpu_interrupt();

    return return_value;
}