/****************************************************************************\
 *           Copyright (C) 2005~2008 Texas Instruments Incorporated.             *
 *                           All Rights Reserved                            *
 *                                                                          *
 * GENERAL DISCLAIMER                                                       *
 * ------------------                                                       *
 * All software and related documentation is provided "AS IS" and without   *
 * warranty or support of any kind and Texas Instruments expressly disclaims*
 * all other warranties, express or implied, including, but not limited to, *
 * the implied warranties of merchantability and fitness for a particular   *
 * purpose.  Under no circumstances shall Texas Instruments be liable for   *
 * any incidental, special or consequential damages that result from the    *
 * use or inability to use the software or related documentation, even if   *
 * Texas Instruments has been advised of the liability.                     *
  ****************************************************************************
This example shows Ethernet data transfer between two DSP on TCI6482 EVM
Steps to run the test:
1, connect two DSP on the TCI6482 EVM with ethernet cable
2, load this project to both DSPs on TCI6482 EVM
3, run both DSP simultaneously through CCS parellel debug manager
4, check the stdout of both DSP for result
result on first DSP should look like:
-------------------------------------------------------
Calling EMAC_open()
Waiting for link...
Link Status  : 100Mb/s Full Duplex MII on PHY number 1
Packets Held : 32-RX  0-TX
Interrupt Pacing: 0 micro second
Starting packet transfer...
Sent 8192 packets (12288000 Bytes), packet size is 1500 bytes, achieve bandwidth   97538 kbps
Sent 8192 packets (10649600 Bytes), packet size is 1300 bytes, achieve bandwidth   87742 kbps
Sent 8192 packets ( 9011200 Bytes), packet size is 1100 bytes, achieve bandwidth   96669 kbps
Sent 8192 packets ( 7372800 Bytes), packet size is  900 bytes, achieve bandwidth   95957 kbps
Sent 8192 packets ( 5734400 Bytes), packet size is  700 bytes, achieve bandwidth   79339 kbps
Sent 8192 packets ( 4096000 Bytes), packet size is  500 bytes, achieve bandwidth   92944 kbps
Sent 8192 packets ( 2457600 Bytes), packet size is  300 bytes, achieve bandwidth   88765 kbps
Sent 8192 packets (  819200 Bytes), packet size is  100 bytes, achieve bandwidth   72470 kbps
Calling EMAC_close()
-------------------------------------------------------
result on second DSP should look like:
-------------------------------------------------------
Calling EMAC_open()
Waiting for link...
Link Status  : 100Mb/s Full Duplex RGMII on PHY number 0
Packets Held : 32-RX  0-TX
Interrupt Pacing: 0 micro second
Starting packet receiving...
Received 16084 packets
Received 39779 packets
Received 65536 packets
 ****************************************************************************
 * Created by :                                                             *
 *            Brighton Feng                                    *
 *            Texas Instruments                                             * 
 *            10 Mar, 2008                                                  *
***************************************************************************/

#include <c6x.h>
#include <stdio.h>
#include <csl_dev.h>
#include <csl_tsc.h>
#include <csl_cache.h>
#include <csl_emac.h>
#include <cslr_ectl.h>

#define RX_BUFF_FLOW_CONTROL 	1

#define DSP_CLK_KHZ 			1000000
#define MAX_PACKET_SIZE		1514
#define MIN_PACKET_SIZE		60
#define INT_PACING 			0 	/*Interrupt pacing in microsecond*/

#define TEST_PKT_NUMBER 		(1024*8)
#define RX_DES_BUFFER 		32
#define TX_DES_BUFFER 		32

/*
 * Raw Data Buffers
 * buffer number should be enough for both TX and RX
 * If the buffers were in cacheable external
 * memory, we'd have to make sure each was cache aligned, and
 * thus use a size of at least 1536 because a buffer must fill an
 * the entire cache line.
 */
#define PKT_BUFFER_NUMBER 		2*(RX_DES_BUFFER+ TX_DES_BUFFER)
#pragma DATA_SECTION(packet_header, "EMAC_DATA")
EMAC_Pkt packet_header[PKT_BUFFER_NUMBER];
#pragma DATA_SECTION(packet_buffer, "EMAC_DATA")
Uint8 packet_buffer[PKT_BUFFER_NUMBER][1536];

Uint8 LocalMAC[6]; 	
Uint8 DestMAC[6]; 	

