/*
* Copyright c                  Realtek Semiconductor Corporation, 2002  
* All rights reserved.
* 
* Program : Source File for IC-specific Function
* Abstract : 
* Author : Louis Yung-Chieh Lo (yjlou@realtek.com.tw)               
* $Id: rtl865xc_testModel.c,v 1.3 2012/10/24 04:31:12 ikevin362 Exp $
*/

#include <linux/delay.h>
#include "rtl865xc_testModel.h"
#include <net/rtl/rtl867x_hwnat_api.h>

#if defined(CONFIG_RTL_8685S_HWNAT)
#include "../AsicDriver/rtl865x_asicBasic.h"
#endif

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 *  Shared Packet Memory Space for test cases.
 */
 
//0-> virtualMac Input/output 1->expect packet  2->data buffer
uint8 RTL865xC_Test_SharedPkt[RTL865xC_TEST_SHARE_PKT_NUM][RTL865xC_TEST_SHARE_PKT_LEN];

void rtl865xC_swDriver_init(void)
{
	/* IPQoS */	
	#ifdef CONFIG_RTL_HW_QOS_SUPPORT
	//rtl8676_IPQos_Disable(); //we not care qos
	#endif

	/* acl */
	#if defined(CONFIG_RTL_HARDWARE_NAT) && defined(CONFIG_RTL_LAYERED_DRIVER_ACL) 
	rtl865x_acl_control_L2_permit_clean();	
	rtl865x_acl_control_L34_permit_clean();
	rtl865x_acl_control_L34_redirect_clean();
	rtl865x_acl_control_set_mode(RTL865X_ACL_Mode_Normal);
	#else
	rtl865x_reinit_acl();
	#endif	

	/*event management */
	#ifdef CONFIG_RTL_LAYERED_DRIVER_L2
	rtl865x_reInitEventMgr();
	#endif

	/*l4*/
	#ifdef CONFIG_RTL_LAYERED_DRIVER_L4
	rtl865x_nat_reinit();
	#endif
	
	/*l3*/
	#ifdef CONFIG_RTL_LAYERED_DRIVER_L3
	rtl865x_reinitMulticast();
	rtl865x_reinitRouteTable();
	rtl865x_reinitNxtHopTable();	
	rtl865x_reinitPppTable();	
	rtl865x_arp_reinit();	
	rtl865x_reinitIpTable();	
	#endif

	/*l2*/
	#ifdef CONFIG_RTL_LAYERED_DRIVER_L2
	rtl865x_layer2_reinit();
	#endif	

	/*common*/	
	rtl865x_reinitNetifTable();	
	rtl865x_reinitVlantable();	


//reinit all asic table

#if defined(CONFIG_RTL_8685S_HWNAT)
{
	int8 *str[] = { "TYPE_L2_SWITCH_TABLE", "TYPE_ARP_TABLE", "TYPE_L3_ROUTING_TABLE", "TYPE_MULTICAST_TABLE", "TYPE_NETINTERFACE_TABLE",
		"TYPE_EXT_INT_IP_TABLE", "TYPE_VLAN_TABLE", "TYPE_VLAN1_TABLE","non_Table","TYPE_L4_TCP_UDP_TABLE",
		"non_Table","TYPE_PPPOE_TABLE","TYPE_ACL_RULE_TABLE","TYPE_NEXT_HOP_TABLE","TYPE_RATE_LIMIT_TABLE","non_Table",
		"TYPE_DS_LITE_TABLE","TYPE_6RD_TABLE","TYPE_IPv6_ROUTING_TABLE","TYPE_IPv6_NEXTHOP_TABLE","TYPE_IPV6_NEIGH_TABLE","TYPE_IPv6_MULTICAST_TABLE"};

	uint32 tableEntryNumSize[]={
#if defined(CONFIG_RTL_8685S_HWNAT)
		/*TYPE_L2_SWITCH_TABLE*/2048,
#else
		/*TYPE_L2_SWITCH_TABLE*/1024,
#endif
		/*TYPE_ARP_TABLE*/512,
		/*TYPE_L3_ROUTING_TABLE*/8,
		/*TYPE_MULTICAST_TABLE*/256,
		/*TYPE_NETINTERFACE_TABLE*/8,
		/*TYPE_EXT_INT_IP_TABLE*/16,
		/*TYPE_VLAN_TABLE*/2048,
		/*TYPE_VLAN1_TABLE*/2048,
		/*non_Table*/8,
		/*TYPE_L4_TCP_UDP_TABLE*/1024,
		/*non_Table*/8,
		/*TYPE_PPPOE_TABLE*/8,
		/*TYPE_ACL_RULE_TABLE*/253,
		/*TYPE_NEXT_HOP_TABLE*/32,
		/*TYPE_RATE_LIMIT_TABLE*/32,
		/*non_Table*/8,
		/*TYPE_DS_LITE_TABLE*/8,
		/*TYPE_6RD_TABLE*/8,
		/*TYPE_IPv6_ROUTING_TABLE*/8,
		/*TYPE_IPv6_NEXTHOP_TABLE*/32,
		/*TYPE_IPV6_ARP_TABLE*/256,
		/*TYPE_IPv6_MULTICAST_TABLE*/256};

	uint32   entry[11];
	int tableNum,entryNum;
	memset(&entry ,0x0 ,sizeof(entry));
	for(tableNum=0 ; tableNum< 22 ; tableNum++)
	{
		//ingore non_table
		if(str[tableNum] == "non_Table" )
			continue;
		for(entryNum=0 ; entryNum < tableEntryNumSize[tableNum];entryNum++){
//			printk("entryNum = %d  tableEntryNumSize[tableNum]=%d\n",entryNum,tableEntryNumSize[tableNum]);
			_rtl8651_forceAddAsicEntry(tableNum, entryNum, &entry);
		}
	}
}
#endif

	
}


