/*****************************************************************************
 *                            Intel Proprietary
 *
 * Copyright (c) 1998-2002 By Intel Corporation.  All rights reserved.
 * No part of this program or publication may be reproduced, transmitted,
 * transcribed, stored in a retrieval system, or translated into any language
 * or computer language in any form or by any means, electronic, mechanical,
 * magnetic, optical, chemical, manual, or otherwise, without the prior
 * written permission of:
 *                        Intel Corporation
 *                        2200 Mission College Blvd.
 *                        Santa Clara, CA  95052-8119
 *****************************************************************************/

/**
 *****************************************************************************
 * @ingroup PppEncap
 * File:  ppp_encap.c
 * @description
 *        MicroC file for PPP Encap microblock main functions.
 *****************************************************************************/

/*****************************************************************************
 *
 * Contents:
 *        Declaration of following global variables:
 *			 srcIfMessage
 *			 sinkIfMessage
 *           inPayload
 *			 outHdrPayload;
 *
 *        Declaration of following global SIGNALs: 
 *            sig_next_thrd_1
 *            sig_next_thrd_2
 *            sig_next_thrd_3
 *            sig_next_thrd_4
 *			  sig_sramRead
 *			  sig_sramWrite
 *            sig_dramRead
 *			  sig_dramWrite
 *			  sig_scratchRead
 *            sig_scratchWrite
 *
 *        Definitions of following exported function:
 *            main()
 *        Definitions of following local function:
 *            PppEncap      
 *
 *****************************************************************************/

#ifndef __PPP_ENCAP_C__
#define __PPP_ENCAP_C__

#define	INLINE	static __forceinline
 	
// Following definition enable this microblock waiting for an inter-ME signal 
// generated by the ME whcih initializes common resources, such as scratch ring,
// near the end of thread 0 of this microblockinitialization to make sure all 
// common resource are available. This option should be enabled when this POS TX 
// microblock is integrated with other egress microblocks.  
#define WAIT_FOR_COMMON_RESOURCE_INITIALIZATION 

#define TMP_REPLACE_DL_METALOADCACHE

#include "ppp_encap.h"
#include "ppp_encap_init.c"
#include "ppp_encap_util.c"

///////////////////////////////////////////////////////////////////////////////
//
//
//      File Name: ppp_encap.uc
//
//      Purpose: POS layer 2 encap for Egress IXP2400
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// This a context pipe-stage microblock which receives tansmit request from 
// CSIX RX, add PPP header, then send this transmit request to Queue 
// Manager. After it get transmit request from CSIX RX, it gets next hop ID 
// from meta data, if next_hop_id = 0xFFFF, it means PPP header is already
// in DRAM, this microblock just send this transmit request to Queue Manager.
// If next_hop_id !=0xFFFF, it aligns PPP header with payload and write back to 
// DRAM, then send this transmit request to Queue Manager. 
//
// This microblock runs in four phases.
//
/////////////////////////////////////////////////////////////////////////////////////

__declspec(gp_reg shared) same_me_signal_t next_thrd_1_gpr;
__declspec(gp_reg shared) same_me_signal_t next_thrd_2_gpr;
__declspec(gp_reg shared) same_me_signal_t next_thrd_3_gpr;
__declspec(gp_reg shared) same_me_signal_t next_thrd_4_gpr;

unsigned int pppHeader;
unsigned int scrRing, sinkRing;
__declspec(sram_read_reg) if_message_t srcIfMessage;
__declspec(sram_write_reg) if_message_t sinkIfMessage;
__declspec(dram_read_reg) hdr_paylo_dram_t inPayload;
__declspec(dram_write_reg) hdr_paylo_dram_t outHdrPayload;
__declspec(sram_read_reg) dl_meta_t in_meta;
__declspec(sram_write_reg) dl_meta_t out_meta;

SIGNAL sig_next_thrd_1, sig_next_thrd_2, sig_next_thrd_3, sig_next_thrd_4;
SIGNAL sig_sramRead; 					/*signal for sram read*/
SIGNAL sig_sramWrite; 					/*signal for sram write*/
SIGNAL_PAIR sig_dramRead; 				/*signal for dram read*/
SIGNAL_PAIR sig_dramWrite; 				/*signal for dram write*/
SIGNAL sig_scratchRead; 				/*signal for scratch ring read*/
SIGNAL sig_scratchWrite; 				/*signal for scratch ring write*/
SIGNAL sig_commonInitComplete;
SIGNAL_MASK sigmask_phs1Default;
SIGNAL_MASK sigmask_phs2Default;
SIGNAL_MASK sigmask_phs3Default;
SIGNAL_MASK sigmask_phs4Default;