volatile Uint32 	uiTotalPacketsToTransfer=0;
volatile Uint32 	uiTotalPacketsReceived=0;
volatile CSL_EmacRegs * EmacRegs= ((CSL_EmacRegs *)CSL_EMAC_0_REGS);
volatile CSL_EctlRegs * EmacControlRegs= ((CSL_EctlRegs *)CSL_ECTL_0_REGS);
volatile CSL_DevRegs  *devRegs  = (CSL_DevRegs *)CSL_DEV_REGS;

/*
 * Packet Queue
 *
 * This simple queue object is just for our example packet
 * queue. It is not requried for using EMAC/MDIO
 *
 */
typedef struct app_pktq {
  Uint32            Count;      /**< Number of packets in queue */
  EMAC_Pkt          *pHead;     /**< Pointer to first packet    */
  EMAC_Pkt          *pTail;     /**< Pointer to last packet     */
} APP_PKTQ;

/*
 * Queue Helper Functions
 */
static inline EMAC_Pkt *App_pqPop( APP_PKTQ *pq );
static inline App_pqPush( APP_PKTQ *pq, EMAC_Pkt *pPktHdr );

/*
 * Declare our packet queues
 */
APP_PKTQ     FreeQueue;             /* Free packets for RX or TX */
APP_PKTQ     RxQueue;               /* Received packets */

/*
 * Declare some local status variables
 */
Handle            hEMAC = 0;       /* Handle to our EMAC instance */
volatile Uint32   LinkStatus = 0;  /* Our current link status */
volatile Uint32   LocalTicks = 0;  /* Current time in 100ms ticks */

#define EMAC_INT_VAL    5
#define EMAC_INT_MASK   (1<<EMAC_INT_VAL)

volatile Uint32 uiMacMode;

static EMAC_Status status;
static char *LinkStr[] ={ 
					"No Link", 
					"10Mb/s Half Duplex", 
					"10Mb/s Full Duplex",
					"100Mb/s Half Duplex", 
					"100Mb/s Full Duplex", 
					"1000Mb/s Full Duplex"
					};

/*
 * Declare some local functions
 */
static EMAC_Pkt *GetPacket(Handle hApplication);
static void     FreePacket(Handle hApplication, EMAC_Pkt *pPKT);
static EMAC_Pkt *RxPacket( Handle hApplication, EMAC_Pkt *pPKT);
static void     StatusUpdate(Handle hApplication);
static void     StatisticsUpdate(Handle hApplication);
/* EMAC interrupt function */
extern void EmacTimerInitialization(void);
extern void EmacInterruptsInitialization(void);
extern void EmacInterruptEnd(void);
void EmacHwInt();
int emac_Init();
void emacTxPackets(Int32 uiPacketSize);
void emacRxPackets();
void closeEMAC();

/* ============================================================================
 *  @func gblUserInit()
 *
 *  @desc
 *      Initialize the system for EMAC. This is called at the begining
 *
 *   @arg
 *      None
 *      
 *   @eg
 *      gblUserInit(); //Refer description
 * ============================================================================
 */
void gblUserInit()
{
	CSL_DevHandle           hDev;
	CSL_DevObj              devObj;
	CSL_Status              status;
	CSL_DevPeripherals      peripheral;
	CSL_DevPeriStatQuery    peripheralStatQuery; 

	/* Initialise DEV module */
	status = CSL_devInit(NULL);

	/* Open DEV CSL module */
	hDev = CSL_devOpen(&devObj, (CSL_InstNum)CSL_DEV, NULL, &status);

	/* Enable EMAC */
	peripheral = CSL_DEV_PERI_EMAC;
	CSL_devHwControl(hDev, CSL_DEV_CMD_PERI_ENABLE, &peripheral);

	peripheralStatQuery.periName = peripheral;
	do {
		CSL_devGetHwStatus(hDev, CSL_DEV_QUERY_PERI_STATE, &peripheralStatQuery);
	} while (peripheralStatQuery.periState != CSL_DEV_PERI_ENABLED);

	/* Enable TIMER0 */
	peripheral = CSL_DEV_PERI_TIMER0;
	CSL_devHwControl(hDev, CSL_DEV_CMD_PERI_ENABLE, &peripheral);

	peripheralStatQuery.periName = peripheral;
	do {
		CSL_devGetHwStatus(hDev, CSL_DEV_QUERY_PERI_STATE, &peripheralStatQuery);
	} while (peripheralStatQuery.periState != CSL_DEV_PERI_ENABLED);

}