/*
	reinit sw driver ->    reinit hw  ->  reinit sw driver
	
     Note. when deleting sw entry, it would check whether the hw entry existes.
	 		Hence, we cannot reset hw until clear sw table .
			
			However, we have to reinit sw driver agina after hw reinit.
			sw. will init some reg. (ex. Mulitacst MTU)
*/
int32 rtl865xC_virtualMacInit(void)
{
	/* In pure model code mode (either USER or MODEL), we configure to MII-Like mode. */	
	
	enum PORTID port;
	int32 needDelay = 0;
	int i;


	/*re-init sequence eventmgr->l4->l3->l2->common is to make sure delete asic entry,
	if not following this sequence, 
	some asic entry can't be deleted due to reference count is not zero*/

	/* step1. reset sw : Use driver-layer API   */
	rtl865xC_swDriver_init();

	/* step2. reset switch and PCS  :  REG'h1800_030C_Bit[3]*/
	WRITE_MEM32(0xb800030c, READ_MEM32(0xb800030c)&(~0x8));
	mdelay(10);
	WRITE_MEM32(0xb800030c, READ_MEM32(0xb800030c)|0x8);
	mdelay(10);

#if !defined(CONFIG_RTL_8685S_HWNAT)
	/* step3. Enable test mode (TX/RX port0~port5)  */
	WRITE_MEM32( TMCR, READ_MEM32(TMCR)|(0x3f<<RX_TEST_PORT_OFFSET));
	WRITE_MEM32( TMCR, READ_MEM32(TMCR)|(0x3f<<TX_TEST_PORT_OFFSET));
#endif


	/* step4. We set every port in 1000Mbps force mode. */
	for( port = PHY0; port<=RTL8651_MAC_NUMBER; port++ )
	{
		uint32 config;
		config = READ_MEM32( PCRP0+port*4 );
		if ( (config&EnForceMode)==1 )
		{
			/* already configured, do nothing for speed up */
		}
		else
		{	/* Not configured, this is the first time system initialization. */
	
			config &= (BYPASS_TCRC|MIIcfg_CRS|MIIcfg_COL|MIIcfg_RXER|GMIIcfg_CRS|BCSC_Types_MASK|
			           EnLoopBack|PauseFlowControl_MASK|DisBKP|STP_PortST_MASK|AcptMaxLen_MASK); /* keep value */
			
			config |= ((port<<ExtPHYID_OFFSET)|EnForceMode|ForceLink|ForceSpeed100M|ForceDuplex|
						PauseFlowControlEtxErx|EnablePHYIf|MacSwReset);	

			WRITE_MEM32( PCRP0+port*4, config );
			mdelay(10);
			needDelay++;
		}
	}

#if defined(CONFIG_RTL_8685S_HWNAT)
		/* step3. Enable test mode (TX/RX port0~port5)	*/
		WRITE_MEM32( TMCR, READ_MEM32(TMCR)|(0x3f<<RX_TEST_PORT_OFFSET));
		mdelay(10);
		WRITE_MEM32( TMCR, READ_MEM32(TMCR)|(0x3f<<TX_TEST_PORT_OFFSET));
#endif

	if ( needDelay > 0 )
	{ /* delay 1/100 sec for link REALLY up (only IC need delay) */
		mdelay(10);		
	}
		mdelay(10);

	/* step5. prepare share packet buffer for test mode */
	for(i=0;i<RTL865xC_TEST_SHARE_PKT_NUM;i++)
		memset( RTL865xC_Test_SharedPkt[i], 0, RTL865xC_TEST_SHARE_PKT_LEN*sizeof(*RTL865xC_Test_SharedPkt[i]) );
	
	//data set to 0xdd
	memset(RTL865xC_Test_SharedPkt[2],0xdd, RTL865xC_TEST_SHARE_PKT_LEN*sizeof(*RTL865xC_Test_SharedPkt[2]));

	/* step6. start hw. */
	REG32(SIRR) = 1;	
	mdelay(3000);

	/* step7. reset sw : Use driver-layer API   */
	rtl865xC_swDriver_init();

	return SUCCESS;
}


