/*  ============================================================================
 *   Copyright (c) Texas Instruments Inc 2013
 *
 *   Use of this software is controlled by the terms and conditions found in the
 *   license agreement under which this software has been supplied.
* ============================================================================
 Examples to show the usage of GE on KeyStone DSP
 these tests showe GE transfer between 2 DSPs or between DSP and PC
* =============================================================================
 *  Revision History
 *  ===============
 *  July 4, 2013 Kevin Cai   File Created
 * ============================================================================
 */
#include <stdio.h>
#include <string.h>
#include <csl_qm_queue.h>
#include "KeyStone_common.h"
#include "KeyStone_GE_Init_drv.h"
#include "GE_test.h"
#include "GE_debug.h"
#include "GE_PktDMA_Init.h"
#include "GE_2DSP_test.h"

/*delay some time between packets in case the other side does not 
support flow control*/
#define DELAY_BETWEEN_PACKET_MS 	1

/*Fllowing table specifies the packet transfered on 2 ports,
number of packets of each port should be less than 64 for this test*/
GE_2DSP_Transfer_Param test_2DSP_cfg[GE_NUM_ETHERNET_PORT]=
{
    /*payloadNumBytes, dataPattern, numPackets*/
    {46,                0x12,        4},  /*SGMII port0*/
//    {1500,              0x55,        2},  /*SGMII port0*/
    {46,                0x01,        32}  /*SGMII port1*/
};

/*******************************************************/
/*Ethernet IP header length in bytes*/
#define IP_HEADER_LEN 			20
/*Ethernet UDP header length in bytes*/
#define UDP_HEADER_LEN 			8

unsigned short SourPort=8080,DestPort=8080;
unsigned  int Recv_IP=0xC0A8000B,DestIP=0xC0A8000A;
/*******************************************************/


Uint32 Get_TX_Good_Frames()
{
	Uint32 uiTxGoodFrames;

	uiTxGoodFrames= gpStats_regs[GE_STATSB]->TXGOODFRAMES;

	return uiTxGoodFrames;
}

Uint32 TxDescriptorTempBuffer[DDR_SIZE1_PKT_BUF_NUM+DDR_SIZE0_PKT_BUF_NUM];
void GE_2DSP_Test()
{
	int i, j;
	GE_2DSP_Transfer_Param * transferParam;
	Uint32 uiFDQ, uiPayloadNumBytes;
	Uint32 uiTotalBytes, uiTotalNumPackets, uiCycles, uiTxGoodFrames;
	Uint8 * ucpBuffer;
	HostPacketDescriptor * hostDescriptor;

	uiTotalBytes= 0;
	uiTotalNumPackets= 0;
	for(j= 0; j< GE_NUM_ETHERNET_PORT; j++)
	{
		if(FALSE==Port_OK(j))
			continue;

		transferParam= &test_2DSP_cfg[j];
		uiPayloadNumBytes= transferParam->payloadNumBytes;
		if((uiPayloadNumBytes<46)||(uiPayloadNumBytes>9216))
		{
			printf("invalid packet payload size %d for port %d\n", uiPayloadNumBytes, j+1);
			continue;
		}

		if(uiPayloadNumBytes>DDR_PACKET_BUFFER_SIZE0)
			uiFDQ= DDR_HOST_SIZE1_FDQ;
		else
			uiFDQ= DDR_HOST_SIZE0_FDQ;

		for(i=0; i<transferParam->numPackets; i++)
		{
			hostDescriptor= (HostPacketDescriptor *)KeyStone_queuePop(uiFDQ);
			if(NULL==hostDescriptor)
			{
				printf("Source queue %d is NULL\n", uiFDQ);
				GE_Check_Free_Queues(); 	//for debug
				break;
			}
		
			/*invalid cache before read descriptor RAM*/
			InvalidCache((void *)hostDescriptor, 64);

			/*Directed packet to port. Setting these bits to a non-zero value 
			indicates that the packet is a directed packet. Packets with the 
			these bits set will bypass the ALE and send the packet directly 
			to the port indicated.*/
			hostDescriptor->ps_flags= j+1;

			/*initialize the source buffer*/
			ucpBuffer= (Uint8 *)hostDescriptor->buffer_ptr;

			/*fill MAC header*/
			Fill_EMAC_header(ucpBuffer, ETHERNET_IPV4_PACKET, Source_MAC_address[j],
				Dest_MAC_address[j]);
			/*******************************************************/
			Fill_IP_header(ucpBuffer,Recv_IP,DestIP, IP_HEADER_LEN+UDP_HEADER_LEN+uiPayloadNumBytes);
			Fill_UDP_header(ucpBuffer,SourPort,DestPort,UDP_HEADER_LEN+uiPayloadNumBytes);
			//添加IP层的校验和
			Uint16 check;
			Uint16 Buffer1[10]={0};
			int a;
			int b=0;
			for(a=14;a<34;a=a+2){
				Buffer1[b]=(ucpBuffer[a] &0xff)<<8 | (ucpBuffer[a+1] &0xff);
				b++;
				}
			check= checksum(Buffer1, 20);
			ucpBuffer[24]=((check)>>8)&0xFF; // 头部校验  16位
			ucpBuffer[25]= ((check)>>0)&0xFF;

			/*fill data pattern*/
			memset(ucpBuffer+ EMAC_HEADER_LEN+ IP_HEADER_LEN+ UDP_HEADER_LEN, transferParam->dataPattern, uiPayloadNumBytes);//
			hostDescriptor->packet_length= uiPayloadNumBytes+ EMAC_HEADER_LEN+ IP_HEADER_LEN+ UDP_HEADER_LEN;//
			/*******************************************************/
			/*write back data from cache to descriptor RAM*/
			WritebackCache((void *)hostDescriptor, 64);
			WritebackCache((void *)ucpBuffer, uiPayloadNumBytes+EMAC_HEADER_LEN+ IP_HEADER_LEN+ UDP_HEADER_LEN);//

			//save descriptors to temp buffer
			TxDescriptorTempBuffer[uiTotalNumPackets]= (Uint32)hostDescriptor;

			uiTotalBytes += uiPayloadNumBytes;
			uiTotalNumPackets++;
		}
	}

	//TSC_delay_ms(10000);
	uiTxGoodFrames= Get_TX_Good_Frames();
	
	uiCycles= TSCL;
	for(i=0; i< uiTotalNumPackets; i++)
	{
		/*push the packet descriptor to Packet DMA TX queue*/
		KeyStone_queuePush(GE_DIRECT_TX_QUEUE,
			TxDescriptorTempBuffer[i]|FETCH_SIZE_64);

		//delay to avoid potentail overflow, for debug only
		TSC_delay_ms(DELAY_BETWEEN_PACKET_MS);
	}

	/*wait all packets have been send out successfully*/
	while((Get_TX_Good_Frames()-uiTxGoodFrames)<uiTotalNumPackets)
	{
		asm(" NOP 5");
#if 1 	//for debug
		if(TSC_count_cycle_from(uiCycles)>0x3FFFFFFF) 	//timeout
		{
			puts("waiting for transfer complete timeout!");
			print_GE_status_error(); 	//for debug
			while(1); 	//trap
		}
#endif
	}

	uiCycles= TSC_count_cycle_from(uiCycles);
	printf("Transferred %8d bytes with %8d cycles, throughput= %4dMbps.\n", 
		uiTotalBytes, uiCycles, 
		(unsigned long long)uiTotalBytes*8*gDSP_Core_Speed_Hz/uiCycles/1000000);

}