/*
 * =============================================================================
 *   @func   main
 *
 *   @desc
 *     This is the main entry point.
 *
 *   @arg
 *      None
 *      
 * =============================================================================
 */
void main()
{
	Int32 i, uiPacketSize;

	//Configure L1 as 32KB cache
	CACHE_setL1pSize(CACHE_L1_32KCACHE);
	CACHE_setL1dSize(CACHE_L1_32KCACHE);
	CACHE_setL2Size(CACHE_256KCACHE);

	gblUserInit();
	CSL_tscEnable();

	if(!emac_Init())
	{
		printf("failed to initialize EMAC\n");
		return;
	}

	printf("Interrupt Pacing: %d micro second\n", INT_PACING);
	EmacControlRegs->EWINTTCNT= INT_PACING*1000/6;

	//for this test, DSP on DSK transfer packet to the DSP on mezzanine card and measure the throughput
	//the DSP on the mezzanine receive packet and count the packet number
	if(CSL_DEV_DEVSTAT_MACSEL_MII== uiMacMode) 	//DSK
	{
		printf("\nStarting packet transfer...\n");
		/*delay the DSP on DSK, make sure the DSP on the mezzanine card is ready before packet tranfer*/
		for(i=0; i<5000; i++)
		{
			asm(" nop 5");
		}
		for(uiPacketSize= MAX_PACKET_SIZE; uiPacketSize>= MIN_PACKET_SIZE; uiPacketSize-=200)
			emacTxPackets(uiPacketSize);
	}
	else 	//mezzanine card
	{
		printf("\nStarting packet receiving...\n");
		emacRxPackets();
	}
	
	closeEMAC();
}
int emac_Init()
{
	EMAC_Config ecfg;
	Uint32      i, j;


	/* Do timer intialization for tick*/
	EmacTimerInitialization();
	/* Do interrupt setup for EMAC*/
	EmacInterruptsInitialization();


	/*
	*  Determine which board we are running on
	*
	*  Look at the MACSEL bits [10:9] in the DEVSTAT register.
	*    CSL_DEV_DEVSTAT_MACSEL_MII   -> 10/100 EMAC      -> DSK board
	*    CSL_DEV_DEVSTAT_MACSEL_RGMII -> 10/100/1000 EMAC -> Mezzanine board
	*
	*  If this is not the Himalaya EVM, this check might have to change!
	*/
	uiMacMode= (devRegs->DEVSTAT & CSL_DEV_DEVSTAT_MACSEL_MASK);
	if (CSL_DEV_DEVSTAT_MACSEL_MII== uiMacMode) {
		/* This is the DSK chip. */
		for (i=0; i<6; i++)
		{
			LocalMAC[i]=i;	
			DestMAC[i]= 6+i;
		}
	}
	else {
		/* This is the mezzanine chip. */
		for (i=0; i<6; i++)
		{
			LocalMAC[i]=6+i;	
			DestMAC[i]= i;
		}
	}

	/* Initialize our buffer pool */
	memset( &FreeQueue, 0, sizeof(APP_PKTQ) );
	memset( &RxQueue, 0, sizeof(APP_PKTQ) );
	for( i=0; i<PKT_BUFFER_NUMBER; i++ ) 
	{
		/* Init packet data array */
		for( j=0; j<6; j++ ) 
		{
			packet_buffer[i][j] = DestMAC[j]; 	//destination address
		}
		for( j=6; j<12; j++ ) 
		{
			packet_buffer[i][j] = LocalMAC[j-6]; 	//source address
		}
		//packet type: IP 0800
		packet_buffer[i][12]= 0x08;
		packet_buffer[i][13]= 0x00;
	    for( j=14; j<1514; j++ ) {
			packet_buffer[i][j] = j;
		}
		/*
		 * Init the buffer headers. Note that the buffer pointer
		 * and buffer length are fixed and to not change for this test
		 */
		memset( &packet_header[i], 0, sizeof(EMAC_Pkt) );
	        packet_header[i].pDataBuffer = (Uint8 *)(packet_buffer[i]);
		packet_header[i].BufferLen   = 1536;
		App_pqPush( &FreeQueue, &packet_header[i] );
	}

	/*
	 * Inialize Configuration and Open EMAC
	 */
	ecfg.UseMdio      = 1;
	ecfg.MdioModeFlags  = MDIO_MODEFLG_AUTONEG; //MDIO_MODEFLG_AUTONEG;

	/* packet size */
	ecfg.PktMTU = 1536;
	/* selects CPPI RAM for Descriptor memory */
	ecfg.DescBase = EMAC_DESC_BASE_CPPI;

	/* Setup the EMAC configuration */
	ecfg.ModeFlags      = EMAC_CONFIG_MODEFLG_FULLDUPLEX|
    					EMAC_CONFIG_MODEFLG_RXFIFOFLOWCNTL|
    					EMAC_CONFIG_MODEFLG_TXPACE|
    					EMAC_CONFIG_MODEFLG_TXFLOWCNTL;

	ecfg.TxChannels     = 1;
	ecfg.RxMaxPktPool = RX_DES_BUFFER;
	ecfg.pfcbGetPacket  = &GetPacket;
	ecfg.pfcbFreePacket = &FreePacket;
	ecfg.pfcbRxPacket   = &RxPacket;
	ecfg.pfcbStatus     = &StatusUpdate;
	ecfg.pfcbStatistics = &StatisticsUpdate;

	/*
	* For this test we'll set our EMAC address to pre-defined value
	* If this were a real driver, we'd have to read the EMAC
	* address from where it is stored in hardware (board dependent)
	*/
	ecfg.TotalNumOfMacAddrs = 1;
	ecfg.MacAddr = (EMAC_AddrConfig **)malloc(ecfg.TotalNumOfMacAddrs * sizeof(EMAC_AddrConfig *));
	for (j=0; j<ecfg.TotalNumOfMacAddrs; j++)
	{
		ecfg.MacAddr[j] = (EMAC_AddrConfig *)malloc(sizeof(EMAC_AddrConfig));
		for( i=0; i<6; i++ )
			ecfg.MacAddr[j]->Addr[i]= LocalMAC[i];
	}

	/* Open EMAC instance */
	printf("Calling EMAC_open()\n");
	i = EMAC_open( 1, (Handle)0x12345678, &ecfg, &hEMAC );
	if(i)
	{
		printf("EMAC_open Returned error %08x\n",i);
		return 0;
	}

	/* Set the receive filter */
	i = EMAC_setReceiveFilter( hEMAC, EMAC_RXFILTER_DIRECT );
	if(i)
	{
		printf("EMAC_setReceiveFilter Returned error %08x\n",i);
		return 0;
	}
	EmacRegs->FIFOCONTROL = CSL_FMK( EMAC_FIFOCONTROL_RXFIFOFLOWTHRESH, 24)|
							CSL_FMK( EMAC_FIFOCONTROL_TXCELLTHRESH, 10); 
#if RX_BUFF_FLOW_CONTROL
	EmacRegs->RX0FLOWTHRESH = 8;
	EmacRegs->RX0FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX1FLOWTHRESH = 8;
	EmacRegs->RX1FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX2FLOWTHRESH = 8;
	EmacRegs->RX2FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX3FLOWTHRESH = 8;
	EmacRegs->RX3FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX4FLOWTHRESH = 8;
	EmacRegs->RX4FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX5FLOWTHRESH = 8;
	EmacRegs->RX5FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX6FLOWTHRESH = 8;
	EmacRegs->RX6FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->RX7FLOWTHRESH = 8;
	EmacRegs->RX7FREEBUFFER = RX_DES_BUFFER;
	EmacRegs->MACSRCADDRLO = LocalMAC[0]<<8|LocalMAC[1];
	EmacRegs->MACSRCADDRHI = LocalMAC[2]<<24|LocalMAC[3]<<16|LocalMAC[4]<<8|LocalMAC[5];
	EmacRegs->MACCONTROL |= CSL_FMKT( EMAC_MACCONTROL_RXBUFFERFLOWEN, ENABLE); 

#else
	EmacRegs->MACCONTROL |= CSL_FMKT( EMAC_MACCONTROL_RXBUFFERFLOWEN, DISABLE); 
#endif	
	/*
	* Wait for the device to link
	* The device can not send or receive packets until its
	* linked.
	*/
	printf("Waiting for link...\n");
	LocalTicks = 0;
	while( !LinkStatus && LocalTicks < 50 );

	/* Need to print this here, as it's not possible from the callback function */
	EMAC_getStatus( hEMAC, &status );

	LinkStatus = status.MdioLinkStatus;
	if( LinkStatus <= 5 )
	{
		if (CSL_DEV_DEVSTAT_MACSEL_MII== uiMacMode)
			printf("Link Status  : %s MII on PHY number %d\n", LinkStr[LinkStatus],status.PhyDev);
		else
			printf("Link Status  : %s RGMII on PHY number %d\n", LinkStr[LinkStatus],status.PhyDev);
	}
	printf("Packets Held : %d-RX  %d-TX\n",	status.RxPktHeld, status.TxPktHeld);
	if( status.FatalError )
		printf("Fatal Error  : %d\n",status.FatalError);

	if( !LinkStatus )
		printf("\nWARNING: No device LINK.\n");

	return 1;
}