/*
 *  Send the packet to the Mii-like port to simulate a received packet from physical port to SWCORE.
 *    len - included L2 CRC
 */
int32 rtl865xC_virtualMacInput( enum PORTID fromPort, uint8* packet, int32 len )
{
	int32 i;
	uint32 regRx;
	uint32 rxEnMask;
	uint32 byteOffset;

	/* GMII, support JUMBO frame */
	if ( len > (16*1024-1) )
	{
		rtlglue_printf("Leave %s @ %d  : Packet is larger than JUMBO frame (len=%d).\n", __FUNCTION__, __LINE__, len );
		return FAILED;
	}	

	if( packet ==NULL )
	{
		rtlglue_printf("Leave %s @ %d  : Ppacket ==NULL\n", __FUNCTION__, __LINE__ );
		return FAILED;
	}	
	

	/*************************************************************
	 *  MiiRx (CPU sends packet to ASIC)
	 *************************************************************/	



	/*------------------------------------------------------------
	 * 0. Prepare variables
	 */
	regRx = MIITM_RXR0+(fromPort/3)*4;
	rxEnMask = 1<<(P0RxEN_OFFSET+(fromPort%3));
	byteOffset = (fromPort%3)*8+P0RXD_OFFSET;
	

	/*------------------------------------------------------------
	 * 1. Send preamble (8 bytes, 5555 5555 5555 55d5)
	 */
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0x55<<byteOffset));
	WRITE_MEM32( regRx, rxEnMask|(0xd5<<byteOffset));
	
	/*------------------------------------------------------------
	 * 2. Send packet content
	 */
	for( i = 0; i<len; i++ )
	{
		WRITE_MEM32( regRx, rxEnMask|(packet[i]<<byteOffset) );
	}

	/*------------------------------------------------------------
	 * 3. Send tailing octets (12 Bytes)
	 */
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));
	WRITE_MEM32( regRx, (0x00<<byteOffset));

	return SUCCESS;
}


/*
 *  Receive the packet from the Mii-like port to simulate a sending packet from swcore to physical port.
 */