INLINE PppEncap_ImplicitReadAllSigs(void)
{
__implicit_read(&sig_next_thrd_1);
__implicit_read(&sig_next_thrd_2);
__implicit_read(&sig_next_thrd_3);
__implicit_read(&sig_next_thrd_4);
__implicit_read(&sig_sramRead);
__implicit_read(&sig_sramWrite);
__implicit_read(&sig_dramRead);
__implicit_read(&sig_dramWrite);
__implicit_read(&sig_scratchRead);
__implicit_read(&sig_scratchWrite);
__implicit_read(&sig_commonInitComplete);
}


INLINE PppEncap_AssignSigReg(void)
{
__assign_relative_register(&sig_commonInitComplete, ME_INIT_SIGNAL_C);
}
														
/*****************************************************************************
 * Abstract:
 *    POS Layer 2 haeader encap 
 *
 * Side Effects:
 *    None
 *
 * Assumptions:
 * 	  None
 *****************************************************************************/											
INLINE void											/* OUT: No return value  */
PppEncap(void)
{
SIGNAL_MASK sigmask, sigmask1, sigmask2, sigmask3, sigmask4;
exe_stat_flag_t exeStatFlag;
unsigned int offsetPayLoad;
unsigned int dramAddr;

	dl_source((__declspec(sram_read_reg) void *)&srcIfMessage, 
			scrRingSource, &sig_scratchRead); /* Read source scratch ring*/

	wait_for_all(&sig_scratchRead);

	// The first time through the loop, wait for next thread signal only 
	//ctx_arb[sig1_next_context]
	wait_for_all(&sig_next_thrd_1);
	
	while (1)
	{
	
		/*
		 * start phase 1														  
		 */
		// wake up next thread in the very beginning of phase 2 to reduce wakeup 
		// latency (1)
		signal_next_ctx(next_thrd_1_gpr);

		// set sig_mask to sigmask_phs1Default for phase 1 
		//sigmask = sigmask_phs1Default;

		exeStatFlag.value = 0;					/* reset exeStatFlag */

		// check ppp encap source message
		if(srcIfMessage.value[0])			/* valid ppp_encap source */
		{
#ifdef TMP_REPLACE_DL_METALOADCACHE
			int sram_addr;
#endif /* TMP_REPLACE_DL_METALOADCACHE */
#ifndef TMP_REPLACE_DL_METALOADCACHE
		 	Dl_MetaLoadCache(srcIfMessage.sopBufHandle, 0, 5,
						SIG_NONE, &sig_sramRead);			 
#else /* TMP_REPLACE_DL_METALOADCACHE */
			sram_addr = Dl_BufGetDesc(srcIfMessage.sopBufHandle);
			sram_read((__declspec(sram_read_reg) void *)&inMetaData, 
						(volatile __declspec(sram) void *)sram_addr, 5, 
						sig_done, &sig_sramRead);
#endif /* TMP_REPLACE_DL_METALOADCACHE */
	        wait_for_all(&sig_next_thrd_2, &sig_sramRead);
	
		}

		else /* no valid ppp_encap source */
		{
		//	sigmask = PppEncap_ClearSignal(sigmask, &sig_sramRead);
			exeStatFlag.noValidSrcMsg = 1;
			wait_for_all(&sig_next_thrd_2);
        }


		// wait for sram read to finish and signal from next thread (4)
//end_of_phase_1#:
		PppEncap_ImplicitReadAllSigs();


		/*
		 * start phase 2												  
		 */
		// wake up next thread in the very beginning of phase 2 to reduce wakeup 
		// latency (1)
		signal_next_ctx(next_thrd_2_gpr);

		// set sig_mask to sigmask_phs2Default for phase 2 
		//sigmask = sigmask_phs2Default;

		if(!exeStatFlag.noValidSrcMsg) /* valid ppp_encap source */
		{
			unsigned int nextHopId = (inMetaData.value[4] >> 16) & 0xFFFF;

			if(nextHopId == NEXT_HOP_ID_MPLS)
			{
				pppHeader = PPP_HEADER_MPLS;
			}
			else
			{
				pppHeader = PPP_HEADER_IP;
			}

			if(nextHopId == L2_HEADER_ALREADY_EXIST_ID)
			{
				PppEncap_saveSrctoSink();
				dl_qm_sink((__declspec(sram_write_reg) void *)&sinkIfMessage, scrRingSink, 
						PPP_ENCAP_SINK_RING_FULL(L2_ENCAP_SINK_SCR_RING),
 						&sig_scratchWrite); 
			//	sigmask = PppEncap_ClearSignalPair(sigmask, &sig_dramRead);
			//	sigmask = PppEncap_SetSignal(sigmask, &sig_scratchWrite);
				exeStatFlag.noValidSrcMsg = 1;	/* set flag */
				wait_for_all(&sig_next_thrd_3, &sig_scratchWrite);
			}
			else /* PPP header not in dram yet */
			{
				offsetPayLoad = inMetaData.value[1] & 0xFFFF;
				dramAddr = Dl_BufGetData(srcIfMessage.sopBufHandle);		

				// get 8 bytes data from dram 
				PppEncap_ReadDram(offsetPayLoad, dramAddr, 1);

				wait_for_all(&sig_next_thrd_3);
			}
		}
		else /* no valid ppp_encap source */
		{
			//sigmask = PppEncap_ClearSignalPair(sigmask, &sig_dramRead);
			wait_for_all(&sig_next_thrd_3);
		}	

	// wait for sram read and dram read to finishand signal from next thread (4)
//end_of_phase_2#:
		
		PppEncap_ImplicitReadAllSigs();

		/*
		 * start phase 3														  
		 */
		// wake up next thread in the very beginning of phase 3 to reduce wakeup 
		// latency 
		signal_next_ctx(next_thrd_3_gpr);

		if(!exeStatFlag.noValidSrcMsg) /* valid ppp_encap source */
		{
			PppEncap_UpdateMetaData();

			wait_for_all(&sig_next_thrd_4, &sig_dramRead, &sig_sramWrite);
		}
		else /* no valid ppp_encap source */ 
		{
		    wait_for_all(&sig_next_thrd_4);
		}

//end_of_phase_3#:
		PppEncap_ImplicitReadAllSigs();

		/*
		 * start phase 4														  
		 */
		// wake up next thread in the very beginning of phase 4 to reduce wakeup 
		// latency 
		signal_next_ctx(next_thrd_4_gpr);

		// set sigmask to sigmask_phs4Default for phase 4 

		PppEncap_saveSrctoSink();

		// get ppp encap source message for next run
		dl_source((__declspec(sram_read_reg) void *)&srcIfMessage, 
			scrRingSource, &sig_scratchRead); /* Read source scratch ring*/

		if(!exeStatFlag.noValidSrcMsg) /* valid ppp_encap source */
		{
			PppEncap_WritePppHeader(offsetPayLoad, dramAddr);

			dl_qm_sink((__declspec(sram_write_reg) void *)&sinkIfMessage, scrRingSink, 
					PPP_ENCAP_SINK_RING_FULL(L2_ENCAP_SINK_SCR_RING),
	 				&sig_scratchWrite); 
			wait_for_all(&sig_next_thrd_1, &sig_scratchRead, &sig_scratchWrite, &sig_dramWrite);
		}
		else /* no valid ppp_encap source */
		{
			//sigmask = PppEncap_ClearSignal(sigmask, &sig_scratchWrite); /* clear */
			wait_for_all(&sig_next_thrd_1, &sig_scratchRead);
		}
//end_of_phase_4#:
		PppEncap_ImplicitReadAllSigs();
	}
}

// The main code starts here
/**
 ****************************************************************************
 * @ingroup PppEncap
 * Main function of PPP Encap microblock
 * @description
 *    This function in the main function of PPP Encap microblock. It first 
 *    initialized PPP Encap microblock, then enter infinite PPP encap
 *	  processing.
 * @return Nothing
 * @see  main
 *****************************************************************************/
void 
main()
{	

	PppEncap_AssignSigReg();	/* Wait global initialization */
	// initialize the microblock
	PppEncap_Init(); 

	PppEncap();	
}

#endif 		/* __PPP_ENCAP_C__ */

  