void emacTxPackets(Int32 uiPacketSize)
{
	Uint32      iResult, oldTick;
	Uint32 	intmask;
	Uint32      TxCount=0, TxBytes=0, TxDoneCount, preTxDoneCount;
	CSL_Uint64 	timeStampCount;

	EMAC_Pkt    *pPkt;

	oldTick= LocalTicks;
	preTxDoneCount= (EmacRegs->TXGOODFRAMES-EmacRegs->TXPAUSEFRAMES);
	timeStampCount= CSL_tscRead();

	/* See if we should send a packet */
	while( TxCount<TEST_PKT_NUMBER) 
	{
		//FreeQueue is shared by RX and TX, reserve some free queue (equals RX_DES_BUFFER) 
		//for RX, all other can be used for TX
		if(FreeQueue.Count>RX_DES_BUFFER)
		{
			/* First get a packet buffer from our private queue */
			pPkt = App_pqPop( &FreeQueue );

			/* Send the packet */
			pPkt->Flags      = EMAC_PKT_FLAGS_SOP | EMAC_PKT_FLAGS_EOP;
			pPkt->ValidLen   = uiPacketSize;
			pPkt->DataOffset = 0;
			pPkt->PktChannel = 0;
			pPkt->PktLength  = uiPacketSize;
			pPkt->PktFrags   = 1;

			/*
			* IMPORTANT: If our data packet were in EXTERNAL memory,
			* we would have to clean it from the CACHE before submitting
			* it to the EMAC module!!!
			*
			* We should probably do the clean operation right here.
			*/

			/*
			 * Non-Reentrancy
			 *
			 * We are not allowed to re-enter or interrupt EMAC functions.
			 * Different software environments may have different methods
			 * for reentrance protection.
			 */
			intmask = IER&EMAC_INT_MASK;
			IER= IER&(~EMAC_INT_MASK); 	//disable EMAC interrupt
			iResult = EMAC_sendPacket(hEMAC, pPkt);
			IER= IER|intmask; 	//restore EMAC interrupt

			if(iResult) 
			{
				printf("EMAC_sendPacket() returned error %08x\n",iResult);
				break;
			}

			/* Bump the TX count */
			TxCount++;
			TxBytes+= (uiPacketSize-14);
		}

	}
	//Wait for transfer complete
	do
	{
		TxDoneCount= (EmacRegs->TXGOODFRAMES-EmacRegs->TXPAUSEFRAMES)-preTxDoneCount;
		if((LocalTicks-oldTick)>30)
		{
			puts("ERROR: TX timeout!");
		}
	}while(TxDoneCount<TEST_PKT_NUMBER);

	timeStampCount= CSL_tscRead()-timeStampCount;

	printf("Sent %4d packets (%8d Bytes), packet size is %4d bytes, achieve bandwidth %7ld kbps\n", 
		TxCount, TxBytes, uiPacketSize-14, (CSL_Uint64)TxBytes*8* DSP_CLK_KHZ/timeStampCount) ;
}

