/**
 *                                                                          
 *  @file	rvm_mem.c                                              
 *                                                                          
 *  This file contains the functions related to memory management within RVM.
 *
 * @author	David Lamy-Charrier (d-lamy@ti.com)	
 * @version	0.1
 *
 */

/*
 * Revision History:																			
 *
 * 10/26/2001	David Lamy-Charrier		Create for Riviera 1.6.
 *																			
 * (C) Copyright 2001 by Texas Instruments Incorporated, All Rights Reserved
 */

#include "rvm/rvm_i.h"
#include "rvm/rvm_gen.h"
#include "rvm/rvm_api.h"
#include "rvm/rvm_use_id_list.h"
#include "rvf/rvf_env.h"

extern T_RVM_GET_INFO_FUNC RVM_SWE_GET_INFO_ARRAY[];

extern T_RVM_KNOWN_SWE	* rvm_swe_array;

/*******************************************************************************
** Function         rvm_delete_used_memory
**
** Description      Internal function which deletes used local mem if an error
**                  was received or at the end of the start/stop process.
**					
*******************************************************************************/
T_RVM_RETURN rvm_delete_used_memory ( T_RVM_PROCESSING_SWE * appli)
{
	T_RVF_BUFFER_Q			buffer_to_free_q = {0, 0, 0};
	T_RVM_PROCESSING_SWE		* cur_elem = appli;

	while (cur_elem != NULL)
	{
		rvf_enqueue (&buffer_to_free_q, cur_elem);
		cur_elem = cur_elem->next_swe;
	}

	while (buffer_to_free_q.p_first)
	{
		rvf_free_buf (rvf_dequeue (&buffer_to_free_q));
	}

	return RVM_OK;
}


/*******************************************************************************
** Function         rvm_delete_created_mb
**
** Description      Internal function which deletes all created MB if an error
**                  was received, or in case application has to be stopped.
**
*******************************************************************************/
T_RVM_RETURN rvm_delete_created_mb (T_RVM_PROCESSING_SWE * appli)
{
	UINT8 mb_index;
	T_RVM_PROCESSING_SWE * cur_elem = appli;
	volatile T_RV_RET ret_value = RV_OK;
	UINT8 mb_to_delete;

	while (cur_elem != NULL )
	{
		UINT8 swe_index = cur_elem->swe_id;

		/*	If more than one appli is using this SWE, cannot delete MB
			Process to the next SWE. */
		if (rvm_swe_array[swe_index].nb_using_appli > 1)
		{	
			cur_elem = cur_elem->next_swe; /* process the next SWE */ 
			continue;
		}

		/*	If the state is running, it means that this SWE has not
			to be stopped. */
		if (rvm_swe_array[swe_index].swe_state == SWE_RUNNING)
		{
			cur_elem = cur_elem->next_swe; /* process the next SWE */
			continue;
		}

		/* We're here:
			- either because swe_state == SWE_NOT_STARTED => error in starting prcess
			- either because swe_state == SWE_STOPPING => regular stopping process */

		if (cur_elem->nb_created_mb == 0)
		{
			cur_elem = cur_elem->next_swe; /* process the next SWE */
			continue;
		}

		mb_to_delete = cur_elem->nb_created_mb;

		for( mb_index = 0; mb_index < mb_to_delete; mb_index++)
		{
			ret_value = rvf_delete_mb(cur_elem->swe_mem_bank[mb_index].mb_name);
			if (ret_value != RV_OK)
			{
				rvf_send_trace("RVM: Error in deletion of memory bank: ", 39, NULL_PARAM, RV_TRACE_LEVEL_WARNING, RVM_USE_ID );
				rvf_send_trace(cur_elem->swe_mem_bank[mb_index].mb_name, RVF_MAX_MB_LEN, NULL_PARAM, RV_TRACE_LEVEL_WARNING, RVM_USE_ID );
			}
			else
			{
				(cur_elem->nb_created_mb)--;
			}

			ret_value = RVM_OK;
		}

		cur_elem = cur_elem->next_swe; /* process the next SWE */ 
	}

	return ret_value;
}

