| /* |
| * This file contains MCC library common functions |
| * |
| * Copyright (C) 2014 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; |
| } |
| |