void emacRxPackets()
{
	Uint32   oldTick, oldPacketCount;

	EMAC_Pkt    *pPkt;

	oldTick=LocalTicks;
	oldPacketCount=uiTotalPacketsReceived;
	while( 1) 
	{
		/* See if we received a packet*/
		if( pPkt = App_pqPop( &RxQueue ) ) 
		{
			/* Bump the packet count */
			uiTotalPacketsReceived++;
			//free the packet buffer
			App_pqPush( &FreeQueue, pPkt ); 	
#if RX_BUFF_FLOW_CONTROL
			//increment Free Buffer Number by 1
			EmacRegs->RX0FREEBUFFER = 1; 
#endif
		}
		else if((LocalTicks-oldTick)>20&&oldPacketCount!=uiTotalPacketsReceived)
		{
			printf("Received %d packets\n", uiTotalPacketsReceived);
			oldTick= LocalTicks;
			oldPacketCount=uiTotalPacketsReceived;
		}
	}
}
void closeEMAC()
{
	/*
	* Close EMAC
	*/
	EmacInterruptEnd();

	printf("Calling EMAC_close()\n");
	EMAC_close( hEMAC );

	return;
}
/*
 * =============================================================================
 *   @func   HwInt
 *
 *   @desc
 *      Interrupt service routine called as a result of the EMAC hardware 
 *      interrupt.
 *
 *   @arg
 *      None
 *      
 *   @eg
 *      HwInit(); // Refer description
 * =============================================================================
 */
