263 lines
9.2 KiB
C
Executable File
263 lines
9.2 KiB
C
Executable File
/*
|
|
* This file contains MCC library common functions
|
|
*
|
|
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+ and/or BSD-3-Clause
|
|
* The GPL-2.0+ license for this file can be found in the COPYING.GPL file
|
|
* included with this distribution or at
|
|
* http://www.gnu.org/licenses/gpl-2.0.html
|
|
* The BSD-3-Clause License for this file can be found in the COPYING.BSD file
|
|
* included with this distribution or at
|
|
* http://opensource.org/licenses/BSD-3-Clause
|
|
*/
|
|
|
|
#include "mcc_config.h"
|
|
#if (MCC_OS_USED == MCC_MQX)
|
|
#include "mcc_common.h"
|
|
#include "mcc_mqx.h"
|
|
#elif (MCC_OS_USED == MCC_LINUX)
|
|
#include <linux/mcc_api.h>
|
|
#include <linux/mcc_linux.h>
|
|
#endif
|
|
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|
|
/*!
|
|
* \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*));
|
|
}
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|
|
/*!
|
|
* \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;
|
|
}
|
|
|