/*******************************************************************************
**
** Function         rvm_check_memory_requirement
**
** Description      This function checks if there is enough memory 
**					to start a SWE(and all the linked SWEs)
**
** Parameters:		T_RVM_PROCESSING_SWE * appli: list of required SWEs with their parameters.
**
** Returns          T_RVM_RETURN: RVM_OK if there is enough memory, else RVM_MEMORY_ERR.
**
*******************************************************************************/
T_RVM_RETURN rvm_verify_memory_requirement( T_RVM_PROCESSING_SWE * appli,
										    T_RVM_GROUP_DIRECTIVE* gd, 
											UINT8 cnt) {	
	T_RVM_PROCESSING_SWE * cur_swe = appli;
	UINT32 required_mem = 0;
	UINT32 total_mem = 0;
	UINT32 used_mem = 0;
	UINT8 mb_index;
	UINT8 i=0;
	UINT16 host_task_mem=0;


	/* get available memory from the rvf */
	if ( rvf_get_available_mem( &total_mem, &used_mem) != RVF_OK )
	{	return RVM_MEMORY_ERR;
	}

	/* count required memory */
	while (cur_swe !=NULL ) /* for each SWE */
	{
		UINT8 swe_index = cur_swe->swe_id;

		/*
		** If SWE is already running => MB already created => do nothing
		*/
		if (rvm_swe_array[swe_index].swe_state != SWE_RUNNING )
		{
			for( mb_index = 0; mb_index < cur_swe->nb_requested_mb; mb_index++) /* for each mb */
			{	
				required_mem += cur_swe->swe_mem_bank[mb_index].mb_initial_param.size;
			}

			/* add the necessary stack sizes */
			/* TO DO: add the stack size for host groups not yet started */
			if( (cur_swe->swe_type == RVM_SWE_TYPE_3)
				|| (cur_swe->swe_type == RVM_SWE_TYPE_4) )
/*				|| ((cur_swe->swe_type == RVM_SWE_TYPE_2) && (rvm_swe_array[swe_index].group_index == RVM_OWN_GROUP) )) */
			{	
				required_mem += rvm_swe_array[swe_index].swe_stack_size;
				required_mem += SYSTEM_TASK_MEM;  /* only for type 3 & 4. A-M-E-N-D-E-D!    */
			}

		}
		cur_swe = cur_swe->next_swe;
	}

	/* type 2 group host system and stack mem. is catered for here								*/
	for(i=0; i<cnt; i++) host_task_mem+=gd[i].stack_size;			/* A-M-E-N-D-E-D!  */
	host_task_mem+=(cnt*SYSTEM_TASK_MEM);
	
	/* compare available memory and required memory (eventually, use a percentage to improve performances) */
	if ((required_mem+host_task_mem) + used_mem > total_mem ) { 	/* A-M-E-N-D-E-D!  */
		RVM_TRACE_WARNING_PARAM("RVM: Memory required (incl. used): ", (UINT32)(required_mem+host_task_mem+ used_mem) );
		RVM_TRACE_WARNING_PARAM("RVM: Total Memory available      : ", (UINT32)total_mem);
		return RVM_MEMORY_ERR;
	} else{
		return RVM_OK;
	}
}


/*******************************************************************************
**
** Function         rvm_allocate_mem
**
** Description      This function creates all the required memory banks or
**					increases their size if needed, to start a SWE. 
**
** Parameters:		T_RVM_PROCESSING_SWE * appli: list of required SWEs with their parameters.
**
** Returns          T_RVM_RETURN: RVM_OK if all allocations are successful, 
**					else RVM_MEMORY_ERR and it releases all the allocated memory.
**
*******************************************************************************/
T_RVM_RETURN rvm_allocate_mb( T_RVM_PROCESSING_SWE * appli)
{	T_RVM_PROCESSING_SWE * cur_swe = appli;
	UINT8 mb_index;
	volatile T_RVM_RETURN rvm_ret_value = RVM_OK;
	
	/* for each SWE in the list */
	while ((cur_swe != NULL ) && (rvm_ret_value == RVM_OK))
	{
		UINT8 swe_index = cur_swe->swe_id;

		if (rvm_swe_array[swe_index].swe_state == SWE_NOT_STARTED) 
			/* If the state is not SWE_RUNNING, then the MBs have to be created	*/
		{
			for( mb_index = 0; mb_index < cur_swe->nb_requested_mb; mb_index++) /* for each mb */
			{	T_RVF_MB_PARAM mb_param;
				/* add the initial size */
				mb_param.size = cur_swe->swe_mem_bank[mb_index].mb_initial_param.size;
				mb_param.watermark = cur_swe->swe_mem_bank[mb_index].mb_initial_param.watermark;

				/* create the mb */
				if ( mb_param.size != 0)
				{	
					/* create the mb */
					if ( rvf_create_mb( cur_swe->swe_mem_bank[mb_index].mb_name, mb_param, &(cur_swe->bk_id_table[mb_index]) ) != RVF_OK)
					{
						/* if an error occurs */
						rvm_ret_value = RVM_MEMORY_ERR;
						break;
					}
					else
					{
						cur_swe->nb_created_mb++;
					}
				}
			}
		}

		cur_swe = cur_swe->next_swe; /* process the next SWE */ 
	}

	if (rvm_ret_value != RVM_OK)
		/* Something went wrong, should release all used memory */
	{
		rvf_send_trace("RVM: Problem in memory bank creation !!!", 40, NULL_PARAM, RV_TRACE_LEVEL_WARNING, RVM_USE_ID );
		if (rvm_delete_created_mb (appli) != RVM_OK)
		{
			rvf_send_trace("RVM: MB deleting error!!!", 25, NULL_PARAM, RV_TRACE_LEVEL_WARNING, RVM_USE_ID );
		}

	}
	return rvm_ret_value;
}


/*******************************************************************************
**
** Function         rvm_allocate_stack_buffer
**
** Description      This function allocates a buffer for the stack of a new 
**					task created by RVM.
**
** Parameters:		UINT32 stack_size: size of stack.
**					T_RVF_BUFFER** stack_ptr: pointer to the allocated buffer.
**
** Returns          T_RVM_RETURN: RVM_OK if all allocation is successful, 
**					else RVM_MEMORY_ERR.
**
*******************************************************************************/
T_RVM_RETURN rvm_allocate_stack_buffer( UINT32 stack_size, T_RVF_BUFFER** stack_ptr )
{	T_RVF_MB_PARAM mb_params;

	/* increase the size of the stack MB before allocating the new buffer */
	if( rvf_get_mb_param( RVM_STACK_MB, &mb_params) != RV_OK)
	{	return RVM_MEMORY_ERR;
	}
	
	mb_params.size		+= stack_size;
	mb_params.watermark	+= stack_size;

	if( rvf_set_mb_param( RVM_STACK_MB, &mb_params) != RV_OK)
	{	return RVM_MEMORY_ERR;
	}

	if( rvf_get_buf( rvm_stack_mem_bank, stack_size, stack_ptr) == RVF_RED)
	{	return RVM_MEMORY_ERR;
	}
	return RVM_OK;

}