void interrupt EmacHwInt(void)
{
	Uint32 i;

	if( hEMAC ) {
		i = EMAC_serviceCheck( hEMAC );
		if( i ) {
			return;
			// printf("EMAC_serviceCheck() returned error %08x\n",i);
		}
	}
	return;
}


/*
 * =============================================================================
 *   @func   EmacTimerTick
 *
 *   @desc
 *      Timer tick service routine - called from 100ms timer
 *
 *   @arg
 *      None
 *      
 *   @eg
 *      EmacTimerTick(); // Refer description
 * =============================================================================
 */
void interrupt EmacTimerTick(void)
{
	/* Keep track of time for our local timeout loops */
	LocalTicks++;

	/* Poll the EMAC */
	if( hEMAC ) {
		EMAC_timerTick( hEMAC );
	}
}
/*
 * =============================================================================
 *   @func   GetPacket - Get empty packet for RX.
 *
 *   @desc
 *      This function is called from the EMAC module to get an empty packet 
 *      buffer. We need to return a packet buffer to the EMAC or return NULL
 *      if there are no buffers available.
 *
 *   @arg
 *      hApplication    Handle to the application
 *      
 *   @eg
 *      Handle  hApp;
 *      ... // Initialize and get a value to handle- done elsewhere.
 *      GetPacket(hApp); // Refer description
 *      ...
 * =============================================================================
 */
static EMAC_Pkt *GetPacket( Handle hApplication )
{
	EMAC_Pkt *pPkt;

	/* Pop a packet off our local free queue */
	pPkt = App_pqPop(&FreeQueue);

	if( pPkt ) {
		/*
		 * Here we tell the EMAC what offset to use by setting
		 * the DataOffset field in the packet.
		 */
		pPkt->DataOffset = 0;

		/*
		 * IMPORTANT: If our data packet were in EXTERNAL memory,
		 * we would have to invalidated it from the CACHE before
		 * returning it to the EMAC module!!!
		 *
		 * We should probably do the clean operation right here.
		 * However, we are most likely inside an ISR right now.
		 * It may be better to invalidate the buffer before it
		 * is pushed on the FreeQueue.
		 */
	}
//	puts("get a free packet for RX");
	return( pPkt );
}
/*
 * =============================================================================
 *   @func   FreePacket
 *
 *   @desc
 *      Free packet that originated from TX or GetPacket(). This function is
 *      called from the EMAC module to free a packet buffer after a TX 
 *      operation (or RX in the case of a RX shutdown).
 *
 *   @arg
 *      hApplication    handle to the application
 *      pPKT            poiner to the EMAC packet
 *      
 *   @eg
 *      Handle   hApp;
 *      EMAC_Pkt *emacPkt;
 *      ...
 *      FreePacket(hApp, emacPkt); // Refer description
 *      ...
 * =============================================================================
 */
static void FreePacket( Handle hApplication, EMAC_Pkt *pPKT )
{
	App_pqPush( &FreeQueue, pPKT );

//	puts("free a used packet after TX");
}

/*
 * =============================================================================
 *   @func   RxPacket - Reveived packet from the Network.
 *
 *   @desc
 *      This function is called by the EMAC to indicate a receive. Here
 *      we just push the packet onto our receive queue.
 *      
 *      This function returns a free packet to replace the RX packet on
 *      the EMAC queue. If there are no free packets available, we
 *      return NULL.
 *
 *   @arg
 *      hApplication    handle to the application
 *      pPKT            poiner to the EMAC packet
 *      
 *   @eg
 *      Handle   hApp;
 *      EMAC_Pkt *emacPkt;
 *      ...
 *      RxPacket(hApp, emacPkt); // Refer description
 *      ...
 * =============================================================================
 */