#if 0
int32 rtl865xC_virtualMacOutput( uint32 *toPort, uint8* packet, int32 *len )
{
	/*************************************************************
	 *  MiiTx (ASIC sends packet to CPU)
	 *************************************************************/
	uint32 data;
	uint32 Tx_ready_port = 0xffffffff;
	uint32 retlen = 0;
	uint32 regTx;
	uint32 txEnMask;
	uint32 byteOffset;
	uint32 max_try = 512; /* Try times, I hope long enough for FPGA. (unit:byte) */

	
	uint32 port;
	int port_check=-1;



	/*  we only check one port once  */
	for( port = PN_PORT0; port <= PN_PORT5; port++ )
	{
		if ( (*toPort)&(1<<port) )
		{
			if(port_check==-1)
			{
				port_check = port;
			}
			else
			{
				printk("(%s %d) sorry, we only check one port once \n",__func__,__LINE__);
				goto failed;
			}
		}
	}

	if(port_check==-1)
	{
		printk("(%s %d) no ckeck port ?  \n",__func__,__LINE__);
		goto failed;
	}


	/*------------------------------------------------------------
	 * 0. Prepare variables
	 */
	retlen = 0;

	/*------------------------------------------------------------
	 * 1. Polling until Tx packet ready
	 *------------------------------------------------------------*/	
	#if 0 /* Since designer does not implement these status bits, we don't check them. */
	
	while( 1 )
	{
		data = READ_MEM32( TMCR );
		if ( (data>>MiiTxPktRDY_OFFSET)&*toPort )
			break;
			
		if ( (try--)== 0 ) goto failed;
	}
	#endif	
	

	/* Check if any port has valid data. */
	Tx_ready_port = (READ_MEM32(TMCR) & MiiTxPktRDY_MASK)>>MiiTxPktRDY_OFFSET;


#if 0
//polling until MiiTxPktRDY_MASK !=0 , max 5sec
{
	uint32 pollingCount=0;
	while(1)
	{
		 Tx_ready_port = (READ_MEM32(TMCR) & MiiTxPktRDY_MASK)>>MiiTxPktRDY_OFFSET;

		 if((Tx_ready_port !=0))
		 {
		 	break;
		 }else{
		 	printk("MiiTxPktRDY_MASK polling fail \n");
		 	pollingCount++;
		 	mdelay(500);
			if(pollingCount >=10)
				break;
		 	}
	 }
}
#endif

	
	if( (1<<port_check) & Tx_ready_port )
	{
		*toPort = Tx_ready_port;
		goto preamble_found;
	}
	else
	{
		printk("(%s %d)  The port (your input:%d)  has no data  (the ports has data(mask): 0x%X)\n",__func__,__LINE__,port_check,Tx_ready_port);
		goto failed;
	}
	
preamble_found:

	regTx = MIITM_TXR0+(port_check/3)*4;
	txEnMask = 1<<(P0TxEN_OFFSET+(port_check%3));
	byteOffset = (port_check%3)*8+P0TXD_OFFSET;
	//printk("(%s %d)  max_try=%d  *toPort=%u\n",__func__,__LINE__,max_try,*toPort);


	
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );


	/*------------------------------------------------------------
	 * 2. Polling until preamble found (~8Bytes)
	 *------------------------------------------------------------*/	

	/* find preample '55'. */
	do
	{
		if (((data>>byteOffset)&0xff)==0x55)
			break;
		WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
		data = READ_MEM32( regTx ); /* read next byte */
		if ( (max_try--)== 0 ) 
		{		
			printk("(%s %d) no find preample '55'  \n",__func__,__LINE__);
			goto failed;			
		}
	} while (1);


	
	/* find preample 'd5'. */
	do
	{
		if (((data>>byteOffset)&0xff)==0xd5)
			break;
		WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
		data = READ_MEM32( regTx ); /* read next byte */
		if ( (max_try--)== 0 ) 
		{		
			printk("(%s %d) no find preample 'd5'  \n",__func__,__LINE__);
			goto failed;			
		}
	} while (1);


	/*------------------------------------------------------------
	 * 3. Read packet (until packet ends)
	 *------------------------------------------------------------*/
	while( 1 )
	{
		WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
		mdelay(1);
		data = READ_MEM32( regTx ); /* read next byte */
		if ( (data&txEnMask) == 0 ) /* no data valid for P0_TXDV~P5_TXDV */
			break;
		
		packet[retlen] = data>>byteOffset;
		
		retlen++;
	}

	/*------------------------------------------------------------
	 * 4. Read tailing data (12 Bytes) 
	 *------------------------------------------------------------*/
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );
	WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
	data = READ_MEM32( regTx );

	*len = retlen;
	return SUCCESS;

failed:
	*len = 0;
	*toPort = 0;
	return FAILED;
}


#else

/*
 *  Receive the packet from the Mii-like port to simulate a sending packet from swcore to physical port.
 */
