/* * 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