/*******************************************************/
//函数功能：添加IP层

//函数第一个参数：存放UDP包数据的地址

//函数第二个参数：源IP

//函数第三个参数：目的IP

//函数第三个参数：IP层的长度（IP层+UDP层的长度。净荷数据的长度+28）

void Fill_IP_header(Uint8 * buffer,unsigned int sour_add,unsigned int dest_add, short length ){
	buffer[14]= 0x45; 	//8{版本4 位,首部长度4 位}
	buffer[15]= 0x00;	//{服务类型}
	buffer[16]= ((length)>>8)&0xFF; 	//{总长度 16位}IP包的长度以字节为单位
	buffer[17]= ((length)>>0)&0xFF;

	buffer[18]= 0x00; 	// {标识16位}
	buffer[19]= 0x01;
	buffer[20]= 0x00;	//{标志3位,段偏移量13位}
	buffer[21]= 0x00;

	buffer[22]= 0x10;	//{生存期}
	buffer[23]= 0x11;	//{协议}
	buffer[24]= 0x00;	// {首部校验和16位}
	buffer[25]= 0x00;

	buffer[26]= ((sour_add)>>24)&0xFF;	// {源 IP地址32位}  
	buffer[27]= ((sour_add)>>16)&0xFF;
	buffer[28]= ((sour_add)>>8)&0xFF;
	buffer[29]= ((sour_add)>>0)&0xFF;

	buffer[30]= ((dest_add)>>24)&0xFF;	// {目的 IP地址32位}
	buffer[31]= ((dest_add)>>16)&0xFF;
	buffer[32]= ((dest_add)>>8)&0xFF;
	buffer[33]= ((dest_add)>>0)&0xFF;

}
//函数功能：添加UDP层

//函数第一个参数：存放UDP包数据的地址

//函数第二个参数：源端口号

//函数第三个参数：目的端口号

//函数第三个参数：IP层的长度（UDP层的长度。净荷数据的长度+8）

void Fill_UDP_header(Uint8 * buffer,unsigned short sour_port, unsigned short det_port,short length){


	buffer[34]= ((sour_port)>>8)&0xFF;	//{源端口16位}
	buffer[35]= ((sour_port)>>0)&0xFF;

	buffer[36]= ((det_port)>>8)&0xFF;	//{目的端口16位}
	buffer[37]= ((det_port)>>0)&0xFF;

	buffer[38]= ((length)>>8)&0xFF;	//{数据长度16位}
	buffer[39]= ((length)>>0)&0xFF;

	buffer[40]= 0x00;	// {校验和16位}
	buffer[41]= 0x00;
}

//计算校验和的代码
Uint16 checksum(Uint16 *dp, Uint16 length)
{
	Uint32 sum = 0;
	Uint16 len = length >> 1;

	while(len-- > 0)
		sum += *dp++;
	if(length & 1)
		sum += (*dp & 0xFF00);

	sum = (sum >> 16) + (sum & 0xFFFF);
	sum += (sum >> 16);

	len = sum & 0xFFFF;
	return(~len);
}
/*******************************************************/