int32 rtl865xC_virtualMacOutput( uint32 *toPort, uint8* packet, int32 *len )
{
 /*************************************************************
  *  MiiTx (ASIC sends packet to CPU)
  *************************************************************/
 uint32 data;
 uint32 Tx_ready_port = 0xffffffff;
 uint32 retlen = 0;
 uint32 regTx;
 uint32 txEnMask;
 uint32 byteOffset;
 uint32 max_try = 512; /* Try times, I hope long enough for FPGA. (unit:byte) */
 
 
 uint32 port;
 uint32 try = 100 ;/* Try port times, I hope long enough for FPGA. (unit:byte) */
 int port_check=-1;
 
 
 
 /*  we only check one port once  */
 for( port = PN_PORT0; port <= PN_PORT5; port++ )
 {
  if ( (*toPort)&(1<<port) )
  {
   if(port_check==-1)
   {
    port_check = port;
   }
   else
   {
    printk("(%s %d) sorry, we only check one port once \n",__func__,__LINE__);
    goto failed;
   }
  }
 }
 
 if(port_check==-1)
 {
  printk("(%s %d) no ckeck port ?  \n",__func__,__LINE__);
  goto failed;
 }
 

 /*------------------------------------------------------------
  * 0. Prepare variables
  */
 retlen = 0;
 
 /*------------------------------------------------------------
  * 1. Polling until Tx packet ready
  *------------------------------------------------------------*/ 
 #if 0 /* Since designer does not implement these status bits, we don't check them. */
 
 while( 1 )
 {
  data = READ_MEM32( TMCR );
  if ( (data>>MiiTxPktRDY_OFFSET)&*toPort )
   break;
   
  if ( (try--)== 0 ) goto failed;
 }
 #endif 
 
 
#if 0 ////leroy (+)
 /* Check if any port has valid data. */
 Tx_ready_port = (READ_MEM32(TMCR) & MiiTxPktRDY_MASK)>>MiiTxPktRDY_OFFSET;
#endif
 
#if 0
//polling until MiiTxPktRDY_MASK !=0 , max 5sec
{
 uint32 pollingCount=0;
 while(1)
 {
   Tx_ready_port = (READ_MEM32(TMCR) & MiiTxPktRDY_MASK)>>MiiTxPktRDY_OFFSET;
 
   if((Tx_ready_port !=0))
   {
    break;
   }else{
    printk("MiiTxPktRDY_MASK polling fail \n");
    pollingCount++;
    mdelay(500);
   if(pollingCount >=10)
    break;
    }
  }
}
#endif



#if 0 ////leroy (+) 
 if( (1<<port_check) & Tx_ready_port )
 {
  *toPort = Tx_ready_port;
  goto preamble_found;
 }
 else
 {
  printk("(%s %d)  The port (your input:%d)  has no data  (the ports has data(mask): 0x%X)\n",__func__,__LINE__,port_check,Tx_ready_port);
  goto failed;
 }
#endif 



 
////leroy (+)
 while( 1 )
	{
	  /* Check if any port has valid data. */
	  for( port = PN_PORT0; port <= PN_PORT5; port++ )
	  {
	   if ( (*toPort)&(1<<port) )
	   {
	    regTx = MIITM_TXR0+(port/3)*4;
	    txEnMask = 1<<(P0TxEN_OFFSET+(port%3));
	    byteOffset = (port%3)*8+P0TXD_OFFSET;
		mdelay(2);
	    WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
		mdelay(2);
	    data = READ_MEM32( regTx );
	    if ( data & txEnMask )
	     goto preamble_found;
	   }
	  }    
        
  if ( (try--)== 0 ) goto failed;
	}		
 /* yes, port 'port' has valid data. */
 if ( port>PN_PORT5 ) goto failed;
////leroy (-)


	
	



preamble_found:
	mdelay(10);
#if 0 ////leroy (+)
 regTx = MIITM_TXR0+(port_check/3)*4;
 txEnMask = 1<<(P0TxEN_OFFSET+(port_check%3));
 byteOffset = (port_check%3)*8+P0TXD_OFFSET;
 
 //printk("(%s %d)  max_try=%d  *toPort=%u\n",__func__,__LINE__,max_try,*toPort);
 
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
#endif
 
 /*------------------------------------------------------------
  * 2. Polling until preamble found (~8Bytes)
  *------------------------------------------------------------*/ 
 
 /* find preample '55'. */
 do
 {
  if (((data>>byteOffset)&0xff)==0x55)
   break;
  WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
  mdelay(3);
  data = READ_MEM32( regTx ); /* read next byte */
  if ( (max_try--)== 0 ) 
  { 
   printk("(%s %d) no find preample '55'  \n",__func__,__LINE__);
   goto failed;   
  }
 } while (1);
 

 
 /* find preample 'd5'. */
 do
 {
  if (((data>>byteOffset)&0xff)==0xd5)
   break;
  WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
  mdelay(3);
  data = READ_MEM32( regTx ); /* read next byte */
  if ( (max_try--)== 0 ) 
  {  
   printk("(%s %d) no find preample 'd5'  \n",__func__,__LINE__);
   goto failed;   
  }
 } while (1);
 

 /*------------------------------------------------------------
  * 3. Read packet (until packet ends)
  *------------------------------------------------------------*/
 while( 1 )
 {
  WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
  mdelay(3);
  data = READ_MEM32( regTx ); /* read next byte */
  if ( (data&txEnMask) == 0 ) /* no data valid for P0_TXDV~P5_TXDV */
   break;
  
  packet[retlen] = data>>byteOffset;
  
  retlen++;
 }
 
 /*------------------------------------------------------------
  * 4. Read tailing data (12 Bytes) 
  *------------------------------------------------------------*/
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 WRITE_MEM32( regTx, txEnMask ); /* give Mii-Tx a clock */
 data = READ_MEM32( regTx );
 
 *len = retlen;
	return SUCCESS;
 
failed:
 *len = 0;
 *toPort = 0;
 return FAILED;
}


#endif