static EMAC_Pkt *RxPacket( Handle hApplication, EMAC_Pkt *pPKT )
{
	/* Push this packet onto our local receive queue */
	App_pqPush( &RxQueue, pPKT );

	/* We must return a free packet to replace the one we were given */
	return( GetPacket(hApplication) );
}

/*
 * =============================================================================
 *   @func   StatusUpdate
 *
 *   @desc
 *      The EMAC or MDIO status has changed 
 *
 *   @arg
 *      hApplication    handle to the application
 *      
 *   @eg
 *      Handle   hApp;
 *      ...
 *      StatusUpdate(hApp); // Refer description
 *      ...
 * =============================================================================
 */
static void StatusUpdate( Handle hApplication )
{
	/*
	* The status update function is called for a variety of
	* reasons, including LINK change events and EMAC errors.
	* We'll get the current status and print it out. Note we
	* don't start sending packets until we have a good link.
	*
	* NOTE: We call back into the EMAC without any reentrancy
	*       concerns. This because we are a callback function
	*       that was called from EMAC. Thus the reentrancy
	*       protection is still active!
	*/
	EMAC_getStatus( hEMAC, &status );

	LinkStatus = status.MdioLinkStatus;

}

/*
 * =============================================================================
 *   @func   StatisticsUpdate
 *
 *   @desc
 *      The EMAC statistics are in danger of overflow
 *
 *   @arg
 *      hApplication    handle to the application
 *      
 *   @eg
 *      Handle   hApp;
 *      ...
 *      StatisticsUpdate(hApp); // Refer description
 *      ...
 * =============================================================================
 */
static void StatisticsUpdate( Handle hApplication )
{
	/*
	 * Here we could call the EMAC_getStatistics() function and pass
	 * them to whoever wants them. This test app doesn't have
	 * anything to do with them so we do nothing.
	 */
}

/* =============================================================================
 *  @func App_pqPop()
 *
 *  @desc
 *      Pop a desc buffer off a queue
 *
 *   @arg
 *      pq    Application packet
 *      
 *   @eg
 *      APP_PKTQ    *pq;
 *      ... ; // variables to get value elsewhere.
 *      App_pqPop(pq);
 *      ...
 * ============================================================================
 */
static inline EMAC_Pkt *App_pqPop( APP_PKTQ *pq )
{
	Uint32 	intmask;
	EMAC_Pkt *pPktHdr;

	//Queue Operation is protected as critical area
	intmask = IER&EMAC_INT_MASK;
	IER= IER&(~EMAC_INT_MASK); 	//disable EMAC interrupt

	pPktHdr = pq->pHead;

	if( pPktHdr ) {
		pq->pHead = pPktHdr->pNext;
		pq->Count--;
		pPktHdr->pPrev = pPktHdr->pNext = 0;
	}
	IER= IER|intmask; 	//restore EMAC interrupt

	return( pPktHdr );
}

/* ============================================================================
 *  @func App_pqPush()
 *
 *  @desc
 *      Push a desc buffer onto a queue
 *
 *   @arg
 *      pq      Application packet
 *      pPktHdr pointer to EMAC pakcet header
 *      
 *   @eg
 *      APP_PKTQ    *pq;
 *      EMAC_Pkt    *pPktHdr;
 *      ... ; // variables to get value elsewhere.
 *      App_pqPush(pq, pPktHdr);
 *      ...
 * ============================================================================
 */
static inline App_pqPush( APP_PKTQ *pq, EMAC_Pkt *pPktHdr )
{
	Uint32 	intmask;

	//Queue Operation is protected as critical area
	intmask = IER&EMAC_INT_MASK;
	IER= IER&(~EMAC_INT_MASK); 	//disable EMAC interrupt

	pPktHdr->pNext = 0;

	if( !pq->pHead ) {
		/* Queue is empty - Initialize it with this one packet */
		pq->pHead = pPktHdr;
		pq->pTail = pPktHdr;
	}
	else {
		// Queue is not empty - Push onto END
		pq->pTail->pNext = pPktHdr;
		pq->pTail        = pPktHdr;
	}
	pq->Count++;

	IER= IER|intmask; 	//restore EMAC interrupt
}
