diff options
author | Roman Yeryomin <roman@advem.lv> | 2012-09-13 00:40:35 +0300 |
---|---|---|
committer | Roman Yeryomin <roman@advem.lv> | 2012-12-03 00:13:21 +0200 |
commit | 5deb3317cb51ac52de922bb55f8492624018906d (patch) | |
tree | c2fbe6346699d9bb0f2100490c3029519bb8fde8 /target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c | |
parent | 0239d37124f9184b478a42de8a7fa1bc85a6a6fe (diff) |
Add realtek target files
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c')
-rw-r--r-- | target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c | 8846 |
1 files changed, 8846 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c b/target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c new file mode 100644 index 000000000..2bb69510f --- /dev/null +++ b/target/linux/realtek/files/drivers/net/rtl819x/rtl_nic.c @@ -0,0 +1,8846 @@ +/* + * Copyright c Realtek Semiconductor Corporation, 2003 + * All rights reserved. + * + * $Header: /home/cvsroot/linux-2.6.19/linux-2.6.x/drivers/net/re865x/rtl_nic.c,v 1.22 2008/04/11 10:49:14 bo_zhao Exp $ + * + * $Author: bo_zhao $ + * + * Abstract: Pure L2 NIC driver, without RTL865X's advanced L3/4 features. + * + * re865x_nic.c: NIC driver for the RealTek 865* + * + */ + +#define DRV_RELDATE "Mar 25, 2004" +#include <linux/config.h> +#include <linux/autoconf.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/etherdevice.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/crc32.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/slab.h> +#include <linux/signal.h> +#include <linux/proc_fs.h> +#include <linux/time.h> +#include <linux/rtc.h> +#include <bsp/bspchip.h> +#include <linux/timer.h> +#if defined(CONFIG_RTK_VLAN_SUPPORT) +#include <net/rtl/rtk_vlan.h> +#endif + +#if defined(CONFIG_RTL8196_RTL8366) && defined(CONFIG_RTL_IGMP_SNOOPING) +#undef CONFIG_RTL_IGMP_SNOOPING +#endif + +#include "version.h" +#include <net/rtl/rtl_types.h> +#include <net/rtl/rtl_glue.h> + +#include "AsicDriver/asicRegs.h" +#include "AsicDriver/rtl865x_asicCom.h" +#include "AsicDriver/rtl865x_asicL2.h" +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER_L3 +#include "AsicDriver/rtl865x_asicL3.h" +#endif + +#include "common/mbuf.h" +#include <net/rtl/rtl_queue.h> +#include "common/rtl_errno.h" +#include "rtl865xc_swNic.h" + +/*common*/ +#include "common/rtl865x_vlan.h" +#include <net/rtl/rtl865x_netif.h> +#include "common/rtl865x_netif_local.h" + +/*l2*/ +#ifdef CONFIG_RTL_LAYERED_DRIVER_L2 +#include "l2Driver/rtl865x_fdb.h" +#include <net/rtl/rtl865x_fdb_api.h> +#endif + +/*l3*/ +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 +#include "l3Driver/rtl865x_ip.h" +#include "l3Driver/rtl865x_nexthop.h" +#include <net/rtl/rtl865x_ppp.h> +#include "l3Driver/rtl865x_ppp_local.h" +#include "l3Driver/rtl865x_route.h" +#include "l3Driver/rtl865x_arp.h" +#include <net/rtl/rtl865x_nat.h> +#endif + +/*l4*/ +#ifdef CONFIG_RTL865X_ROMEPERF +#include "romeperf.h" +#endif +#include <net/rtl/rtl_nic.h> +#if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_NET_SCHED) && defined(CONFIG_RTL_LAYERED_DRIVER) +#include <net/rtl/rtl865x_outputQueue.h> +#endif + +#ifdef CONFIG_RTL_STP +#include <net/rtl/rtk_stp.h> +#endif + +#if defined(CONFIG_RTL_HW_STP) +#include <net/rtl/rtk_stp.h> +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) +#include <net/rtl/rtl865x_igmpsnooping.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#if defined (CONFIG_RTL_MLD_SNOOPING) +#include <linux/ipv6.h> +int mldSnoopEnabled; +#endif +uint32 nicIgmpModuleIndex=0xFFFFFFFF; +extern int igmpsnoopenabled; +extern uint32 brIgmpModuleIndex; +#if defined (CONFIG_RTL_HARDWARE_MULTICAST) +extern struct net_bridge *bridge0; +extern uint32 br0SwFwdPortMask; +#endif +#endif + +#if defined (CONFIG_RTL_8198_INBAND_AP) || defined (CONFIG_RTL_8198_NFBI_BOARD) +#define CONFIG_819X_PHY_RW 1 +#endif + +static unsigned int curLinkPortMask=0; +static unsigned int newLinkPortMask=0; + +#define SET_MODULE_OWNER(dev) do { } while (0) + +#if defined (CONFIG_RTL_HARDWARE_MULTICAST) +#include <net/rtl/rtl865x_multicast.h> +#endif + +#ifdef CONFIG_RTL8196_RTL8366 +#include "RTL8366RB_DRIVER/gpio.h" +#include "RTL8366RB_DRIVER/rtl8366rb_apiBasic.h" +#endif + +#if (defined(CONFIG_RTL_CUSTOM_PASSTHRU) && !defined(CONFIG_RTL8196_RTL8366)) +__DRAM_FWD static int oldStatus; +static struct proc_dir_entry *res=NULL; +static char passThru_flag[1]; +static int32 __init rtl8651_customPassthru_init(void); +static int32 rtl8651_initStormCtrl(void); +static inline int32 rtl_isPassthruFrame(uint8 *data); +#endif + +#if (defined(CONFIG_RTL_8198)) +static struct proc_dir_entry *phyTest_entry=NULL; +#endif + +#if defined(CONFIG_RTL_ETH_PRIV_SKB) && (defined(CONFIG_NET_WIRELESS_AGN) || defined(CONFIG_NET_WIRELESS_AG) || defined(CONFIG_WIRELESS)) +#include <net/dst.h> +#endif + +#if 0 +#define DEBUG_ERR printk +#else +#define DEBUG_ERR(format, args...) +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) +#include <net/rtl/rtl865x_localPublic.h> +#endif + +static int32 __865X_Config; +#if defined(DYNAMIC_ADJUST_TASKLET) || defined(BR_SHORTCUT) +#if 0 +static int eth_flag=12; // 0 dynamic tasklet, 1 - disable tasklet, 2 - always tasklet , bit2 - bridge shortcut enabled +#endif +#endif +#if defined(BR_SHORTCUT) +__DRAM_FWD unsigned char cached_eth_addr[ETHER_ADDR_LEN]; +EXPORT_SYMBOL(cached_eth_addr); +__DRAM_FWD struct net_device *cached_dev; +EXPORT_SYMBOL(cached_dev); +#if defined(CONFIG_WIRELESS_LAN_MODULE) +struct net_device* (*wirelessnet_hook_shortcut)(unsigned char *da) = NULL; +EXPORT_SYMBOL(wirelessnet_hook_shortcut); +int (*wirelessnet_hook)(void) = NULL; +EXPORT_SYMBOL(wirelessnet_hook); +#endif +#endif + + +#if defined(CONFIG_RTL_REINIT_SWITCH_CORE) +#define STATE_NO_ERROR 0 +#define STATE_SW_CLK_ENABLE_WAITING 1 +#define STATE_TO_REINIT_SWITCH_CORE 2 +int rtl865x_duringReInitSwtichCore=0; +int rtl865x_reInitState=STATE_NO_ERROR; +int rtl865x_reInitWaitCnt=0; +#endif +#if defined (CONFIG_RTL_UNKOWN_UNICAST_CONTROL) +static rtlMacRecord macRecord[RTL_MAC_RECORD_NUM]; +static uint32 macRecordIdx; +static uint8 lanIfName[NETIF_NUMBER]; +static void rtl_unkownUnicastUpdate(uint8 *mac); +static void rtl_unkownUnicastTimer(unsigned long data); +#endif + +#if defined(DYNAMIC_ADJUST_TASKLET) || defined(CONFIG_RTL8186_TR) || defined(RTL8196C_EEE_MAC) || defined(CONFIG_RTL_8198_ESD) +static void one_sec_timer(unsigned long task_priv); +#endif + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET +static void power_save_timer(unsigned long task_priv); +#endif + +//#define CONFIG_RTL_LINKSTATE +#if defined(CONFIG_RTL_LINKSTATE) +static struct timer_list s_timer; +static void linkup_time_handle(unsigned long arg); +static int32 initPortStateCtrl(void); +static void exitPortStateCtrl(void); +#endif +#if defined(CONFIG_RTL_ETH_PRIV_SKB) +__MIPS16 __IRAM_FWD static struct sk_buff *dev_alloc_skb_priv_eth(unsigned int size); +static void init_priv_eth_skb_buf(void); +#endif + +#if defined(CONFIG_RTK_QOS_FOR_CABLE_MODEM) +static void rtl_initVlanTableForCableMode(void); +#endif +__DRAM_FWD static struct ring_que rx_skb_queue; +int skb_num=0; + +#if defined(CONFIG_RTL_MULTIPLE_WAN) +static struct net_device *rtl_multiWan_net_dev; +static int rtl_regist_multipleWan_dev(void); +static int rtl_config_multipleWan_netif(int32 cmd); +static int rtl_port_used_by_device(uint32 portMask); +#endif + +int32 rtl865x_init(void); +int32 rtl865x_config(struct rtl865x_vlanConfig vlanconfig[]); + +/* These identify the driver base version and may not be removed. */ +MODULE_DESCRIPTION("RealTek RTL-8650 series 10/100 Ethernet driver"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_DEFAULTS_KERNEL_2_6 +static char* multicast_filter_limit = "maximum number of filtered multicast addresses"; +module_param (multicast_filter_limit,charp, S_IRUGO); +#else +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +MODULE_PARM (multicast_filter_limit, "i"); +MODULE_PARM_DESC (multicast_filter_limit, "maximum number of filtered multicast addresses"); +#endif + +#define DRV_NAME "re865x_nic" +#define PFX DRV_NAME ": " +#define DRV_VERSION "0.1" +#define TX_TIMEOUT (10*HZ) +#define BDINFO_ADDR 0xbe3fc000 + +#define CONFIG_RTL_REPORT_LINK_STATUS + +#if defined (CONFIG_RTL_PHY_POWER_CTRL) +static int32 rtl865x_initPhyPowerCtrl(void); +#endif + +#if defined(RX_TASKLET) +__DRAM_GEN int rtl_rx_tasklet_running; +#endif +#if defined(TX_TASKLET) +__DRAM_GEN int rtl_tx_tasklet_running; +#endif + +__IRAM_GEN static inline void rtl_rx_interrupt_process(unsigned int status, struct dev_priv *cp); +__IRAM_GEN static inline void rtl_tx_interrupt_process(unsigned int status, struct dev_priv *cp); +#if defined(CONFIG_RTL_IGMP_SNOOPING)||defined(CONFIG_RTL_LINKCHG_PROCESS) || defined (CONFIG_RTL_PHY_PATCH) +__IRAM_GEN static inline void rtl_link_change_interrupt_process(unsigned int status, struct dev_priv *cp); +#endif + +static int rtl_rxTxDoneCnt = 0; +static atomic_t rtl_devOpened; + +__MIPS16 __IRAM_GEN void rtl_rxSetTxDone(int enable) +{ + if (unlikely(rtl_devOpened.counter==0)) + return; + + if (FALSE==enable) + { + rtl_rxTxDoneCnt--; + if (rtl_rxTxDoneCnt==-1) + REG32(CPUIIMR) &= ~(TX_ALL_DONE_IE_ALL); + } + else + { + rtl_rxTxDoneCnt++; + if (rtl_rxTxDoneCnt==0) + REG32(CPUIIMR) |= (TX_ALL_DONE_IE_ALL); + } +} + +#define NEXT_DEV(cp) (cp->dev_next ? cp->dev_next : cp->dev_prev) +#define NEXT_CP(cp) ((struct dev_priv *)((NEXT_DEV(cp))->priv)) +#define IS_FIRST_DEV(cp) (NEXT_CP(cp)->opened ? 0 : 1) +#define GET_IRQ_OWNER(cp) (cp->irq_owner ? cp->dev : NEXT_DEV(cp)) + +#define MAX_PORT_NUM 9 + +static unsigned int rxRingSize[RTL865X_SWNIC_RXRING_HW_PKTDESC] = + {NUM_RX_PKTHDR_DESC, + NUM_RX_PKTHDR_DESC1, + NUM_RX_PKTHDR_DESC2, + NUM_RX_PKTHDR_DESC3, + NUM_RX_PKTHDR_DESC4, + NUM_RX_PKTHDR_DESC5}; +static unsigned int txRingSize[RTL865X_SWNIC_TXRING_HW_PKTDESC] = + {NUM_TX_PKTHDR_DESC, + NUM_TX_PKTHDR_DESC1}; + +#if defined (CONFIG_RTL_MULTI_LAN_DEV)||defined(CONFIG_RTK_VLAN_SUPPORT) +static struct rtl865x_vlanConfig packedVlanConfig[NETIF_NUMBER]; +#endif + +/* +linux protocol stack netif VS rtl819x driver network interface +the name of ps netif maybe different with driver. +*/ +static ps_drv_netif_mapping_t ps_drv_netif_mapping[NETIF_NUMBER]; + +static struct rtl865x_vlanConfig vlanconfig[] = { +/* ifName W/L If type VID FID Member Port UntagSet mtu MAC Addr is_slave */ +/* ===== === ======= === === ========= ======= ==== ==================================== */ + +#ifdef CONFIG_BRIDGE +#if defined (CONFIG_RTL_MULTI_LAN_DEV) + { RTL_DRV_LAN_P0_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_4, RTL_LANPORT_MASK_4, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P4_NETIF_NAME, 1, IF_ETHER, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 0 }, + { RTL_DRV_LAN_P1_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_3, RTL_LANPORT_MASK_3, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P2_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_2, RTL_LANPORT_MASK_2, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P3_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_1, RTL_LANPORT_MASK_1, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, +#else /*CONFIG_RTL_MULTI_LAN_DEV*/ +#if defined(CONFIG_RTK_VLAN_SUPPORT) + { RTL_DRV_LAN_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_4, RTL_LANPORT_MASK_4, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, +#else + { RTL_DRV_LAN_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK, RTL_LANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, +#endif +#if defined(CONFIG_RTL_PUBLIC_SSID) + { RTL_GW_WAN_DEVICE_NAME, 1, IF_ETHER, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 0 }, +#else + { RTL_DRV_WAN0_NETIF_NAME, 1, IF_ETHER, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 0 }, +#endif +#if defined(CONFIG_RTK_VLAN_SUPPORT) + { RTL_DRV_LAN_P1_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_3, RTL_LANPORT_MASK_3, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x92 } }, 0 }, + { RTL_DRV_LAN_P2_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_2, RTL_LANPORT_MASK_2, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x93 } }, 0 }, + { RTL_DRV_LAN_P3_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_1, RTL_LANPORT_MASK_1, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x94 } }, 0 }, +#ifdef CONFIG_8198_PORT5_GMII + { RTL_DRV_LAN_P5_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_5, RTL_LANPORT_MASK_5, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x95 } }, 0 }, +#endif //CONFIG_8198_PORT5_GMII +#endif +#endif +#else /*CONFIG_BRIDGE*/ +#if defined (CONFIG_RTL_MULTI_LAN_DEV) + { RTL_DRV_LAN_P0_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_4, RTL_LANPORT_MASK_4, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P4_NETIF_NAME, 1, IF_ETHER, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 0 }, + { RTL_DRV_LAN_P1_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_3, RTL_LANPORT_MASK_3, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P2_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_2, RTL_LANPORT_MASK_2, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_LAN_P3_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_1, RTL_LANPORT_MASK_1, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, +#else /*CONFIG_RTL_MULTI_LAN_DEV*/ + { RTL_DRV_LAN_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK, RTL_LANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } }, 0 }, + { RTL_DRV_WAN0_NETIF_NAME, 1, IF_ETHER, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 0 }, +#if defined(CONFIG_RTK_VLAN_SUPPORT) + { RTL_DRV_LAN_P1_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_3, RTL_LANPORT_MASK_3, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x92 } }, 0 }, + { RTL_DRV_LAN_P2_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_2, RTL_LANPORT_MASK_2, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x93 } }, 0 }, + { RTL_DRV_LAN_P3_NETIF_NAME, 0, IF_ETHER, RTL_LANVLANID, RTL_LAN_FID, RTL_LANPORT_MASK_1, RTL_LANPORT_MASK_1, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x94 } }, 0 }, +#endif +#endif +#endif + { RTL_DRV_PPP_NETIF_NAME, 1, IF_PPPOE, RTL_WANVLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x91 } }, 1 }, + RTL865X_CONFIG_END, +}; + +#if defined(CONFIG_RTL_MULTIPLE_WAN) +static struct rtl865x_vlanConfig rtl_multiWan_config = { RTL_DRV_WAN1_NETIF_NAME, 1, IF_ETHER, RTL_WAN_1_VLANID, RTL_WAN_FID, RTL_WANPORT_MASK, RTL_WANPORT_MASK, 1500, { { 0x00, 0x12, 0x34, 0x56, 0x78, 0x99 } }, 0 }; +#endif + +#if (defined(CONFIG_PROC_FS) && defined(CONFIG_NET_SCHED) && defined(CONFIG_RTL_LAYERED_DRIVER))||(defined (CONFIG_RTL_HW_QOS_SUPPORT)) +static uint8 netIfName[NETIF_NUMBER][IFNAMSIZ] = {{0}}; +#endif + +#if defined(CONFIG_RTL_ETH_PRIV_SKB) +/* The following structure's field orders was arranged for special purpose, + it should NOT be modify */ +struct priv_skb_buf2 { + unsigned char magic[ETH_MAGIC_LEN]; + void *buf_pointer; + /* the below 2 filed MUST together */ + struct list_head list; + unsigned char buf[ETH_SKB_BUF_SIZE]; +}; + +static struct priv_skb_buf2 eth_skb_buf[MAX_ETH_SKB_NUM+1]; +__DRAM_FWD static struct list_head eth_skbbuf_list; +__DRAM_FWD int eth_skb_free_num; +EXPORT_SYMBOL(eth_skb_free_num); +extern struct sk_buff *dev_alloc_8190_skb(unsigned char *data, int size); +#endif + +#ifdef CONFIG_POCKET_AP_SUPPORT +int rtl865x_curOpMode=BRIDGE_MODE; +#else +int rtl865x_curOpMode=GATEWAY_MODE; +#endif + +__DRAM_FWD static struct re865x_priv _rtl86xx_dev; + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET + static struct timer_list expire_timer2; +#endif + +#ifdef CONFIG_RTL_STP +static unsigned char STPmac[] = { 1, 0x80, 0xc2, 0,0,0}; +#ifdef CONFIG_RTK_MESH +int8 STP_PortDev_Mapping[MAX_RE865X_STP_PORT] ={NO_MAPPING, NO_MAPPING, NO_MAPPING, NO_MAPPING, NO_MAPPING, WLAN_PSEUDO_IF_INDEX, WLAN_MESH_PSEUDO_IF_INDEX}; +#else +int8 STP_PortDev_Mapping[MAX_RE865X_STP_PORT] ={NO_MAPPING, NO_MAPPING, NO_MAPPING, NO_MAPPING, NO_MAPPING, WLAN_PSEUDO_IF_INDEX}; +#endif +static int re865x_stp_get_pseudodevno(uint32 port_num); +static int getVidByPort(uint32 port_num); +#endif + +static int re865x_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int32 reinit_vlan_configure(struct rtl865x_vlanConfig new_vlanconfig[]); +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) +/*FIX ME if mutiple-wan*/ +static unsigned char wan_linkStatus[2]; +static int32 rtk_link_status_read( char *page, char **start, off_t off, int count, int *eof, void *data ); +static int32 rtk_link_status_write( struct file *filp, const char *buff,unsigned long len, void *data ); +#endif +//static void rtl_print_vlanconfig(struct rtl865x_vlanConfig new_vlanconfig[]); +#if defined(CONFIG_RTK_VLAN_SUPPORT) +static int read_proc_vlan(char *page, char **start, off_t off,int count, int *eof, void *data); +static int write_proc_vlan(struct file *file, const char *buffer,unsigned long count, void *data); +static int32 rtk_vlan_support_read( char *page, char **start, off_t off, int count, int *eof, void *data ); +static int32 rtk_vlan_support_write( struct file *filp, const char *buff,unsigned long len, void *data ); +//__DRAM_FWD int rtk_vlan_support_enable; +int rtk_vlan_support_enable; +#if defined(CONFIG_819X_PHY_RW) //#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) +static int32 rtl_phy_status_read( char *page, char **start, off_t off, int count, int *eof, void *data ); +static int32 rtl_phy_status_write( struct file *filp, const char *buff,unsigned long len, void *data ); +static int32 port_mibStats_read_proc( char *page, char **start, off_t off, int count, int *eof, void *data ); +static int32 port_mibStats_write_proc( struct file *filp, const char *buff,unsigned long len, void *data ); + +struct port_mibStatistics { + + /*here is in counters definition*/ + uint32 ifInOctets; + uint64 ifHCInOctets; + uint32 ifInUcastPkts; + uint64 ifHCInUcastPkts; + uint32 ifInMulticastPkts; + uint64 ifHCInMulticastPkts; + uint64 ifHCInBroadcastPkts; + uint32 ifInBroadcastPkts; + uint32 ifInDiscards; + uint32 ifInErrors; + uint64 etherStatsOctets; + uint32 etherStatsUndersizePkts; + uint32 etherStatsFraments; + uint32 etherStatsPkts64Octets; + uint32 etherStatsPkts65to127Octets; + uint32 etherStatsPkts128to255Octets; + uint32 etherStatsPkts256to511Octets; + uint32 etherStatsPkts512to1023Octets; + uint32 etherStatsPkts1024to1518Octets; + uint32 etherStatsOversizePkts; + uint32 etherStatsJabbers; + uint32 dot1dTpPortInDiscards; + uint32 etherStatusDropEvents; + uint32 dot3FCSErrors; + uint32 dot3StatsSymbolErrors; + uint32 dot3ControlInUnknownOpcodes; + uint32 dot3InPauseFrames; + + /*here is out counters definition*/ + uint32 ifOutOctets; + uint64 ifHCOutOctets; + uint32 ifOutUcastPkts; + uint64 ifHCOutUcastPkts; + uint64 ifHCOutMulticastPkts; + uint64 ifHCOutBroadcastPkts; + uint32 ifOutMulticastPkts; + uint32 ifOutBroadcastPkts; + uint32 ifOutDiscards; + uint32 ifOutErrors; + uint32 dot3StatsSingleCollisionFrames; + uint32 dot3StatsMultipleCollisionFrames; + uint32 dot3StatsDefferedTransmissions; + uint32 dot3StatsLateCollisions; + uint32 dot3StatsExcessiveCollisions; + uint32 dot3OutPauseFrames; + uint32 dot1dBasePortDelayExceededDiscards; + uint32 etherStatsCollisions; + + /*here is whole system couters definition*/ + uint32 dot1dTpLearnedEntryDiscards; + uint32 etherStatsCpuEventPkts; + uint32 ifInUnknownProtos; + uint32 ifSpeed; + uint32 ifHighSpeed; + uint32 ifConnectorPresent; + uint32 ifCounterDiscontinuityTime; +}; +#endif //#if defined(CONFIG_819X_PHY_RW) +#endif + +#if defined(RTL8196C_EEE_MAC) +extern int eee_enabled; +extern void eee_phy_enable(void); +extern void eee_phy_disable(void); +#ifdef CONFIG_RTL8196C_REVISION_B +static unsigned char prev_port_sts[MAX_PORT_NUMBER] = { 0, 0, 0, 0, 0 }; +#endif +#endif +#if defined(CONFIG_RTL_LOCAL_PUBLIC) +static int32 rtl865x_getPortlistByMac(const unsigned char *mac,uint32 *portlist); +#endif +static inline int rtl_isWanDev(struct dev_priv *cp); + +#ifdef CONFIG_RTL8196C_ETH_IOT +uint32 port_link_sts = 0; // the port which already linked up does not need to check ... +uint32 port_linkpartner_eee = 0; +#endif + +#ifdef CONFIG_RTL_8196C_ESD +int _96c_esd_counter = 0; +int _96c_esd_reboot_counter = 0; +#endif + +#if defined(PATCH_GPIO_FOR_LED) +#define MIB_RX_PKT_CNT 0 +#define MIB_TX_PKT_CNT 1 + +#define PORT_PABCD_BASE 10 // Base of P0~P1 at PABCD +#define P0_PABCD_BIT 10 +#define P1_PABCD_BIT 11 +#define P2_PABCD_BIT 12 +#define P3_PABCD_BIT 13 +#define P4_PABCD_BIT 14 + +#define SUCCESS 0 +#define FAILED -1 + +#define GPIO_LED_NOBLINK_TIME (12*HZ/10) // time more than 1-sec timer interval +#define GPIO_LED_ON_TIME (4*HZ/100) // 40ms +#define GPIO_LED_ON 0 +#define GPIO_LED_OFF 1 +#define GPIO_LINK_STATUS 1 +#define GPIO_LINK_STATE_CHANGE 0x80000000 + +#define GPIO_UINT32_DIFF(a, b) ((a >= b)? (a - b):(0xffffffff - b + a + 1)) + +struct ctrl_led { + struct timer_list LED_Timer; + unsigned int LED_Interval; + unsigned char LED_Toggle; + unsigned char LED_ToggleStart; + unsigned int LED_tx_cnt_log; + unsigned int LED_rx_cnt_log; + unsigned int LED_tx_cnt; + unsigned int LED_rx_cnt; + unsigned int link_status; + unsigned char blink_once_done; // 1: blink once done +} led_cb[5]; + +static int32 rtl819x_getAsicMibCounter(int port, uint32 counter, uint32 *value) +{ + rtl865x_tblAsicDrv_simpleCounterParam_t simpleCounter; + rtl8651_getSimpleAsicMIBCounter(port, &simpleCounter); + + switch(counter){ + case MIB_RX_PKT_CNT: + *value=simpleCounter.rxPkts; + break; + case MIB_TX_PKT_CNT: + *value=simpleCounter.txPkts; + break; + default: + return FAILED; + } + return SUCCESS; +} +static void gpio_set_led(int port, int flag){ + if (flag == GPIO_LED_OFF){ +/* RTL_W32(PABCD_CNR, RTL_R32(PABCD_CNR) & (~((0x1<<port)<<PORT_PABCD_BASE))); //set GPIO pin +* RTL_W32(PABCD_DIR, RTL_R32(PABCD_DIR) | ((0x1<<port)<<PORT_PABCD_BASE));//output pin +*/ + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) | ((0x1<<port)<<PORT_PABCD_BASE)));//set 1 + } + else{ +/* RTL_W32(PABCD_CNR, RTL_R32(PABCD_CNR) & (~((0x1<<port)<<PORT_PABCD_BASE))); //set GPIO pin +* RTL_W32(PABCD_DIR, RTL_R32(PABCD_DIR) | ((0x1<<port)<<PORT_PABCD_BASE));//output pin +*/ + RTL_W32(PABCD_DAT, (RTL_R32(PABCD_DAT) & (~((0x1<<port)<<PORT_PABCD_BASE))));//set 0 + } +} + +static void gpio_led_Interval_timeout(unsigned long port) +{ + struct ctrl_led *cb = &led_cb[port]; + unsigned long flags; + + local_irq_save(flags); + + if (cb->link_status & GPIO_LINK_STATE_CHANGE) { + cb->link_status &= ~GPIO_LINK_STATE_CHANGE; + if (cb->link_status & GPIO_LINK_STATUS) + cb->LED_ToggleStart = GPIO_LED_ON; + else + cb->LED_ToggleStart = GPIO_LED_OFF; + cb->LED_Toggle = cb->LED_ToggleStart; + gpio_set_led(port, cb->LED_Toggle); + } + else { + if (cb->link_status & GPIO_LINK_STATUS) + gpio_set_led(port, cb->LED_Toggle); + } + + if (cb->link_status & GPIO_LINK_STATUS) { + if (cb->LED_Toggle == cb->LED_ToggleStart){ + mod_timer(&cb->LED_Timer, jiffies + cb->LED_Interval); + cb->blink_once_done=1; + } + else{ + mod_timer(&cb->LED_Timer, jiffies + GPIO_LED_ON_TIME); + cb->blink_once_done=0; + } + + cb->LED_Toggle = (cb->LED_Toggle + 1) & 0x1; //cb->LED_Toggle = (cb->LED_Toggle + 1) % 2; + } + local_irq_restore(flags); +} + +void calculate_led_interval(int port) +{ + struct ctrl_led *cb = &led_cb[port]; + + unsigned int delta = 0; + + /* calculate counter delta */ + delta += GPIO_UINT32_DIFF(cb->LED_tx_cnt, cb->LED_tx_cnt_log); + delta += GPIO_UINT32_DIFF(cb->LED_rx_cnt, cb->LED_rx_cnt_log); + cb->LED_tx_cnt_log = cb->LED_tx_cnt; + cb->LED_rx_cnt_log = cb->LED_rx_cnt; + + /* update interval according to delta */ + if (delta == 0) { + if (cb->LED_Interval == GPIO_LED_NOBLINK_TIME) + mod_timer(&(cb->LED_Timer), jiffies + cb->LED_Interval); + else{ + cb->LED_Interval = GPIO_LED_NOBLINK_TIME; + if(cb->blink_once_done==1){ + mod_timer(&(cb->LED_Timer), jiffies + cb->LED_Interval); + cb->blink_once_done=0; + } + } + } + else + { + if(delta>25){ //That is: 200/delta-GPIO_LED_ON_TIME < GPIO_LED_ON_TIME + cb->LED_Interval = GPIO_LED_ON_TIME; + } + else{ + /* if delta is odd, should be +1 into even. */ + /* just make led blink more stable and smooth. */ + if((delta & 0x1) == 1) + delta++; + + cb->LED_Interval=200/delta-GPIO_LED_ON_TIME; /* rx 1pkt + tx 1pkt => blink one time! */ + +/* if (cb->LED_Interval < GPIO_LED_ON_TIME) +* cb->LED_Interval = GPIO_LED_ON_TIME; +*/ + } + } +} + +void update_mib_counter(int port) +{ + uint32 regVal; + struct ctrl_led *cb = &led_cb[port]; + + regVal=READ_MEM32(PSRP0+(port<<2)); + if((regVal&PortStatusLinkUp)!=0){ + //link up + if (!(cb->link_status & GPIO_LINK_STATUS)) { + cb->link_status = GPIO_LINK_STATE_CHANGE | 1; + } + rtl819x_getAsicMibCounter(port, MIB_TX_PKT_CNT, (uint32 *)&cb->LED_tx_cnt); + rtl819x_getAsicMibCounter(port, MIB_RX_PKT_CNT, (uint32 *)&cb->LED_rx_cnt); + } + else{ + //link down + if (cb->link_status & GPIO_LINK_STATUS) { + cb->link_status = GPIO_LINK_STATE_CHANGE; + } + } +} + +void init_led_ctrl(int port) +{ + struct ctrl_led *cb = &led_cb[port]; + + RTL_W32(PABCD_CNR, RTL_R32(PABCD_CNR) & (~((0x1<<port)<<PORT_PABCD_BASE))); //set GPIO pin + RTL_W32(PABCD_DIR, RTL_R32(PABCD_DIR) | ((0x1<<port)<<PORT_PABCD_BASE));//output pin + + memset(cb, '\0', sizeof(struct ctrl_led)); + + update_mib_counter(port); + calculate_led_interval(port); + cb->link_status |= GPIO_LINK_STATE_CHANGE; + + init_timer(&cb->LED_Timer); + cb->LED_Timer.expires = jiffies + cb->LED_Interval; + cb->LED_Timer.data = (unsigned long)port; + cb->LED_Timer.function = gpio_led_Interval_timeout; + mod_timer(&cb->LED_Timer, jiffies + cb->LED_Interval); + + gpio_led_Interval_timeout(port); +} + +void disable_led_ctrl(int port) +{ + struct ctrl_led *cb = &led_cb[port]; + gpio_set_led(port, GPIO_LED_OFF); + + if (timer_pending(&cb->LED_Timer)) + del_timer_sync(&cb->LED_Timer); +} +#endif // PATCH_GPIO_FOR_LED + +/* +device mapping mainten +*/ +struct rtl865x_vlanConfig * rtl_get_vlanconfig_by_netif_name(const char *name) +{ + int i; + for(i= 0; vlanconfig[i].vid != 0;i++) + { + if(memcmp(vlanconfig[i].ifname,name,strlen(name)) == 0) + return &vlanconfig[i]; + } + + #if defined(CONFIG_RTL_MULTIPLE_WAN) + //check multiple wan device + if(memcmp(rtl_multiWan_config.ifname,name,strlen(name)) == 0) + return &rtl_multiWan_config; + #endif + + return NULL; +} + +#if 1 +void rtl_ps_drv_netif_mapping_show(void) +{ + int i; + DEBUG_ERR("linux netif name VS driver netif name mapping:\n"); + for(i = 0; i < NETIF_NUMBER;i++) + { + DEBUG_ERR("valid(%d),linux netif name(%s) <---->drv netif name(%s)\n",ps_drv_netif_mapping[i].valid, + ps_drv_netif_mapping[i].ps_netif?ps_drv_netif_mapping[i].ps_netif->name:NULL,ps_drv_netif_mapping[i].drvName); + } +} +#endif + +static int rtl_ps_drv_netif_mapping_init(void) +{ + memset(ps_drv_netif_mapping,0,NETIF_NUMBER * sizeof(ps_drv_netif_mapping_t)); + return SUCCESS; +} + +int rtl_get_ps_drv_netif_mapping_by_psdev_name(const char *psname, char *netifName) +{ + int i; + if(netifName == NULL || strlen(psname) >= MAX_IFNAMESIZE ) + return FAILED; + + for(i = 0; i < NETIF_NUMBER;i++) + { + if(ps_drv_netif_mapping[i].valid == 1 && memcmp(ps_drv_netif_mapping[i].ps_netif->name,psname,strlen(psname)) == 0) + { + memcpy(netifName,ps_drv_netif_mapping[i].drvName,MAX_IFNAMESIZE); + return SUCCESS; + } + } + + //back compatible,user use br0 to get lan netif + if(memcmp(psname,RTL_PS_BR0_DEV_NAME,strlen(RTL_PS_BR0_DEV_NAME)) == 0) + { + for(i = 0; i < NETIF_NUMBER;i++) + { + if(ps_drv_netif_mapping[i].valid == 1 && + memcmp(ps_drv_netif_mapping[i].drvName,RTL_DRV_LAN_NETIF_NAME,strlen(RTL_DRV_LAN_NETIF_NAME)) == 0) + { + memcpy(netifName,ps_drv_netif_mapping[i].drvName,MAX_IFNAMESIZE); + return SUCCESS; + } + } + } + + return FAILED; +} + +ps_drv_netif_mapping_t* rtl_get_ps_drv_netif_mapping_by_psdev(struct net_device *dev) +{ + int i; + for(i = 0; i < NETIF_NUMBER;i++) + { + if(ps_drv_netif_mapping[i].valid == 1 && ps_drv_netif_mapping[i].ps_netif == dev) + return &ps_drv_netif_mapping[i]; + } + + //back compatible,user use br0 to get lan netif + if(memcmp(dev->name,RTL_PS_BR0_DEV_NAME,strlen(RTL_PS_BR0_DEV_NAME)) == 0) + { + for(i = 0; i < NETIF_NUMBER;i++) + { + if(ps_drv_netif_mapping[i].valid == 1 && + memcmp(ps_drv_netif_mapping[i].drvName,RTL_DRV_LAN_NETIF_NAME,strlen(RTL_DRV_LAN_NETIF_NAME)) == 0) + return &ps_drv_netif_mapping[i]; + } + } + + return NULL; +} + +int rtl_add_ps_drv_netif_mapping(struct net_device *dev, const char *name) +{ + int i; + + //duplicate check + if(rtl_get_ps_drv_netif_mapping_by_psdev(dev) !=NULL) + return FAILED; + + for(i = 0; i < NETIF_NUMBER;i++) + { + if(ps_drv_netif_mapping[i].valid == 0) + break; + } + + if(i == NETIF_NUMBER) + return FAILED; + + ps_drv_netif_mapping[i].ps_netif = dev; + memcpy(ps_drv_netif_mapping[i].drvName,name,strlen(name)); + ps_drv_netif_mapping[i].valid = 1; + return SUCCESS; +} + +int rtl_del_ps_drv_netif_mapping(struct net_device *dev) +{ + ps_drv_netif_mapping_t *entry; + entry = rtl_get_ps_drv_netif_mapping_by_psdev(dev); + if(entry) + entry->valid = 0; + + return SUCCESS; +} + +/* + * Disable TX/RX through IO_CMD register + */ +static void rtl8186_stop_hw(struct net_device *dev, struct dev_priv *cp) +{ + +#if defined(PATCH_GPIO_FOR_LED) + if (cp->id == RTL_LANVLANID) { + int port; + for (port=0; port<RTL8651_PHY_NUMBER; port++) + disable_led_ctrl(port); + } +#endif + +} + + +/* Set or clear the multicast filter for this adaptor. + * This routine is not state sensitive and need not be SMP locked. + */ +static void re865x_set_rx_mode (struct net_device *dev){ +/* Not yet implemented. + unsigned long flags; + spin_lock_irqsave (&_rtl86xx_dev.lock, flags); + spin_unlock_irqrestore (&_rtl86xx_dev.lock, flags); +*/ +} + +#if defined (CONFIG_RTL_NIC_HWSTATS) + void re865x_accumulate_port_stats(uint32 portnum, struct net_device_stats *net_stats) +{ + uint32 addrOffset_fromP0 =0; + + if( portnum < 0 || portnum > CPU) + return ; + addrOffset_fromP0 = portnum * MIB_ADDROFFSETBYPORT; + /* rx_pkt = rx_unicast +rx_multicast + rx_broadcast */ + net_stats->rx_packets += rtl8651_returnAsicCounter( OFFSET_IFINUCASTPKTS_P0 + addrOffset_fromP0 ) ; + net_stats->rx_packets += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + net_stats->rx_packets += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSBROADCASTPKTS_P0 + addrOffset_fromP0 ) ; + /* tx_pkt = tx_unicast +tx_multicast + tx_broadcast*/ + net_stats->tx_packets += rtl8651_returnAsicCounter( OFFSET_IFOUTUCASTPKTS_P0 + addrOffset_fromP0 ) ; + net_stats->tx_packets += rtl8651_returnAsicCounter( OFFSET_IFOUTMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + net_stats->tx_packets += rtl8651_returnAsicCounter( OFFSET_IFOUTBROADCASTPKTS_P0 + addrOffset_fromP0 ) ; + + net_stats->rx_bytes += rtl8651_returnAsicCounter( OFFSET_IFINOCTETS_P0 + addrOffset_fromP0 ) ; + net_stats->tx_bytes += rtl8651_returnAsicCounter( OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0 ) ; + /*rx_errors = CRC error + Jabber error + Fragment error*/ + net_stats->rx_errors += rtl8651_returnAsicCounter( OFFSET_DOT3STATSFCSERRORS_P0 + addrOffset_fromP0 ) ; + net_stats->rx_errors += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSJABBERS_P0 + addrOffset_fromP0 ) ; + net_stats->rx_errors += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSOVERSIZEPKTS_P0 + addrOffset_fromP0 ) ; + //OFFSET_DOT1DTPPORTINDISCARDS_P0? + //net_stats->rx_dropped += rtl8651_returnAsicCounter( OFFSET_DOT1DTPPORTINDISCARDS_P0 + addrOffset_fromP0 ) ; + net_stats->tx_dropped += rtl8651_returnAsicCounter( OFFSET_IFOUTDISCARDS + addrOffset_fromP0 ) ; + net_stats->multicast += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + + net_stats->collisions += rtl8651_returnAsicCounter( OFFSET_ETHERSTATSCOLLISIONS_P0 + addrOffset_fromP0 ) ; + net_stats->rx_crc_errors += rtl8651_returnAsicCounter( OFFSET_DOT3STATSFCSERRORS_P0 + addrOffset_fromP0 ) ; + return; +} + +void re865x_get_hardwareStats(struct dev_priv *priv) +{ + uint32 portmask; + uint32 port; + + portmask = priv->portmask; + //rx_dropped = priv->net_stats.rx_dropped; + //memset( &priv->net_stats, 0, sizeof(struct net_device_stats) ); + /* reset counters to 0 */ + priv->net_stats.rx_packets = 0; + priv->net_stats.tx_packets = 0; + priv->net_stats.rx_bytes = 0; + priv->net_stats.tx_bytes = 0; + priv->net_stats.rx_errors = 0; + priv->net_stats.tx_dropped = 0; + priv->net_stats.multicast = 0; + priv->net_stats.collisions = 0; + priv->net_stats.rx_crc_errors = 0; + for( port = 0; port < CPU; port++) + { + if((1<<port) & portmask) + { + re865x_accumulate_port_stats(port, &priv->net_stats); + } + + } + return; +} +#endif + +static struct net_device_stats *re865x_get_stats(struct net_device *dev){ + struct dev_priv *dp; + dp = dev->priv; + #if defined (CONFIG_RTL_NIC_HWSTATS) + re865x_get_hardwareStats(dp); + #endif + return &dp->net_stats; +} + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) || defined(CONFIG_RTK_VLAN_SUPPORT) +static int32 re865x_packVlanConfig(struct rtl865x_vlanConfig vlanConfig1[], struct rtl865x_vlanConfig vlanConfig2[]) +{ + int i, j; + uint32 vlanCnt=0; + uint32 found=FALSE; + /*get input vlan config entry number*/ + for(i=0; vlanConfig1[i].ifname[0] != '\0'; i++) + { + if(vlanConfig1[i].vid != 0) + vlanCnt++; + } + if(vlanCnt+1 > NETIF_NUMBER) + DEBUG_ERR("ERROR,vlanCnt(%d) > max size %d\n",vlanCnt,NETIF_NUMBER-1); + + /*initialize output vlan config*/ + memset(vlanConfig2, 0 , (vlanCnt+1)*sizeof(struct rtl865x_vlanConfig)); + + for(i=0; vlanConfig1[i].ifname[0] != '\0'; i++) + { + found=FALSE; + + if(vlanConfig1[i].vid == 0) + continue; + + for(j=0; j<vlanCnt; j++) + { + if(vlanConfig1[i].if_type != vlanConfig2[j].if_type) + { + continue; + } + else + { + if(vlanConfig1[i].if_type==IF_ETHER) + { + /*if multiple vlan config has the same vlan id*/ + /*the first one will decide the real network interface name/asic mtu/hardware address*/ + + /*ethernet interface*/ + if(vlanConfig1[i].vid!=vlanConfig2[j].vid) + { + continue; + } + else + { + found=TRUE; + break; + } + + } + else + { + /*PPP interface*/ + if(strcmp(vlanConfig1[i].ifname, vlanConfig2[j].ifname)) + { + continue; + } + else + { + found=TRUE; + break; + } + } + } + } + + if(found==TRUE) + { + /*merge port mask*/ + vlanConfig2[j].memPort |=vlanConfig1[i].memPort; + vlanConfig2[j].untagSet |=vlanConfig1[i].untagSet; + } + else + { + /*find an empty entry to store this vlan config*/ + for(j=0; j<vlanCnt; j++) + { + if(vlanConfig2[j].vid==0) + { + memcpy(&vlanConfig2[j], &vlanConfig1[i], sizeof(struct rtl865x_vlanConfig)); + if(( vlanConfig1[i].if_type==IF_ETHER) && (vlanConfig1[i].isWan==FALSE) ) + { + /*add cpu port to lan member list*/ + vlanConfig2[j].memPort|=0x100; + vlanConfig2[j].untagSet|=0x100; + } + break; + } + } + } + + } + + return SUCCESS; +} +#endif + +static void rtl865x_disableDevPortForward(struct net_device *dev, struct dev_priv *cp) +{ + int port; + for(port=0;port<RTL8651_AGGREGATOR_NUMBER;port++) + { + if((1<<port) & cp->portmask) + { +#if 1 + REG32(PCRP0+(port<<2))= ((REG32(PCRP0+(port<<2)))&(~ForceLink)); + REG32(PCRP0+(port<<2))= ((REG32(PCRP0+(port<<2)))&(~EnablePHYIf)); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port<<2),EnablePHYIf); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port<<2),ForceLink); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port<<2),EnForceMode); +#else + rtl865xC_setAsicEthernetForceModeRegs(port, TRUE, FALSE, 1, TRUE); +#endif + } + } +#ifdef CONFIG_RTL_8196C_ESD + _96c_esd_counter = 0; // stop counting +#endif +} +#if defined(CONFIG_819X_PHY_RW)//#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) +static void rtl865x_setPortForward(int port_num, int forward) +{ + if(port_num < 0 || port_num >= RTL8651_AGGREGATOR_NUMBER) + return; + + if(forward == FALSE) { + REG32(PCRP0+(port_num<<2))= ((REG32(PCRP0+(port_num<<2)))&(~EnablePHYIf)); +#ifdef CONFIG_RTL_8196C_ESD + _96c_esd_counter = 0; // stop counting +#endif + } + else + REG32(PCRP0+(port_num<<2))= ((REG32(PCRP0+(port_num<<2)))|(EnablePHYIf)); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port_num<<2),EnForceMode); + +} +#endif //#if defined(CONFIG_819X_PHY_RW) +static void rtl865x_enableDevPortForward(struct net_device *dev, struct dev_priv *cp) +{ + int port; + for(port=0;port<RTL8651_AGGREGATOR_NUMBER;port++) + { + if((1<<port) & cp->portmask) + { +#if 1 + REG32(PCRP0+(port<<2))= ((REG32(PCRP0+(port<<2)))|(ForceLink)); + REG32(PCRP0+(port<<2))= ((REG32(PCRP0+(port<<2)))|(EnablePHYIf)); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port<<2),EnablePHYIf); + TOGGLE_BIT_IN_REG_TWICE(PCRP0+(port<<2),ForceLink); +#else + rtl865xC_setAsicEthernetForceModeRegs(port, FALSE, TRUE, 1, TRUE); + rtl8651_restartAsicEthernetPHYNway(port); +#endif + } + } +#ifdef CONFIG_RTL_8196C_ESD + _96c_esd_counter = 1; // start counting and check ESD + _96c_esd_reboot_counter = 0; // reset counter +#endif +} + +static void rtl865x_disableInterrupt(void) +{ + REG32(CPUICR) = 0; + REG32(CPUIIMR) = 0; + REG32(CPUIISR) = REG32(CPUIISR); +} + +static void rtk_queue_init(struct ring_que *que) +{ + memset(que, 0, sizeof(struct ring_que)); + que->ring = (struct sk_buff **)kmalloc( + (sizeof(struct skb_buff*)*(rtl865x_maxPreAllocRxSkb+1)) + ,GFP_ATOMIC); + memset(que->ring, 0, (sizeof(struct sk_buff *))*(rtl865x_maxPreAllocRxSkb+1)); + que->qmax = rtl865x_maxPreAllocRxSkb; +} + +__MIPS16 +__IRAM_FWD +static int rtk_queue_tail(struct ring_que *que, struct sk_buff *skb) +{ + int next; + + + if (que->head == que->qmax) + next = 0; + else + next = que->head + 1; + + if (que->qlen >= que->qmax || next == que->tail) { + return 0; + } + + que->ring[que->head] = skb; + que->head = next; + que->qlen++; + + return 1; +} + +__MIPS16 +__IRAM_FWD +static struct sk_buff *rtk_dequeue(struct ring_que *que) +{ + struct sk_buff *skb; + + if (que->qlen <= 0 || que->tail == que->head) + { + return NULL; + } + + skb = que->ring[que->tail]; + + if (que->tail == que->qmax) + que->tail = 0; + else + que->tail++; + + que->qlen--; + + return (struct sk_buff *)skb; +} + +#if defined(CONFIG_RTL_ETH_PRIV_SKB_DEBUG) +int get_buf_in_rx_skb_queue(void) +{ + return rx_skb_queue.qlen; +} + +int get_buf_in_poll(void) +{ + return eth_skb_free_num; +} +#endif + +//__MIPS16 +__IRAM_FWD +static void refill_rx_skb(void) +{ + struct sk_buff *skb; + unsigned long flags; + int idx; + + idx = RTL865X_SWNIC_RXRING_MAX_PKTDESC -1; + +#ifdef DELAY_REFILL_ETH_RX_BUF + while (rx_skb_queue.qlen < rtl865x_maxPreAllocRxSkb || ((idx>=0)&&(SUCCESS==check_rx_pkthdr_ring(idx, &idx)))) +#else + while (rx_skb_queue.qlen < rtl865x_maxPreAllocRxSkb) +#endif + { + #if defined(CONFIG_RTL_ETH_PRIV_SKB) + skb = dev_alloc_skb_priv_eth(CROSS_LAN_MBUF_LEN); + #else + skb = dev_alloc_skb(CROSS_LAN_MBUF_LEN); + #endif + + if (skb == NULL) { + DEBUG_ERR("EthDrv: dev_alloc_skb() failed!\n"); + return; + } + skb_reserve(skb, RX_OFFSET); + + #ifdef DELAY_REFILL_ETH_RX_BUF + // return to rx descriptor ring first if the rings still have the OWN bit which be RISC_OWNED. + if (idx>=0) { + if (SUCCESS==check_and_return_to_rx_pkthdr_ring(skb, idx)) { + continue; + } + } + #endif + + #if defined(RTK_QUE) + local_irq_save(flags); + rtk_queue_tail(&rx_skb_queue, skb); + local_irq_restore(flags); + #else + __skb_queue_tail(&rx_skb_queue, skb); + #endif + } +} + +//--------------------------------------------------------------------------- +static void free_rx_skb(void) +{ + struct sk_buff *skb; + + swNic_freeRxBuf(); + + while (rx_skb_queue.qlen > 0) { +#if defined(RTK_QUE) + skb = rtk_dequeue(&rx_skb_queue); +#else + skb = __skb_dequeue(&rx_skb_queue); +#endif + dev_kfree_skb_any(skb); + } +} + +//--------------------------------------------------------------------------- +__IRAM_FWD +unsigned char *alloc_rx_buf(void **skb, int buflen) +{ + struct sk_buff *new_skb; + unsigned long flags; + + if (rx_skb_queue.qlen == 0) { + #if defined(CONFIG_RTL_ETH_PRIV_SKB) + new_skb = dev_alloc_skb_priv_eth(CROSS_LAN_MBUF_LEN); + #else + new_skb = dev_alloc_skb(CROSS_LAN_MBUF_LEN); + #endif + if (new_skb == NULL) { + DEBUG_ERR("EthDrv: alloc skb failed!\n"); + } + else + skb_reserve(new_skb, RX_OFFSET); + } + else { + #if defined(RTK_QUE) + local_irq_save(flags); + new_skb = rtk_dequeue(&rx_skb_queue); + local_irq_restore(flags); + #else + new_skb = __skb_dequeue(&rx_skb_queue); + #endif + } + + if (new_skb == NULL) + return NULL; + + *skb = new_skb; + + return new_skb->data; +} + +//--------------------------------------------------------------------------- +void free_rx_buf(void *skb) +{ + dev_kfree_skb_any((struct sk_buff *)skb); +} + +//--------------------------------------------------------------------------- +#if defined(CONFIG_RTL_FAST_BRIDGE) +void tx_done_callback(void *skb) +{ +#if defined(CONFIG_RTL_FAST_BRIDGE) + #define RTL_PRIV_DATA_SIZE 128 + unsigned long flags; + //hyking: + //queue private skb and buffer + if (((struct sk_buff*)skb)->fast_br_forwarding_flags == 1 && is_rtl865x_eth_priv_buf(((struct sk_buff *)skb)->head)) + { + if(!(skb_cloned(skb))) + { + //disable irq + local_irq_save(flags); + if(rtk_queue_tail(&rx_skb_queue,(struct sk_buff *)skb)) + { + unsigned char *data; + struct skb_shared_info *shinfo; + int size; + data = (((struct sk_buff *)skb)->head); + + memset(skb, 0, offsetof(struct sk_buff, truesize)); + atomic_set(&((struct sk_buff *)skb)->users, 1); + ((struct sk_buff *)skb)->head = data; + ((struct sk_buff *)skb)->data = data; + ((struct sk_buff *)skb)->tail = data; + + size = (CROSS_LAN_MBUF_LEN+128+NET_SKB_PAD); + + ((struct sk_buff *)skb)->end = data + size; + ((struct sk_buff *)skb)->truesize = size + sizeof(struct sk_buff); + + /* make sure we initialize shinfo sequentially */ + shinfo = skb_shinfo(skb); + atomic_set(&shinfo->dataref, 1); + shinfo->nr_frags = 0; + shinfo->gso_size = 0; + shinfo->gso_segs = 0; + shinfo->gso_type = 0; + shinfo->ip6_frag_id = 0; + shinfo->frag_list = NULL; + +#ifdef CONFIG_RTK_VOIP_VLAN_ID + ((struct sk_buff *)skb)->rx_vlan = 0; + ((struct sk_buff *)skb)->rx_wlan = 0; + ((struct sk_buff *)skb)->priority = 0; +#endif + +#ifdef CONFIG_RTL_HARDWARE_MULTICAST + ((struct sk_buff *)skb)->srcPort=0xFFFF; + ((struct sk_buff *)skb)->srcVlanId=0; +#endif + +#if defined(CONFIG_RTL_QOS_8021P_SUPPORT) + ((struct sk_buff *)skb)->srcVlanPriority=0; +#endif + +#if defined(CONFIG_NETFILTER_XT_MATCH_PHYPORT)|| defined(CONFIG_RTL_FAST_FILTER) || defined(CONFIG_RTL_QOS_PATCH) + ((struct sk_buff *)skb)->srcPhyPort=0xFF; + ((struct sk_buff *)skb)->dstPhyPort=0xFF; +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + ((struct sk_buff *)skb)->tag.v = 0; +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + ((struct sk_buff *)skb)->srcLocalPublicIp=0; + ((struct sk_buff *)skb)->fromLocalPublic=0; + ((struct sk_buff *)skb)->toLocalPublic=0; +#endif + +#ifdef CONFIG_RTK_VOIP_VLAN_ID + skb_reserve(((struct sk_buff *)skb), RTL_PRIV_DATA_SIZE+4); // for VLAN TAG insertion +#else + skb_reserve(((struct sk_buff *)skb), RTL_PRIV_DATA_SIZE); +#endif + //reserve for 4 byte alignment + skb_reserve(((struct sk_buff *)skb), RX_OFFSET); + //enable irq + local_irq_restore(flags); + return; + } + + //enable irq + local_irq_restore(flags); + } + } +#endif + dev_kfree_skb_any((struct sk_buff *)skb); +} +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) +#if defined (CONFIG_BRIDGE) +extern void br_signal_igmpProxy(void); +#endif + +static inline struct iphdr * re865x_getIpv4Header(uint8 *macFrame) +{ + uint8 *ptr; + struct iphdr *iph=NULL; + + ptr=macFrame+12; + if(*(int16 *)(ptr)==(int16)htons(ETH_P_8021Q)) + { + ptr=ptr+4; + } + + /*it's not ipv4 packet*/ + if(*(int16 *)(ptr)!=(int16)htons(ETH_P_IP)) + { + return NULL; + } + + iph=(struct iphdr *)(ptr+2); + + return iph; +} + +#if defined (CONFIG_RTL_MLD_SNOOPING) +static inline struct ipv6hdr* re865x_getIpv6Header(uint8 *macFrame) +{ + uint8 *ptr; + struct ipv6hdr *ipv6h=NULL; + + ptr=macFrame+12; + if(*(int16 *)(ptr)==(int16)htons(ETH_P_8021Q)) + { + ptr=ptr+4; + } + + /*it's not ipv6 packet*/ + if(*(int16 *)(ptr)!=(int16)htons(ETH_P_IPV6)) + { + return NULL; + } + + ipv6h=(struct ipv6hdr *)(ptr+2); + + return ipv6h; +} + +#define IPV6_ROUTER_ALTER_OPTION 0x05020000 +#define HOP_BY_HOP_OPTIONS_HEADER 0 +#define ROUTING_HEADER 43 +#define FRAGMENT_HEADER 44 +#define DESTINATION_OPTION_HEADER 60 + +#define PIM_PROTOCOL 103 +#define MOSPF_PROTOCOL 89 +#define TCP_PROTOCOL 6 +#define UDP_PROTOCOL 17 +#define NO_NEXT_HEADER 59 +#define ICMP_PROTOCOL 58 + +#define MLD_QUERY 130 +#define MLDV1_REPORT 131 +#define MLDV1_DONE 132 +#define MLDV2_REPORT 143 + +#define IS_IPV6_PIM_ADDR(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x0000000D)) +#define IS_IPV6_MOSPF_ADDR1(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000005)) +#define IS_IPV6_MOSPF_ADDR2(ipv6addr) ((ipv6addr[0] == 0xFF020000)&&(ipv6addr[1] == 0x00000000)&&(ipv6addr[2] == 0x00000000)&&(ipv6addr[3] ==0x00000006)) + + +int re865x_getIpv6TransportProtocol(struct ipv6hdr* ipv6h) +{ + + unsigned char *ptr=NULL; + unsigned char *startPtr=NULL; + unsigned char *lastPtr=NULL; + unsigned char nextHeader=0; + unsigned short extensionHdrLen=0; + + unsigned char optionDataLen=0; + unsigned char optionType=0; + unsigned int ipv6RAO=0; + + if(ipv6h==NULL) + { + return -1; + } + + if(ipv6h->version!=6) + { + return -1; + } + + startPtr= (unsigned char *)ipv6h; + lastPtr=startPtr+sizeof(struct ipv6hdr)+(ipv6h->payload_len); + nextHeader= ipv6h ->nexthdr; + ptr=startPtr+sizeof(struct ipv6hdr); + + while(ptr<lastPtr) + { + switch(nextHeader) + { + case HOP_BY_HOP_OPTIONS_HEADER: + /*parse hop-by-hop option*/ + nextHeader=ptr[0]; + extensionHdrLen=((uint16)(ptr[1])+1)*8; + ptr=ptr+2; + + while(ptr<(startPtr+extensionHdrLen+sizeof(struct ipv6hdr))) + { + optionType=ptr[0]; + /*pad1 option*/ + if(optionType==0) + { + ptr=ptr+1; + continue; + } + + /*padN option*/ + if(optionType==1) + { + optionDataLen=ptr[1]; + ptr=ptr+optionDataLen+2; + continue; + } + + /*router altert option*/ + if(ntohl(*(uint32 *)(ptr))==IPV6_ROUTER_ALTER_OPTION) + { + ipv6RAO=IPV6_ROUTER_ALTER_OPTION; + ptr=ptr+4; + continue; + } + + /*other TLV option*/ + if((optionType!=0) && (optionType!=1)) + { + optionDataLen=ptr[1]; + ptr=ptr+optionDataLen+2; + continue; + } + + + } + + break; + + case ROUTING_HEADER: + nextHeader=ptr[0]; + extensionHdrLen=((uint16)(ptr[1])+1)*8; + ptr=ptr+extensionHdrLen; + break; + + case FRAGMENT_HEADER: + nextHeader=ptr[0]; + ptr=ptr+8; + break; + + case DESTINATION_OPTION_HEADER: + nextHeader=ptr[0]; + extensionHdrLen=((uint16)(ptr[1])+1)*8; + ptr=ptr+extensionHdrLen; + break; + + case ICMP_PROTOCOL: + nextHeader=NO_NEXT_HEADER; + if((ptr[0]==MLD_QUERY) ||(ptr[0]==MLDV1_REPORT) ||(ptr[0]==MLDV1_DONE) ||(ptr[0]==MLDV2_REPORT)) + { + return ICMP_PROTOCOL; + + } + break; + + case PIM_PROTOCOL: + nextHeader=NO_NEXT_HEADER; + if(IS_IPV6_PIM_ADDR(ipv6h->daddr.s6_addr32)) + { + return PIM_PROTOCOL; + } + + break; + + case MOSPF_PROTOCOL: + nextHeader=NO_NEXT_HEADER; + + if(IS_IPV6_MOSPF_ADDR1(ipv6h->daddr.s6_addr32) || IS_IPV6_MOSPF_ADDR2(ipv6h->daddr.s6_addr32)) + { + return MOSPF_PROTOCOL; + } + break; + + case TCP_PROTOCOL: + nextHeader=NO_NEXT_HEADER; + return TCP_PROTOCOL; + + break; + + case UDP_PROTOCOL: + nextHeader=NO_NEXT_HEADER; + return UDP_PROTOCOL; + + break; + + default: + /*not ipv6 multicast protocol*/ + return -1; + break; + } + + } + return -1; +} +#endif +static inline void re865x_relayTrappedMCast(struct sk_buff *skb, unsigned int vid, unsigned int mcastFwdPortMask, unsigned int keepOrigSkb) +{ + rtl_nicTx_info nicTx; + struct sk_buff *skb2=NULL; + + if(mcastFwdPortMask==0) + { + return; + } + + if(keepOrigSkb==TRUE) + { + skb2= skb_clone(skb, GFP_ATOMIC); + } + else + { + skb2=skb; + } + + if(skb2!=NULL) + { + nicTx.txIdx=0; +#if defined(CONFIG_RTL_QOS_PATCH) + if(((struct sk_buff *)skb)->srcPhyPort == QOS_PATCH_RX_FROM_LOCAL){ + nicTx.priority = QOS_PATCH_HIGH_QUEUE_PRIO; + nicTx.txIdx=RTL865X_SWNIC_TXRING_MAX_PKTDESC-1; //use the highest tx ring index, note: not RTL865X_SWNIC_TXRING_HW_PKTDESC-1 + } +#endif + nicTx.vid = vid; + nicTx.portlist = mcastFwdPortMask; + nicTx.srcExtPort = 0; + nicTx.flags = (PKTHDR_USED|PKT_OUTGOING); + _dma_cache_wback_inv((unsigned long)skb2->data, skb2->len); + if (swNic_send((void *)skb2, skb2->data, skb2->len, &nicTx) < 0) + { + dev_kfree_skb_any(skb2); + } + + } + return; +} + +void rtl865x_igmpSyncLinkStatus(void) +{ + rtl_igmpPortInfo_t portInfo; + + portInfo.linkPortMask=newLinkPortMask; + rtl865x_igmpLinkStatusChangeCallback(nicIgmpModuleIndex, &portInfo); + + #if defined (CONFIG_BRIDGE) + if((newLinkPortMask & (~curLinkPortMask))!=0) + { + /*there is some port linking up*/ + /*notice igmp proxy daemon to send general query to newly link up client*/ + #ifdef CONFIG_RTL8196BU_8186SDK_MP_SPI + #else + br_signal_igmpProxy(); + #endif + } + #endif + + return; + +} + +#endif /* defined (CONFIG_RTL_IGMP_SNOOPING) */ + + +#if defined (CONFIG_RTL_IGMP_SNOOPING) +#if defined (CONFIG_NETFILTER) +unsigned int (*IgmpRxFilter_Hook)(struct sk_buff *skb, + unsigned int hook, + const struct net_device *in, + const struct net_device *out, + struct xt_table *table); +EXPORT_SYMBOL(IgmpRxFilter_Hook); + +static bool rtl_MulticastRxFilterOff(struct sk_buff *skb, int ipversion) +{ + bool ret = true; + if(IgmpRxFilter_Hook == NULL) + { + DEBUG_ERR("IgmpRxFilter_hook is NULL\n"); + return false; + } + if(ipversion ==4) + skb->network_header = (sk_buff_data_t)re865x_getIpv4Header(skb->data); + else if(ipversion ==6) + skb->network_header = (sk_buff_data_t)re865x_getIpv6Header(skb->data); + else + return ret;//error shouldn't happen +#ifdef NET_SKBUFF_DATA_USES_OFFSET + skb->mac_header = (sk_buff_data_t)(skb->data - skb->head); +#else + skb->mac_header = (sk_buff_data_t)skb->data; +#endif + + //data should point to l3 header while doing iptables check + skb->data = skb->data+ETH_HLEN; + + if(ipversion ==4) + ret = ((IgmpRxFilter_Hook(skb, NF_INET_PRE_ROUTING, skb->dev, NULL,dev_net(skb->dev)->ipv4.iptable_filter)) !=NF_ACCEPT); + else if(ipversion ==6) + ret = false;//ipv6 hava no iptables rule now + + if(ret) + { + DEBUG_ERR(" filter a v%d pkt\n", ipversion); + } + // return point to l2 header + skb->data = skb->data-ETH_HLEN; + return ret; +} +#endif + +__MIPS16 +int rtl_MulticastRxCheck(struct sk_buff *skb,rtl_nicRx_info *info) +{ + + unsigned int vlanRelayPortMask=0; + struct iphdr *iph=NULL; + struct rtl_multicastDataInfo multicastDataInfo; + struct rtl_multicastFwdInfo nicMCastFwdInfo; + struct rtl_multicastFwdInfo br0MCastFwdInfo; + +#if defined (CONFIG_RTL_MLD_SNOOPING) + struct ipv6hdr *ipv6h=NULL; +#endif + unsigned int l4Protocol=0; + int ret=FAILED; +#if defined (CONFIG_RTL_MLD_SNOOPING) + struct dev_priv *cp_this=info->priv; +#endif + int vid=info->vid; + int pid=info->pid; + + if((skb->data[0] &0x01) ==0) + { + return -1; + } + + /*set flooding port mask first*/ + vlanRelayPortMask=rtl865x_getVlanPortMask(vid) & (~(1<<pid)) & ((1<<RTL8651_MAC_NUMBER)-1); + + if((skb->data[0]==0x01) && (skb->data[1]==0x00)&& (skb->data[2]==0x5e)) + { + #if defined(CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable) + { + /*let bridge handle it*/ + return 0; + } + #endif + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + skb->srcVlanId=vid; + skb->srcPort=pid; + #endif + + /*hardware ip multicast table will trap 0x01-00-5e-XX-XX-XX type packets*/ + /*how about other packets not trapped by hardware multicast table?---->we assume it has been flooded by l2 table*/ + iph=re865x_getIpv4Header(skb->data); + if(iph!=NULL) + { + /*udp or tcp packet*/ + l4Protocol=iph->protocol; + if((l4Protocol==IPPROTO_UDP) || (l4Protocol==IPPROTO_TCP)) + { + + + /*relay packets which are trapped by hardware multicast table*/ + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + if(igmpsnoopenabled && (nicIgmpModuleIndex!=0xFFFFFFFF)) + { + multicastDataInfo.ipVersion=4; + multicastDataInfo.sourceIp[0]= (uint32)(iph->saddr); + multicastDataInfo.groupAddr[0]= (uint32)(iph->daddr); + ret=rtl_getMulticastDataFwdInfo(nicIgmpModuleIndex, &multicastDataInfo, &nicMCastFwdInfo); + vlanRelayPortMask=rtl865x_getVlanPortMask(vid)& (~(1<<pid)) & nicMCastFwdInfo.fwdPortMask & ((1<<RTL8651_MAC_NUMBER)-1); + + if(ret==SUCCESS) + { + + } + else + { + ret=rtl_getMulticastDataFwdInfo(brIgmpModuleIndex, &multicastDataInfo, &br0MCastFwdInfo); + if(ret==SUCCESS) + { + /*there is wireless client,can not flooding in vlan */ + vlanRelayPortMask=0; + } + + } + } + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + #endif/*end of CONFIG_RTL_HARDWARE_MULTICAST*/ + } + else if(l4Protocol==IPPROTO_IGMP) + { + if(igmpsnoopenabled && (nicIgmpModuleIndex!=0xFFFFFFFF)) + { + /*igmp packet*/ + #if defined (CONFIG_NETFILTER) + if(rtl_MulticastRxFilterOff(skb, 4) == true) + return 0;//filter by iptables + #endif + rtl_igmpMldProcess(nicIgmpModuleIndex, skb->data, pid, &vlanRelayPortMask); + vlanRelayPortMask=rtl865x_getVlanPortMask(vid) & vlanRelayPortMask & ((1<<RTL8651_MAC_NUMBER)-1); + } + + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + + } + else + { + + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + #endif + + } + } + + + } +#if defined (CONFIG_RTL_MLD_SNOOPING) + else if ((skb->data[0]==0x33) && (skb->data[1]==0x33) && (skb->data[2]!=0xff)) + { + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + skb->srcVlanId=0; + skb->srcPort=0xFFFF; + #endif + + if(mldSnoopEnabled!=TRUE) + { + return 0; + } + + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU) + if ((rtl_isPassthruFrame(skb->data)==SUCCESS)&&(rtl_isWanDev(cp_this)==TRUE)) + { + /*don't relay it,let linux protocol stack bridge handle it*/ + return 0; + } + #endif + + #if defined(CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable) + { + /*let bridge handle it*/ + return 0; + } + #endif + + /*when enable mld snooping, gateway will add acl to trap packet with dmac equal to 0x33-33-xx-xx-xx-xx */ + ipv6h=re865x_getIpv6Header(skb->data); + if(ipv6h!=NULL) + { + l4Protocol=re865x_getIpv6TransportProtocol(ipv6h); + /*udp or tcp packet*/ + if((l4Protocol==IPPROTO_UDP) || (l4Protocol==IPPROTO_TCP)) + { + + if(igmpsnoopenabled && (nicIgmpModuleIndex!=0xFFFFFFFF)) + { + multicastDataInfo.ipVersion=6; + memcpy(&multicastDataInfo.sourceIp, &ipv6h->saddr, 16); + memcpy(&multicastDataInfo.groupAddr, &ipv6h->daddr, 16); + + ret=rtl_getMulticastDataFwdInfo(nicIgmpModuleIndex, &multicastDataInfo, &nicMCastFwdInfo); + + vlanRelayPortMask=rtl865x_getVlanPortMask(vid)& (~(1<<pid)) & nicMCastFwdInfo.fwdPortMask & ((1<<RTL8651_MAC_NUMBER)-1); + if(ret==SUCCESS) + { + + } + else + { + ret=rtl_getMulticastDataFwdInfo(brIgmpModuleIndex, &multicastDataInfo, &br0MCastFwdInfo); + if(ret==SUCCESS) + { + /*there is wireless client,can not flooding in vlan */ + vlanRelayPortMask=0; + } + } + } + + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + + } + else if(l4Protocol==IPPROTO_ICMPV6) + { + /*icmp packet*/ + if(igmpsnoopenabled && (nicIgmpModuleIndex!=0xFFFFFFFF)) + { + rtl_igmpMldProcess(nicIgmpModuleIndex, skb->data, pid, &vlanRelayPortMask); + vlanRelayPortMask=rtl865x_getVlanPortMask(vid) & vlanRelayPortMask & ((1<<RTL8651_MAC_NUMBER)-1); + } + + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + + } + else + { + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + } + } + else + { + re865x_relayTrappedMCast( skb, vid, vlanRelayPortMask, TRUE); + } + + } +#endif + else + { + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + skb->srcVlanId=0; + skb->srcPort=0xFFFF; + #endif + } + + #if 0 + if(rx_skb_queue.qlen < (rtl865x_maxPreAllocRxSkb/3)) + { + refill_rx_skb(); + } + #endif + + return 0; +} +#endif /*end of CONFIG_RTL865X_IGMP_SNOOPING*/ + +static inline int32 rtl_isWanDev(struct dev_priv *cp) +{ +#if defined(CONFIG_RTK_VLAN_SUPPORT) + return (!cp->vlan_setting.is_lan); +#else + #if defined(CONFIG_RTL_MULTIPLE_WAN) + return (cp->id==RTL_WANVLANID || cp->id == RTL_WAN_1_VLANID); + #else + return (cp->id==RTL_WANVLANID ); + #endif +#endif +} + +#if defined(CONFIG_RTL_CUSTOM_PASSTHRU) +static inline int32 rtl_isPassthruFrame(uint8 *data) +{ + int ret; + + ret = FAILED; + if (oldStatus) + { + if (oldStatus&IP6_PASSTHRU_MASK) + { + if ((*((uint16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_IPV6)) || + ((*((uint16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_8021Q))&&(*((uint16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_IPV6)))) + { + ret = SUCCESS; + } + } + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU_PPPOE) + if (oldStatus&PPPOE_PASSTHRU_MASK) + { + if (((*((uint16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_PPP_SES))||(*((uint16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_PPP_DISC))) || + ((*((uint16*)(data+(ETH_ALEN<<1)))==__constant_htons(ETH_P_8021Q))&&((*((uint16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_PPP_SES))||(*((uint16*)(data+(ETH_ALEN<<1)+VLAN_HLEN))==__constant_htons(ETH_P_PPP_DISC))))) + { + ret = SUCCESS; + } + } + #endif + } + + return ret; +} +#endif + +#if defined(RTL_CPU_QOS_ENABLED) +#define MAX_HIGH_PRIO_TRY 20 //Try to rx high prio pkt for MAX_HIGH_PRIO_TRY times. +__DRAM_FWD static int highPrioRxTryCnt; +__DRAM_FWD static int highestPriority; +__DRAM_FWD static int cpuQosHoldLow; +__DRAM_FWD static int totalLowQueueCnt; + +static rtl_queue_entry pktQueueByPri[RTL865X_SWNIC_RXRING_MAX_PKTDESC] = {{0}}; + +__MIPS16 +__IRAM_FWD +int rtl_enqueueSkb(rtl_nicRx_info *info) +{ + rtl_queue_entry *entry; + + entry = &pktQueueByPri[info->priority]; + + if (info->priority<cpuQosHoldLow) + totalLowQueueCnt++; + + memcpy(&entry->entry[entry->end], info, sizeof(rtl_nicRx_info)); + entry->cnt++; + entry->end = (entry->end==(RTL_NIC_QUEUE_LEN-1))?0:(entry->end+1); + + if (entry->cnt==RTL_NIC_QUEUE_LEN) + return SUCCESS; + else + return FAILED; +} + +__MIPS16 +__IRAM_FWD +int rtl_dequeueSkb(rtl_nicRx_info *info) +{ + rtl_queue_entry *entry; + + entry = &pktQueueByPri[info->priority]; + + if(entry->cnt==0) + { + return FAILED; + } + else + { + memcpy(info, &entry->entry[entry->start], sizeof(rtl_nicRx_info)); + entry->cnt--; + entry->start = (entry->start==(RTL_NIC_QUEUE_LEN-1))?0:(entry->start+1); + return SUCCESS; + } +} +#endif + +#if defined(RTL_CPU_QOS_ENABLED) +__MIPS16 +__IRAM_FWD +static inline int32 rtl_processReceivedInfo(rtl_nicRx_info *info, int nicRxRet) +{ + int ret; + + ret = RTL_RX_PROCESS_RETURN_BREAK; + switch(nicRxRet) + { + case RTL_NICRX_OK: + { + if (highestPriority<info->priority) + { + highestPriority = info->priority; + cpuQosHoldLow = highestPriority; + } + + if (info->priority==(RTL865X_SWNIC_RXRING_MAX_PKTDESC-1)) + { + ret = RTL_RX_PROCESS_RETURN_SUCCESS; + } + else if (rtl_enqueueSkb(info) == SUCCESS) + { + rtl_dequeueSkb(info); + ret = RTL_RX_PROCESS_RETURN_SUCCESS; + } + else + ret = RTL_RX_PROCESS_RETURN_CONTINUE; + + break; + } + case RTL_NICRX_NULL: + { + info->priority = cpuQosHoldLow; + if (rtl_dequeueSkb(info)==SUCCESS) + { + ret = RTL_RX_PROCESS_RETURN_SUCCESS; + } + else if((highestPriority>0) && ((--highPrioRxTryCnt)<0)) + { + //Only for using rxring 0 and rxring 5 + highPrioRxTryCnt=MAX_HIGH_PRIO_TRY; + highestPriority=0; + cpuQosHoldLow=highestPriority; + ret = RTL_RX_PROCESS_RETURN_CONTINUE; + } + else if(highestPriority==0) + { + /* highestPriority=0 */ + if (cpuQosHoldLow>0) + { + swNic_flushRxRingByPriority(cpuQosHoldLow); + } + ret = RTL_RX_PROCESS_RETURN_BREAK; + } + + break; + } + case RTL_NICRX_REPEAT: + ret = RTL_RX_PROCESS_RETURN_BREAK; + break; + } + return ret; +} +#else /* defined(RTL_CPU_QOS_ENABLED) */ +__MIPS16 +__IRAM_FWD +static inline int32 rtl_processReceivedInfo(rtl_nicRx_info *info, int nicRxRet) +{ + int ret; + + ret = RTL_RX_PROCESS_RETURN_BREAK; + switch(nicRxRet) + { + case RTL_NICRX_OK: + { + ret = RTL_RX_PROCESS_RETURN_SUCCESS; + break; + } + case RTL_NICRX_NULL: + case RTL_NICRX_REPEAT: + break; + } + return ret; +} +#endif /* defined(RTL_CPU_QOS_ENABLED) */ + +__MIPS16 +__IRAM_FWD +static inline int32 rtl_decideRxDevice(rtl_nicRx_info *info) +{ + struct dev_priv *cp; + int32 pid, i, ret; + struct sk_buff *skb; + uint8* data; + #if defined(CONFIG_RTL_STP) + int32 dev_no; + #endif + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU) + unsigned char dest_mac[MAX_ADDR_LEN]; + #endif + + pid = info->pid; + skb = info->input; + data = skb->data; + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU) + memcpy(dest_mac, data, 6); + #endif + + + info->isPdev=FALSE; + ret = SUCCESS; + + #if defined(CONFIG_RTL_STP) + info->isStpVirtualDev=FALSE; + if ((data[0]&0x01) && !memcmp(data, STPmac, 5) && !(data[5] & 0xF0)) + { + /* It's a BPDU */ + dev_no = re865x_stp_get_pseudodevno(pid); + if (dev_no != NO_MAPPING) + { + info->priv = _rtl86xx_dev.stp_port[dev_no]->priv; + info->isStpVirtualDev=TRUE; + } + else + { + dev_kfree_skb_any(skb); + ret = FAILED; + } + } + else + #endif + { + #if defined(CONFIG_RTL_MULTIPLE_WAN) + //mac based decision + for(i = 0; i < ETH_INTF_NUM; i++) + { + cp = ((struct dev_priv *)_rtl86xx_dev.dev[i]->priv); + if(cp && cp->opened && memcmp(skb->data,cp->dev->dev_addr,6) == 0) + { + info->priv = cp; + goto out; + } + } + //rtl_multiWan_config + if(rtl_multiWan_net_dev) + { + cp = (struct dev_priv *)rtl_multiWan_net_dev->priv; + if(cp && cp->opened && memcmp(skb->data,cp->dev->dev_addr,6) == 0) + { + info->priv = cp; + goto out; + } + } + #endif + + for(i = 0; i < ETH_INTF_NUM; i++) + { + cp = ((struct dev_priv *)_rtl86xx_dev.dev[i]->priv); + //printk("=========%s(%d),cp(%s),i(%d)\n",__FUNCTION__,__LINE__,cp->dev->name,i); + if(cp && cp->opened && (cp->portmask & (1<<pid))) + { + info->priv = cp; + break; + } + } + + //printk("====%s(%d),dev(%s),i(%d)\n",__FUNCTION__,__LINE__,cp->dev->name,i); + if(ETH_INTF_NUM==i) + { + info->priv = NULL; + dev_kfree_skb_any(skb); + ret = FAILED;; + } + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU) + else if (SUCCESS==rtl_isPassthruFrame(data)&&(rtl_isWanDev(cp)==TRUE) + && (compare_ether_addr((char* )cp->dev->dev_addr, (char*)dest_mac))) + { + info->priv = _rtl86xx_dev.pdev->priv; + info->isPdev=TRUE; + } + #endif + } +#if defined(CONFIG_RTL_MULTIPLE_WAN) +out: +#endif + return ret; +} + +#if defined(BR_SHORTCUT) +__MIPS16 +__IRAM_FWD +static inline int32 rtl_processBridgeShortCut(struct sk_buff *skb, struct dev_priv *cp_this, rtl_nicRx_info *info) +{ + struct net_device *dev; + + if ( + #if 0 + (eth_flag & BIT(2)) && + #endif +#if defined(CONFIG_DOMAIN_NAME_QUERY_SUPPORT) + (skb->data[37] != 68) && /*port 68 is dhcp dest port. In order to hack dns ip, so dhcp packag can't enter bridge short cut.*/ +#endif + #if defined(CONFIG_WIRELESS_LAN_MODULE) + (wirelessnet_hook_shortcut !=NULL ) && ((dev = wirelessnet_hook_shortcut(skb->data)) != NULL) + #else + ((dev = get_shortcut_dev(skb->data)) != NULL) + #endif + ) + { + #if defined(CONFIG_RTL_HARDWARE_NAT) + if (memcmp(&skb->data[ETH_ALEN], cp_this->dev->dev_addr, ETH_ALEN)) + #endif + { + memcpy(cached_eth_addr, &skb->data[ETH_ALEN], ETH_ALEN); + cached_dev = cp_this->dev; + } + + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_HARDWARE_NAT) + skb->cb[0] = info->rxPri; + #endif + /*skb->dev = dev;*/ /* for performance */ + #if defined(CONFIG_COMPAT_NET_DEV_OPS) + dev->hard_start_xmit(skb, dev); + #else + dev->netdev_ops->ndo_start_xmit(skb,dev); + #endif + DEBUG_ERR("[%s][%d]-[%s]\n", __FUNCTION__, __LINE__, skb->dev->name); + return SUCCESS; + #if 0 + } else if (info->vid == PKTHDR_EXTPORT_MAGIC) { + /* the pkt should be tx out by a wlanx interface. + * But we don't not which one... + * Pass it to protocol stack. + */ + /* + cp_this->net_stats.rx_dropped++; + dev_kfree_skb_any(skb); + return SUCCESS; + */ + #endif + } + return FAILED; +} +#elif defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) +__MIPS16 +__IRAM_FWD +static inline int32 rtl_processExtensionPortShortCut(struct sk_buff *skb, struct dev_priv *cp_this, rtl_nicRx_info *info) +{ + struct net_device *dev; + + if ((PKTHDR_EXTPORT_MAGIC!=info->vid)||(info->pid!=PKTHDR_EXTPORT_P3)) + return FAILED; + + dev = get_shortcut_dev(skb->data); + + if (dev!=NULL) { + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_HARDWARE_NAT) + skb->cb[0] = info->rxPri; + #endif + /*skb->dev = dev;*/ /* for performance */ + #if defined(CONFIG_COMPAT_NET_DEV_OPS) + dev->hard_start_xmit(skb, dev); + #else + dev->netdev_ops->ndo_start_xmit(skb,dev); + #endif + DEBUG_ERR("[%s][%d]-[%s]\n", __FUNCTION__, __LINE__, skb->dev->name); + + return SUCCESS; + #if 0 + } else { + /* the pkt should be tx out by a wlanx interface. + * But we don't not which one... + * Pass it to protocol stack. + */ + /* + cp_this->net_stats.rx_dropped++; + dev_kfree_skb_any(skb); + */ + #endif + } + + return FAILED; +} +#endif + +__MIPS16 +__IRAM_FWD +static inline void rtl_processRxToProtcolStack(struct sk_buff *skb, struct dev_priv *cp_this) +{ + skb->protocol = eth_type_trans(skb, skb->dev); + skb->ip_summed = CHECKSUM_NONE; + //printk("[%s][%d]-skb->dev[%s],proto(0x%x)\n", __FUNCTION__, __LINE__, skb->dev->name,skb->protocol); + +#if defined(RX_TASKLET) + #if defined(CONFIG_RTL_LOCAL_PUBLIC) + skb->localPublicFlags = 0; + #endif + #if defined(CONFIG_RTL_FAST_BRIDGE) + skb->fast_br_forwarding_flags = 0; + #endif + netif_receive_skb(skb); +#else /* defined(RX_TASKLET) */ + netif_rx(skb); +#endif /* defined(RX_TASKLET) */ +} + +__MIPS16 +__IRAM_FWD +static inline void rtl_processRxFrame(rtl_nicRx_info *info) +{ + struct dev_priv *cp_this; + struct sk_buff *skb; + uint32 vid, pid, len; + uint8 *data; + + cp_this = info->priv; + skb = info->input; + vid = info->vid; + data = skb->tail = skb->data; + +#if defined(CONFIG_RTL_STP) + if(info->isStpVirtualDev){ + pid = info->pid; + len = info->len; + skb->len = 0; + skb_put(skb, len); + skb->dev=info->priv->dev; + goto RxToPs; + } +#endif + + /* sanity check */ + if ((memcmp(&data[ETH_ALEN], cp_this->dev->dev_addr, ETH_ALEN)==0)||PKTHDR_EXTPORT_MAGIC2==vid||PKTHDR_EXTPORT_MAGIC==vid)// check source mac + { + #if defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) + if ((PKTHDR_EXTPORT_MAGIC!=vid)||(info->pid!=PKTHDR_EXTPORT_P3)) + #endif + { + cp_this->net_stats.rx_dropped++; + dev_kfree_skb_any(skb); + return; + } + } + + if (skb->head==NULL||skb->end==NULL) + { + dev_kfree_skb_any(skb); + return; + } + /* sanity check end */ + + pid = info->pid; + len = info->len; + skb->len = 0; + skb_put(skb, len); + skb->dev=info->isPdev?_rtl86xx_dev.pdev:info->priv->dev; + //skb->dev=cp_this->dev; + +#if defined(CONFIG_NETFILTER_XT_MATCH_PHYPORT) || defined(CONFIG_RTL_FAST_FILTER) || defined(CONFIG_RTL_QOS_PATCH) + skb->srcPhyPort=(uint8)pid; +#endif + //printk("=======%s(%d),cp_this(%s)\n",__FUNCTION__,__LINE__,cp_this->dev->name); + /* vlan process (including strip vlan tag) */ + #if defined(CONFIG_RTK_VLAN_SUPPORT) + if (rtk_vlan_support_enable && cp_this->vlan_setting.global_vlan) + { + if (rx_vlan_process(cp_this->dev, &cp_this->vlan_setting, skb)) + { + cp_this->net_stats.rx_dropped++; + dev_kfree_skb_any(skb); + return; + } + + #if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) + if(rtk_vlan_support_enable == 2) + { + DEBUG_ERR("====%s(%d),cp(%s),cp->vlan.id(%d),skb->tag.vid(%d)\n",__FUNCTION__,__LINE__, + cp_this->dev->name,cp_this->vlan_setting.id,skb->tag.f.pci&0xfff); + if(cp_this->vlan_setting.vlan && skb->tag.f.tpid == htons(ETH_P_8021Q) && (skb->tag.f.pci & 0xfff) != cp_this->vlan_setting.id) + { + if(cp_this->vlan_setting.is_lan == 0) + { + struct net_device* vap; + /* look up vap */ + vap = get_dev_by_vid(skb->tag.f.pci & 0xfff); + if(vap) + { + + skb->dev = vap; + vap->netdev_ops->ndo_start_xmit(skb,vap); + return; + } + } + } + } + #endif + } + #endif /* defined(CONFIG_RTK_VLAN_SUPPORT) */ + + if (*((uint16*)(skb->data+(ETH_ALEN<<1))) == __constant_htons(ETH_P_8021Q)) { + vid = *((unsigned short *)(data+(ETH_ALEN<<1)+2)); + #if defined(CONFIG_RTL_QOS_8021P_SUPPORT) + skb->srcVlanPriority = (vid>>13)&0x7; + #endif + vid &= 0x0fff; + + memmove(data + VLAN_HLEN, data, VLAN_ETH_ALEN<<1); + skb_pull(skb, VLAN_HLEN); + } + /* vlan process end (vlan tag has already stripped) */ + + /* update statistics */ + #if !defined(CONFIG_RTL_NIC_HWSTATS) + cp_this->net_stats.rx_packets++; + cp_this->net_stats.rx_bytes += skb->len; + #endif + cp_this->dev->last_rx = jiffies; + /* update statistics end */ + + if (0==(data[0]&0x01)) /* unicast pkt only */ + { + /* shortcut process */ + #if defined(BR_SHORTCUT) + if (SUCCESS==rtl_processBridgeShortCut(skb,cp_this, info)) { + return; + } + #elif defined(CONFIG_RTL_HARDWARE_NAT)&&(defined(CONFIG_RTL8192SE)||defined(CONFIG_RTL8192CD)) + if (SUCCESS==rtl_processExtensionPortShortCut(skb,cp_this, info)) { + return; + } + #endif + + /* shortcut process end */ + + /* unknow unicast control */ + #if defined (CONFIG_RTL_UNKOWN_UNICAST_CONTROL) + rtl_unkownUnicastUpdate(skb->data); + #endif + /* unknow unicast control end */ + } + else /* multicast */ + { + /* multicast process */ + #if defined (CONFIG_RTL_IGMP_SNOOPING) + //rtl_MulticastRxCheck(skb, cp_this, vid, pid); + rtl_MulticastRxCheck(skb, info); + #endif /*end of CONFIG_RTL865X_IGMP_SNOOPING*/ + /* multicast process end */ + } + +#if defined(CONFIG_RTL_STP) +RxToPs: +#endif + /* finally successfuly rx to protocol stack */ + rtl_processRxToProtcolStack(skb, cp_this); +} + +#if defined (CONFIG_RTK_VOIP_QOS) +int ( *check_voip_channel_loading )( void ); +#endif + +__DRAM_FWD rtlInterruptRxData RxIntData; + +#if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST) +__IRAM_FWD +static inline int32 interrupt_dsr_rx_per_packe_check(rtlInterruptRxData *rxData, unsigned long task_priv) +{ + if (( (rxData->voip_rx_cnt++ > 100) || ((jiffies - rxData->voip_rx_start_time) >= 1 ))&& (check_voip_channel_loading && (check_voip_channel_loading() > 0))) + { + #ifdef RX_TASKLET + // avoid cp change! + tasklet_schedule(&(( struct dev_priv *)task_priv)->rx_dsr_tasklet); + #endif + return RTL_RX_PROCESS_RETURN_BREAK; + } + return RTL_RX_PROCESS_RETURN_SUCCESS; +} +#endif + +#if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST) +static inline int32 interrupt_dsr_rx_check(rtlInterruptRxData *rxData) +{ + rxData->voip_rx_start_time = jiffies; + rxData->voip_rx_cnt = 0; + return RTL_RX_PROCESS_RETURN_SUCCESS; +} +#endif + +__IRAM_FWD static void interrupt_dsr_rx_done(rtlInterruptRxData *rxData) +{ +#ifdef RX_TASKLET + unsigned long flags; + + local_irq_save(flags); + rtl_rxSetTxDone(TRUE); + REG32(CPUIIMR) |= (RX_DONE_IP_ALL); + rtl_rx_tasklet_running = 0; + local_irq_restore(flags); +#endif +} + +__MIPS16 +__IRAM_FWD +static int32 interrupt_dsr_rx(unsigned long task_priv) +{ + static __DRAM_FWD rtl_nicRx_info info; + int ret, count; + + #if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST) + interrupt_dsr_rx_check(&RxIntData); + #endif + while (1) + { + #if defined (CONFIG_RTK_VOIP_QOS) && !defined (CONFIG_RTK_VOIP_ETHERNET_DSP_IS_HOST) + if (RTL_RX_PROCESS_RETURN_BREAK==interrupt_dsr_rx_per_packe_check(&RxIntData, task_priv)) + break; + #endif + + #if defined(RTL_MULTIPLE_RX_TX_RING) + info.priority = RTL_ASSIGN_RX_PRIORITY; + #endif + + count = 0; + do { + ret = swNic_receive(&info, count++); + } while (ret==RTL_NICRX_REPEAT); + + switch(rtl_processReceivedInfo(&info, ret)) { + case RTL_RX_PROCESS_RETURN_SUCCESS: + if (SUCCESS==rtl_decideRxDevice(&info)) { + rtl_processRxFrame(&info); + } + break; + case RTL_RX_PROCESS_RETURN_BREAK: + {goto rx_out;} + default: + break; + } + } + +rx_out: + interrupt_dsr_rx_done(&RxIntData); + + return RTL_NICRX_OK; +} + + +__IRAM_FWD +static void interrupt_dsr_tx(unsigned long task_priv) +{ + int32 idx; + #ifdef TX_TASKLET + unsigned long flags; + #endif + + for(idx=RTL865X_SWNIC_TXRING_MAX_PKTDESC-1;idx>=0;idx--) + { + swNic_txDone(idx); + } + + refill_rx_skb(); + #ifdef TX_TASKLET + local_irq_save(flags); + rtl_rxSetTxDone(TRUE); + rtl_tx_tasklet_running = 0; + local_irq_restore(flags); + #endif +} + +#ifdef CONFIG_RTL8196C_ETH_IOT +static int re865x_setPhyGrayCode(void) +{ + uint32 agc, cb0, snr, new_port_link_sts=0, val; + uint32 DUT_eee, Linkpartner_eee; + int i; + + /************ Link down check ************/ + for(i=0; i<RTL8651_PHY_NUMBER; i++) { + if ((REG32(PSRP0 + (i * 4)) & LinkDownEventFlag) != 0){ // !!! LinkDownEventFlag is a read clear bit, so these code must ahead of "Link up check" + if ((REG32(PSRP0 + (i * 4)) & PortStatusLinkUp) == 0) { + /*=========== ###01 ===========*/ + extern void set_gray_code_by_port(int); + set_gray_code_by_port(i); + + /*=========== ###03 ===========*/ + // read DUT eee 100 ability + rtl8651_setAsicEthernetPHYReg( i, 13, 0x7 ); + rtl8651_setAsicEthernetPHYReg( i, 14, 0x3c ); + rtl8651_setAsicEthernetPHYReg( i, 13, 0x4007 ); + rtl8651_getAsicEthernetPHYReg( i, 14, &DUT_eee ); + + // due to the RJ45 cable is plug out now, we can't read the eee 100 ability of link partner. + // we use the variable port_linkpartner_eee to keep link partner's eee 100 ability after RJ45 cable is plug in. + if ( ( ((DUT_eee & 0x2) ) == 0) || ((port_linkpartner_eee & (1<<i)) == 0) ) { + rtl8651_getAsicEthernetPHYReg( i, 21, &val ); + val = val & ~(0x4000); + rtl8651_setAsicEthernetPHYReg( i, 21, val ); + } + } + } + } + + /************ Link up check ************/ + for(i=0; i<RTL8651_PHY_NUMBER; i++) { + if ((REG32(PSRP0 + (i * 4)) & PortStatusLinkUp) != 0) { + + if ((port_link_sts & (1<<i)) == 0) { // the port which already linked up does not need to check ... + + /*=========== ###03 ===========*/ + // read DUT eee 100 ability + rtl8651_setAsicEthernetPHYReg( i, 13, 0x7 ); + rtl8651_setAsicEthernetPHYReg( i, 14, 0x3c ); + rtl8651_setAsicEthernetPHYReg( i, 13, 0x4007 ); + rtl8651_getAsicEthernetPHYReg( i, 14, &DUT_eee ); + + // read Link partner eee 100 ability + rtl8651_setAsicEthernetPHYReg( i, 13, 0x7 ); + rtl8651_setAsicEthernetPHYReg( i, 14, 0x3d ); + rtl8651_setAsicEthernetPHYReg( i, 13, 0x4007 ); + rtl8651_getAsicEthernetPHYReg( i, 14, &Linkpartner_eee ); + + if ( ( ((DUT_eee & 0x2) ) != 0) && ( ((Linkpartner_eee & 0x2) ) != 0) ) { + rtl8651_getAsicEthernetPHYReg( i, 21, &snr ); + snr = snr | 0x4000; + rtl8651_setAsicEthernetPHYReg( i, 21, snr ); + } + + if ( ((Linkpartner_eee & 0x2) ) != 0) + port_linkpartner_eee |= (1 << i); + else + port_linkpartner_eee &= ~(1 << i); + + /*=========== ###02 ===========*/ + /* + 1. reg17 = 0x1f10¡Aread reg29, for SNR + 2. reg17 = 0x1f11¡Aread reg29, for AGC + 3. reg17 = 0x1f18¡Aread reg29, for cb0 + */ + // 1. for SNR + snr = 0; + for(val=0; val<3; val++) { + rtl8651_getAsicEthernetPHYReg(i, 29, &agc); + snr += agc; + } + snr = snr / 3; + + // 3. for cb0 + rtl8651_getAsicEthernetPHYReg( i, 17, &val ); + val = (val & 0xfff0) | 0x8; + rtl8651_setAsicEthernetPHYReg( i, 17, val ); + rtl8651_getAsicEthernetPHYReg( i, 29, &cb0 ); + + // 2. for AGC + val = (val & 0xfff0) | 0x1; + rtl8651_setAsicEthernetPHYReg( i, 17, val ); + rtl8651_getAsicEthernetPHYReg( i, 29, &agc ); + + // set bit 3~0 to 0x0 for reg 17 + val = val & 0xfff0; + rtl8651_setAsicEthernetPHYReg( i, 17, val ); + + if ( ( ( ((agc & 0x70) >> 4) < 4 ) && ((cb0 & 0x80) != 0) ) || (snr > 4150) ) { // "> 4150" = "< 18dB" + rtl8651_restartAsicEthernetPHYNway(i); + } + + } + + new_port_link_sts = new_port_link_sts | (1 << i); + } + } + + port_link_sts = new_port_link_sts; + + return SUCCESS; +} +#endif + +#if defined (CONFIG_RTL_PHY_PATCH) +#define SNR_THRESHOLD 1000 + +//db = -(10 * log10(sum/262144)); +//18db:SNR_THRESHOLD=4155 +//20db:SNR_THRESHOLD=2621 +//21db:SNR_THRESHOLD=2082 +//22db:SNR_THRESHOLD=1654 +//24.18db:SNR_THRESHOLD=1000 +#define MAX_RESTART_NWAY_INTERVAL (60*HZ) +#define MAX_RESTART_NWAY_CNT 3 + +struct rtl_nWayCtrl_s +{ + unsigned long restartNWayTime; + unsigned long restartNWayCnt; +}; + +struct rtl_nWayCtrl_s re865x_restartNWayCtrl[RTL8651_PHY_NUMBER]; + +unsigned int re865x_getPhySnr(unsigned int port) +{ + unsigned int sum=0; + unsigned int j; + unsigned int regData; + + if(port >= RTL8651_PHY_NUMBER) + { + return -1; + } + + if (REG32(PSRP0 + (port * 4)) & PortStatusLinkUp) + { + for (j=0, sum=0;j<10;j++) + { + rtl8651_getAsicEthernetPHYReg(port, 29, ®Data); + sum += regData; + mdelay(10); + } + sum /= 10; + return sum; + } + + return 0; +} + +#if defined(CONFIG_RTL_8196C) +#if 1 +static int re865x_checkPhySnr(void) +{ + + unsigned int port; + unsigned int snr=0; + unsigned int val, cb0, agc; + for (port=0; port<RTL8651_PHY_NUMBER; port++) + { + if((1<<port) & (newLinkPortMask & (~curLinkPortMask)) ) + { + snr=re865x_getPhySnr(port); + + // 3. for cb0 + rtl8651_getAsicEthernetPHYReg( port, 17, &val ); + val = (val & 0xfff0) | 0x8; + rtl8651_setAsicEthernetPHYReg( port, 17, val ); + rtl8651_getAsicEthernetPHYReg( port, 29, &cb0 ); + + // 2. for AGC + val = (val & 0xfff0) | 0x1; + rtl8651_setAsicEthernetPHYReg( port, 17, val ); + rtl8651_getAsicEthernetPHYReg(port, 29, &agc ); + //printk("snr is %d\n",snr); + //printk("cb0 is 0x%x,agc is 0x%x\n",cb0,agc); + //if( ((cb0 & 0x80) != 0)|| (snr>4155)) + if ( ( ( ((agc & 0x70) >> 4) < 4 ) && ((cb0 & 0x80) != 0) ) || (snr > 4155) ) + { + //printk("restart nway\n"); + rtl8651_restartAsicEthernetPHYNway(port); + } + val = val & 0xfff0; + rtl8651_setAsicEthernetPHYReg( port, 17, val ); + + } + + } + return 0; + +} +#else +static int re865x_checkPhySnr(void) +{ + + unsigned int port; + unsigned int snr=0; + + for (port=0; port<RTL8651_PHY_NUMBER; port++) + { + if((1<<port) & (newLinkPortMask & (~curLinkPortMask))) + { + snr=re865x_getPhySnr(port); + //printk("%s:%d, port is %d, snr is %d\n",__FUNCTION__,__LINE__,port,snr); + if(snr>SNR_THRESHOLD) + { + /*poor snr, we should restart n-way*/ + if(re865x_restartNWayCtrl[port].restartNWayTime==0) + { + /*last time snr is good*/ + re865x_restartNWayCtrl[port].restartNWayTime=jiffies; + re865x_restartNWayCtrl[port].restartNWayCnt=1; + + rtl8651_restartAsicEthernetPHYNway(port); + + } + else if(time_after(jiffies,re865x_restartNWayCtrl[port].restartNWayTime+MAX_RESTART_NWAY_INTERVAL) ) + { + /*last time SNR is bad, but interval is long enough, we can take another restart n-way action*/ + re865x_restartNWayCtrl[port].restartNWayTime=jiffies; + re865x_restartNWayCtrl[port].restartNWayCnt=1; + rtl8651_restartAsicEthernetPHYNway(port); + + } + else if (re865x_restartNWayCtrl[port].restartNWayCnt>MAX_RESTART_NWAY_CNT) + { + /*within restart n-way interval and exceed max try cnt*/ + /*shouldn't do it any more, otherwise it will cause phy link up/down repeatly*/ + //printk("%s:%d,restartNWayCnt>MAX_RESTART_NWAY_CNT,stop do restart n-way\n",__FUNCTION__,__LINE__); + } + else + { + //printk("%s:%d,restartNWayCnt is %lu\n",__FUNCTION__,__LINE__,re865x_restartNWayCtrl[port].restartNWayCnt); + re865x_restartNWayCtrl[port].restartNWayCnt++; + rtl8651_restartAsicEthernetPHYNway(port); + } + } + else + { + re865x_restartNWayCtrl[port].restartNWayTime=0; + re865x_restartNWayCtrl[port].restartNWayCnt=0; + } + + } + + } + return 0; + +} +#endif +#endif +#endif + +unsigned int rtl865x_getPhysicalPortLinkStatus(void) +{ + unsigned int port_num=0; + unsigned int linkPortMask=0; + for(port_num=0;port_num<=RTL8651_PHY_NUMBER;port_num++) + { + if((READ_MEM32(PSRP0+(port_num<<2))&PortStatusLinkUp)!=0) + { + linkPortMask |= 1<<port_num; + } + + } + return linkPortMask; +} + +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) +unsigned int rtl865x_setLinkStatusFlag(unsigned int newportmask) +{ + int i; + struct dev_priv * cp=NULL; + if(rtl865x_curOpMode == GATEWAY_MODE) + { + for(i = 0; i < ETH_INTF_NUM; i++) + { + cp = ((struct dev_priv *)_rtl86xx_dev.dev[i]->priv); + if(cp && cp->opened && rtl_isWanDev(cp) && (cp->portmask & newportmask)) + { + wan_linkStatus[0] = 1; + return SUCCESS; + } + } + } + return 0; +} +#endif + +#ifdef CONFIG_RTL_8198_ESD +static uint32 phy_reg30[RTL8651_PHY_NUMBER] = { 0, 0, 0, 0, 0}; +static int one_second_counter = 0; +static int first_time_read_reg6 = 1; +static int need_to_check_esd2 = 1; + +inline static int diff_more_than_1(uint32 a, uint32 b) +{ + uint32 c; + + if (a==b) + return 0; + if (a<b) + { c=a; a=b; b=c; } + if ((a-b) >=2) + return 1; + else + return 0; +} + +static int esd_recovery(void) +{ + uint32 val; + int i; + + for (i=0; i<RTL8651_PHY_NUMBER; i++) { + /************ Link down ************/ + if ((REG32(PSRP0 + (i * 4)) & PortStatusLinkUp) == 0) { + phy_reg30[i] = 0; + } + /************ Link up ************/ + else if (phy_reg30[i] == 0) { + rtl8651_getAsicEthernetPHYReg( i, 22, &val ); + rtl8651_setAsicEthernetPHYReg( i, 22, ((val & (0xff00)) | 0x17) ); + rtl8651_getAsicEthernetPHYReg( i, 30, &val ); + phy_reg30[i] = BIT(31) | (val & 0xfff); + } + } + return SUCCESS; +} +#endif + +static void interrupt_dsr_link(unsigned long task_priv) +{ +#ifdef CONFIG_RTL_8198_ESD + esd_recovery(); +#endif + +#ifdef CONFIG_RTL8196C_ETH_IOT +/*LinkDownEventFlag is a read clear bit, so re865x_setPhyGrayCode() should be call headmost */ + re865x_setPhyGrayCode(); +#endif + + newLinkPortMask=rtl865x_getPhysicalPortLinkStatus(); + +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) + rtl865x_setLinkStatusFlag(newLinkPortMask); +#endif +#if defined(CONFIG_RTL_IGMP_SNOOPING) + rtl865x_igmpSyncLinkStatus(); +#endif + +#if defined(CONFIG_RTL_LINKCHG_PROCESS) + rtl865x_LinkChange_Process(); +#endif + +#if defined(CONFIG_RTL_8196C) && defined(CONFIG_RTL_PHY_PATCH) + re865x_checkPhySnr(); +#endif + curLinkPortMask=newLinkPortMask; + +#ifdef LINK_TASKLET + REG32(CPUIIMR) |= (LINK_CHANGE_IP); +#endif + + return; +} + + +__IRAM_GEN static inline void rtl_rx_interrupt_process(unsigned int status, struct dev_priv *cp) +{ + #if defined(CONFIG_RTL_REINIT_SWITCH_CORE) + if(rtl865x_duringReInitSwtichCore==1) { + return; + } + #endif + + //if (status & (RX_DONE_IP_ALL)) + { + #if defined(RX_TASKLET) + if (rtl_rx_tasklet_running==0) { + rtl_rx_tasklet_running=1; + REG32(CPUIIMR) &= ~(RX_DONE_IE_ALL); + rtl_rxSetTxDone(FALSE); + tasklet_hi_schedule(&cp->rx_dsr_tasklet); + } + #else + interrupt_dsr_rx((unsigned long)cp); + #endif + } +} + +__IRAM_GEN static inline void rtl_tx_interrupt_process(unsigned int status, struct dev_priv *cp) +{ + if (status & TX_ALL_DONE_IP_ALL) + { + #if defined(TX_TASKLET) + if (rtl_tx_tasklet_running==0) { + rtl_tx_tasklet_running=1; + rtl_rxSetTxDone(FALSE); + tasklet_hi_schedule(&cp->tx_dsr_tasklet); + } + #else + interrupt_dsr_tx((unsigned long)cp); + #endif + } +} + +#if defined(CONFIG_RTL_IGMP_SNOOPING)||defined(CONFIG_RTL_LINKCHG_PROCESS) || defined (CONFIG_RTL_PHY_PATCH) +__IRAM_GEN static inline void rtl_link_change_interrupt_process(unsigned int status, struct dev_priv *cp) +{ + if (status & LINK_CHANGE_IP) + { + #if defined(LINK_TASKLET) + #if defined(CONFIG_RTK_VOIP_BOARD) + REG32(CPUIIMR) &= ~LINK_CHANGE_IP; + //tasklet_schedule(&cp->link_dsr_tasklet); + REG32(CPUIIMR) |= (LINK_CHANGE_IP); + #else + REG32(CPUIIMR) &= ~LINK_CHANGE_IP; + tasklet_schedule(&cp->link_dsr_tasklet); + #endif //CONFIG_RTK_VOIP_BOARD + #else + interrupt_dsr_link((unsigned long)cp); + #endif + } +} +#endif + +__MIPS16 +__IRAM_FWD +irqreturn_t interrupt_isr(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct dev_priv *cp; + unsigned int status; + cp = dev->priv; + status = REG32(CPUIISR); + REG32(CPUIISR) = status; + status &= REG32(CPUIIMR); + + rtl_rx_interrupt_process(status, cp); + + rtl_tx_interrupt_process(status, cp); + + #if defined(CONFIG_RTL_IGMP_SNOOPING)||defined(CONFIG_RTL_LINKCHG_PROCESS) || defined (CONFIG_RTL_PHY_PATCH) + if (status & LINK_CHANGE_IP) + rtl_link_change_interrupt_process(status, cp); + #endif + + return IRQ_HANDLED; +} + +static int rtl865x_init_hw(void) +{ + unsigned int mbufRingSize; + int i; + + mbufRingSize = rtl865x_rxSkbPktHdrDescNum; /* rx ring 0 */ + for(i=1;i<RTL865X_SWNIC_RXRING_HW_PKTDESC;i++) + { + mbufRingSize += rxRingSize[i]; + } + + /* Initialize NIC module */ + if (swNic_init(rxRingSize, mbufRingSize, txRingSize, MBUF_LEN)) + { + printk("865x-nic: swNic_init failed!\n"); + return FAILED; + } + + return SUCCESS; +} + +#ifdef CONFIG_RTL_HARDWARE_NAT +static void reset_hw_mib_counter(struct net_device *dev) +{ + int i, port; + int32 totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for(i=0;i<totalVlans;i++) + { + if (IF_ETHER!=vlanconfig[i].if_type) + { + continue; + } + if (!memcmp(vlanconfig[i].mac.octet, dev->dev_addr, 6)) + { + for (port=0; port<RTL8651_AGGREGATOR_NUMBER; port++) + { + if (vlanconfig[i].memPort & (1<<port)) + WRITE_MEM32(MIB_CONTROL, (1<<port*2) | (1<<(port*2+1))); + return; + } + } + } +} +#endif + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET +int total_time_for_5_port = 15*HZ; +int port_pwr_save_low = 0; +#endif + +#if defined(DYNAMIC_ADJUST_TASKLET) || defined(CONFIG_RTL8186_TR) || defined(CONFIG_RTL8196C_REVISION_B) || defined(CONFIG_RTL_8198) || defined(RTL8196C_EEE_MAC) || defined(RTL_CPU_QOS_ENABLED) +static void one_sec_timer(unsigned long task_priv) +{ + unsigned long flags; + struct dev_priv *cp; +#if defined (CONFIG_RTL_REINIT_SWITCH_CORE) + int i; +#endif + + cp = ((struct net_device *)task_priv)->priv; + + //spin_lock_irqsave (&cp->lock, flags); + local_irq_save(flags); + +#if defined(PATCH_GPIO_FOR_LED) + if (((struct net_device *)task_priv)->name[3] == '0' ) { // eth0 + int port; + + for (port=0; port<RTL8651_PHY_NUMBER; port++) { + update_mib_counter(port); + calculate_led_interval(port); + if (led_cb[port].link_status & GPIO_LINK_STATE_CHANGE) + { + gpio_led_Interval_timeout(port); + } + } + } +#endif + +#if defined(DYNAMIC_ADJUST_TASKLET) + if (((struct net_device *)task_priv)->name[3] == '0' && rx_pkt_thres > 0 && + ((eth_flag&TASKLET_MASK) == 0)) { + if (rx_cnt > rx_pkt_thres) { + if (!rx_tasklet_enabled) { + rx_tasklet_enabled = 1; + } + } + else { + if (rx_tasklet_enabled) { // tasklet enabled + rx_tasklet_enabled = 0; + } + } + rx_cnt = 0; + } +#endif + +#ifdef CONFIG_RTL8186_TR + cp->tx_avarage = (cp->tx_avarage/10)*7 + (cp->tx_byte_cnt/10)*3; + if (cp->tx_avarage > cp->tx_peak) + cp->tx_peak = cp->tx_avarage; + cp->tx_byte_cnt = 0; + + cp->rx_avarage = (cp->rx_avarage/10)*7 + (cp->rx_byte_cnt/10)*3; + if (cp->rx_avarage > cp->rx_peak) + cp->rx_peak = cp->rx_avarage; + cp->rx_byte_cnt = 0; +#endif + +#ifdef CONFIG_RTL8196C_REVISION_B + if ((REG32(REVR) == RTL8196C_REVISION_A) && (eee_enabled)) { + int i, curr_sts; + uint32 reg; + + /* + prev_port_sts[] = 0, current = 0 : do nothing + prev_port_sts[] = 0, current = 1 : update prev_port_sts[] + prev_port_sts[] = 1, current = 0 : update prev_port_sts[], disable EEE + prev_port_sts[] = 1, current = 1 : enable EEE if EEE is disabled + */ + for (i=0; i<MAX_PORT_NUMBER; i++) + { + curr_sts = (REG32(PSRP0 + (i * 4)) & PortStatusLinkUp) >> 4; + + if ((prev_port_sts[i] == 1) && (curr_sts == 0)) { + // disable EEE MAC + REG32(EEECR) = (REG32(EEECR) & ~(0x1f << (i * 5))) | + ((EN_P0_FRC_EEE|FRC_P0_EEE_100) << (i * 5)); + //printk(" disable EEE for port %d\n", i); + } + else if ((prev_port_sts[i] == 1) && (curr_sts == 1)) { + reg = REG32(EEECR); + if ((reg & (1 << (i * 5))) == 0) { + // enable EEE MAC + REG32(EEECR) = (reg & ~(0x1f << (i * 5))) | + ((FRC_P0_EEE_100|EN_P0_TX_EEE|EN_P0_RX_EEE) << (i * 5)); + //printk(" enable EEE for port %d\n", i); + } + } + prev_port_sts[i] = curr_sts; + } + //printk(" %d %d %d %d %d\n", port_sts[0], port_sts[1], port_sts[2], port_sts[3], port_sts[4]); + } +#endif + +#if defined(RTL_CPU_QOS_ENABLED) + totalLowQueueCnt = 0; +#endif + +#ifdef CONFIG_RTL_8198_ESD +#if defined(CONFIG_PRINTK) +#define panic_printk printk +#endif + { + int phy; + uint32 val; + if (first_time_read_reg6) { + first_time_read_reg6 = 0; + + for (phy=0; phy<5; phy++) { + rtl8651_setAsicEthernetPHYReg( phy, 31, 5 ); + rtl8651_getAsicEthernetPHYReg(phy, 1, &val); + rtl8651_setAsicEthernetPHYReg(phy, 1, val | 0x4); + + rtl8651_setAsicEthernetPHYReg(phy, 5, 0xfff6); + rtl8651_getAsicEthernetPHYReg(phy, 6, &val); + rtl8651_setAsicEthernetPHYReg( phy, 31, 0 ); + + if ((val & 0xff) == 0xFF) { + need_to_check_esd2 = 0; + } + if (phy_reg30[phy] != 0) { + rtl8651_getAsicEthernetPHYReg( phy, 22, &val ); + rtl8651_setAsicEthernetPHYReg( phy, 22, ((val & (0xff00)) | 0x17) ); + rtl8651_getAsicEthernetPHYReg( phy, 30, &val ); + + phy_reg30[phy] = BIT(31) | (val & 0xfff); + } + } + } + + if (++one_second_counter >= 10) { + for (phy=0; phy<5; phy++) + { + if (phy_reg30[phy] != 0) { + rtl8651_setAsicEthernetPHYReg( phy, 31, 5 ); + rtl8651_setAsicEthernetPHYReg(phy, 5, 0); + + rtl8651_getAsicEthernetPHYReg(phy, 6, &val); + rtl8651_setAsicEthernetPHYReg( phy, 31, 0 ); + + if ((val & 0xffff) != 0xAE04) + { + panic_printk(" ESD-1\n"); + do {} while(1); // reboot + } + + if (need_to_check_esd2) { + rtl8651_setAsicEthernetPHYReg( phy, 31, 5 ); + rtl8651_setAsicEthernetPHYReg(phy, 5, 0xfff6); + + rtl8651_getAsicEthernetPHYReg(phy, 6, &val); + rtl8651_setAsicEthernetPHYReg( phy, 31, 0 ); + + if ((val & 0xff) != 0xFC) + { + panic_printk(" ESD-2\n"); + do {} while(1); // reboot + } + } + + rtl8651_getAsicEthernetPHYReg( phy, 22, &val ); + rtl8651_setAsicEthernetPHYReg( phy, 22, ((val & (0xff00)) | 0x17) ); + rtl8651_getAsicEthernetPHYReg( phy, 30, &val ); + + if ((phy_reg30[phy] & 0xfff) != (val & 0xfff)) { + if (diff_more_than_1((phy_reg30[phy] & 0xf), (val & 0xf)) || + diff_more_than_1(((phy_reg30[phy] >> 4) & 0xf), ((val >> 4) & 0xf)) || + diff_more_than_1(((phy_reg30[phy] >> 8) & 0xf), ((val >> 8) & 0xf)) + ) { + panic_printk(" ESD-3: old= 0x%x, new= 0x%x\n", phy_reg30[phy] & 0xfff, val & 0xfff); + do {} while(1); // reboot + } + phy_reg30[phy] = BIT(31) | (val & 0xfff); + } + } + + } + + one_second_counter = 0; + } + } +#endif + +#ifdef CONFIG_RTL_8196C_ESD +#if defined(CONFIG_PRINTK) +#define panic_printk printk +#endif + if (_96c_esd_counter) { + + extern int is_fault; +#if 0 + if (++_96c_esd_counter >= 20) { + + if( (RTL_R32(PCRP4) & EnablePHYIf) == 0) + { + panic_printk(" ESD reboot...\n"); + is_fault = 1; + } + _96c_esd_counter = 1; + } +#else + if( (RTL_R32(PCRP4) & EnablePHYIf) == 0) + { + if (++_96c_esd_reboot_counter >= 20) { + panic_printk(" ESD reboot...\n"); + is_fault = 1; + } + } + else { + _96c_esd_reboot_counter = 0; + } +#endif + + + } +#endif + +#if defined (CONFIG_RTL_REINIT_SWITCH_CORE) + for(i = 0; i < ETH_INTF_NUM; i++) + { + struct dev_priv *tmp_cp; + + int portnum; + tmp_cp = ((struct dev_priv *)_rtl86xx_dev.dev[i]->priv); + if(tmp_cp && tmp_cp->portmask && tmp_cp->opened) { + for(portnum=0;portnum<5;portnum++) + { + if(tmp_cp->portmask & (1<<portnum)) + break; + } + if(5 == portnum) + continue; + if((RTL_R32(PCRP0+portnum*4) & EnablePHYIf) == 0) + { + switch(rtl865x_reInitState) + { + case STATE_NO_ERROR: + if(( REG32(SYS_CLK_MAG) & SYS_SW_CLK_ENABLE)==0) + { + rtl865x_reInitState=STATE_SW_CLK_ENABLE_WAITING; + rtl865x_reInitWaitCnt=2; + REG32(SYS_CLK_MAG)=REG32(SYS_CLK_MAG)|SYS_SW_CLK_ENABLE; + } + else + { + rtl865x_reinitSwitchCore(); + rtl865x_reInitState=STATE_NO_ERROR; + } + break; + + case STATE_SW_CLK_ENABLE_WAITING: + rtl865x_reInitWaitCnt--; + if(rtl865x_reInitWaitCnt<=0) + { + rtl865x_reInitWaitCnt=2; + rtl865x_reInitState=STATE_TO_REINIT_SWITCH_CORE; + + } + break; + + case STATE_TO_REINIT_SWITCH_CORE: + rtl865x_reInitWaitCnt--; + if(rtl865x_reInitWaitCnt<=0) + { + rtl865x_reinitSwitchCore(); + rtl865x_reInitState=STATE_NO_ERROR; + } + break; + + default : + rtl865x_reinitSwitchCore(); + rtl865x_reInitState=STATE_NO_ERROR; + break; + } + break; + } + } + } +#endif + mod_timer(&cp->expire_timer, jiffies + HZ); + + //spin_unlock_irqrestore(&cp->lock, flags); + local_irq_restore(flags); +} +#endif + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET +static void power_save_timer(unsigned long task_priv) +{ + unsigned long flags; + //struct dev_priv *cp; + + //cp = ((struct net_device *)task_priv)->priv; + + //spin_lock_irqsave (&cp->lock, flags); + local_irq_save(flags); + + set_phy_pwr_save(port_pwr_save_low, 1); + + port_pwr_save_low = (port_pwr_save_low + 1) % 5; + set_phy_pwr_save(port_pwr_save_low, 0); + + //mod_timer(&cp->expire_timer2, jiffies + (total_time_for_5_port / 5 / 10)); + mod_timer(&expire_timer2, jiffies + (total_time_for_5_port / 5 / 10)); + + //spin_unlock_irqrestore(&cp->lock, flags); + local_irq_restore(flags); +} +#endif +static struct net_device *irqDev=NULL; +static int re865x_open (struct net_device *dev) +{ + struct dev_priv *cp; + unsigned long flags; + int rc; + #if defined(CONFIG_RTL_MULTIPLE_WAN) + char drvNetif_name[MAX_IFNAMESIZE]; + #endif + + cp = dev->priv; + if (cp->opened) + return SUCCESS; + + /* The first device be opened */ + if (atomic_read(&rtl_devOpened)==0) + { + /* this is the first open dev */ + /* should not call rtl865x_down() here */ + /* rtl865x_down();*/ + //spin_lock_irqsave(&cp->lock, flags); + local_irq_save(flags); + rtk_queue_init(&rx_skb_queue); + rc = rtl865x_init_hw(); + local_irq_restore(flags); + refill_rx_skb(); + //spin_unlock_irqrestore(&cp->lock, flags); + if (rc) { + //printk("rtl865x_init_hw() failed!\n"); + return FAILED; + } + +#if defined(RX_TASKLET) + tasklet_init(&cp->rx_dsr_tasklet, (void *)interrupt_dsr_rx, (unsigned long)cp); +#endif +#ifdef TX_TASKLET + tasklet_init(&cp->tx_dsr_tasklet, interrupt_dsr_tx, (unsigned long)cp); +#endif + +#ifdef LINK_TASKLET + tasklet_init(&cp->link_dsr_tasklet, interrupt_dsr_link, (unsigned long)cp); +#endif + +#ifdef CONFIG_RTL_PHY_PATCH + memset(re865x_restartNWayCtrl,0, sizeof(re865x_restartNWayCtrl)); +#endif + + + rc = request_irq(dev->irq, interrupt_isr, IRQF_DISABLED, dev->name, dev); + if (rc) + { + printk("request_irq() error!\n"); + goto err_out_hw; + } + irqDev=dev; + //cp->irq_owner =1; + rtl865x_start(); + } + + atomic_inc(&rtl_devOpened); + cp->opened = 1; + +#ifdef CONFIG_RTL_HARDWARE_NAT + reset_hw_mib_counter(dev); +#endif + + netif_start_queue(dev); + +#if defined(DYNAMIC_ADJUST_TASKLET) || defined(CONFIG_RTL8186_TR) || defined(CONFIG_RTL8196C_REVISION_B)|| defined(CONFIG_RTL_8198) || defined(RTL8196C_EEE_MAC) + #if !defined(CONFIG_RTL8186_TR) + if (dev->name[3] == '0') + #endif + { + init_timer(&cp->expire_timer); + cp->expire_timer.expires = jiffies + HZ; + cp->expire_timer.data = (unsigned long)dev; + cp->expire_timer.function = one_sec_timer; + mod_timer(&cp->expire_timer, jiffies + HZ); +#ifdef DYNAMIC_ADJUST_TASKLET + rx_cnt = 0; +#endif + } +#endif + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET + if (REG32(REVR) == RTL8196C_REVISION_B) { + //if (dev->name[3] == '0') + if (atomic_read(&rtl_devOpened)==1) + { + #if 0 + init_timer(&cp->expire_timer2); + cp->expire_timer2.expires = jiffies + HZ; + cp->expire_timer2.data = (unsigned long)dev; + cp->expire_timer2.function = power_save_timer; + mod_timer(&cp->expire_timer2, jiffies + HZ); + #else + init_timer(&expire_timer2); + expire_timer2.expires = jiffies + HZ; + expire_timer2.data = (unsigned long)dev; + expire_timer2.function = power_save_timer; + mod_timer(&expire_timer2, jiffies + HZ); + #endif + } + } +#endif + +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + /*FIXME_hyking: should add default route to cpu....*/ + if(rtl865x_curOpMode == GATEWAY_MODE) +#if defined(CONFIG_RTL_PUBLIC_SSID) + rtl865x_addRoute(0,0,0,RTL_GW_WAN_DEVICE_NAME,0); +#else + rtl865x_addRoute(0,0,0,RTL_DRV_WAN0_NETIF_NAME,0); +#endif +#endif + + #if defined(CONFIG_RTL_MULTIPLE_WAN) + memset(drvNetif_name,0,MAX_IFNAMESIZE); + if(rtl_get_ps_drv_netif_mapping_by_psdev_name(dev->name,drvNetif_name) == SUCCESS) + rtl_enable_advRt_by_netifName(drvNetif_name); + #endif + rtl865x_enableDevPortForward( dev, cp); + + return SUCCESS; + +err_out_hw: + rtl8186_stop_hw(dev, cp); + rtl865x_down(); + return rc; +} + +static int re865x_close (struct net_device *dev) +{ + struct dev_priv *cp; +#if defined(CONFIG_RTL_MULTIPLE_WAN) + char drvNetif_name[MAX_IFNAMESIZE]; +#endif + + cp = dev->priv; +// cp = netdev_priv(dev); + if (!cp->opened) + return SUCCESS; + + netif_stop_queue(dev); + /* The last opened device */ + if (atomic_read(&rtl_devOpened)==1) + { + /* warning: + 1.if we don't reboot,we shouldn't hold switch core from rx/tx, otherwise there will be some problem during change operation mode + 2.only when two devices go down,can we shut down nic interrupt + 3.the interrupt will be re_enable by rtl865x_start() + */ + rtl865x_disableInterrupt(); + + //free_irq(dev->irq, GET_IRQ_OWNER(cp)); + //((struct dev_priv *)((GET_IRQ_OWNER(cp))->priv))->irq_owner = 0; + free_irq(dev->irq, irqDev); + //((struct dev_priv *)(irqDev->priv))->irq_owner = 0; + + +#ifdef RX_TASKLET + tasklet_kill(&cp->rx_dsr_tasklet); +#endif + +#ifdef TX_TASKLET + tasklet_kill(&cp->tx_dsr_tasklet); +#endif + +#ifdef LINK_TASKLET + tasklet_kill(&cp->link_dsr_tasklet); +#endif + +#ifdef CONFIG_RTL_PHY_PATCH + memset(re865x_restartNWayCtrl,0, sizeof(re865x_restartNWayCtrl)); +#endif + free_rx_skb(); + } + + memset(&cp->net_stats, '\0', sizeof(struct net_device_stats)); + atomic_dec(&rtl_devOpened); + cp->opened = 0; + + #if defined(CONFIG_RTL_MULTIPLE_WAN) + memset(drvNetif_name,0,MAX_IFNAMESIZE); + if(rtl_get_ps_drv_netif_mapping_by_psdev_name(dev->name,drvNetif_name) == SUCCESS) + rtl_disable_advRt_by_netifName(drvNetif_name); + + if(rtl_port_used_by_device(cp->portmask) == FAILED) + #endif + { + rtl865x_disableDevPortForward(dev, cp); + rtl8186_stop_hw(dev, cp); + } + +#if defined(DYNAMIC_ADJUST_TASKLET) || defined(CONFIG_RTL8186_TR) || defined(BR_SHORTCUT) || defined(CONFIG_RTL8196C_REVISION_B) || defined(CONFIG_RTL_8198) + if (timer_pending(&cp->expire_timer)) + del_timer_sync(&cp->expire_timer); +#endif + +#ifdef CONFIG_RTL8196C_GREEN_ETHERNET + if (atomic_read(&rtl_devOpened)==0) + { + if (REG32(REVR) == RTL8196C_REVISION_B) { + #if 0 + if (timer_pending(&cp->expire_timer2)) + del_timer_sync(&cp->expire_timer2); + #else + if (timer_pending(&expire_timer2)) + del_timer_sync(&expire_timer2); + #endif + } + } +#endif + +#ifdef BR_SHORTCUT + if (dev == cached_dev) + cached_dev=NULL; +#endif + +#ifdef CONFIG_RTL_HARDWARE_NAT + reset_hw_mib_counter(dev); +#endif + + return SUCCESS; +} + +#if defined(CONFIG_RTL_STP) || (defined(CONFIG_RTL_CUSTOM_PASSTHRU)) +static int re865x_pseudo_open (struct net_device *dev) +{ + struct dev_priv *cp; + + cp = dev->priv; + //cp = netdev_priv(dev); + if (cp->opened) + return SUCCESS; + + cp->opened = 1; + netif_start_queue(dev); + return SUCCESS; +} + + +static int re865x_pseudo_close (struct net_device *dev) +{ + struct dev_priv *cp; + + cp = dev->priv; +// cp = netdev_priv(dev); + + if (!cp->opened) + return SUCCESS; + netif_stop_queue(dev); + + memset(&cp->net_stats, '\0', sizeof(struct net_device_stats)); + cp->opened = 0; + +#ifdef BR_SHORTCUT + if (dev == cached_dev) + cached_dev=NULL; +#endif + return SUCCESS; +} +#endif + +#if defined(CONFIG_RTL_STP) +static int re865x_stp_mapping_init(void) +{ + int i, j, k, totalVlans; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for (i = 0; i < MAX_RE865X_STP_PORT; i++) + { + STP_PortDev_Mapping[i] = NO_MAPPING; + } + + STP_PortDev_Mapping[WLAN_PSEUDO_IF_INDEX] = WLAN_PSEUDO_IF_INDEX; + #ifdef CONFIG_RTK_MESH + STP_PortDev_Mapping[WLAN_MESH_PSEUDO_IF_INDEX] = WLAN_MESH_PSEUDO_IF_INDEX; + #endif + + j = 0; + for(k=0;k<totalVlans;k++) + { + if (vlanconfig[k].isWan == FALSE) + { + for(i=0; i< MAX_RE865X_ETH_STP_PORT ; i++) + { + if ( (1<<i) & vlanconfig[k].memPort ) + { + STP_PortDev_Mapping[j] = i; + j++; + } + } + + break; + } + } + + return SUCCESS; +} + +static int re865x_stp_mapping_reinit(void) +{ + int i, j, k, totalVlans; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for (i = 0; i < MAX_RE865X_STP_PORT; i++) + { + STP_PortDev_Mapping[i] = NO_MAPPING; + } + + STP_PortDev_Mapping[WLAN_PSEUDO_IF_INDEX] = WLAN_PSEUDO_IF_INDEX; + #ifdef CONFIG_RTK_MESH + STP_PortDev_Mapping[WLAN_MESH_PSEUDO_IF_INDEX] = WLAN_MESH_PSEUDO_IF_INDEX; + #endif + + j = 0; + for(k=0;k<totalVlans;k++) + { + if (vlanconfig[k].isWan == FALSE) + { + for(i=0; i< MAX_RE865X_ETH_STP_PORT; i++) + { + if ( (1<<i) & vlanconfig[k].memPort ) + { + STP_PortDev_Mapping[j] = i; + j++; + } + } + + break; + } + } + + return SUCCESS; +} + +static int re865x_stp_get_pseudodevno(uint32 port_num) +{ + int i, dev_no; + for(i=0; i< MAX_RE865X_STP_PORT-1 ; i++) + { + if( STP_PortDev_Mapping[i] == port_num) + { + dev_no = i; + return dev_no; + } + } + return NO_MAPPING; + +} + +static int getVidByPort(uint32 port_num) +{ + int i, totalVlans, retVid; + + retVid=0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for(i=0;i<totalVlans;i++) + { + if((1<<port_num) & vlanconfig[i].memPort) + { + retVid=vlanconfig[i].vid; + break; + } + } + + return retVid; +} +#endif + +#if defined(CONFIG_RTL_LOCAL_PUBLIC) +//hyking:this function should move to rtl865x_fdb.c +//implement it at here just for releaae to natami... +//2010-02-22 +static int32 rtl865x_getPortlistByMac(const unsigned char *mac,uint32 *portlist) +{ + int32 found = FAILED; + ether_addr_t *macAddr; + int32 column; + rtl865x_tblAsicDrv_l2Param_t fdbEntry; + + macAddr = (ether_addr_t *)(mac); + found = rtl865x_Lookup_fdb_entry(0, macAddr, FDB_DYNAMIC, &column, &fdbEntry); + if(found == SUCCESS) + { + if(portlist) + *portlist = fdbEntry.memberPortMask; + } + + return found; + +} +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) +int re865x_setMCastTxInfo(struct sk_buff *skb,struct net_device *dev, rtl_nicTx_info *nicTx) +{ + int32 ret; + struct dev_priv *cp; + struct iphdr *iph=NULL; + #if defined (CONFIG_RTL_MLD_SNOOPING) + struct ipv6hdr *ipv6h=NULL; + #endif + unsigned int l4Protocol=0; + struct rtl_multicastDataInfo multicastDataInfo; + struct rtl_multicastFwdInfo multicastFwdInfo; + + if((skb==NULL) || (dev==NULL) ||(nicTx==NULL)) + { + return -1; + } + + if((igmpsnoopenabled==0) || (nicIgmpModuleIndex==0xFFFFFFFF)) + { + return -1; + } + + + cp = dev->priv; + + nicTx->portlist=cp->portmask; + + if((skb->data[0]==0x01) && (skb->data[1]==0x00) && (skb->data[2]==0x5e)) + { + iph = re865x_getIpv4Header(skb->data); + if(iph) + { + l4Protocol=iph->protocol; + if((l4Protocol==IPPROTO_UDP) || (l4Protocol==IPPROTO_TCP) ) + { + if(cp->portnum<=1) + { + return -1; + } + + /*only process tcp/udp in igmp snooping data plane*/ + multicastDataInfo.ipVersion=4; + memcpy(multicastDataInfo.sourceIp,&(iph->saddr),4); + memcpy(multicastDataInfo.groupAddr,&(iph->daddr),4); + /* + multicastDataInfo.sourceIp[0]= (uint32)(iph->saddr); + multicastDataInfo.groupAddr[0]= (uint32)(iph->daddr); + */ + ret= rtl_getMulticastDataFwdInfo(nicIgmpModuleIndex, &multicastDataInfo, &multicastFwdInfo); + nicTx->portlist = multicastFwdInfo.fwdPortMask& cp->portmask & ((1<<RTL8651_MAC_NUMBER)-1); + + + + } + } + } +#if defined (CONFIG_RTL_MLD_SNOOPING) + else if ((skb->data[0]==0x33) && (skb->data[1]==0x33) && (skb->data[2]!=0xff)) + { + + if(mldSnoopEnabled!=TRUE) + { + return -1; + } + if(cp->portnum<=1) + { + return -1; + } + + ipv6h=re865x_getIpv6Header(skb->data); + if(ipv6h!=NULL) + { + l4Protocol=re865x_getIpv6TransportProtocol(ipv6h); + /*udp or tcp packet*/ + if((l4Protocol==IPPROTO_UDP) || (l4Protocol==IPPROTO_TCP)) + { + /*only process tcp/udp in igmp snooping data plane*/ + multicastDataInfo.ipVersion=6; + memcpy(&multicastDataInfo.sourceIp, &ipv6h->saddr, 16); + memcpy(&multicastDataInfo.groupAddr, &ipv6h->daddr, 16); + ret= rtl_getMulticastDataFwdInfo(nicIgmpModuleIndex, &multicastDataInfo, &multicastFwdInfo); + nicTx->portlist = multicastFwdInfo.fwdPortMask& cp->portmask & ((1<<RTL8651_MAC_NUMBER)-1); + + } + + } + + + } +#endif + return 0; +} +#endif + +//#if defined(CONFIG_RTK_VLAN_SUPPORT) && defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) +struct net_device* re865x_get_netdev_by_name(const char* name) +{ + int i; + for(i = 0; i < ETH_INTF_NUM; i++) + { + if(strcmp(_rtl86xx_dev.dev[i]->name,name) == 0) + return _rtl86xx_dev.dev[i]; + } + return NULL; +} +//#endif + +#if defined(CONFIG_RTL_STP) +static inline int rtl_process_stp_tx(rtl_nicTx_info *txInfo) +{ + struct net_device *dev; + struct sk_buff *skb = NULL; + struct dev_priv *cp; + uint8 stpPortNum; + + skb = txInfo->out_skb; + dev = skb->dev; + cp = dev->priv; + if(!dev->irq){ + //virtual interfaces have no IRQ assigned. + //We use device name to identify STP port interfaces(virtual devices). + if(memcmp((void *)(dev->name), "port", 4)==0) + { + if ((skb->data[0]&0x01) && !memcmp(&(skb->data[0]), STPmac, 5) && !(skb->data[5] & 0xF0)) + { + stpPortNum= dev->name[strlen(dev->name)-1]-'0'; + if (STP_PortDev_Mapping[stpPortNum] != NO_MAPPING) + { + cp->id=getVidByPort(stpPortNum); + cp->portmask = 1<<STP_PortDev_Mapping[stpPortNum]; + cp->portnum = 1; //Multicast process will check this entry. + } + else + { + dev_kfree_skb_any(skb); + return FAILED; + } + } + else + { + //To STP port interfaces(virtual devices), drop non bpdu tx pkt. + dev_kfree_skb_any(skb); + return FAILED; + } + } + } + + return SUCCESS; +} +#endif + +//__MIPS16 +#if defined(CONFIG_RTL_CUSTOM_PASSTHRU) +static inline int rtl_process_passthru_tx(rtl_nicTx_info *txInfo) +{ + struct net_device *dev; + struct sk_buff *skb = NULL; + struct dev_priv *cp; + + if(oldStatus) + { + skb = txInfo->out_skb; + dev = skb->dev; + if (dev==_rtl86xx_dev.pdev) + { + if (SUCCESS==rtl_isPassthruFrame(skb->data)) + { + cp = _rtl86xx_dev.pdev->priv; + skb->dev=cp->dev; + + } + else + { + dev_kfree_skb_any(skb); + return FAILED; + } + } + } + + return SUCCESS; +} +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) +static inline int rtl_process_rtk_vlan_tx(rtl_nicTx_info *txInfo) +{ + struct net_device *dev; + struct sk_buff *skb = NULL; + struct sk_buff *newskb; + struct dev_priv *cp; + if(rtk_vlan_support_enable) + { + skb = txInfo->out_skb; + dev = skb->dev; + cp = dev->priv; + if (cp->vlan_setting.global_vlan) + { + newskb = NULL; + if (skb_cloned(skb)) + { + newskb = skb_copy(skb, GFP_ATOMIC); + if (newskb == NULL) + { + cp->net_stats.tx_dropped++; + dev_kfree_skb_any(skb); + return FAILED; + } + dev_kfree_skb_any(skb); + skb = newskb; + txInfo->out_skb = skb; + } + + if (tx_vlan_process(dev, &cp->vlan_setting, skb, 0)) + { + cp->net_stats.tx_dropped++; + dev_kfree_skb_any(skb); + return FAILED; + } + } + } + return SUCCESS; +} +#endif + +static inline int rtl_pstProcess_xmit(struct dev_priv *cp,int len) +{ +#if !defined(CONFIG_RTL_NIC_HWSTATS) + cp->net_stats.tx_packets++; + cp->net_stats.tx_bytes += len; +#endif + cp->dev->trans_start = jiffies; + return SUCCESS; +} + +static inline int rtl_preProcess_xmit(rtl_nicTx_info *txInfo) +{ + int retval = FAILED; + #if defined(CONFIG_RTL_STP) + retval = rtl_process_stp_tx(txInfo); + if(FAILED == retval) + return retval; + #endif + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU) + retval = rtl_process_passthru_tx(txInfo); + if(FAILED == retval) + return retval; + #endif + #if defined(CONFIG_RTK_VLAN_SUPPORT) + retval = rtl_process_rtk_vlan_tx(txInfo); + if(FAILED == retval) + return retval; + #endif + + #if defined(CONFIG_RTL_REINIT_SWITCH_CORE) + if(rtl865x_duringReInitSwtichCore==1) { + dev_kfree_skb_any(txInfo->out_skb); + return FAILED; + } + #endif + + return SUCCESS; +} + +static inline void rtl_direct_txInfo(uint32 port_mask,rtl_nicTx_info *txInfo) +{ + txInfo->portlist = port_mask & 0x3f; + txInfo->srcExtPort = 0; //PKTHDR_EXTPORT_LIST_CPU; + txInfo->flags = (PKTHDR_USED|PKT_OUTGOING); +} + +static inline void rtl_hwLookup_txInfo(rtl_nicTx_info *txInfo) +{ + txInfo->portlist = RTL8651_CPU_PORT; /* must be set 0x7 */ + txInfo->srcExtPort = PKTHDR_EXTPORT_LIST_CPU; + txInfo->flags = (PKTHDR_USED|PKTHDR_HWLOOKUP|PKTHDR_BRIDGING|PKT_OUTGOING); +} + +static inline int rtl_ip_option_check(struct sk_buff *skb) +{ + int flag = FALSE; + if (((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_IP)) + && ((*((unsigned char*)(skb->data+ETH_ALEN*2+2)) != __constant_htons(0x45)))) || + ((*((unsigned short *)(skb->data+ETH_ALEN*2)) == __constant_htons(ETH_P_8021Q))&& + (*((unsigned short *)(skb->data+ETH_ALEN*2+2)) == __constant_htons(ETH_P_IP))&& + ((*((unsigned char*)(skb->data+ETH_ALEN*2+4)) != __constant_htons(0x45))))) + flag = TRUE; + return flag; +} +static inline int rtl_isHwlookup(struct sk_buff *skb, struct dev_priv *cp, uint32 *portlist) +{ + int flag = FALSE; + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined (CONFIG_POCKET_ROUTER_SUPPORT) + goto assign_portmask; +#elif defined(CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable ==1) { + goto assign_portmask; + } +#endif + + if ((rtl_isWanDev(cp)!=TRUE) && (rtl_ip_option_check(skb) != TRUE)) { + flag = TRUE; + } else { + flag = FALSE; + } + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + //hyking: + //when hw local public and sw localpublic exist at same time, + //pkt to sw local public would be trap to cpu by default ACL + //2010-02-22 + flag = FALSE; + if(rtl_isWanDev(cp)!=TRUE) + { + //hyking: default acl issue, direct tx now... + rtl865x_getPortlistByMac(skb->data, portlist); + } else +#endif + if (flag==FALSE) { +#if defined(CONFIG_RTL_MULTI_LAN_DEV) || defined(CONFIG_POCKET_ROUTER_SUPPORT) || defined(CONFIG_RTK_VLAN_SUPPORT) +assign_portmask: +#endif + *portlist = cp->portmask; + } + + return flag; +} +static inline int rtl_fill_txInfo(rtl_nicTx_info *txInfo) +{ + uint32 portlist; + struct sk_buff *skb = txInfo->out_skb; + struct dev_priv *cp; + cp = skb->dev->priv; + txInfo->vid = cp->id; + + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + txInfo->priority= rtl_qosGetPriorityByVid(cp->id, skb->mark); + #endif + + //default output queue is 0 + txInfo->txIdx = 0; + + if((skb->data[0]&0x01)==0) + { + if(rtl_isHwlookup(skb, cp, &portlist) == TRUE) + { + rtl_hwLookup_txInfo(txInfo); + } + else + { + rtl_direct_txInfo(portlist, txInfo); + } + } else { + /*multicast process*/ + rtl_direct_txInfo(cp->portmask,txInfo); +#if defined (CONFIG_RTL_IGMP_SNOOPING) + /*multicast process*/ + if( ((skb->data[0]==0x01) && (skb->data[1]==0x00) && (skb->data[2]==0x5e)) +#if defined (CONFIG_RTL_MLD_SNOOPING) + || ((skb->data[0]==0x33) && (skb->data[1]==0x33) && (skb->data[2]!=0xFF)) +#endif + ) + { + re865x_setMCastTxInfo(skb,cp->dev, txInfo); + } +#endif + + } + if(txInfo->portlist==0) + { + dev_kfree_skb_any(skb); + return FAILED; + } + return SUCCESS; +} + +#define RTL_NIC_TX_RETRY_MAX (128) +__MIPS16 +__IRAM_FWD +static int re865x_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int retval, tx_retry_cnt; + struct dev_priv *cp; + struct sk_buff *tx_skb; + rtl_nicTx_info nicTx; + + nicTx.out_skb = skb; + retval = rtl_preProcess_xmit(&nicTx); + + if(FAILED == retval) + { + return 0; + } + tx_skb = nicTx.out_skb; + cp = tx_skb->dev->priv; + + if((cp->id==0) || (cp->portmask ==0)) { + dev_kfree_skb_any(tx_skb); + return 0; + } + +#if defined (CONFIG_RTL_IGMP_SNOOPING) + retval = rtl_fill_txInfo(&nicTx); + if(FAILED == retval) + { + return 0; + } + +#if defined(CONFIG_RTL_QOS_PATCH) + if(((struct sk_buff *)tx_skb)->srcPhyPort == QOS_PATCH_RX_FROM_LOCAL){ + nicTx.priority = QOS_PATCH_HIGH_QUEUE_PRIO; + nicTx.txIdx=RTL865X_SWNIC_TXRING_MAX_PKTDESC-1; //use the highest tx ring index, note: not RTL865X_SWNIC_TXRING_HW_PKTDESC-1 + } +#endif + + _dma_cache_wback_inv((unsigned long) tx_skb->data, tx_skb->len); + tx_retry_cnt = 0; + while(swNic_send((void *)tx_skb, tx_skb->data, tx_skb->len, &nicTx) < 0) + { + swNic_txDone(nicTx.txIdx); + if ((tx_retry_cnt++)>RTL_NIC_TX_RETRY_MAX) { + dev_kfree_skb_any(tx_skb); + return 0; + } + } + +#else //CONFIG_RTL_IGMP_SNOOPING + #error "By default should define CONFIG_RTL_IGMP_SNOOPING" +#endif + + rtl_pstProcess_xmit(cp,tx_skb->len); + //cp->net_stats.tx_packets++; + //cp->net_stats.tx_bytes += tx_skb->len; + + return 0; +} + + +static void re865x_tx_timeout (struct net_device *dev) +{ + rtlglue_printf("Tx Timeout!!! Can't send packet\n"); +} + +#if defined(RTL819X_PRIV_IOCTL_ENABLE) + int rtl819x_get_port_status(int portnum , struct lan_port_status *port_status) +{ + uint32 regData; + uint32 data0; + + if( portnum < 0 || portnum > CPU) + return -1; + + regData = READ_MEM32(PSRP0+((portnum)<<2)); + + //printk("rtl819x_get_port_status port = %d data=%x\n", portnum,regData); //mark_debug + data0 = regData & PortStatusLinkUp; + if (data0) + port_status->link =1; + else + port_status->link =0; + + data0 = regData & PortStatusNWayEnable; + if (data0) + port_status->nway=1; + else + port_status->nway =0; + + data0 = regData & PortStatusDuplex; + if (data0) + port_status->duplex=1; + else + port_status->duplex =0; + + data0 = (regData&PortStatusLinkSpeed_MASK)>>PortStatusLinkSpeed_OFFSET; + port_status->speed = data0 ; // 0 = 10M , 1= 100M , 2=1G , + + return 0; +} + + int rtl819x_get_port_stats(int portnum , struct port_statistics *port_stats) + { + + uint32 addrOffset_fromP0 =0; + + //printk("rtl819x_get_port_stats port = %d \n", portnum); //mark_debug + if( portnum < 0 || portnum > CPU) + return -1; + + addrOffset_fromP0 = portnum * MIB_ADDROFFSETBYPORT; + + //port_stats->rx_bytes =(uint32) (rtl865xC_returnAsicCounter64( OFFSET_IFINOCTETS_P0 + addrOffset_fromP0 )) ; + port_stats->rx_bytes =rtl8651_returnAsicCounter( OFFSET_IFINOCTETS_P0 + addrOffset_fromP0 ) ; + port_stats->rx_unipkts= rtl8651_returnAsicCounter( OFFSET_IFINUCASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->rx_mulpkts= rtl8651_returnAsicCounter( OFFSET_ETHERSTATSMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->rx_bropkts= rtl8651_returnAsicCounter( OFFSET_ETHERSTATSBROADCASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->rx_discard= rtl8651_returnAsicCounter( OFFSET_DOT1DTPPORTINDISCARDS_P0 + addrOffset_fromP0 ) ; + port_stats->rx_error= (rtl8651_returnAsicCounter( OFFSET_DOT3STATSFCSERRORS_P0 + addrOffset_fromP0 ) + + rtl8651_returnAsicCounter( OFFSET_ETHERSTATSJABBERS_P0 + addrOffset_fromP0 )); + + //port_stats->tx_bytes =(uint32) (rtl865xC_returnAsicCounter64( OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0 )) ; + port_stats->tx_bytes =rtl8651_returnAsicCounter( OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0 ) ; + port_stats->tx_unipkts= rtl8651_returnAsicCounter( OFFSET_IFOUTUCASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->tx_mulpkts= rtl8651_returnAsicCounter( OFFSET_IFOUTMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->tx_bropkts= rtl8651_returnAsicCounter( OFFSET_IFOUTBROADCASTPKTS_P0 + addrOffset_fromP0 ) ; + port_stats->tx_discard= rtl8651_returnAsicCounter( OFFSET_IFOUTDISCARDS + addrOffset_fromP0 ) ; + port_stats->tx_error= (rtl8651_returnAsicCounter( OFFSET_ETHERSTATSCOLLISIONS_P0 + addrOffset_fromP0 ) + + rtl8651_returnAsicCounter( OFFSET_DOT3STATSDEFERREDTRANSMISSIONS_P0 + addrOffset_fromP0 )); + + return 0; + } + +int re865x_priv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int32 rc = 0; + unsigned long *data_32; + int portnum=0; + struct lan_port_status port_status; + struct port_statistics port_stats; + + data_32 = (unsigned long *)rq->ifr_data; + if (copy_from_user(&portnum, data_32, 1*sizeof(unsigned long))) + { + return -EFAULT; + } + + switch (cmd) + { + case RTL819X_IOCTL_READ_PORT_STATUS: + rc = rtl819x_get_port_status(portnum,&port_status); //portnumber + if(rc != 0) + return -EFAULT; + if (copy_to_user((void *)rq->ifr_data, (void *)&port_status, sizeof(struct lan_port_status))) + return -EFAULT; + break; + case RTL819X_IOCTL_READ_PORT_STATS: + rc = rtl819x_get_port_stats(portnum,&port_stats); //portnumber + if(rc != 0) + return -EFAULT; + if (copy_to_user((void *)rq->ifr_data, (void *)&port_stats, sizeof(struct port_statistics))) + return -EFAULT; + break; + break; + default : + rc = -EOPNOTSUPP; + break; + } + return SUCCESS; + +} + +#endif +int re865x_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int32 rc = 0; + unsigned long *data; + int32 args[4]; + int32 * pRet; + #if defined(CONFIG_RTL8186_KB)||defined(CONFIG_RTL8186_GR) + uint32 *pU32; + #endif + + if (cmd != SIOCDEVPRIVATE) + { + #if defined(RTL819X_PRIV_IOCTL_ENABLE) + rc = re865x_priv_ioctl(dev,rq,cmd); + return rc; + #else + goto normal; + #endif + } + + data = (unsigned long *)rq->ifr_data; + + if (copy_from_user(args, data, 4*sizeof(unsigned long))) + { + return -EFAULT; + } + + switch (args[0]) + { + +#ifdef CONFIG_RTL8196_RTL8366 + case RTL8651_IOCTL_GETWANLINKSTATUS: + { + uint32 phyNum; + uint32 linkStatus; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + phyNum=4;//8366 WAN port + rc=rtl8366rb_getPHYLinkStatus(phyNum, &linkStatus); + + if(rc==SUCCESS) + { + if(linkStatus==1) + { + *pRet = SUCCESS; + } + } + + break; + } +#else + case RTL8651_IOCTL_GETWANLINKSTATUS: + { + int i; + int wanPortMask; + int32 totalVlans; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + wanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==TRUE) + wanPortMask = vlanconfig[i].memPort; + } + + if (wanPortMask==0) + { + /* no wan port exist */ + break; + } + + for(i=0;i<RTL8651_AGGREGATOR_NUMBER;i++) + { + if( (1<<i)&wanPortMask ) + { + if((READ_MEM32(PSRP0+(i<<2))&PortStatusLinkUp)!=0) + { + *pRet = SUCCESS; + } + break; + } + } + + break; + } +#endif + case RTL8651_IOCTL_GETWANLINKSPEED: + { + int i; + int wanPortMask; + int32 totalVlans; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = FAILED; + + wanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==TRUE) + wanPortMask = vlanconfig[i].memPort; + } + + if (wanPortMask==0) + { + /* no wan port exist */ + break; + } + + for(i=0;i<RTL8651_AGGREGATOR_NUMBER;i++) + { + if( (1<<i)&wanPortMask ) + { + break; + } + } + + switch(READ_MEM32(PSRP0 + (i<<2)) & PortStatusLinkSpeed_MASK) + { + case PortStatusLinkSpeed10M: + *pRet = PortStatusLinkSpeed10M; + rc = SUCCESS; + break; + case PortStatusLinkSpeed100M: + *pRet = PortStatusLinkSpeed100M; + rc = SUCCESS; + break; + case PortStatusLinkSpeed1000M: + *pRet = PortStatusLinkSpeed1000M; + rc = SUCCESS; + break; + default: + break; + } + break; + } +#if defined(CONFIG_RTL8186_KB)|| defined(CONFIG_RTL8186_GR) + case RTL8651_IOCTL_GETLANLINKSTATUS: + { + int i; + int lanPortMask; + int32 totalVlans; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + lanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==FALSE) + { + lanPortMask = vlanconfig[i].memPort; + if (lanPortMask==0) + { + /* no wan port exist */ + continue; + } + + for(i=0;i<=RTL8651_PHY_NUMBER;i++) + { + if( (1<<i)&lanPortMask ) + { + if((READ_MEM32(PSRP0+(i<<2))&PortStatusLinkUp)!=0) + { + //rtlglue_printf("Lan port i=%d\n",i);//Added for test + *pRet = SUCCESS; + return rc; + } + } + } + } + } + + break; + } +#if defined(CONFIG_RTL8186_KB) + case RTL8651_IOCTL_GETWANTHROUGHPUT: + { + static unsigned long last_jiffies = 0; + static unsigned long last_rxtx = 0; + int i; + int32 totalVlans; + struct dev_priv *cp; + int32 *throughputLevel; + unsigned long diff_jiffies; + pRet = (int32 *)args[3]; + + diff_jiffies = (jiffies-last_jiffies); + if (diff_jiffies>HZ) + { + pU32 = (uint32*)args[1]; + throughputLevel = (uint32*)pU32[0]; + rc = SUCCESS; + + cp = NULL; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==TRUE) + { + cp = _rtl86xx_dev.dev[i]->priv; + break; + } + } + + if (cp==NULL) + { + /* no wan port exist */ + rc = FAILED; + } + + for(i=1;i<20;i++) + { + if (diff_jiffies < (HZ<<i)) + break; + } + /* get the throughput level */ + *throughputLevel = (((cp->net_stats.rx_bytes + cp->net_stats.tx_bytes)-last_rxtx)>>(17+i)); + + last_jiffies = jiffies; + last_rxtx = (cp->net_stats.rx_bytes + cp->net_stats.tx_bytes); + *pRet = SUCCESS; + } + else + { + *pRet = FAILED; + } + } +#endif +#endif +#ifdef CONFIG_RTL_LAYERED_DRIVER +#if defined(CONFIG_RTL8186_GR) + case RTL8651_IOCTL_SETWANLINKSTATUS: + { + int i; + int wanPortMask; + int32 totalVlans; + int portStatusToSet; + int forceMode; + int forceLink; + int forceLinkSpeed; + int forceDuplex; + uint32 regValue; + uint32 advCapability; + #define SPEED10M 0 + #define SPEED100M 1 + #define SPEED1000M 2 + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + pU32 = (uint32*)args[1]; + portStatusToSet = *(uint32*)pU32[0]; + + wanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==TRUE) + wanPortMask = vlanconfig[i].memPort; + } + + if (wanPortMask==0) + { + /* no wan port exist */ + break; + } + + for(i=0;i<RTL8651_AGGREGATOR_NUMBER;i++) + { + if( (1<<i)&wanPortMask ) + { + /*write register*/ + + if(HALF_DUPLEX_10M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED10M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_10M); + }else if(HALF_DUPLEX_100M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED100M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_100M); + }else if(HALF_DUPLEX_1000M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED1000M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_1000M); + }else if(DUPLEX_10M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED10M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_10M); + }else if(DUPLEX_100M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED100M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_100M); + }else if(DUPLEX_1000M == portStatusToSet) + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED1000M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_1000M); + }else if(PORT_AUTO == portStatusToSet) + { + forceMode=FALSE; + forceLink=TRUE; + /*all capality*/ + advCapability=(1<<PORT_AUTO); + + }else + { + forceMode=FALSE; + forceLink=TRUE; + } + rtl865xC_setAsicEthernetForceModeRegs(i, forceMode, forceLink, forceLinkSpeed, forceDuplex); + + /*Set PHY Register*/ + rtl8651_setAsicEthernetPHYSpeed(i,forceLinkSpeed); + rtl8651_setAsicEthernetPHYDuplex(i,forceDuplex); + rtl8651_setAsicEthernetPHYAutoNeg(i,TRUE); + rtl8651_setAsicEthernetPHYAdvCapality(i,advCapability); + rtl8651_restartAsicEthernetPHYNway(i); + break; + } + } + + break; + } + case RTL8651_IOCTL_GETLANPORTLINKSTATUS: + { + int i; + int lanPortMask; + int32 totalVlans; + int32 *lanportnum; + int32 lanPortTypeMask; + uint32 regVal; + uint32 portLinkSpeed; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + pU32 = (uint32*)args[1]; + lanportnum = (uint32*)pU32[0]; + + lanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==FALSE) + { + lanPortMask = vlanconfig[i].memPort; + if (lanPortMask==0) + { + /* no wan port exist */ + continue; + } + + for(i=0;i<=RTL8651_PHY_NUMBER;i++) + { + if( (1<<i)&lanPortMask ) + { + regVal=READ_MEM32(PSRP0+(i<<2)); + if((regVal&PortStatusLinkUp)!=0) + { + if(i==(*lanportnum)) + { + *pRet = SUCCESS; + + if((regVal&PortStatusDuplex)!=0) + { + lanPortTypeMask=1; + *pRet |= lanPortTypeMask; + } + + portLinkSpeed=regVal&PortStatusLinkSpeed_MASK; + if(PortStatusLinkSpeed100M==portLinkSpeed) + { + lanPortTypeMask=4; + *pRet |= lanPortTypeMask; + } + else if(PortStatusLinkSpeed1000M==portLinkSpeed) + { + lanPortTypeMask=8; + *pRet |= lanPortTypeMask; + } + else + { + lanPortTypeMask=2; + *pRet |= lanPortTypeMask; + } + + return rc; + } + } + } + } + } + } + + break; + } + + case RTL8651_IOCTL_GETWANPORTLINKSTATUS: + { + int i; + int wanPortMask; + int32 totalVlans; + int32 wanPortTypeMask; + uint32 regVal; + uint32 portLinkSpeed; + + pRet = (int32 *)args[3]; + *pRet = FAILED; + rc = SUCCESS; + + wanPortMask = 0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].isWan==TRUE) + wanPortMask = vlanconfig[i].memPort; + } + + if (wanPortMask==0) + { + /* no wan port exist */ + break; + } + + for(i=0;i<RTL8651_AGGREGATOR_NUMBER;i++) + { + if( (1<<i)&wanPortMask ) + { + /*check phy status link up or down*/ + rtl8651_getAsicEthernetPHYStatus(i,®Val); + if(regVal & (1<<2)) + { + regVal=READ_MEM32(PSRP0+(i<<2)); + if((regVal&PortStatusLinkUp)!=0) + { + *pRet = SUCCESS; + + if((regVal&PortStatusDuplex)!=0) + { + wanPortTypeMask=1; + *pRet |= wanPortTypeMask; + } + + portLinkSpeed=regVal&PortStatusLinkSpeed_MASK; + if(PortStatusLinkSpeed100M==portLinkSpeed) + { + wanPortTypeMask=4; + *pRet |= wanPortTypeMask; + } + else if(PortStatusLinkSpeed1000M==portLinkSpeed) + { + wanPortTypeMask=8; + *pRet |= wanPortTypeMask; + } + else + { + wanPortTypeMask=2; + *pRet |= wanPortTypeMask; + } + } + } + break; + } + } + + break; + } +#endif +#endif + default: + rc = SUCCESS; + break; + } + + return rc; +#if !defined(RTL819X_PRIV_IOCTL_ENABLE) +normal: +#endif + if (!netif_running(dev)) + return -EINVAL; + switch (cmd) + { + default: + rc = -EOPNOTSUPP; + break; + } + return rc; +} + +static int rtl865x_set_hwaddr(struct net_device *dev, void *addr) +{ + unsigned long flags; + int i; + unsigned char *p; + ps_drv_netif_mapping_t * mapp_entry; + struct rtl865x_vlanConfig *vlancfg_entry; + + p = ((struct sockaddr *)addr)->sa_data; + local_irq_save(flags); + + for (i = 0; i<ETHER_ADDR_LEN; ++i) { + dev->dev_addr[i] = p[i]; + } + + mapp_entry = rtl_get_ps_drv_netif_mapping_by_psdev(dev); + if(mapp_entry == NULL) + goto out; + + vlancfg_entry = rtl_get_vlanconfig_by_netif_name(mapp_entry->drvName); + if(vlancfg_entry == NULL) + goto out; + + if(vlancfg_entry->vid != 0) + { + rtl865x_netif_t netif; + memcpy(vlancfg_entry->mac.octet,dev->dev_addr,ETHER_ADDR_LEN); + memcpy(netif.macAddr.octet,vlancfg_entry->mac.octet,ETHER_ADDR_LEN); + memcpy(netif.name,vlancfg_entry->ifname,MAX_IFNAMESIZE); + rtl865x_setNetifMac(&netif); + } + +out: + local_irq_restore(flags); + return SUCCESS; +} + +#if defined(CONFIG_RTL8186_LINK_CHANGE) +static int rtl865x_set_link(struct net_device *dev, int enable) +{ + int32 i; + struct dev_priv *cp; + int32 portmask; + int32 totalVlans; + + cp = dev->priv; +#if defined (CONFIG_RTL_MULTI_LAN_DEV) + portmask=cp->portmask; +#else + portmask=0; + totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for(i=0;i<totalVlans;i++) + { + if(vlanconfig[i].vid==cp->id) + { + portmask = vlanconfig[i].memPort; + break; + } + } +#endif + if (portmask) + { + if (enable) + { + for(i=0;i<RTL8651_PHY_NUMBER;i++) + { + if (portmask & (1<<i)) + { + rtl865xC_setAsicEthernetForceModeRegs(i, FALSE, TRUE, 1, TRUE); + rtl8651_restartAsicEthernetPHYNway(i); + } + } + } + else + { + for(i=0;i<RTL8651_PHY_NUMBER;i++) + { + if (portmask & (1<<i)) + rtl865xC_setAsicEthernetForceModeRegs(i, TRUE, FALSE, 1, TRUE); + } + } + } + + return SUCCESS; +} +#endif + +static int rtl865x_set_mtu(struct net_device *dev, int new_mtu) +{ + unsigned long flags; + ps_drv_netif_mapping_t * mapp_entry; + struct rtl865x_vlanConfig *vlancfg_entry; + + local_irq_save(flags); + dev->mtu = new_mtu; + + mapp_entry = rtl_get_ps_drv_netif_mapping_by_psdev(dev); + if(mapp_entry == NULL) + goto out; + + vlancfg_entry = rtl_get_vlanconfig_by_netif_name(mapp_entry->drvName); + if(vlancfg_entry == NULL) + goto out; + + if(vlancfg_entry->vid !=0) + { + rtl865x_netif_t netif; + vlancfg_entry->mtu = new_mtu; + netif.mtu = new_mtu; + memcpy(netif.name,vlancfg_entry->ifname,MAX_IFNAMESIZE); + + rtl865x_setNetifMtu(&netif); + } + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + rtlglue_printf("%s:%d:new_mtu is %d\n",__FUNCTION__,__LINE__,new_mtu); + #endif + +out: + local_irq_restore(flags); + + return SUCCESS; +} + +#if defined(CONFIG_COMPAT_NET_DEV_OPS) +#else +static const struct net_device_ops rtl819x_netdev_ops = { + .ndo_open = re865x_open, + .ndo_stop = re865x_close, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = rtl865x_set_hwaddr, + .ndo_set_multicast_list = re865x_set_rx_mode, + .ndo_get_stats = re865x_get_stats, + .ndo_do_ioctl = re865x_ioctl, + .ndo_start_xmit = re865x_start_xmit, + .ndo_tx_timeout = re865x_tx_timeout, +#if defined(CP_VLAN_TAG_USED) + .ndo_vlan_rx_register = cp_vlan_rx_register, +#endif + .ndo_change_mtu = rtl865x_set_mtu, + +}; +#endif + + +#if defined (CONFIG_RTL_MLD_SNOOPING) +static int rtl865x_addAclForMldSnooping(struct rtl865x_vlanConfig* vlanConfig) +{ + int i; + #if defined (CONFIG_RTL_MULTI_LAN_DEV) || defined(CONFIG_RTK_VLAN_SUPPORT) + struct rtl865x_vlanConfig tmpVlanConfig[NETIF_NUMBER]; + #endif + struct rtl865x_vlanConfig *pVlanConfig=NULL; + rtl865x_AclRule_t rule; + int ret=FAILED; + + if(vlanConfig==NULL) + { + return FAILED; + } + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined(CONFIG_RTK_VLAN_SUPPORT) + re865x_packVlanConfig(vlanConfig, tmpVlanConfig); + pVlanConfig=tmpVlanConfig; +#else + pVlanConfig=vlanConfig; +#endif + + for(i=0; pVlanConfig[i].vid != 0; i++) + { + if (IF_ETHER!=pVlanConfig[i].if_type) + { + continue; + } + + + if(pVlanConfig[i].isWan==0)/*lan config*/ + { + rtl865x_regist_aclChain(pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED, RTL865X_ACL_INGRESS); + /*ping6 issue*/ + bzero((void*)&rule,sizeof(rtl865x_AclRule_t)); + rule.ruleType_ = RTL865X_ACL_MAC; + rule.actionType_ = RTL865X_ACL_PERMIT; + rule.pktOpApp_ = RTL865X_ACL_ALL_LAYER; + rule.dstMac_.octet[0]=0x33; + rule.dstMac_.octet[1]=0x33; + rule.dstMac_.octet[2]=0xFF; + + rule.dstMacMask_.octet[0]=0xFF; + rule.dstMacMask_.octet[1]=0xFF; + rule.dstMacMask_.octet[2]=0xFF; + + ret= rtl865x_add_acl(&rule, pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED); + + /*ipv6 multicast data issue*/ + bzero((void*)&rule,sizeof(rtl865x_AclRule_t)); + rule.ruleType_ = RTL865X_ACL_MAC; + rule.actionType_ = RTL865X_ACL_TOCPU; + rule.pktOpApp_ = RTL865X_ACL_ALL_LAYER; + rule.dstMac_.octet[0]=0x33; + rule.dstMac_.octet[1]=0x33; + rule.dstMac_.octet[2]=0x00; + rule.dstMac_.octet[3]=0x00; + rule.dstMac_.octet[4]=0x00; + rule.dstMac_.octet[5]=0x00; + + rule.dstMacMask_.octet[0]=0xFF; + rule.dstMacMask_.octet[1]=0xFF; + + ret= rtl865x_add_acl(&rule, pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED); + + } + else/*wan config*/ + { + rtl865x_regist_aclChain(pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED, RTL865X_ACL_INGRESS); + /*ipv6 multicast data issue*/ + bzero((void*)&rule,sizeof(rtl865x_AclRule_t)); + rule.ruleType_ = RTL865X_ACL_MAC; + rule.actionType_ = RTL865X_ACL_TOCPU; + rule.pktOpApp_ = RTL865X_ACL_ALL_LAYER; + rule.dstMac_.octet[0]=0x33; + rule.dstMac_.octet[1]=0x33; + rule.dstMac_.octet[2]=0x00; + rule.dstMac_.octet[3]=0x00; + rule.dstMac_.octet[4]=0x00; + rule.dstMac_.octet[5]=0x00; + + rule.dstMacMask_.octet[0]=0xFF; + rule.dstMacMask_.octet[1]=0xFF; + + ret= rtl865x_add_acl(&rule, pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED); + + } + + #if defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) + #else + rtl865x_reConfigDefaultAcl(pVlanConfig[i].ifname); + #endif + } + + return SUCCESS; +} + +static int rtl865x_removeAclForMldSnooping(struct rtl865x_vlanConfig* vlanConfig) +{ + int i; + #if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined(CONFIG_RTK_VLAN_SUPPORT) + struct rtl865x_vlanConfig tmpVlanConfig[NETIF_NUMBER]; + #endif + + struct rtl865x_vlanConfig *pVlanConfig=NULL; + + if(vlanConfig==NULL) + { + return FAILED; + } +#if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined(CONFIG_RTK_VLAN_SUPPORT) + re865x_packVlanConfig(vlanConfig, tmpVlanConfig); + pVlanConfig=tmpVlanConfig; +#else + pVlanConfig=vlanConfig; +#endif + + for(i=0; pVlanConfig[i].vid != 0; i++) + { + if (IF_ETHER!=pVlanConfig[i].if_type) + { + continue; + } + + if(pVlanConfig[i].isWan==0)/*lan config*/ + { + rtl865x_unRegist_aclChain(pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED, RTL865X_ACL_INGRESS); + } + else/*wan config*/ + { + rtl865x_unRegist_aclChain(pVlanConfig[i].ifname, RTL865X_ACL_IPV6_USED, RTL865X_ACL_INGRESS); + } + + } + +#if defined (CONFIG_RTL_IPTABLES_RULE_2_ACL) + +#else +#if defined (CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable==0) + { + rtl865x_setDefACLForAllNetif(RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL); + } + else + { + rtl865x_setDefACLForAllNetif(RTL865X_ACLTBL_ALL_TO_CPU, RTL865X_ACLTBL_ALL_TO_CPU, RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL); + } +#else + rtl865x_setDefACLForAllNetif(RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL, RTL865X_ACLTBL_PERMIT_ALL); +#endif +#endif + + return SUCCESS; +} +#endif + + +#if !defined(CONFIG_COMPAT_NET_DEV_OPS) && (defined(CONFIG_RTL_CUSTOM_PASSTHRU) || defined(CONFIG_RTL_STP)) +static const struct net_device_ops rtl819x_pseudodev_ops = { + .ndo_open = re865x_pseudo_open, + .ndo_stop = re865x_pseudo_close, + + .ndo_get_stats = re865x_get_stats, + .ndo_do_ioctl = re865x_ioctl, + .ndo_start_xmit = re865x_start_xmit, +}; +#endif + +int __init re865x_probe (void) +{ +/*2007-12-19*/ + int32 i, j; + int32 totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; +#if defined (CONFIG_RTL_IGMP_SNOOPING) + int32 retVal; + int32 igmpInitFlag=FAILED; + struct rtl_mCastSnoopingGlobalConfig mCastSnoopingGlobalConfig; + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + rtl865x_mCastConfig_t mCastConfig; + #endif +#endif +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) || defined(CONFIG_RTK_VLAN_SUPPORT) + struct proc_dir_entry *res_stats_root; +#endif + +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) + struct proc_dir_entry *rtk_link_status_entry; +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + struct proc_dir_entry *res_stats; + struct proc_dir_entry *rtk_vlan_support_entry; +#if defined(CONFIG_819X_PHY_RW)//#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) + uint32 portnum; + char port_mibEntry_name[10]; + struct proc_dir_entry *rtl_phy; + struct proc_dir_entry *port_mibStats_root; + struct proc_dir_entry *port_mibStats_entry; +#endif //#if defined(CONFIG_819X_PHY_RW) +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + struct rtl865x_interface_info ifInfo; +#endif + +#if defined(PATCH_GPIO_FOR_LED) + int port; +#endif + //WRITE_MEM32(PIN_MUX_SEL_2, 0x7<<21); + + rtlglue_printf("\n\n\nProbing RTL8186 10/100 NIC-kenel stack size order[%d]...\n", THREAD_SIZE_ORDER); + REG32(CPUIIMR) = 0x00; + REG32(CPUICR) &= ~(TXCMD | RXCMD); + rxMbufRing=NULL; + + /*Initial ASIC table*/ +#ifdef CONFIG_RTL8198_REVISION_B + if (REG32(BSP_REVR) >= BSP_RTL8198_REVISION_B) + { + REG32(SYS_CLK_MAG)&=(~(SYS_SW_RESET)); + mdelay(300); + REG32(SYS_CLK_MAG)|=(SYS_SW_RESET); + mdelay(50); + } + else +#endif + FullAndSemiReset(); + + { + rtl8651_tblAsic_InitPara_t para; + + memset(¶, 0, sizeof(rtl8651_tblAsic_InitPara_t)); + + /* + For DEMO board layout, RTL865x platform define corresponding PHY setting and PHYID. + */ + + rtl865x_wanPortMask = RTL865X_PORTMASK_UNASIGNED; + + INIT_CHECK(rtl865x_initAsicL2(¶)); + +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER_L3 + INIT_CHECK(rtl865x_initAsicL3()); +#endif +#if defined(CONFIG_RTL_LAYERED_ASIC_DRIVER_L4) && defined(CONFIG_RTL_8198) + INIT_CHECK(rtl865x_initAsicL4()); +#endif + + /* + Re-define the wan port according the wan port detection result. + NOTE: + There are a very strong assumption that if port5 was giga port, + then wan port was port 5. + */ + if (RTL865X_PORTMASK_UNASIGNED==rtl865x_wanPortMask) + { + /* keep the original mask */ + assert(RTL865X_PORTMASK_UNASIGNED==rtl865x_lanPortMask); + rtl865x_wanPortMask = RTL_WANPORT_MASK; + rtl865x_lanPortMask = RTL_LANPORT_MASK; + } + else + { + /* redefine wan port mask */ + assert(RTL865X_PORTMASK_UNASIGNED!=rtl865x_lanPortMask); + for(i=0;i<totalVlans;i++) + { + if (TRUE==vlanconfig[i].isWan) + { + vlanconfig[i].memPort = vlanconfig[i].untagSet = rtl865x_wanPortMask; + } + else + { + vlanconfig[i].memPort = vlanconfig[i].untagSet = rtl865x_lanPortMask; + } + } + } +#if 1 /* 10/100 & giga use the same pre-allocated skb number */ + /* + Re-define the pre-allocated skb number according the wan + port detection result. + NOTE: + There are a very strong assumption that if port1~port4 were + all giga port, then the sdram was 32M. + */ + { + if (RTL865X_PREALLOC_SKB_UNASIGNED==rtl865x_maxPreAllocRxSkb) + { + assert(rtl865x_rxSkbPktHdrDescNum== + rtl865x_txSkbPktHdrDescNum== + RTL865X_PREALLOC_SKB_UNASIGNED); + + rtl865x_maxPreAllocRxSkb = MAX_PRE_ALLOC_RX_SKB; + rtl865x_rxSkbPktHdrDescNum = NUM_RX_PKTHDR_DESC; + rtl865x_txSkbPktHdrDescNum = NUM_TX_PKTHDR_DESC; + } + else + { + assert(rtl865x_rxSkbPktHdrDescNum!=RTL865X_PREALLOC_SKB_UNASIGNED); + assert(rtl865x_txSkbPktHdrDescNum!=RTL865X_PREALLOC_SKB_UNASIGNED); + /* Assigned value in function of rtl8651_initAsic() */ + rxRingSize[0] = rtl865x_rxSkbPktHdrDescNum; + txRingSize[0] = rtl865x_txSkbPktHdrDescNum; + } + + for(i=1;i<RTL865X_SWNIC_RXRING_HW_PKTDESC;i++) + { + rtl865x_maxPreAllocRxSkb += rxRingSize[i]; + } + } +#else + { + rtl865x_maxPreAllocRxSkb = MAX_PRE_ALLOC_RX_SKB; + rtl865x_rxSkbPktHdrDescNum = NUM_RX_PKTHDR_DESC; + rtl865x_txSkbPktHdrDescNum = NUM_TX_PKTHDR_DESC; + } +#endif + } + + +#ifdef BR_SHORTCUT + cached_dev=NULL; +#endif + /*init PHY LED style*/ +#if defined(CONFIG_RTL865X_BICOLOR_LED) + #ifdef BICOLOR_LED_VENDOR_BXXX + REG32(LEDCR) |= (1 << 19); // 5 ledmode set to 1 for bi-color LED + REG32(PABCNR) &= ~0x001f0000; /* set port port b-4/3/2/1/0 to gpio */ + REG32(PABDIR) |= 0x001f0000; /* set port port b-4/3/2/1/0 gpio direction-output */ + #else + //8650B demo board default: Bi-color 5 LED + WRITE_MEM32(LEDCR, READ_MEM32(LEDCR) | 0x01180000 ); // bi-color LED + #endif + /* config LED mode */ + WRITE_MEM32(SWTAA, PORT5_PHY_CONTROL); + WRITE_MEM32(TCR0, 0x000002C2); //8651 demo board default: 15 LED boards + WRITE_MEM32(SWTACR, CMD_FORCE | ACTION_START); // force add +#else /* CONFIG_RTL865X_BICOLOR_LED */ + + /* config LED mode */ + WRITE_MEM32(LEDCR, 0x00000000 ); // 15 LED + WRITE_MEM32(SWTAA, PORT5_PHY_CONTROL); + WRITE_MEM32(TCR0, 0x000002C7); //8651 demo board default: 15 LED boards + WRITE_MEM32(SWTACR, CMD_FORCE | ACTION_START); // force add +#endif /* CONFIG_RTL865X_BICOLOR_LED */ + +/*2007-12-19*/ +#if defined(CONFIG_RTK_VLAN_SUPPORT) + //port based decision + rtl865xC_setNetDecisionPolicy(NETIF_PORT_BASED); + WRITE_MEM32(PLITIMR,0); + +#endif + + + INIT_CHECK(rtl865x_init()); + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) || defined(CONFIG_RTK_VLAN_SUPPORT) + re865x_packVlanConfig(vlanconfig, packedVlanConfig); + INIT_CHECK(rtl865x_config(packedVlanConfig)); +#else + INIT_CHECK(rtl865x_config(vlanconfig)); +#endif + + /* create all default VLANs */ +// rtlglue_printf(" creating eth0~eth%d...\n",totalVlans-1 ); +#if defined (CONFIG_RTL_IGMP_SNOOPING) + memset(&mCastSnoopingGlobalConfig, 0, sizeof(struct rtl_mCastSnoopingGlobalConfig)); + mCastSnoopingGlobalConfig.maxGroupNum=256; + mCastSnoopingGlobalConfig.maxSourceNum=300; + mCastSnoopingGlobalConfig.hashTableSize=64; + + mCastSnoopingGlobalConfig.groupMemberAgingTime=260; + mCastSnoopingGlobalConfig.lastMemberAgingTime=2; + mCastSnoopingGlobalConfig.querierPresentInterval=260; + + mCastSnoopingGlobalConfig.dvmrpRouterAgingTime=120; + mCastSnoopingGlobalConfig.mospfRouterAgingTime=120; + mCastSnoopingGlobalConfig.pimRouterAgingTime=120; + + igmpInitFlag=rtl_initMulticastSnooping(mCastSnoopingGlobalConfig); +#endif + + for(i=0;i<totalVlans;i++) + { + struct net_device *dev; + struct dev_priv *dp; + int rc; + + if (IF_ETHER!=vlanconfig[i].if_type) + { + continue; + } + dev = alloc_etherdev(sizeof(struct dev_priv)); + if (!dev) { + printk("failed to allocate dev %d", i); + return -1; + } + SET_MODULE_OWNER(dev); + dp = dev->priv; + memset(dp,0,sizeof(*dp)); + dp->dev = dev; + dp->id = vlanconfig[i].vid; + dp->portmask = vlanconfig[i].memPort; + dp->portnum = 0; + #if defined(CONFIG_RTK_VLAN_SUPPORT) + dp->vlan_setting.is_lan = (dp->id!=RTL_WANVLANID); + #endif + for(j=0;j<RTL8651_AGGREGATOR_NUMBER;j++){ + if(dp->portmask & (1<<j)) + dp->portnum++; + } + + memcpy((char*)dev->dev_addr,(char*)(&(vlanconfig[i].mac)),ETHER_ADDR_LEN); +#if defined(CONFIG_COMPAT_NET_DEV_OPS) + dev->open = re865x_open; + dev->stop = re865x_close; + dev->set_multicast_list = re865x_set_rx_mode; + dev->hard_start_xmit = re865x_start_xmit; + dev->get_stats = re865x_get_stats; + dev->do_ioctl = re865x_ioctl; + dev->tx_timeout = re865x_tx_timeout; + dev->set_mac_address = rtl865x_set_hwaddr; + dev->change_mtu = rtl865x_set_mtu; +#if defined(CONFIG_RTL8186_LINK_CHANGE) + dev->change_link = rtl865x_set_link; +#endif +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = cp_vlan_rx_register; + dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid; +#endif + +#else + dev->netdev_ops = &rtl819x_netdev_ops; +#endif + dev->watchdog_timeo = TX_TIMEOUT; +#if 0 + dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; +#endif +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + + dev->irq = BSP_SWCORE_IRQ; + rc = register_netdev(dev); + if(!rc){ + _rtl86xx_dev.dev[i]=dev; + rtl_add_ps_drv_netif_mapping(dev,vlanconfig[i].ifname); + /*2007-12-19*/ + rtlglue_printf("eth%d added. vid=%d Member port 0x%x...\n", i,vlanconfig[i].vid ,vlanconfig[i].memPort ); + }else + rtlglue_printf("Failed to allocate eth%d\n", i); + +#if defined(CONFIG_RTK_VLAN_SUPPORT) || defined(CONFIG_RTL_REPORT_LINK_STATUS) + res_stats_root = proc_mkdir(dev->name, NULL); + if (res_stats_root == NULL) + { + printk("proc_mkdir failed!\n"); + } +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + if ((res_stats = create_proc_read_entry("mib_vlan", 0644, res_stats_root, + read_proc_vlan, (void *)dev)) == NULL) + { + printk("create_proc_read_entry failed!\n"); + } + res_stats->write_proc = write_proc_vlan; + +#endif + +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) + /*FIXME if mutliple-WAN*/ + wan_linkStatus[0]=0; + rtk_link_status_entry=create_proc_entry("up_flag",0,res_stats_root); + if(rtk_link_status_entry) + { + rtk_link_status_entry->read_proc=rtk_link_status_read; + rtk_link_status_entry->write_proc=rtk_link_status_write; + } +#endif + + + } + +#if defined(CONFIG_RTL_MULTIPLE_WAN) + retVal = rtl_config_multipleWan_netif(RTL_MULTIWAN_ADD); + rtl_regist_multipleWan_dev(); +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) + retVal=rtl_registerIgmpSnoopingModule(&nicIgmpModuleIndex); + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + if(retVal==SUCCESS) + { + rtl_multicastDeviceInfo_t devInfo; + memset(&devInfo, 0 , sizeof(rtl_multicastDeviceInfo_t)); + strcpy(devInfo.devName, "eth*"); + for(i=0;i<totalVlans;i++) + { + if( vlanconfig[i].if_type==IF_ETHER) + { + devInfo.portMask|=vlanconfig[i].memPort; + } + } + devInfo.swPortMask=devInfo.portMask & (~ ((1<<RTL8651_MAC_NUMBER)-1)); + rtl_setIgmpSnoopingModuleDevInfo(nicIgmpModuleIndex, &devInfo); + } + #endif + rtl_setIpv4UnknownMCastFloodMap(nicIgmpModuleIndex, 0x0); + rtl_setIpv6UnknownMCastFloodMap(nicIgmpModuleIndex, 0xFFFFFFFF); + + curLinkPortMask=rtl865x_getPhysicalPortLinkStatus(); + + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + memset(&mCastConfig, 0, sizeof(rtl865x_mCastConfig_t)); + for(i=0;i<totalVlans;i++) + { + if (TRUE==vlanconfig[i].isWan) + { + mCastConfig.externalPortMask |=vlanconfig[i].memPort; + } + } + rtl865x_initMulticast(&mCastConfig); + + #endif +#endif + +#ifdef CONFIG_RTL_STP + printk("Configuration ether driver to process port 0 ~ port %d for Spanning tree process\n",MAX_RE865X_ETH_STP_PORT-1); + //Initial: disable Realtek Hardware STP + rtl865x_setSpanningEnable(FALSE); + + for ( i = 0 ; i < MAX_RE865X_ETH_STP_PORT; i ++ ) + { + struct net_device *dev; + struct dev_priv *dp; + int rc; + struct re865x_priv *rp; + + rp = &_rtl86xx_dev; + dev = alloc_etherdev(sizeof(struct dev_priv)); + if (!dev){ + rtlglue_printf("failed to allocate dev %d", i); + return -1; + } + strcpy(dev->name, "port%d"); + memcpy((char*)dev->dev_addr,(char*)(&(vlanconfig[0].mac)),ETHER_ADDR_LEN); + dp = dev->priv; + memset(dp,0,sizeof(*dp)); + dp->dev = dev; +#ifdef CONFIG_COMPAT_NET_DEV_OPS + dev->open = re865x_pseudo_open; + dev->stop = re865x_pseudo_close; + dev->set_multicast_list = NULL; + dev->hard_start_xmit = re865x_start_xmit; + dev->get_stats = re865x_get_stats; + dev->do_ioctl = re865x_ioctl; + dev->tx_timeout = NULL; +#else + dev->netdev_ops = &rtl819x_pseudodev_ops; +#endif + dev->watchdog_timeo = TX_TIMEOUT; + dev->irq = 0; /* virtual interfaces has no IRQ allocated */ + rc = register_netdev(dev); + if (rc == 0) + { + _rtl86xx_dev.stp_port[i] = dev; + printk("=> [stp pseudo port%d] done\n", i); + } else + { + printk("=> Failed to register [stp pseudo port%d]", i); + return -1; + } + } + + re865x_stp_mapping_init(); + +#endif +#if defined(CONFIG_RTL_HW_STP) + //Initial: disable Realtek Hardware STP + rtl865x_setSpanningEnable(FALSE); +#endif + + ((struct dev_priv*)((_rtl86xx_dev.dev[0])->priv))->dev_next = _rtl86xx_dev.dev[1]; + ((struct dev_priv*)((_rtl86xx_dev.dev[1])->priv))->dev_prev = _rtl86xx_dev.dev[0]; + +#if defined(CONFIG_RTL_ETH_PRIV_SKB) + init_priv_eth_skb_buf(); +#endif + +#if (defined(CONFIG_RTL_CUSTOM_PASSTHRU) && !defined(CONFIG_RTL8196_RTL8366)) + //cary + rtl8651_customPassthru_init(); +#endif + rtl8651_initStormCtrl(); + +#if (defined(CONFIG_RTL_8198)) + // initial proc for phyRegTest + phyRegTest_init(); +#endif + +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER_L3 +#if defined (CONFIG_RTL_HARDWARE_MULTICAST) + rtl8651_setAsicMulticastEnable(TRUE); +#else + rtl8651_setAsicMulticastEnable(FALSE); +#endif +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + + rtk_vlan_support_enable= 0; + rtk_vlan_support_entry=create_proc_entry("rtk_vlan_support",0,NULL); + if (rtk_vlan_support_entry) + { + rtk_vlan_support_entry->read_proc=rtk_vlan_support_read; + rtk_vlan_support_entry->write_proc=rtk_vlan_support_write; + } +#endif + +#if defined(CONFIG_819X_PHY_RW) +//#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) + rtl_phy = create_proc_entry("rtl_phy_status",0,NULL); + if(rtl_phy) + { + rtl_phy->read_proc = rtl_phy_status_read; + rtl_phy->write_proc = rtl_phy_status_write; + } + port_mibStats_root = proc_mkdir("ethPort_mibStats", NULL); + if (port_mibStats_root == NULL) + { + printk("proc_mkdir failed!\n"); + } + for(portnum=0; portnum<CPU; portnum++) + { + sprintf(&port_mibEntry_name[0], "port%u", portnum); + port_mibStats_entry = create_proc_entry(port_mibEntry_name, 0, port_mibStats_root); + port_mibStats_entry->data = (void *)portnum; + if(port_mibStats_entry) + { + port_mibStats_entry->read_proc = port_mibStats_read_proc; + port_mibStats_entry->write_proc = port_mibStats_write_proc; + } + } +#endif //#if defined(CONFIG_819X_PHY_RW) + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + rtl865x_initLocalPublic(NULL); + + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); +#if defined(CONFIG_RTL_PUBLIC_SSID) + strcpy(ifInfo.ifname,RTL_GW_WAN_DEVICE_NAME); +#else + strcpy(ifInfo.ifname, RTL_DRV_WAN0_NETIF_NAME); +#endif + ifInfo.isWan=1; + for(i=0;i<totalVlans;i++) + { + if ((TRUE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort |= vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); + + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + strcpy(ifInfo.ifname,RTL_DRV_LAN_NETIF_NAME); + ifInfo.isWan=0; + for(i=0;i<totalVlans;i++) + { + if ((FALSE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort|=vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); +#endif + rtl_rxTxDoneCnt=0; + atomic_set(&rtl_devOpened, 0); + +#if defined(PATCH_GPIO_FOR_LED) + for (port=0; port<RTL8651_PHY_NUMBER; port++) + init_led_ctrl(port); +#endif + +#if defined(CONFIG_RTL_LINKSTATE) + initPortStateCtrl(); +#endif + +#if defined (CONFIG_RTL_MLD_SNOOPING) + rtl8651_initMldSnooping(); +#endif +#if defined (CONFIG_RTL_PHY_POWER_CTRL) + rtl865x_initPhyPowerCtrl(); +#endif + +#if defined(RTL_CPU_QOS_ENABLED) + highPrioRxTryCnt = MAX_HIGH_PRIO_TRY; + highestPriority = 0; + cpuQosHoldLow = 0; + totalLowQueueCnt = 0; + memset(pktQueueByPri, 0, sizeof(rtl_queue_entry)*(RTL865X_SWNIC_RXRING_MAX_PKTDESC)); +#endif + + rtl865x_config_callback_for_get_drv_netifName(rtl_get_ps_drv_netif_mapping_by_psdev_name); +#if defined (CONFIG_RTL_REINIT_SWITCH_CORE) + rtl865x_creatReInitSwitchCoreProc(); +#endif + + #if defined(RX_TASKLET) + rtl_rx_tasklet_running=0; + #endif + #if defined(TX_TASKLET) + rtl_tx_tasklet_running=0; + #endif + + return 0; +} + +#if defined(CONFIG_RTL_ETH_PRIV_SKB) + +//--------------------------------------------------------------------------- +static void init_priv_eth_skb_buf(void) +{ + int i; + + DEBUG_ERR("Init priv skb.\n"); + memset(eth_skb_buf, '\0', sizeof(struct priv_skb_buf2)*(MAX_ETH_SKB_NUM)); + INIT_LIST_HEAD(ð_skbbuf_list); + eth_skb_free_num=MAX_ETH_SKB_NUM; + + for (i=0; i<MAX_ETH_SKB_NUM; i++) { + memcpy(eth_skb_buf[i].magic, ETH_MAGIC_CODE, ETH_MAGIC_LEN); + eth_skb_buf[i].buf_pointer = (void*)(ð_skb_buf[i]); + INIT_LIST_HEAD(ð_skb_buf[i].list); + list_add_tail(ð_skb_buf[i].list, ð_skbbuf_list); + } +} + +static __inline__ unsigned char *get_buf_from_poll(struct list_head *phead, unsigned int *count) +{ + unsigned long flags; + unsigned char *buf; + struct list_head *plist; + + local_irq_save(flags); + + if (list_empty(phead)) { + local_irq_restore(flags); + DEBUG_ERR("eth_drv: phead=%X buf is empty now!\n", (unsigned int)phead); + DEBUG_ERR("free count %d\n", *count); + return NULL; + } + + if (*count == 1) { + local_irq_restore(flags); + DEBUG_ERR("eth_drv: phead=%X under-run!\n", (unsigned int)phead); + return NULL; + } + + *count = *count - 1; + plist = phead->next; + list_del_init(plist); + buf = (unsigned char *)((unsigned int)plist + sizeof (struct list_head)); + local_irq_restore(flags); + return buf; +} + +static __inline__ void release_buf_to_poll(unsigned char *pbuf, struct list_head *phead, unsigned int *count) +{ + unsigned long flags; + struct list_head *plist; + + local_irq_save(flags); + + *count = *count + 1; + plist = (struct list_head *)((unsigned int)pbuf - sizeof(struct list_head)); + list_add_tail(plist, phead); + local_irq_restore(flags); +} + +__IRAM_GEN void free_rtl865x_eth_priv_buf(unsigned char *head) +{ + #ifdef DELAY_REFILL_ETH_RX_BUF + if (FAILED==return_to_rx_pkthdr_ring(head)) + #endif + {release_buf_to_poll(head, ð_skbbuf_list, (unsigned int *)ð_skb_free_num);} +} + +__MIPS16 +__IRAM_FWD +static struct sk_buff *dev_alloc_skb_priv_eth(unsigned int size) +{ + struct sk_buff *skb; + unsigned char *data; + + /* first argument is not used */ + if(eth_skb_free_num>0) + { + data = get_buf_from_poll(ð_skbbuf_list, (unsigned int *)ð_skb_free_num); + if (data == NULL) { + DEBUG_ERR("eth_drv: priv_skb buffer empty!\n"); + return NULL; + } + + skb = dev_alloc_8190_skb(data, size); + + if (skb == NULL) { + //free_rtl865x_eth_priv_buf(data); + release_buf_to_poll(data, ð_skbbuf_list, (unsigned int *)ð_skb_free_num); + DEBUG_ERR("alloc linux_skb buff failed!\n"); + return NULL; + } + return skb; + } + + return NULL; +} + +__MIPS16 +__IRAM_FWD +int is_rtl865x_eth_priv_buf(unsigned char *head) +{ + unsigned long offset = (unsigned long)(&((struct priv_skb_buf2 *)0)->buf); + struct priv_skb_buf2 *priv_buf = (struct priv_skb_buf2 *)(((unsigned long)head) - offset); + + if ((!memcmp(priv_buf->magic, ETH_MAGIC_CODE, ETH_MAGIC_LEN)) && + (priv_buf->buf_pointer==(void*)(priv_buf))) { + return 1; + } + else { + return 0; + } +} + +#if defined(CONFIG_RTL_ETH_PRIV_SKB) || defined(CONFIG_NET_WIRELESS_AGN) || defined(CONFIG_NET_WIRELESS_AG) +struct sk_buff *priv_skb_copy(struct sk_buff *skb) +{ + struct sk_buff *n; + unsigned long flags; + + if (rx_skb_queue.qlen == 0) { + n = dev_alloc_skb_priv_eth(CROSS_LAN_MBUF_LEN); + } + else { + #if defined(RTK_QUE) + local_irq_save(flags); + n = rtk_dequeue(&rx_skb_queue); + local_irq_restore(flags); + #else + n = __skb_dequeue(&rx_skb_queue); + #endif + } + + if (n == NULL) { + return NULL; + } + + /* Set the tail pointer and length */ + skb_put(n, skb->len); + n->csum = skb->csum; + n->ip_summed = skb->ip_summed; + memcpy(n->data, skb->data, skb->len); + + copy_skb_header(n, skb); + return n; +} +EXPORT_SYMBOL(priv_skb_copy); +#endif // defined(CONFIG_NET_WIRELESS_AGN) || defined(CONFIG_NET_WIRELESS_AG) +#endif // CONFIG_RTL_ETH_PRIV_SKB + +static void __exit re865x_exit (void) +{ + +#ifdef RTL865X_DRIVER_DEBUG_FLAG + rtl865x_proc_debug_cleanup(); +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NET_SCHED) && defined(CONFIG_RTL_LAYERED_DRIVER) +#if defined(CONFIG_RTL_HW_QOS_SUPPORT) + rtl865x_exitOutputQueue(); +#endif +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) + rtl_exitMulticastSnooping(); +#endif + +#if defined(CONFIG_RTL_LINKSTATE) + exitPortStateCtrl(); +#endif + return; +} + +module_init(re865x_probe); +module_exit(re865x_exit); + +/* +@func enum RTL_RESULT | rtl865x_init | Initialize light rome driver and RTL865x ASIC. +@rvalue RTL_SUCCESS | Initial success. +@comm + Its important to call this API before using the driver. Note taht you can not call this API twice ! +*/ +int32 rtl865x_init(void) +{ + int32 retval = 0; + + + __865X_Config = 0; + +#ifdef CONFIG_RTL8196_RTL8366 + /* configure 8366 */ + { + int ret; + int i; + rtl8366rb_phyAbility_t phy; + + REG32(PEFGHCNR_REG) = REG32(PEFGHCNR_REG)& (~(1<<11) ); //set byte F GPIO3 = gpio + REG32(PEFGHDIR_REG) = REG32(PEFGHDIR_REG) | (1<<11); //0 input, 1 output, set F bit 3 output + REG32(PEFGHDAT_REG) = REG32(PEFGHDAT_REG) |( (1<<11) ); //F3 GPIO + mdelay(150); + + ret = smi_init(GPIO_PORT_F, 2, 1); + ret = rtl8366rb_initChip(); + ret = rtl8366rb_initVlan(); + ret = smi_write(0x0f09, 0x0020); + ret = smi_write(0x0012, 0xe0ff); + + memset(&phy, 0, sizeof(rtl8366rb_phyAbility_t)); + phy.Full_1000 = 1; + phy.Full_100 = 1; + phy.Full_10 = 1; + phy.Half_100 = 1; + phy.Half_10 = 1; + phy.FC = 1; + phy.AsyFC = 1; + phy.AutoNegotiation = 1; + for(i=0;i<5;i++) + { + ret = rtl8366rb_setEthernetPHY(i,&phy); + } + } + + REG32(0xb8010000)=REG32(0xb8010000)&(0x20000000); + REG32(0xbb80414c)=0x00037d16; + REG32(0xbb804100)=1; + REG32(0xbb804104)=0x00E80367; +#endif + +/*common*/ + retval = rtl865x_initNetifTable(); + retval = rtl865x_initVlanTable(); +#ifdef CONFIG_RTL_LAYERED_DRIVER_ACL + retval = rtl865x_init_acl(); +#endif + retval = rtl865x_initEventMgr(NULL); + +/*l2*/ + #ifdef CONFIG_RTL_LAYERED_DRIVER_L2 + retval = rtl865x_layer2_init(); + #endif + + +/*layer3*/ +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + retval = rtl865x_initIpTable(); + retval = rtl865x_initPppTable(); + retval = rtl865x_initRouteTable(); + retval = rtl865x_initNxtHopTable(); + retval = rtl865x_arp_init(); +#endif + +/*layer4*/ +#if defined(CONFIG_RTL_LAYERED_DRIVER_L4) && defined(CONFIG_RTL_8198) + rtl865x_nat_init(); +#endif + + /*queue id & rx ring descriptor mapping*/ + /*queue id & rx ring descriptor mapping*/ + REG32(CPUQDM0)=QUEUEID1_RXRING_MAPPING|(QUEUEID0_RXRING_MAPPING<<16); + REG32(CPUQDM2)=QUEUEID3_RXRING_MAPPING|(QUEUEID2_RXRING_MAPPING<<16); + REG32(CPUQDM4)=QUEUEID5_RXRING_MAPPING|(QUEUEID4_RXRING_MAPPING<<16); + + rtl8651_setAsicOutputQueueNumber(CPU, RTL_CPU_RX_RING_NUM); + +#ifdef RTL865X_DRIVER_DEBUG_FLAG + rtl865x_proc_debug_init(); +#endif + +#if defined(PATCH_GPIO_FOR_LED) + rtl8651_resetAllAsicMIBCounter(); +#endif + + rtl_ps_drv_netif_mapping_init(); + + return SUCCESS; +} + + + +/* +@func enum RTL_RESULT | rtl865x_config | Configure light rome driver. Create VLAN and Network interface. +@parm struct rtl865x_vlanConfig * | vlanconfig | +@rvlaue RTL_SUCCESS | Sucessful configuration. +@rvalue RTL_INVVID | Invalid VID. +@comm + struct rtl865x_vlanConfig is defined as follows: + + ifname: Layer 3 Network Interface name, eg: eth0, eth1, ppp0...etc,. If it is specified, both layer 2 vlan and layer 3 + netwrok interface are created and bound together. It also can be a NULL value. In this case, only a layer 2 VLAN + is created. + isWan: 1 for WAN interface and 0 for LAN interface in a layer 4 mode. + if_type: IF_ETHER sets a network interface to be ETHER type. Instead, IF_PPPOE sets a netwrok to be PPPoE type. + This field is meaningful only when the ifname is specified. + vid: VLAN ID to create a vlan. + memPort: VLAN member port. + untagSet: VLAN untag Set. + mtu: MTU. + mac: MAC address of the VLAN or network interface. + eg1: + + struct rtl865x_vlanConfig vlanconfig[] = { + { "eth0", 1, IF_ETHER, 8, 1, 0x01, 0x01, 1500, { { 0x00, 0x00, 0xda, 0xcc, 0xcc, 0x08 } } }, + { "eth1", 0, IF_ETHER, 9, 1, 0x1e, 0x1e, 1500, { { 0x00, 0x00, 0xda, 0xcc, 0xcc, 0x09 } } }, + + LRCONFIG_END, + } +*/ +int32 rtl865x_config(struct rtl865x_vlanConfig vlanconfig[]) +{ + uint16 pvid; + int32 i, j; + int32 retval = 0; + uint32 valid_port_mask = 0; + + if (!vlanconfig[0].vid) + return RTL_EINVALIDVLANID; + + INIT_CHECK(rtl8651_setAsicOperationLayer(2)); + + for(i=0; vlanconfig[i].vid != 0; i++) + { + rtl865x_netif_t netif; + + if(vlanconfig[i].memPort == 0) + continue; + + valid_port_mask = vlanconfig[i].memPort; + if(vlanconfig[i].isWan == 0) + valid_port_mask |= 0x100; + + /*add vlan*/ + retval = rtl865x_addVlan(vlanconfig[i].vid); + + if(retval == SUCCESS) + { + rtl865x_addVlanPortMember(vlanconfig[i].vid,vlanconfig[i].memPort & valid_port_mask); + rtl865x_setVlanFilterDatabase(vlanconfig[i].vid,vlanconfig[i].fid); + } + /*add network interface*/ + memset(&netif, 0, sizeof(rtl865x_netif_t)); + memcpy(netif.name,vlanconfig[i].ifname,MAX_IFNAMESIZE); + memcpy(netif.macAddr.octet,vlanconfig[i].mac.octet,ETHER_ADDR_LEN); + netif.mtu = vlanconfig[i].mtu; + netif.if_type = vlanconfig[i].if_type; + netif.vid = vlanconfig[i].vid; + netif.is_wan = vlanconfig[i].isWan; + netif.is_slave = vlanconfig[i].is_slave; + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + netif.enableRoute=1; + #endif + retval = rtl865x_addNetif(&netif); + + if(netif.is_slave == 1) +#if defined(CONFIG_RTL_PUBLIC_SSID) + rtl865x_attachMasterNetif(netif.name,RTL_GW_WAN_DEVICE_NAME); +#else + rtl865x_attachMasterNetif(netif.name, RTL_DRV_WAN0_NETIF_NAME); +#endif +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NET_SCHED) && defined(CONFIG_RTL_LAYERED_DRIVER) + memcpy(&netIfName[i][0], vlanconfig[i].ifname, sizeof(vlanconfig[i].ifname)); +#endif + +#if defined (CONFIG_RTL_UNKOWN_UNICAST_CONTROL) + if (vlanconfig[i].isWan==0) + memcpy(lanIfName, vlanconfig[i].ifname, sizeof(vlanconfig[i].ifname)); +#endif + if(retval != SUCCESS && retval != RTL_EVLANALREADYEXISTS) + return retval; + + } + + /*this is a one-shot config*/ + if ((++__865X_Config) == 1) + { + for(i=0; i<RTL8651_PORT_NUMBER + 3; i++) + { + /* Set each port's PVID */ + for(j=0,pvid=0; vlanconfig[j].vid != 0; j++) + { + if ( (1<<i) & vlanconfig[j].memPort ) + { + pvid = vlanconfig[j].vid; + break; + } + } + + if (pvid!=0) + { + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + rtlglue_printf("%s:%d:lrconfig[j].vid is %d,pvid is %d, j is %d,i is %d\n",__FUNCTION__,__LINE__,vlanconfig[j].vid,pvid,j, i); + #endif + + CONFIG_CHECK(rtl8651_setAsicPvid(i, pvid)); + #if defined(CONFIG_RTK_VLAN_SUPPORT) + rtl865x_setPortToNetif(vlanconfig[j].ifname,i); + #endif + } + } + } + + #if defined (CONFIG_RTL_HW_QOS_SUPPORT) + rtl865x_initOutputQueue((uint8 **)netIfName); + #endif + + #if defined (CONFIG_RTL_UNKOWN_UNICAST_CONTROL) + { + rtl865x_tblAsicDrv_rateLimitParam_t asic_rl; + /* + * Designer said: The time unit used to achieve rate limit is 1.67s (5/3), hence here we change + * the time unit to 1 sec. + */ + bzero(&asic_rl, sizeof(rtl865x_tblAsicDrv_rateLimitParam_t)); + asic_rl.maxToken = RTL_MAC_REFILL_TOKEN; + asic_rl.refill_number = RTL_MAC_REFILL_TOKEN; + asic_rl.t_intervalUnit = 1; + asic_rl.t_remainUnit = 1; + asic_rl.token = RTL_MAC_REFILL_TOKEN; + rtl8651_setAsicRateLimitTable(0, &asic_rl); + + macRecordIdx = 0; + bzero(macRecord, RTL_MAC_RECORD_NUM*sizeof(rtlMacRecord)); + + for(i=0;i<RTL_MAC_RECORD_NUM;i++) + { + init_timer(&macRecord[i].timer); + macRecord[i].timer.function = rtl_unkownUnicastTimer; + } + + WRITE_MEM32(TEACR, (READ_MEM32(TEACR)|EnRateLimitTbAging)); + } + #endif + + return SUCCESS; +} + +#if defined (CONFIG_RTL_UNKOWN_UNICAST_CONTROL) +static void rtl_unkownUnicastTimer(unsigned long data) +{ + rtlMacRecord *record; + rtl865x_AclRule_t rule; + + record = (rtlMacRecord*)data; + bzero((void*)&rule,sizeof(rtl865x_AclRule_t)); + rule.ruleType_ = RTL865X_ACL_MAC; + rule.pktOpApp_ = RTL865X_ACL_ONLY_L2; + rule.actionType_ = RTL865X_ACL_DROP_RATE_EXCEED_PPS; + memset(rule.dstMacMask_.octet, 0xff, ETHER_ADDR_LEN); + memcpy(rule.dstMac_.octet, record->mac, ETHER_ADDR_LEN); + rtl865x_del_acl(&rule, lanIfName, RTL865X_ACL_SYSTEM_USED); + + bzero(record, sizeof(rtlMacRecord)); + init_timer(&record->timer); + record->timer.function = rtl_unkownUnicastTimer; +} + +static void rtl_unkownUnicastUpdate(uint8 *mac) +{ + int idx; + rtl865x_AclRule_t rule; + + for(idx=0;idx<RTL_MAC_RECORD_NUM;idx++) + { + if (macRecord[idx].enable==0||memcmp(mac, macRecord[idx].mac, ETHER_ADDR_LEN)) + continue; + + /* The mac has already recorded */ + if (macRecord[idx].cnt==RTL_MAC_THRESHOLD||++macRecord[idx].cnt<RTL_MAC_THRESHOLD) + return; + + break; + } + + /* add/del the rules at lan side */ + bzero((void*)&rule,sizeof(rtl865x_AclRule_t)); + rule.ruleType_ = RTL865X_ACL_MAC; + rule.pktOpApp_ = RTL865X_ACL_ONLY_L2; + rule.actionType_ = RTL865X_ACL_DROP_RATE_EXCEED_PPS; + memset(rule.dstMacMask_.octet, 0xff, ETHER_ADDR_LEN); + + if (idx==RTL_MAC_RECORD_NUM) + { + if (macRecord[macRecordIdx].enable!=0&&macRecord[macRecordIdx].cnt>RTL_MAC_THRESHOLD) + { + memcpy(rule.dstMac_.octet, macRecord[macRecordIdx].mac, ETHER_ADDR_LEN); + rtl865x_del_acl(&rule, lanIfName, RTL865X_ACL_SYSTEM_USED); + init_timer(&macRecord[macRecordIdx].timer); + macRecord[macRecordIdx].timer.function = rtl_unkownUnicastTimer; + } + else + { + macRecord[macRecordIdx].enable = 1; + } + macRecord[macRecordIdx].cnt = 0; + memcpy(macRecord[macRecordIdx].mac, mac, ETHER_ADDR_LEN); + macRecordIdx = (macRecordIdx+1)&(RTL_MAC_RECORD_NUM-1); + } + else + { + memcpy(rule.dstMac_.octet, mac, ETHER_ADDR_LEN); + rtl865x_add_acl(&rule, lanIfName, RTL865X_ACL_SYSTEM_USED); + macRecord[idx].timer.data = (unsigned long)&(macRecord[idx]); + mod_timer(&macRecord[idx].timer, jiffies+RTL_MAC_TIMEOUT); + } +} +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) + +static int re865x_reInitIgmpSetting(int mode) +{ + #if defined (CONFIG_RTL_MULTI_LAN_DEV) + #else + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + rtl_multicastDeviceInfo_t devInfo; + uint32 externalPortMask=0; + #endif + int32 i; + int32 totalVlans=((sizeof(vlanconfig))/(sizeof(struct rtl865x_vlanConfig)))-1; + + for(i=0; i<totalVlans; i++) + { + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + if (TRUE==vlanconfig[i].isWan) + { + externalPortMask |=vlanconfig[i].memPort; + } + else + { + devInfo.portMask|=vlanconfig[i].memPort ; + } + #endif + + if(mode==GATEWAY_MODE) + { + rtl_setIgmpSnoopingModuleStaticRouterPortMask(nicIgmpModuleIndex, 0); + } + else + { + rtl_setIgmpSnoopingModuleStaticRouterPortMask(nicIgmpModuleIndex, 0x01); + } + + //rtl_setIgmpSnoopingModuleUnknownMCastFloodMap(nicIgmpModuleIndex, 0x0); + rtl_setIpv4UnknownMCastFloodMap(nicIgmpModuleIndex, 0x0); + rtl_setIpv6UnknownMCastFloodMap(nicIgmpModuleIndex, 0xFFFFFFFF); + + } + #endif + + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + rtl865x_reinitMulticast(); + //rtl865x_setMulticastExternalPortMask(externalPortMask); + rtl865x_setMulticastExternalPortMask(0); + #endif + rtl865x_igmpSyncLinkStatus(); + return SUCCESS; +} +#endif + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) +unsigned int rtl865x_getEthDevLinkStatus(struct net_device *dev) +{ + if(dev!=NULL) + { + struct dev_priv *cp =dev->priv; + //struct dev_priv *cp=netdev_priv(dev); + return (cp->portmask & rtl865x_getPhysicalPortLinkStatus()); + + } + else + { + return 0; + } +} +#endif + +static int32 rtl_reinit_hw_table(void) +{ + /*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*/ + + /*to-do:in each layer reinit function, memset all software entry to zero, + and force to clear all asic entry of own module, + then the re-init sequence can be common->l2->l3->l4 */ + /* FullAndSemiReset should not be called here + * it will make switch core action totally wrong + */ + + /*event management */ + rtl865x_reInitEventMgr(); + + /*l4*/ + #if defined(CONFIG_RTL_LAYERED_DRIVER_L4) && defined(CONFIG_RTL_8198) + rtl865x_nat_reinit(); + #endif + + /*l3*/ + #ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + rtl865x_reinitRouteTable(); + rtl865x_reinitNxtHopTable(); + rtl865x_reinitIpTable(); + rtl865x_reinitPppTable(); + rtl865x_arp_reinit(); + #endif + + /*l2*/ + #ifdef CONFIG_RTL_LAYERED_DRIVER_L2 + rtl865x_layer2_reinit(); + #endif + + /*common*/ + rtl865x_reinitNetifTable(); + rtl865x_reinitVlantable(); + rtl865x_reinit_acl(); + + /*queue id & rx ring descriptor mapping*/ + //Use REG32 instead of REG16 because CPUQDM4 is set to 0 unexpectedly when use REG16 + REG32(CPUQDM0)=QUEUEID1_RXRING_MAPPING|(QUEUEID0_RXRING_MAPPING<<16); + REG32(CPUQDM2)=QUEUEID3_RXRING_MAPPING|(QUEUEID2_RXRING_MAPPING<<16); + REG32(CPUQDM4)=QUEUEID5_RXRING_MAPPING|(QUEUEID4_RXRING_MAPPING<<16); + + WRITE_MEM32(PLITIMR,0); + + rtl8651_setAsicOperationLayer(2); + + return SUCCESS; + +} +#if defined(CONFIG_RTK_VLAN_SUPPORT) || defined (CONFIG_RTL_MULTI_LAN_DEV) +static int rtl_config_perport_perdev_vlanconfig(int mode) +{ + vlanconfig[0].vid = RTL_LANVLANID; + vlanconfig[0].memPort = RTL_LANPORT_MASK_4; + vlanconfig[0].untagSet= RTL_LANPORT_MASK_4; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = RTL_LANPORT_MASK_4; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID_1; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portnum = 1; + + if((mode == BRIDGE_MODE) || (mode== WISP_MODE)) + { + vlanconfig[1] .vid = RTL_LANVLANID; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_LANVLANID; + } + else + { + vlanconfig[1] .vid = RTL_WANVLANID; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; + } + vlanconfig[1].memPort = RTL_WANPORT_MASK; + vlanconfig[1].untagSet= RTL_WANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = RTL_WANPORT_MASK; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portnum = 1; + + vlanconfig[2] .vid = RTL_LANVLANID; + vlanconfig[2].memPort = RTL_LANPORT_MASK_3; + vlanconfig[2].untagSet = RTL_LANPORT_MASK_3; + ((struct dev_priv *)_rtl86xx_dev.dev[2]->priv)->portmask = RTL_LANPORT_MASK_3; //eth2 + ((struct dev_priv *)_rtl86xx_dev.dev[2]->priv)->id = RTL_LANVLANID_2; //eth2 + ((struct dev_priv *)_rtl86xx_dev.dev[2]->priv)->portnum = 1; + + vlanconfig[3] .vid = RTL_LANVLANID; + vlanconfig[3].memPort = RTL_LANPORT_MASK_2; + vlanconfig[3].untagSet = RTL_LANPORT_MASK_2; + ((struct dev_priv *)_rtl86xx_dev.dev[3]->priv)->portmask = RTL_LANPORT_MASK_2; //eth3 + ((struct dev_priv *)_rtl86xx_dev.dev[3]->priv)->id = RTL_LANVLANID_3; //eth3 + ((struct dev_priv *)_rtl86xx_dev.dev[3]->priv)->portnum = 1; + + vlanconfig[4] .vid = RTL_LANVLANID; + vlanconfig[4].memPort = RTL_LANPORT_MASK_1; + vlanconfig[4].untagSet = RTL_LANPORT_MASK_1; + ((struct dev_priv *)_rtl86xx_dev.dev[4]->priv)->portmask = RTL_LANPORT_MASK_1; //eth4 + ((struct dev_priv *)_rtl86xx_dev.dev[4]->priv)->id = RTL_LANVLANID_4; //eth4 + ((struct dev_priv *)_rtl86xx_dev.dev[4]->priv)->portnum = 1; + + #if defined(CONFIG_8198_PORT5_GMII) + vlanconfig[5] .vid = RTL_LANVLANID; + vlanconfig[5].memPort = RTL_LANPORT_MASK_5; + vlanconfig[5].untagSet = RTL_LANPORT_MASK_5; + ((struct dev_priv *)_rtl86xx_dev.dev[5]->priv)->portmask = RTL_LANPORT_MASK_5; //eth5 + ((struct dev_priv *)_rtl86xx_dev.dev[5]->priv)->id = RTL_LANVLANID_5; //eth5 + ((struct dev_priv *)_rtl86xx_dev.dev[5]->priv)->portnum = 1; + #endif + return SUCCESS; +} +#endif +static int rtl_config_lanwan_dev_vlanconfig(int mode) +{ + /*lan config*/ +#if defined (CONFIG_RTK_VLAN_SUPPORT) + { + vlanconfig[2].vid = 0; //eth2 + vlanconfig[3].vid = 0; //eth3 + vlanconfig[4].vid = 0; //eth4 + #if defined(CONFIG_8198_PORT5_GMII) + vlanconfig[5].vid = 0; + #endif + } +#endif + +#if defined (CONFIG_RTL_IVL_SUPPORT) + #if defined(CONFIG_POCKET_ROUTER_SUPPORT) + if(mode == GATEWAY_MODE) + { + vlanconfig[0].memPort = 0; + vlanconfig[0].vid=RTL_LANVLANID; + vlanconfig[0].untagSet = 0; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = 0; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID; + vlanconfig[1].vid = RTL_WANVLANID; + vlanconfig[1].memPort = RTL_WANPORT_MASK; + vlanconfig[1].untagSet = RTL_WANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = RTL_WANPORT_MASK; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; //eth1 + } + else + { + vlanconfig[0].memPort = RTL_LANPORT_MASK; + vlanconfig[0].vid=RTL_LANVLANID; + vlanconfig[0].untagSet = RTL_LANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = RTL_LANPORT_MASK; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID; + + vlanconfig[1].vid = 0; + vlanconfig[1].memPort = 0; + vlanconfig[1].untagSet = 0; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = 0; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; //eth1 + } + + #else //else CONFIG_POCKET_ROUTER_SUPPORT + vlanconfig[0].memPort = RTL_LANPORT_MASK; + vlanconfig[0].vid=RTL_LANVLANID; + vlanconfig[0].untagSet = RTL_LANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = RTL_LANPORT_MASK; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID; + + vlanconfig[1].vid = RTL_WANVLANID; + vlanconfig[1].memPort = RTL_WANPORT_MASK; + vlanconfig[1].untagSet = RTL_WANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = RTL_WANPORT_MASK; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; //eth1 + #endif //endif CONFIG_POCKET_ROUTER_SUPPORT + +#else + if(mode == BRIDGE_MODE || mode== WISP_MODE) + { + vlanconfig[0].memPort = RTL_LANPORT_MASK |RTL_WANPORT_MASK; + vlanconfig[0].untagSet = RTL_LANPORT_MASK |RTL_WANPORT_MASK; + vlanconfig[0].vid=RTL_LANVLANID; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = RTL_LANPORT_MASK |RTL_WANPORT_MASK; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID; + + vlanconfig[1].vid = 0; + vlanconfig[1].memPort=0x0; + vlanconfig[1].untagSet=0x0; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = 0x0; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = 0; + } + else + { + vlanconfig[0].memPort = RTL_LANPORT_MASK; + vlanconfig[0].vid=RTL_LANVLANID; + vlanconfig[0].untagSet = RTL_LANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->portmask = RTL_LANPORT_MASK; //eth0 + ((struct dev_priv *)_rtl86xx_dev.dev[0]->priv)->id = RTL_LANVLANID; + + vlanconfig[1].vid = RTL_WANVLANID; + vlanconfig[1].memPort = RTL_WANPORT_MASK; + vlanconfig[1].untagSet = RTL_WANPORT_MASK; + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->portmask = RTL_WANPORT_MASK; //eth1 + ((struct dev_priv *)_rtl86xx_dev.dev[1]->priv)->id = RTL_WANVLANID; //eth1 + } +#endif + + return SUCCESS; +} +#if defined (CONFIG_RTL_MULTI_LAN_DEV) +static int rtl_config_multi_lan_dev_vlanconfig(int mode) +{ + rtl_config_perport_perdev_vlanconfig(mode); + return SUCCESS; + +} +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) +static int rtl_config_rtkVlan_vlanconfig(int mode) +{ + if(!rtk_vlan_support_enable) + rtl_config_lanwan_dev_vlanconfig(mode); + else if(rtk_vlan_support_enable == 1) + { + rtl_config_perport_perdev_vlanconfig(mode); + } + else if(rtk_vlan_support_enable == 2) + rtl_config_lanwan_dev_vlanconfig(mode); + + return SUCCESS; +} +#endif + +static int rtl_config_operation_layer(int mode) +{ +#if defined(CONFIG_RTL_LAYERED_DRIVER) + switch(mode) + { + case GATEWAY_MODE: + rtl8651_setAsicOperationLayer(4); + break; + case BRIDGE_MODE: + case WISP_MODE: + rtl8651_setAsicOperationLayer(3); + break; + default: + rtl8651_setAsicOperationLayer(2); + } +#endif + return SUCCESS; +} + +static int rtl_config_vlanconfig(int mode) +{ + #if defined (CONFIG_RTL_MULTI_LAN_DEV) + rtl_config_multi_lan_dev_vlanconfig(mode); + #else + #if defined(CONFIG_RTK_VLAN_SUPPORT) + rtl_config_rtkVlan_vlanconfig(mode); + #else + rtl_config_lanwan_dev_vlanconfig(mode); + #endif + #endif + + return SUCCESS; + +} + +int32 rtl865x_changeOpMode(int mode) +{ +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + struct rtl865x_interface_info ifInfo; +#endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable==0) + { + if(mode==rtl865x_curOpMode) + { + return SUCCESS; + } + } +#else + if(mode==rtl865x_curOpMode) + { + return SUCCESS; + } +#endif + + /*config vlan config*/ + rtl_config_vlanconfig(mode); + + if (!vlanconfig[0].vid && !vlanconfig[1].vid ) + return RTL_EINVALIDVLANID; + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) + if(mode==GATEWAY_MODE) + { + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); +#if defined(CONFIG_RTL_PUBLIC_SSID) + strcpy(ifInfo.ifname,RTL_GW_WAN_DEVICE_NAME); +#else + strcpy(ifInfo.ifname, RTL_DRV_WAN0_NETIF_NAME); +#endif + ifInfo.isWan=1; + for(i=0;vlanconfig[i].vid!=0; i++) + { + if ((TRUE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort|=vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); + + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + strcpy(ifInfo.ifname, RTL_DRV_LAN_NETIF_NAME); + ifInfo.isWan=0; + for(i=0;vlanconfig[i].vid!=0;i++) + { + if ((FALSE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort|=vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); + } + else if(mode==WISP_MODE) + { + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + strcpy(ifInfo.ifname, RTL_PS_WLAN0_DEV_NAME); + ifInfo.isWan=1; + rtl865x_setLpIfInfo(&ifInfo); + + + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + strcpy(ifInfo.ifname,RTL_DRV_LAN_NETIF_NAME); + ifInfo.isWan=0; + for(i=0;vlanconfig[i].vid!=0;i++) + { + if ((FALSE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort|=vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); + } + else + { + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + ifInfo.isWan=1; + rtl865x_setLpIfInfo(&ifInfo); + + memset(&ifInfo, 0 , sizeof(struct rtl865x_interface_info)); + strcpy(ifInfo.ifname, RTL_DRV_LAN_NETIF_NAME); + ifInfo.isWan=0; + for(i=0;vlanconfig[i].vid!=0;i++) + { + if ((FALSE==vlanconfig[i].isWan) && (vlanconfig[i].if_type==IF_ETHER)) + { + ifInfo.memPort|=vlanconfig[i].memPort; + ifInfo.fid=vlanconfig[i].fid; + } + } + rtl865x_setLpIfInfo(&ifInfo); + } +#endif + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined(CONFIG_RTK_VLAN_SUPPORT) + re865x_packVlanConfig(vlanconfig, packedVlanConfig); +#endif + + /*reinit hw tables*/ + rtl_reinit_hw_table(); + +#if defined (CONFIG_RTL_MULTI_LAN_DEV) ||defined(CONFIG_RTK_VLAN_SUPPORT) + reinit_vlan_configure(packedVlanConfig); +#else + reinit_vlan_configure(vlanconfig); +#endif + +#if defined (CONFIG_RTL_IGMP_SNOOPING) + re865x_reInitIgmpSetting(mode); +#if defined (CONFIG_RTL_MLD_SNOOPING) +#if defined(CONFIG_RTK_VLAN_SUPPORT) + if((mldSnoopEnabled==TRUE)&& (rtk_vlan_support_enable==0)) +#else + if(mldSnoopEnabled==TRUE) +#endif + { +#if defined (CONFIG_RTL_MULTI_LAN_DEV) + rtl865x_addAclForMldSnooping(packedVlanConfig); +#else + rtl865x_addAclForMldSnooping(vlanconfig); +#endif + } +#endif +#endif + +#if defined (CONFIG_RTL_IVL_SUPPORT) + if(mode==GATEWAY_MODE) + { + WRITE_MEM32( FFCR, READ_MEM32( FFCR ) & ~EN_UNUNICAST_TOCPU ); + } + else if((mode==BRIDGE_MODE) ||(mode==WISP_MODE)) + { + WRITE_MEM32( FFCR, READ_MEM32( FFCR ) | EN_UNUNICAST_TOCPU ); + } + else + { + WRITE_MEM32( FFCR, READ_MEM32( FFCR ) & ~EN_UNUNICAST_TOCPU ); + } +#endif + + /*update current operation mode*/ + rtl865x_curOpMode=mode; + + //setAsicOperationLayer + rtl_config_operation_layer(mode); + + //always init the default route... + if(rtl8651_getAsicOperationLayer() >2) + { + rtl865x_addRoute(0,0,0,RTL_DRV_WAN0_NETIF_NAME,0); + } + + //checksum control register + switch(mode) + { + case GATEWAY_MODE: + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L2_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L3_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L4_CHKSUM_ERR); + break; + case BRIDGE_MODE: + case WISP_MODE: + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L2_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)|ALLOW_L3_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)|ALLOW_L4_CHKSUM_ERR); + break; + default: + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L2_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L3_CHKSUM_ERR); + WRITE_MEM32(CSCR,READ_MEM32(CSCR)&~ALLOW_L4_CHKSUM_ERR); + } + + return SUCCESS; +} + + +int rtl865x_reChangeOpMode (void) +{ + unsigned long flags; + local_irq_save(flags); + if(rtl865x_curOpMode==GATEWAY_MODE) + { + rtl865x_changeOpMode(BRIDGE_MODE); + rtl865x_changeOpMode(GATEWAY_MODE); + } + else if (rtl865x_curOpMode==BRIDGE_MODE) + { + rtl865x_changeOpMode(GATEWAY_MODE); + rtl865x_changeOpMode(BRIDGE_MODE); + } + else if (rtl865x_curOpMode==WISP_MODE) + { + rtl865x_changeOpMode(GATEWAY_MODE); + rtl865x_changeOpMode(WISP_MODE); + } + local_irq_restore(flags); + return 0; +} + + +static int32 reinit_vlan_configure(struct rtl865x_vlanConfig new_vlanconfig[]) +{ + uint16 pvid; + int32 i, j; + uint32 valid_port_mask = 0; + struct rtl865x_vlanConfig *pvlanconfig = NULL; + int32 totalVlans = 0; + pvlanconfig = new_vlanconfig; + + + /*get input vlan config entry number*/ + for(i=0; pvlanconfig[i].ifname[0] != '\0' ; i++) + { + if(pvlanconfig[i].vid != 0) + totalVlans++; + } + //because the new_vlanconfig should be packedVlanConfig + totalVlans = totalVlans > NETIF_NUMBER? NETIF_NUMBER:totalVlans; + + for(i=0; i<totalVlans; i++) + { + rtl865x_netif_t netif; + + if(pvlanconfig[i].vid == 0) + continue; + + valid_port_mask = pvlanconfig[i].memPort; + if(pvlanconfig[i].isWan == 0) + valid_port_mask |= 0x100; + + /*add vlan*/ + if(pvlanconfig[i].if_type==IF_ETHER) + { + rtl865x_addVlan(pvlanconfig[i].vid); + rtl865x_addVlanPortMember(pvlanconfig[i].vid,pvlanconfig[i].memPort & valid_port_mask); + rtl865x_setVlanFilterDatabase(pvlanconfig[i].vid,pvlanconfig[i].fid); + } + + /*add network interface*/ + memset(&netif, 0, sizeof(rtl865x_netif_t)); + memcpy(netif.name,pvlanconfig[i].ifname,MAX_IFNAMESIZE); + memcpy(netif.macAddr.octet,pvlanconfig[i].mac.octet,ETHER_ADDR_LEN); + netif.mtu = pvlanconfig[i].mtu; + netif.if_type = pvlanconfig[i].if_type; + netif.vid = pvlanconfig[i].vid; + netif.is_wan = pvlanconfig[i].isWan; + netif.is_slave = pvlanconfig[i].is_slave; + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + netif.enableRoute=1; + #endif + rtl865x_addNetif(&netif); + if(netif.is_slave == 1) +#if defined(CONFIG_RTL_PUBLIC_SSID) + rtl865x_attachMasterNetif(netif.name,RTL_GW_WAN_DEVICE_NAME); +#else + rtl865x_attachMasterNetif(netif.name,RTL_DRV_WAN0_NETIF_NAME); +#endif + } + + #if defined(CONFIG_RTL_MULTIPLE_WAN) + rtl_config_multipleWan_netif(RTL_MULTIWAN_ADD); + #endif + +#if defined(CONFIG_RTK_VLAN_SUPPORT) + if(rtk_vlan_support_enable == 1) + rtl865x_enable_acl(0); + else + rtl865x_enable_acl(1); +#endif + + + for(i=0; i<RTL8651_PORT_NUMBER + 3; i++) + { + /* Set each port's PVID */ + for(j=0,pvid=0; pvlanconfig[j].vid != 0; j++) + { + if ( (1<<i) & pvlanconfig[j].memPort ) + { + pvid = pvlanconfig[j].vid; + break; + } + } + + if (pvid!=0) + { + CONFIG_CHECK(rtl8651_setAsicPvid(i,pvid)); + rtl865x_setPortToNetif(pvlanconfig[j].ifname, i); + } + } +#ifdef CONFIG_RTL_STP + re865x_stp_mapping_reinit(); +#endif + + rtl_config_operation_layer(rtl865x_curOpMode); + + return SUCCESS; +} +#if defined(CONFIG_RTL_REPORT_LINK_STATUS) +static int32 rtk_link_status_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int len; + len = sprintf(page, "%d\n",wan_linkStatus[0]); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; + + return len; +} +static int32 rtk_link_status_write( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + char tmpbuf[4]; + if (buff && !copy_from_user(tmpbuf, buff, len)) + { + if(0 == (tmpbuf[0]-'0')) + wan_linkStatus[0] = 0; + } + return len; +} +#endif +#if defined(CONFIG_RTK_VLAN_SUPPORT) +static int32 rtk_vlan_support_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int len; + len = sprintf(page, "%s %d\n", "rtk_vlan_support_enable:",rtk_vlan_support_enable); + + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; + + return len; +} + +static int32 rtk_vlan_support_write( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + char tmpbuf[32]; + int i=0; + int j=0; + struct net_device *dev; + struct dev_priv *dp; + + if (buff && !copy_from_user(tmpbuf, buff, len)) + { + tmpbuf[len] = '\0'; + #if defined (CONFIG_RTL_IGMP_SNOOPING) && defined (CONFIG_RTL_MLD_SNOOPING) + if(mldSnoopEnabled) + { + rtl865x_removeAclForMldSnooping(vlanconfig); + } + #endif + if(tmpbuf[0] == '0') + { + rtk_vlan_support_enable = 0; + + rtl_config_rtkVlan_vlanconfig(rtl865x_curOpMode); + re865x_packVlanConfig(vlanconfig, packedVlanConfig); + rtl_reinit_hw_table(); + reinit_vlan_configure(packedVlanConfig); + + //unknow vlan drop + REG32(SWTCR0) &= ~(1 << 15); + +#if defined(CONFIG_RTL_LAYERED_DRIVER_ACL) + rtl865x_enable_acl(1); //enable acl feature +#endif + } + else if(tmpbuf[0] == '1') + { + rtk_vlan_support_enable = 1; + + rtl_config_rtkVlan_vlanconfig(rtl865x_curOpMode); + re865x_packVlanConfig(vlanconfig, packedVlanConfig); + rtl_reinit_hw_table(); + reinit_vlan_configure(packedVlanConfig); + + //unknow vid to cpu + REG32(SWTCR0) |= 1 << 15; +#if defined(CONFIG_RTL_LAYERED_DRIVER_ACL) + rtl865x_enable_acl(0); //disable acl feature +#endif + } +#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) + else if(tmpbuf[0] == '2') + { + rtk_vlan_support_enable = 2; + //unknow vid to cpu + REG32(SWTCR0) |= 1 << 15; + } +#endif + else + { + printk("current support: 0/1/2\n"); + return len; + } + + /*update dev port number*/ + for(i=0; vlanconfig[i].vid != 0; i++) + { + if (IF_ETHER!=vlanconfig[i].if_type) + { + continue; + } + + dev=_rtl86xx_dev.dev[i]; + dp = dev->priv; + dp->portnum = 0; + for(j=0;j<RTL8651_AGGREGATOR_NUMBER;j++) + { + if(dp->portmask & (1<<j)) + dp->portnum++; + } + + } + + #if defined (CONFIG_RTL_IGMP_SNOOPING) + re865x_reInitIgmpSetting(rtl865x_curOpMode); + #if defined (CONFIG_RTL_MLD_SNOOPING) + if(mldSnoopEnabled && (rtk_vlan_support_enable==0)) + { + re865x_packVlanConfig(vlanconfig, packedVlanConfig); + rtl865x_addAclForMldSnooping(packedVlanConfig); + } + #endif + #endif + + //always init the default route... + if(rtl8651_getAsicOperationLayer() >2) + { + rtl865x_addRoute(0,0,0,RTL_DRV_WAN0_NETIF_NAME,0); + } + + } + return len; +} + +#if defined(CONFIG_819X_PHY_RW) //#if defined(CONFIG_RTK_VLAN_FOR_CABLE_MODEM) +static int32 rtl_phy_status_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int len; + uint32 regData; + uint32 data0; + int port; + + len = sprintf(page, "Port Status:\n"); + + for(port=PHY0;port<CPU;port++) + { + regData = READ_MEM32(PSRP0+((port)<<2)); + + len += sprintf(page+len, "Port%d ", port); + data0 = regData & PortStatusLinkUp; + + if (data0) + len += sprintf(page+len, "LinkUp | "); + else + { + len += sprintf(page+len, "LinkDown\n\n"); + continue; + } + data0 = regData & PortStatusDuplex; + len += sprintf(page+len, " Duplex %s | ", data0?"Enabled":"Disabled"); + data0 = (regData&PortStatusLinkSpeed_MASK)>>PortStatusLinkSpeed_OFFSET; + len += sprintf(page+len, "Speed %s\n\n", data0==PortStatusLinkSpeed100M?"100M": + (data0==PortStatusLinkSpeed1000M?"1G": + (data0==PortStatusLinkSpeed10M?"10M":"Unkown"))); + } + + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; + + return len; +} + + + +static int32 rtl_phy_status_write( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + char tmpbuf[64]; + uint32 port_mask; + char *strptr, *cmd_addr; + char *tokptr; + int type; + int port; + int forceMode = 0; + int forceLink = 0; + int forceLinkSpeed = 0; + int forceDuplex = 0; + uint32 advCapability = 0; + int forwardEnable = TRUE; + + #define SPEED10M 0 + #define SPEED100M 1 + #define SPEED1000M 2 + + if (buff && !copy_from_user(tmpbuf, buff, len)) { + tmpbuf[len-1] = '\0'; + strptr=tmpbuf; + cmd_addr = strsep(&strptr," "); + if (cmd_addr==NULL) + { + goto errout; + } + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + + if (!memcmp(cmd_addr, "port", 4)) + { + port_mask=simple_strtol(tokptr, NULL, 0); + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + + if(strcmp(tokptr,"10_half") == 0) + type = HALF_DUPLEX_10M; + else if(strcmp(tokptr,"100_half") == 0) + type = HALF_DUPLEX_100M; + else if(strcmp(tokptr,"1000_half") == 0) + type = HALF_DUPLEX_1000M; + else if(strcmp(tokptr,"10_full") == 0) + type = DUPLEX_10M; + else if(strcmp(tokptr,"100_full") == 0) + type = DUPLEX_100M; + else if(strcmp(tokptr,"1000_full") == 0) + type = DUPLEX_1000M; + else + type = PORT_AUTO; + + tokptr = strsep(&strptr," "); + if(tokptr == NULL) + goto errout; + + forwardEnable = simple_strtol(tokptr,NULL,0); + + switch(type) + { + case HALF_DUPLEX_10M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED10M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_10M); + break; + } + case HALF_DUPLEX_100M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED100M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_100M); + break; + } + case HALF_DUPLEX_1000M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED1000M; + forceDuplex=FALSE; + advCapability=(1<<HALF_DUPLEX_1000M); + break; + } + case DUPLEX_10M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED10M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_10M); + break; + } + case DUPLEX_100M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED100M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_100M); + break; + } + case DUPLEX_1000M: + { + forceMode=TRUE; + forceLink=TRUE; + forceLinkSpeed=SPEED1000M; + forceDuplex=TRUE; + advCapability=(1<<DUPLEX_1000M); + break; + } + default: + { + forceMode=FALSE; + forceLink=TRUE; + /*all capality*/ + advCapability=(1<<PORT_AUTO); + } + } + + + for(port = 0; port < CPU; port++) + { + if((1<<port) & port_mask) + { + rtl865xC_setAsicEthernetForceModeRegs(port, forceMode, forceLink, forceLinkSpeed, forceDuplex); + + /*Set PHY Register*/ + rtl8651_setAsicEthernetPHYSpeed(port,forceLinkSpeed); + rtl8651_setAsicEthernetPHYDuplex(port,forceDuplex); + rtl8651_setAsicEthernetPHYAutoNeg(port,forceMode?FALSE:TRUE); + rtl8651_setAsicEthernetPHYAdvCapality(port,advCapability); + rtl8651_restartAsicEthernetPHYNway(port); + rtl865x_setPortForward(port,forwardEnable); + } + } + + } + else + { + goto errout; + } + } + else + { +errout: + printk("port status only support \"port\" as the first parameter\n"); + printk("format: \"port port_mask 10_half/100_half/10_full/100_full/1000_full/auto\"\n"); + } + return len; +} + +//mib counter + int rtl819x_get_port_mibStats(int port , struct port_mibStatistics *port_stats) + + { + uint32 addrOffset_fromP0 =0; + + if((port>CPU)||(port_stats==NULL) ) + { + return FAILED; + } + + addrOffset_fromP0= port* MIB_ADDROFFSETBYPORT; + + memset(port_stats,0,sizeof(struct port_mibStatistics)); + /* update the mib64 counters from 32bit counters*/ + //rtl8651_updateAdvancedMibCounter((unsigned long)(&rtl865x_updateMib64Param)); //mark_rm + + port_stats->ifInOctets=rtl8651_returnAsicCounter(OFFSET_IFINOCTETS_P0 + addrOffset_fromP0); + //rtl865xC_getAsicCounter64(OFFSET_IFINOCTETS_P0 + addrOffset_fromP0, &(port_stats->ifHCInOctets)); //mark_rm + port_stats->ifHCInOctets = port_stats->ifInOctets; + + port_stats->ifInUcastPkts=rtl8651_returnAsicCounter(OFFSET_IFINUCASTPKTS_P0 + addrOffset_fromP0) ; + //port_stats->ifHCInUcastPkts = rtl865x_updateMib64Param[port].ifHCInUcastPkts; + port_stats->ifHCInUcastPkts = port_stats->ifInUcastPkts; + + port_stats->ifInDiscards=rtl8651_returnAsicCounter(OFFSET_DOT1DTPPORTINDISCARDS_P0+ addrOffset_fromP0);//?? + port_stats->ifInErrors=(rtl8651_returnAsicCounter( OFFSET_DOT3STATSFCSERRORS_P0 + addrOffset_fromP0 ) + + rtl8651_returnAsicCounter( OFFSET_ETHERSTATSJABBERS_P0 + addrOffset_fromP0 )); + port_stats->ifInMulticastPkts= rtl8651_returnAsicCounter( OFFSET_ETHERSTATSMULTICASTPKTS_P0 + addrOffset_fromP0 ) ; + //port_stats->ifHCInMulticastPkts= rtl865x_updateMib64Param[port].ifHCInMulticastPkts; + port_stats->ifHCInMulticastPkts = port_stats->ifInMulticastPkts; + + port_stats->ifInBroadcastPkts= rtl8651_returnAsicCounter( OFFSET_ETHERSTATSBROADCASTPKTS_P0 + addrOffset_fromP0 ) ; + //port_stats->ifHCInBroadcastPkts= rtl865x_updateMib64Param[port].ifHCInBroadcastPkts; + port_stats->ifHCInBroadcastPkts = port_stats->ifInBroadcastPkts; + + //rtl865xC_getAsicCounter64(OFFSET_ETHERSTATSOCTETS_P0 + addrOffset_fromP0, &port_stats->etherStatsOctets ); + port_stats->etherStatsOctets = rtl8651_returnAsicCounter(OFFSET_ETHERSTATSOCTETS_P0 + addrOffset_fromP0); //replace above , mark_rm + //port_stats->etherStatsOctets=rtl865xC_returnAsicCounter64(OFFSET_ETHERSTATSOCTETS_P0 + addrOffset_fromP0); //not by mark_rm + port_stats->etherStatsUndersizePkts=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSUNDERSIZEPKTS_P0 + addrOffset_fromP0); + port_stats->etherStatsFraments=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSFRAGMEMTS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts64Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS64OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts65to127Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS65TO127OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts128to255Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS128TO255OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts256to511Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS256TO511OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts512to1023Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS512TO1023OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsPkts1024to1518Octets=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSPKTS1024TO1518OCTETS_P0 + addrOffset_fromP0); + port_stats->etherStatsOversizePkts=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSOVERSIZEPKTS_P0 + addrOffset_fromP0); + port_stats->etherStatsJabbers=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSJABBERS_P0 + addrOffset_fromP0); + port_stats->etherStatusDropEvents=rtl8651_returnAsicCounter( OFFSET_ETHERSTATSDROPEVENTS_P0 + addrOffset_fromP0); + port_stats->dot3FCSErrors=rtl8651_returnAsicCounter( OFFSET_DOT3STATSFCSERRORS_P0 + addrOffset_fromP0); + port_stats->dot3StatsSymbolErrors=rtl8651_returnAsicCounter( OFFSET_DOT3STATSSYMBOLERRORS_P0 + addrOffset_fromP0); + port_stats->dot3ControlInUnknownOpcodes=rtl8651_returnAsicCounter( OFFSET_DOT3CONTROLINUNKNOWNOPCODES_P0 + addrOffset_fromP0); + port_stats->dot3InPauseFrames=rtl8651_returnAsicCounter( OFFSET_DOT3INPAUSEFRAMES_P0 + addrOffset_fromP0); + + port_stats->ifOutOctets=rtl8651_returnAsicCounter(OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0); + //rtl865xC_getAsicCounter64(OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0, &port_stats->ifHCOutOctets); + port_stats->ifHCOutOctets = port_stats->ifOutOctets; + + // port_stats->ifHCOutOctets=rtl865xC_returnAsicCounter64(OFFSET_IFOUTOCTETS_P0 + addrOffset_fromP0);//not by mark_rm + port_stats->ifOutUcastPkts=rtl8651_returnAsicCounter(OFFSET_IFOUTUCASTPKTS_P0 + addrOffset_fromP0); + //port_stats->ifHCOutUcastPkts = rtl865x_updateMib64Param[port].ifHCOutUcastPkts; + port_stats->ifHCOutUcastPkts = port_stats->ifOutUcastPkts; + port_stats->ifOutDiscards=rtl8651_returnAsicCounter(OFFSET_IFOUTDISCARDS+ addrOffset_fromP0); + port_stats->ifOutErrors=(rtl8651_returnAsicCounter( OFFSET_ETHERSTATSCOLLISIONS_P0 + addrOffset_fromP0 ) + + rtl8651_returnAsicCounter( OFFSET_DOT3STATSDEFERREDTRANSMISSIONS_P0 + addrOffset_fromP0 )); + port_stats->ifOutMulticastPkts=rtl8651_returnAsicCounter(OFFSET_IFOUTMULTICASTPKTS_P0 + addrOffset_fromP0); + port_stats->ifOutBroadcastPkts=rtl8651_returnAsicCounter(OFFSET_IFOUTBROADCASTPKTS_P0 + addrOffset_fromP0); + //port_stats->ifHCOutMulticastPkts=rtl865x_updateMib64Param[port].ifHCOutMulticastPkts; + port_stats->ifHCOutMulticastPkts = port_stats->ifOutMulticastPkts; + //port_stats->ifHCOutBroadcastPkts=rtl865x_updateMib64Param[port].ifHCOutBroadcastPkts; + port_stats->ifHCOutBroadcastPkts = port_stats->ifOutBroadcastPkts; + + port_stats->ifOutDiscards=rtl8651_returnAsicCounter(OFFSET_IFOUTDISCARDS + addrOffset_fromP0); + port_stats->dot3StatsSingleCollisionFrames=rtl8651_returnAsicCounter(OFFSET_DOT3STATSSINGLECOLLISIONFRAMES_P0+ addrOffset_fromP0); + port_stats->dot3StatsMultipleCollisionFrames=rtl8651_returnAsicCounter(OFFSET_DOT3STATSMULTIPLECOLLISIONFRAMES_P0 + addrOffset_fromP0); + port_stats->dot3StatsDefferedTransmissions=rtl8651_returnAsicCounter(OFFSET_DOT3STATSDEFERREDTRANSMISSIONS_P0 + addrOffset_fromP0); + port_stats->dot3StatsLateCollisions=rtl8651_returnAsicCounter(OFFSET_DOT3STATSLATECOLLISIONS_P0 + addrOffset_fromP0); + port_stats->dot3StatsExcessiveCollisions=rtl8651_returnAsicCounter(OFFSET_DOT3STATSEXCESSIVECOLLISIONS_P0 + addrOffset_fromP0); + port_stats->dot3OutPauseFrames=rtl8651_returnAsicCounter(OFFSET_DOT3OUTPAUSEFRAMES_P0 + addrOffset_fromP0); + port_stats->dot1dBasePortDelayExceededDiscards=rtl8651_returnAsicCounter(OFFSET_DOT1DBASEPORTDELAYEXCEEDEDDISCARDS_P0 + addrOffset_fromP0); + port_stats->etherStatsCollisions=rtl8651_returnAsicCounter(OFFSET_ETHERSTATSCOLLISIONS_P0 + addrOffset_fromP0); + + + //port_stats->ifInUnknownProtos = ethPortInUnknownProtos[port]; //mark_rm + port_stats->ifInUnknownProtos = 0; + port_stats->dot1dTpLearnedEntryDiscards=rtl8651_returnAsicCounter(MIB_ADDROFFSETBYPORT); + port_stats->etherStatsCpuEventPkts=rtl8651_returnAsicCounter(MIB_ADDROFFSETBYPORT); + + return SUCCESS; + } + +static int show_port_mibStats(struct port_mibStatistics *port_stats, int port, char *page, int off) +{ + int len; + //struct lan_port_status tmp_port_status; + len = off; + /*here is in counters definition*/ + len += sprintf(page+len, "%s%u\n", "ifInOctets=", port_stats->ifInOctets); + len += sprintf(page+len, "%s%llu\n", "ifHCInOctets=", port_stats->ifHCInOctets); + len += sprintf(page+len, "%s%u\n", "ifInUcastPkts=", port_stats->ifInUcastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCInUcastPkts=", port_stats->ifHCInUcastPkts); + len += sprintf(page+len, "%s%u\n", "ifInMulticastPkts=", port_stats->ifInMulticastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCInMulticastPkts=", port_stats->ifHCInMulticastPkts); + len += sprintf(page+len, "%s%u\n", "ifInBroadcastPkts=", port_stats->ifInBroadcastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCInBroadcastPkts=", port_stats->ifHCInBroadcastPkts); + len += sprintf(page+len, "%s%u\n", "ifInDiscards=", port_stats->ifInDiscards); + len += sprintf(page+len, "%s%u\n", "ifInErrors=", port_stats->ifInErrors); + len += sprintf(page+len, "%s%llu\n", "etherStatsOctets=", port_stats->etherStatsOctets); + len += sprintf(page+len, "%s%u\n", "etherStatsUndersizePkts=", port_stats->etherStatsUndersizePkts); + len += sprintf(page+len, "%s%u\n", "etherStatsFraments=", port_stats->etherStatsFraments); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts64Octets=", port_stats->etherStatsPkts64Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts65to127Octets=", port_stats->etherStatsPkts65to127Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts128to255Octets=", port_stats->etherStatsPkts128to255Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts256to511Octets=", port_stats->etherStatsPkts256to511Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts512to1023Octets=", port_stats->etherStatsPkts512to1023Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsPkts1024to1518Octets=", port_stats->etherStatsPkts1024to1518Octets); + len += sprintf(page+len, "%s%u\n", "etherStatsOversizePkts=", port_stats->etherStatsOversizePkts); + len += sprintf(page+len, "%s%u\n", "etherStatsJabbers=", port_stats->etherStatsJabbers); + len += sprintf(page+len, "%s%u\n", "dot1dTpPortInDiscards=", port_stats->dot1dTpPortInDiscards); + len += sprintf(page+len, "%s%u\n", "etherStatusDropEvents=", port_stats->etherStatusDropEvents); + len += sprintf(page+len, "%s%u\n", "dot3FCSErrors=", port_stats->dot3FCSErrors); + len += sprintf(page+len, "%s%u\n", "dot3StatsSymbolErrors=", port_stats->dot3StatsSymbolErrors); + len += sprintf(page+len, "%s%u\n", "dot3ControlInUnknownOpcodes=", port_stats->dot3ControlInUnknownOpcodes); + len += sprintf(page+len, "%s%u\n", "dot3InPauseFrames=", port_stats->dot3InPauseFrames); + /*here is out counters definition*/ + len += sprintf(page+len, "%s%u\n", "ifOutOctets=", port_stats->ifOutOctets); + len += sprintf(page+len, "%s%llu\n", "ifHCOutOctets=", port_stats->ifHCOutOctets); + len += sprintf(page+len, "%s%u\n", "ifOutUcastPkts=", port_stats->ifOutUcastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCOutUcastPkts=", port_stats->ifHCOutUcastPkts); + len += sprintf(page+len, "%s%u\n", "ifOutMulticastPkts=", port_stats->ifOutMulticastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCOutMulticastPkts=", port_stats->ifHCOutMulticastPkts); + len += sprintf(page+len, "%s%u\n", "ifOutBroadcastPkts=", port_stats->ifOutBroadcastPkts); + len += sprintf(page+len, "%s%llu\n", "ifHCOutBroadcastPkts=", port_stats->ifHCOutBroadcastPkts); + len += sprintf(page+len, "%s%u\n", "ifOutDiscards=", port_stats->ifOutDiscards); + len += sprintf(page+len, "%s%u\n", "ifOutErrors=", port_stats->ifOutErrors); + len += sprintf(page+len, "%s%u\n", "dot3StatsSingleCollisionFrames=", port_stats->dot3StatsSingleCollisionFrames); + len += sprintf(page+len, "%s%u\n", "dot3StatsMultipleCollisionFrames=", port_stats->dot3StatsMultipleCollisionFrames); + len += sprintf(page+len, "%s%u\n", "dot3StatsDefferedTransmissions=", port_stats->dot3StatsDefferedTransmissions); + len += sprintf(page+len, "%s%u\n", "dot3StatsLateCollisions=", port_stats->dot3StatsLateCollisions); + len += sprintf(page+len, "%s%u\n", "dot3StatsExcessiveCollisions=", port_stats->dot3StatsExcessiveCollisions); + len += sprintf(page+len, "%s%u\n", "dot3OutPauseFrames=", port_stats->dot3OutPauseFrames); + len += sprintf(page+len, "%s%u\n", "dot1dBasePortDelayExceededDiscards=", port_stats->dot1dBasePortDelayExceededDiscards); + len += sprintf(page+len, "%s%u\n", "etherStatsCollisions=", port_stats->etherStatsCollisions); + /*here is whole system couters definition*/ + //mark_rm len += sprintf(page+len, "%s%u\n", "dot1dTpLearnedEntryDiscards=", port_stats->dot1dTpLearnedEntryDiscards); + //mark_rm len += sprintf(page+len, "%s%u\n", "etherStatsCpuEventPkts=", port_stats->etherStatsCpuEventPkts); + //len += sprintf(page+len, "%s%u\n", "ifInUnknownProtos=", port_stats->ifInUnknownProtos); //mark_rm + //len += sprintf(page+len, "%s%u\n", "ifAdminStatus=", PortAdminStatus[port]);//mark_rm + //len += sprintf(page+len, "%s%u\n", "ifOperStatus=", PortifOperStatus[port]);//mark_rm + //len += sprintf(page+len, "%s%u\n", "ifLastChange=", PortLastChange[port]);//mark_rm + //len += sprintf(page+len, "%s%u\n", "ifSpeed=",port_stats->ifSpeed); + //len += sprintf(page+len, "%s%u\n", "ifHighSpeed=",port_stats->ifHighSpeed); + //len += sprintf(page+len, "%s%u\n", "ifCounterDiscontinuityTime=", port_stats->ifCounterDiscontinuityTime); + /*//mark_rm + rtl819x_get_port_status(port, &tmp_port_status); + if(tmp_port_status.link == 1) + port_stats->ifConnectorPresent = 1;//link + else + port_stats->ifConnectorPresent = 2;//unlink + len += sprintf(page+len, "%s%u\n", "ifConnectorPresent=", port_stats->ifConnectorPresent); + */ + + return len; +} + +static int port_mibStats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{//TODO + int len; + uint32 port; + struct port_mibStatistics port_stats; + len = 0; + port = (uint32)data; + if(port > CPU) + return 0; + rtl819x_get_port_mibStats(port , &port_stats); + len = show_port_mibStats(&port_stats, port, page, len); + + return len; +} + +static int32 port_mibStats_write_proc( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + if (len < 2) + return -EFAULT; + + rtl8651_clearAsicCounter(); + return len; +} + + +#endif //#if defined(CONFIG_819X_PHY_RW) + + +static int read_proc_vlan(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + + struct net_device *dev = (struct net_device *)data; + struct dev_priv *cp; + int len; + + cp = dev->priv; + len = sprintf(page, "gvlan=%d, lan=%d, vlan=%d, tag=%d, vid=%d, priority=%d, cfi=%d\n", + cp->vlan_setting.global_vlan, cp->vlan_setting.is_lan, cp->vlan_setting.vlan, cp->vlan_setting.tag, + cp->vlan_setting.id, cp->vlan_setting.pri, cp->vlan_setting.cfi); + + if (len <= off+count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static int write_proc_vlan(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct net_device *dev = (struct net_device *)data; + struct dev_priv *cp; + #define VLAN_MAX_INPUT_LEN 128 + char *tmp; + + tmp = kmalloc(VLAN_MAX_INPUT_LEN, GFP_KERNEL); + if (count < 2 || tmp==NULL) + goto out; + + cp = dev->priv; + if(rtk_vlan_support_enable == 0) + goto out; + + if (buffer && !copy_from_user(tmp, buffer, VLAN_MAX_INPUT_LEN)) + { + int num = sscanf(tmp, "%d %d %d %d %d %d %d", + &cp->vlan_setting.global_vlan, &cp->vlan_setting.is_lan, + &cp->vlan_setting.vlan, &cp->vlan_setting.tag, + &cp->vlan_setting.id, &cp->vlan_setting.pri, + &cp->vlan_setting.cfi); + + if (num != 7) { + printk("invalid vlan parameter!\n"); + goto out; + } + #if 0 + printk("===%s(%d), cp->name(%s),global_vlan(%d),is_lan(%d),vlan(%d),tag(%d),id(%d),pri(%d),cfi(%d)",__FUNCTION__,__LINE__, + cp->dev->name,cp->vlan_setting.global_vlan,cp->vlan_setting.is_lan,cp->vlan_setting.vlan,cp->vlan_setting.tag, + cp->vlan_setting.id,cp->vlan_setting.pri,cp->vlan_setting.cfi); + printk("-------------%s(%d),cp->portmask(%d)\n",__FUNCTION__,__LINE__,cp->portmask); + #endif + } +out: + if(tmp) + kfree(tmp); + + return count; +} +#endif // CONFIG_RTK_VLAN_SUPPORT + +#if (defined(CONFIG_RTL_CUSTOM_PASSTHRU) && !defined(CONFIG_RTL8196_RTL8366)) + +static unsigned long atoi_dec(char *s) +{ + unsigned long k = 0; + + k = 0; + while (*s != '\0' && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + return k; +} + +static int custom_Passthru_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + len = sprintf(page, "%s\n", passThru_flag); + if (len <= off+count) + *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) + len = count; + + if (len<0) len = 0; + + return len; +} + +static int custom_createPseudoDevForPassThru(void) +{ + struct net_device *dev, *wanDev; + struct dev_priv *dp; + int rc, i; + unsigned long flags; + + wanDev = NULL; + /* find wan device first */ + for(i=0;i<ETH_INTF_NUM;i++) + { + dp = _rtl86xx_dev.dev[i]->priv; + if (rtl_isWanDev(dp)==TRUE) + { + wanDev = _rtl86xx_dev.dev[i]; + break; + } + } + + /* can't find any wan device, just return */ + if (wanDev==NULL) + return -1; + + dev = alloc_etherdev(sizeof(struct dev_priv)); + if (!dev){ + rtlglue_printf("failed to allocate passthru pseudo dev.\n"); + return -1; + } + strcpy(dev->name, "peth%d"); + /* default set lan side mac */ + memcpy((char*)dev->dev_addr,(char*)(&(vlanconfig[0].mac)),ETHER_ADDR_LEN); + dp = dev->priv; + memset(dp,0,sizeof(*dp)); + dp->dev = wanDev; +#if defined(CONFIG_COMPAT_NET_DEV_OPS) + dev->open = re865x_pseudo_open; + dev->stop = re865x_pseudo_close; + dev->set_multicast_list = NULL; + dev->hard_start_xmit = re865x_start_xmit; + dev->get_stats = re865x_get_stats; + dev->do_ioctl = re865x_ioctl; +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = cp_vlan_rx_register; + dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid; +#endif + +#else + dev->netdev_ops = &rtl819x_pseudodev_ops; +#endif + +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + dev->watchdog_timeo = TX_TIMEOUT; + + dev->irq = 0; + rc = register_netdev(dev); + if(!rc){ + local_irq_save(flags); + //spin_lock_irqsave(&_rtl86xx_dev.lock, flags); + _rtl86xx_dev.pdev = dev; + //spin_unlock_irqrestore(&_rtl86xx_dev.lock, flags); + local_irq_restore(flags); + rtlglue_printf("[%s] added, mapping to [%s]...\n", dev->name, dp->dev->name); + }else + rtlglue_printf("Failed to allocate [%s]\n", dev->name); + + return 0; +} + +static int custom_Passthru_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int flag,i; + +#if !defined(CONFIG_RTL_LAYERED_DRIVER) + struct rtl865x_vlanConfig passThruVlanConf = {"passThru",0,IF_ETHER,PASSTHRU_VLAN_ID,0, + rtl865x_lanPortMask|rtl865x_wanPortMask, + rtl865x_lanPortMask|rtl865x_wanPortMask, + 1500,{ { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 } } }; +#endif + + if (buffer && !copy_from_user(&passThru_flag, buffer, count)) + { + flag=(int)atoi_dec(passThru_flag); + + if(flag ^ oldStatus) + { + //IPv6 PassThru + if((flag & IP6_PASSTHRU_MASK) ^ (oldStatus & IP6_PASSTHRU_MASK)) + { + if(flag & IP6_PASSTHRU_MASK) + {//add + for(i=0; i<RTL865XC_PORT_NUMBER; i++) + { + rtl8651_setProtocolBasedVLAN(IP6_PASSTHRU_RULEID, i, TRUE, PASSTHRU_VLAN_ID); + } + } + else + {//delete + for(i=0; i<RTL865XC_PORT_NUMBER; i++) + { + rtl8651_setProtocolBasedVLAN(IP6_PASSTHRU_RULEID, i, FALSE, PASSTHRU_VLAN_ID); + } + } + } + + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU_PPPOE) + //PPPoE PassThru + if((flag & PPPOE_PASSTHRU_MASK) ^ (oldStatus & PPPOE_PASSTHRU_MASK)) + { + if(flag & PPPOE_PASSTHRU_MASK) + {//add + for(i=0; i<RTL865XC_PORT_NUMBER; i++) + { + rtl8651_setProtocolBasedVLAN(RTL8651_PBV_RULE_PPPOE_CONTROL, i, TRUE, PASSTHRU_VLAN_ID); + rtl8651_setProtocolBasedVLAN(RTL8651_PBV_RULE_PPPOE_SESSION, i, TRUE, PASSTHRU_VLAN_ID); + } + } + else + {//delete + for(i=0; i<RTL865XC_PORT_NUMBER; i++) + { + rtl8651_setProtocolBasedVLAN(RTL8651_PBV_RULE_PPPOE_CONTROL, i, FALSE, PASSTHRU_VLAN_ID); + rtl8651_setProtocolBasedVLAN(RTL8651_PBV_RULE_PPPOE_SESSION, i, FALSE, PASSTHRU_VLAN_ID); + } + } + } + #endif + } + + //passthru vlan + if(flag==0) + { + //To del passthru vlan + //Do nothing here because change_op_mode reinit vlan already + } + else + { + //To add passthru vlan + rtl865x_addVlan(PASSTHRU_VLAN_ID); + #if defined(CONFIG_POCKET_ROUTER_SUPPORT) + rtl865x_addVlanPortMember(PASSTHRU_VLAN_ID, rtl865x_lanPortMask|rtl865x_wanPortMask|0x100); + #else + rtl865x_addVlanPortMember(PASSTHRU_VLAN_ID, rtl865x_lanPortMask|rtl865x_wanPortMask); + #endif + } + + oldStatus=flag; + return count; + } + return -EFAULT; +} + +static int32 rtl8651_customPassthru_init(void) +{ + oldStatus=0; + res = create_proc_entry("custom_Passthru", 0, NULL); + if(res) + { + res->read_proc = custom_Passthru_read_proc; + res->write_proc = custom_Passthru_write_proc; + } + rtl8651_defineProtocolBasedVLAN( IP6_PASSTHRU_RULEID, 0x0, __constant_htons(ETH_P_IPV6) ); + #if defined(CONFIG_RTL_CUSTOM_PASSTHRU_PPPOE) + rtl8651_defineProtocolBasedVLAN( PPPOE_PASSTHRU_RULEID1, 0x0, __constant_htons(ETH_P_PPP_SES) ); + rtl8651_defineProtocolBasedVLAN( PPPOE_PASSTHRU_RULEID2, 0x0, __constant_htons(ETH_P_PPP_DISC) ); + #endif + custom_createPseudoDevForPassThru(); + return 0; +} + +static void __exit rtl8651_customPassthru_exit(void) +{ + if (res) { + remove_proc_entry("custom_Passthru", res); + res = NULL; + } +} +#define MULTICAST_STORM_CONTROL 1 +#define BROADCAST_STORM_CONTROL 2 + +static struct proc_dir_entry *stormCtrlProc=NULL; +static int rtl865x_stormCtrlReadProc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len=0; + if (len <= off+count) + *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) + len = count; + + if (len<0) len = 0; + + return len; +} + +static int rtl865x_stormCtrlWriteProc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + uint32 tmpBuf[32]; + uint32 stormCtrlType=MULTICAST_STORM_CONTROL; + uint32 enableStormCtrl=FALSE; + uint32 percentage=0; + uint32 uintVal; + + if (buffer && !copy_from_user(tmpBuf, buffer, count)) + { + tmpBuf[count-1]=0; + uintVal=simple_strtol((const char *)tmpBuf, NULL, 0); + //printk("%s(%d),tmpBuf=%s,count=%d,uintVal=%d\n",__FUNCTION__,__LINE__, + // tmpBuf,count,uintVal);//Added for test + if(uintVal>100) + { + enableStormCtrl=FALSE; + percentage=0; + } + else + { + enableStormCtrl=TRUE; + percentage=uintVal; + } + rtl865x_setStormControl(stormCtrlType,enableStormCtrl,percentage); + return count; + } + return -EFAULT; +} + +int32 rtl8651_initStormCtrl(void) +{ + stormCtrlProc = create_proc_entry("StormCtrl", 0, NULL); + if(stormCtrlProc) + { + stormCtrlProc->read_proc = rtl865x_stormCtrlReadProc; + stormCtrlProc->write_proc = rtl865x_stormCtrlWriteProc; + } + + return 0; +} + +void __exit rtl8651_exitStormCtrl(void) +{ + if (stormCtrlProc) { + remove_proc_entry("StormCtrl", stormCtrlProc); + stormCtrlProc = NULL; + } +} + + +#endif + +#if defined(CONFIG_RTL_8198) +static int32 proc_phyTest_read( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + return 0; +} + +static int32 proc_phyTest_write( struct file *filp, const char *buff,unsigned long len1, void *data ) +{ + char tmpbuf[64]; + uint32 phyId=0, regId=0,iNo=0,iPort=0,len=0,regData=0; + char *strptr, *cmd_addr; + char *tokptr; + int32 i=0,port=0; + int32 ret=FAILED; + if (buff && !copy_from_user(tmpbuf, buff, len1)) { + tmpbuf[len1-1] = '\0'; + strptr=tmpbuf; + cmd_addr = strsep(&strptr," "); + if (cmd_addr==NULL) + { + goto errout; + } + + if (!memcmp(cmd_addr, "read", 4)) + { + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + regId=simple_strtol(tokptr, NULL, 0); + + ret=rtl8651_getAsicEthernetPHYReg(phyId, regId, ®Data); + if(ret==SUCCESS) + { + printk("read phyId(%d), regId(%d),regData:0x%x\n", phyId, regId, regData); + } + else + { + printk("error input!\n"); +// goto errout; + } + } + else if (!memcmp(cmd_addr, "test", 4)) + { + printk("\r\n"); + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + iNo=simple_strtol(tokptr, NULL, 0); + if(iNo==1)//test mode 1 + { + + unsigned int default_val_t1[]={ + 4,0x1f,0x0002, + 4,0x13,0xAA00, + 4,0x14,0xAA00, + 4,0x15,0xAA00, + 4,0x16,0xFA00, + 4,0x17,0xAF00 + }; + printk("PHY Test 1 Mode: No\n"); + for(i=0; i<5; i++) + REG32(PCRP0+i*4) |= (EnForceMode); + len=sizeof(default_val_t1)/sizeof(unsigned int); + + for(i=0;i<len;i=i+3) + { + port=default_val_t1[i]; + rtl8651_setAsicEthernetPHYReg(port, default_val_t1[i+1], default_val_t1[i+2]); + } + for(i=0; i<5; i++) + { + rtl8651_setAsicEthernetPHYReg(i, 0x1f, 0x0000); + rtl8651_setAsicEthernetPHYReg(i, 0x09, 0x2E00); + } + for(i=0; i<5; i++) + REG32(PCRP0+i*4) &= ~(EnForceMode); + printk("Please reset the target after leaving Test Mode\n"); + ret=SUCCESS; + } + #if 0 + else if(iNo==2)//test mode 2 + { + + unsigned int default_val_t2[]={ + 1, 0x1f, 0x0002, + 1, 0x11, 0x5E00, + 1, 0x1f, 0x0000, + 4, 0x1f, 0x0002, + 4, 0x11, 0x5E00, + 4, 0x1f, 0x0000 + + }; + printk("PHY Test 2 Mode: No\n"); + for(i=0; i<5; i++) + REG32(PCRP0+i*4) |= (EnForceMode); + len=sizeof(default_val_t2)/sizeof(unsigned int); + + for(i=0;i<len;i=i+3) + { + port=default_val_t2[i]; + rtl8651_setAsicEthernetPHYReg(port, default_val_t2[i+1], default_val_t2[i+2]); + } + for(i=0; i<5; i++) + { + rtl8651_setAsicEthernetPHYReg(i, 0x1f, 0x0000); + rtl8651_setAsicEthernetPHYReg(i, 0x09, 0x4E00); + } + for(i=0; i<5; i++) + REG32(PCRP0+i*4) &= ~(EnForceMode); + printk("Please reset the target after leaving Test Mode\n"); + ret=SUCCESS; + } + else if(iNo==3)//test mode 2 + { + unsigned int default_val_t3[]={ + 1, 0x1f, 0x0002, + 1, 0x11, 0x4000, + }; + for(i=0; i<5; i++) + REG32(PCRP0+i*4) |= (EnForceMode); + + printk("PHY Test 3 Mode: No Port{0~4} Channel{A,B,C,D}\n"); + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + iPort=simple_strtol(tokptr, NULL, 0); + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + len=sizeof(default_val_t3)/sizeof(unsigned int); + for(i=0;i<len;i=i+3) + { + port=default_val_t3[i]; + rtl8651_setAsicEthernetPHYReg(port, default_val_t3[i+1], default_val_t3[i+2]); + } + + switch(*tokptr) + { + + case 'A': + rtl8651_setAsicEthernetPHYReg(1, 0x10, 0x1100); + rtl8651_setAsicEthernetPHYReg(1, 0x1f, 0x0000); + printk("A channel\n"); + + break; + case 'B': + rtl8651_setAsicEthernetPHYReg(1, 0x10, 0x1300); + rtl8651_setAsicEthernetPHYReg(1, 0x1f, 0x0000); + printk("B channel\n"); + break; + case 'C': + rtl8651_setAsicEthernetPHYReg(1, 0x10, 0x1500); + rtl8651_setAsicEthernetPHYReg(1, 0x1f, 0x0000); + printk("C channel\n"); + break; + case 'D': + rtl8651_setAsicEthernetPHYReg(1, 0x10, 0x1700); + rtl8651_setAsicEthernetPHYReg(1, 0x1f, 0x0000); + printk("D channel\n"); + break; + } + rtl8651_setAsicEthernetPHYReg(iPort, 0x1f, 0x0000); + rtl8651_setAsicEthernetPHYReg(iPort, 0x09, 0x6e00); + for(i=0; i<5; i++) + REG32(PCRP0+i*4) &= ~(EnForceMode); + printk("Please reset the target after leaving Test Mode\n"); + ret=SUCCESS; + } + #endif + else if(iNo==4)//test mode 2 + { + unsigned int default_val_t4[]={ + 0, 0x1f, 0x0002, + 0, 0x07, 0x3678, + 0, 0x1f, 0x0000, + 0, 0x09, 0x8e00 + }; + + for(i=0; i<5; i++) + REG32(PCRP0+i*4) |= (EnForceMode); + + len=sizeof(default_val_t4)/sizeof(unsigned int); + + + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + iPort=simple_strtol(tokptr, NULL, 0); + printk("PHY Test 4 Mode: No:%d Port:%d \n",iNo,iPort); + for(i=0;i<len;i=i+3) + { + rtl8651_setAsicEthernetPHYReg(iPort, default_val_t4[i+1], default_val_t4[i+2]); + } + + for(i=0; i<5; i++) + REG32(PCRP0+i*4) &= ~(EnForceMode); + printk("Please reset the target after leaving Test Mode\n"); + ret=SUCCESS; + } + + +#if 0 + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + regId=simple_strtol(tokptr, NULL, 0); + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errout; + } + regData=simple_strtol(tokptr, NULL, 0); + + ret=rtl8651_setAsicEthernetPHYReg(phyId, regId, regData); +#endif + if(ret==SUCCESS) + { + //printk("Write phyId(%d), regId(%d), regData:0x%x\n", phyId, regId, regData); + } + else + { + printk("error input!\n"); +// goto errout; + } + } + else + { + goto errout; + } + + return len1; + +errout: + printk("\nTest format: \"Test 1~4\"\n"); + printk("PHY Test 1 Mode: No\n"); + //printk("PHY Test 2 Mode: No\n"); + //printk("PHY Test 3 Mode: No Port{0~4} Channel{A,B,C,D}\n"); + printk("PHY Test 4 Mode: No Port{0~4} \n"); + + return len1; + } + + return -EFAULT; +} + +int32 phyRegTest_init(void) +{ + phyTest_entry= create_proc_entry("phyRegTest", 0, NULL); + if(phyTest_entry != NULL) + { + phyTest_entry->read_proc = proc_phyTest_read; + phyTest_entry->write_proc = proc_phyTest_write; + } + + return 0; +} + +void __exit phyRegTest_exit(void) +{ + if (phyTest_entry) + { + remove_proc_entry("phyTest_entry", phyTest_entry); + phyTest_entry = NULL; + } +} +#endif + +#if defined (CONFIG_RTL_MLD_SNOOPING) + +static struct proc_dir_entry *mldSnoopingProc=NULL; + + +static int rtl865x_mldSnoopingReadProc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + len = sprintf(page, "%s\n", (mldSnoopEnabled==TRUE)?"enable":"disable"); + if (len <= off+count) + *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) + len = count; + + if (len<0) len = 0; + + return len; +} + +static int rtl865x_mldSnoopingWriteProc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + uint32 tmpBuf[32]; + uint32 uintVal; + + if (buffer && !copy_from_user(tmpBuf, buffer, count)) + { + tmpBuf[count-1]=0; + uintVal=simple_strtol((const char *)tmpBuf, NULL, 0); + if(uintVal!=0) + { + if(mldSnoopEnabled==FALSE) + { + rtl865x_removeAclForMldSnooping(vlanconfig); + rtl865x_addAclForMldSnooping(vlanconfig); + mldSnoopEnabled=TRUE; + } + } + else + { + if(mldSnoopEnabled==TRUE) + { + rtl865x_removeAclForMldSnooping(vlanconfig); + mldSnoopEnabled=FALSE; + } + } + + return count; + } + return -EFAULT; +} + +int32 rtl8651_initMldSnooping(void) +{ + mldSnoopingProc = create_proc_entry("br_mldsnoop", 0, NULL); + if(mldSnoopingProc) + { + mldSnoopingProc->read_proc = rtl865x_mldSnoopingReadProc; + mldSnoopingProc->write_proc = rtl865x_mldSnoopingWriteProc; + } + mldSnoopEnabled=FALSE; + return 0; +} + +void __exit rtl8651_exitMldSnoopingCtrl(void) +{ + if (mldSnoopingProc) { + remove_proc_entry("mldSnooping", mldSnoopingProc); + mldSnoopingProc = NULL; + } +} + +#endif + +#if defined (CONFIG_RTL_PHY_POWER_CTRL) +static struct proc_dir_entry *phyPowerCtrlProc=NULL; +#define PHY_POWER_OFF 0 +#define PHY_POWER_ON 1 +static int rtl865x_setPhyPowerOff(unsigned int port) +{ + unsigned int offset = port * 4; + unsigned int pcr = 0; + unsigned int regData; + unsigned int macLinkStatus; + unsigned int phyLinkStatus; + if(port >=RTL8651_PHY_NUMBER) + { + return -1; + } + + /*must set mac force link down first*/ + pcr=READ_MEM32( PCRP0 + offset ); + pcr |= EnForceMode; + pcr &= ~ForceLink; + WRITE_MEM32( PCRP0 + offset, pcr ); + TOGGLE_BIT_IN_REG_TWICE(PCRP0 + offset,EnForceMode); + + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + regData=regData |(1<<11); + rtl8651_setAsicEthernetPHYReg(port, 0, regData); + + /*confirm shutdown phy power successfully*/ + regData = READ_MEM32(PSRP0+offset); + macLinkStatus = regData & PortStatusLinkUp; + + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + phyLinkStatus=!(regData & (1<<11)); + while((macLinkStatus) || (phyLinkStatus) ) + { + //printk("port is %d,macLinkStatus is %d,phyLinkStatus is %d\n",port,macLinkStatus,phyLinkStatus); + pcr=READ_MEM32( PCRP0 + offset ); + pcr |= EnForceMode; + pcr &= ~ForceLink; + WRITE_MEM32( PCRP0 + offset, pcr ); + TOGGLE_BIT_IN_REG_TWICE(PCRP0 + offset,EnForceMode); + + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + regData=regData |(1<<11); + rtl8651_setAsicEthernetPHYReg(port, 0, regData); + + regData = READ_MEM32(PSRP0+offset); + macLinkStatus = regData & PortStatusLinkUp; + + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + phyLinkStatus=!(regData & (1<<11)); + } + return 0; + +} + +static int rtl865x_setPhyPowerOn(unsigned int port) +{ + unsigned int offset = port * 4; + unsigned int pcr = 0; + + unsigned int regData; + + if(port >=RTL8651_PHY_NUMBER) + { + return -1; + } + + pcr=READ_MEM32( PCRP0 + offset ); + pcr |= EnForceMode; + + WRITE_MEM32( PCRP0 + offset, pcr ); + TOGGLE_BIT_IN_REG_TWICE(PCRP0 + offset,EnForceMode); + + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + regData=regData &(~(1<<11)); + rtl8651_setAsicEthernetPHYReg(port, 0, regData); + + pcr &=~EnForceMode; + WRITE_MEM32( PCRP0 + offset, pcr); + TOGGLE_BIT_IN_REG_TWICE(PCRP0 + offset,EnForceMode); + return 0; + +} + + +static int rtl865x_phyPowerCtrlReadProc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len=0; + int port; + unsigned int regData; + for(port=0;port<RTL8651_PHY_NUMBER;port++) + { + rtl8651_getAsicEthernetPHYReg(port, 0, ®Data); + if(regData & (1<<11)) + { + len += sprintf(page+len, "port[%d] phy is power off\n",port ); + } + else + { + len += sprintf(page+len, "port[%d] phy is power on\n",port ); + } + } + + if (len <= off+count) + *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) + len = count; + + if (len<0) len = 0; + + return len; +} + +static int rtl865x_phyPowerCtrlWriteProc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmpBuf[256]; + char *strptr; + char *tokptr; + unsigned int portMask; + unsigned int action; + int i; + if (buffer && !copy_from_user(tmpBuf, buffer, count)) + { + tmpBuf[count-1]=0; + strptr=tmpBuf; + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errOut; + } + portMask=simple_strtol(tokptr, NULL, 0); + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errOut; + } + action=simple_strtol(tokptr, NULL, 0); + + for(i=0;i<RTL8651_PHY_NUMBER;i++) + { + if((1<<i) &portMask) + { + if(action==PHY_POWER_OFF) + { + rtl865x_setPhyPowerOff(i); + } + else if (action==PHY_POWER_ON) + { + rtl865x_setPhyPowerOn(i); + } + } + + } + + return count; + } + +errOut: + return -EFAULT; +} + + +static int32 rtl865x_initPhyPowerCtrl(void) +{ + phyPowerCtrlProc = create_proc_entry("phyPower", 0, NULL); + if(phyPowerCtrlProc) + { + phyPowerCtrlProc->read_proc = rtl865x_phyPowerCtrlReadProc; + phyPowerCtrlProc->write_proc = rtl865x_phyPowerCtrlWriteProc; + } + + return 0; +} + +void __exit rtl865x_exitPhyPowerCtrl(void) +{ + if (phyPowerCtrlProc) { + remove_proc_entry("phyPower", phyPowerCtrlProc); + phyPowerCtrlProc = NULL; + } +} + +#endif + + +#if defined(CONFIG_RTL_LINKSTATE) + +static struct proc_dir_entry *portStateProc=NULL; +static unsigned int linkUpTime[RTL8651_PHY_NUMBER] = {0,0,0,0,0}; + +static void init_linkup_time(void) +{ + init_timer(&s_timer); + s_timer.function = &linkup_time_handle; + s_timer.expires = jiffies + HZ; + add_timer(&s_timer); +} + +static void linkup_time_handle(unsigned long arg) +{ + int port; + uint32 regData; + uint32 data0; + mod_timer(&s_timer,jiffies +HZ); + for(port=PHY0;port<PHY5;port++) + { + regData = READ_MEM32(PSRP0+((port)<<2)); + data0 = regData & PortStatusLinkUp; + if (data0) + { + linkUpTime[port]++; + } + else + { + linkUpTime[port]=0; + } + } +} + +static int32 port_state_read_proc( char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int len; + uint32 regData; + uint32 data0; + int port; + + len = sprintf(page, "Port Link State:\n"); + + for(port=PHY0;port<PHY5;port++) + { + regData = READ_MEM32(PSRP0+((port)<<2)); + + //if (port==CPU) + //len += sprintf(page+len, "CPUPort "); + //else + len += sprintf(page+len, "Port[%d]:", port); + data0 = regData & PortStatusLinkUp; + + if (data0) + { + len += sprintf(page+len, "LinkUp|"); + } + else + { + len += sprintf(page+len, "LinkDown\n"); + continue; + } + //data0 = regData & PortStatusNWayEnable; + //len += sprintf(page+len, "NWay Mode %s\n", data0?"Enabled":"Disabled"); + data0 = regData & PortStatusRXPAUSE; + len += sprintf(page+len, "RXPause:%s|", data0?"Enable":"Disable"); + data0 = regData & PortStatusTXPAUSE; + len += sprintf(page+len, "TXPause:%s|", data0?"Enable":"Disable"); + data0 = regData & PortStatusDuplex; + len += sprintf(page+len, "Duplex:%s|", data0?"Enable":"Disable"); + data0 = (regData&PortStatusLinkSpeed_MASK)>>PortStatusLinkSpeed_OFFSET; + len += sprintf(page+len, "Speed:%s|", data0==PortStatusLinkSpeed100M?"100M": + (data0==PortStatusLinkSpeed1000M?"1G": + (data0==PortStatusLinkSpeed10M?"10M":"Unkown"))); + len += sprintf(page+len, "UpTime:%ds\n", linkUpTime[port]); + } + + return len; +} + +static int32 port_state_write_proc( struct file *filp, const char *buff,unsigned long len, void *data ) +{ + return len; +} + +static int32 initPortStateCtrl(void) +{ + portStateProc = create_proc_entry("portState", 0, NULL); + if(portStateProc) + { + portStateProc->read_proc = port_state_read_proc; + portStateProc->write_proc = port_state_write_proc; + } + memset(linkUpTime,0,sizeof(linkUpTime)); + init_linkup_time(); + + return 0; +} + +static void exitPortStateCtrl(void) +{ + if (portStateProc) { + remove_proc_entry("portState", portStateProc); + portStateProc = NULL; + } + del_timer(&s_timer); +} +#endif + +#if defined(CONFIG_RTL_MULTIPLE_WAN) +static int rtl_port_used_by_device(uint32 portMask) +{ + int i; + struct dev_priv *cp; + int retval = FAILED; + + for(i = 0; i < ETH_INTF_NUM; i++) + { + cp = ((struct dev_priv *)_rtl86xx_dev.dev[i]->priv); + if(cp && cp->opened && (cp->portmask & portMask)) + { + retval = SUCCESS; + break; + } + + } + + cp = (struct dev_priv *)rtl_multiWan_net_dev->priv; + if(cp && cp->opened && (cp->portmask & portMask)) + retval = SUCCESS; + + return retval; +} + + +static int rtl_regist_multipleWan_dev(void) +{ + int j; + struct net_device *dev; + struct dev_priv *dp; + int rc; + + dev = alloc_etherdev(sizeof(struct dev_priv)); + if (!dev) { + printk("====%s(%d) failed to allocate\n",__FUNCTION__,__LINE__); + return FAILED; + } + SET_MODULE_OWNER(dev); + dp = dev->priv; + memset(dp,0,sizeof(*dp)); + dp->dev = dev; + dp->id = rtl_multiWan_config.vid; + dp->portmask = rtl_multiWan_config.memPort; + dp->portnum = 0; + for(j=0;j<RTL8651_AGGREGATOR_NUMBER;j++){ + if(dp->portmask & (1<<j)) + dp->portnum++; + } + + memcpy((char*)dev->dev_addr,(char*)(&(rtl_multiWan_config.mac)),ETHER_ADDR_LEN); +#if defined(CONFIG_COMPAT_NET_DEV_OPS) + dev->open = re865x_open; + dev->stop = re865x_close; + dev->set_multicast_list = re865x_set_rx_mode; + dev->hard_start_xmit = re865x_start_xmit; + dev->get_stats = re865x_get_stats; + dev->do_ioctl = re865x_ioctl; + dev->tx_timeout = re865x_tx_timeout; + dev->set_mac_address = rtl865x_set_hwaddr; + dev->change_mtu = rtl865x_set_mtu; +#if defined(CONFIG_RTL8186_LINK_CHANGE) + dev->change_link = rtl865x_set_link; +#endif +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = cp_vlan_rx_register; + dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid; +#endif + +#else + dev->netdev_ops = &rtl819x_netdev_ops; +#endif + dev->watchdog_timeo = TX_TIMEOUT; + +#ifdef CP_VLAN_TAG_USED + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + + dev->irq = 0; + rc = register_netdev(dev); + if(!rc){ + rtl_multiWan_net_dev = dev; + rtl_add_ps_drv_netif_mapping(dev,rtl_multiWan_config.ifname); + printk("==%s(%d) %s added. vid=%d Member port 0x%x...\n",__FUNCTION__,__LINE__,dev->name,rtl_multiWan_config.vid ,rtl_multiWan_config.memPort ); + }else + printk("===%s(%d) Failed to allocate,rc(%d)\n",__FUNCTION__,__LINE__,rc); + + // +} +#if 0 +static int rtl_unregist_multipleWan_dev(void) +{ + if(rtl_multiWan_net_dev) + unregister_netdev(rtl_multiWan_net_dev); + + rtl_multiWan_net_dev = NULL; + return SUCCESS; +} +#endif +static int rtl_config_multipleWan_netif(int32 cmd) +{ + int retval = FAILED; + switch(cmd) + { + case RTL_MULTIWAN_ADD: + { + rtl865x_netif_t netif; + + /*add vlan*/ + retval = rtl865x_addVlan(rtl_multiWan_config.vid); + if(retval == SUCCESS) + { + rtl865x_addVlanPortMember(rtl_multiWan_config.vid,rtl_multiWan_config.memPort); + rtl865x_setVlanFilterDatabase(rtl_multiWan_config.vid,rtl_multiWan_config.fid); + + } + else if (retval == RTL_EVLANALREADYEXISTS) + { + //only add memberport to vlan + rtl865x_addVlanPortMember(rtl_multiWan_config.vid,rtl_multiWan_config.memPort); + } + + /*add network interface*/ + memset(&netif, 0, sizeof(rtl865x_netif_t)); + memcpy(netif.name,rtl_multiWan_config.ifname,MAX_IFNAMESIZE); + memcpy(netif.macAddr.octet, rtl_multiWan_config.mac.octet,ETHER_ADDR_LEN); + netif.mtu = rtl_multiWan_config.mtu; + netif.if_type = rtl_multiWan_config.if_type; + netif.vid = rtl_multiWan_config.vid; + netif.is_wan = rtl_multiWan_config.isWan; + netif.is_slave = rtl_multiWan_config.is_slave; + #if defined (CONFIG_RTL_HARDWARE_MULTICAST) + netif.enableRoute=1; + #endif + retval = rtl865x_addNetif(&netif); + rtl865x_reConfigDefaultAcl(netif.name); + + if(retval != SUCCESS && retval != RTL_EVLANALREADYEXISTS) + { + printk("=======%s(%d),retval(%d)\n",__FUNCTION__,__LINE__,retval); + } + } + rtl_init_advRt(); + break; + case RTL_MULTIWAN_DEL: + rtl_exit_advRt(); + rtl865x_delNetif(rtl_multiWan_config.ifname); + rtl865x_delVlanPortMember(rtl_multiWan_config.vid,rtl_multiWan_config.memPort); + break; + default: + retval = FAILED; + } + + return retval; +} +#endif + + +#if defined(CONFIG_RTL_REINIT_SWITCH_CORE) +int re865x_reProbe (void) +{ + rtl8651_tblAsic_InitPara_t para; + unsigned long flags; + + local_irq_save(flags); + //WRITE_MEM32(PIN_MUX_SEL_2, 0x7<<21); + /*Initial ASIC table*/ + +#ifdef CONFIG_RTL8198_REVISION_B + if (REG32(BSP_REVR) >= BSP_RTL8198_REVISION_B) + { + REG32(SYS_CLK_MAG)&=(~(SYS_SW_RESET)); + mdelay(300); + REG32(SYS_CLK_MAG)|=(SYS_SW_RESET); + mdelay(100); + + } + else +#endif + FullAndSemiReset(); + + memset(¶, 0, sizeof(rtl8651_tblAsic_InitPara_t)); + + /* + For DEMO board layout, RTL865x platform define corresponding PHY setting and PHYID. + */ + + INIT_CHECK(rtl865x_initAsicL2(¶)); + +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER_L3 + INIT_CHECK(rtl865x_initAsicL3()); +#endif +#if defined(CONFIG_RTL_LAYERED_ASIC_DRIVER_L4) && defined(CONFIG_RTL_8198) + INIT_CHECK(rtl865x_initAsicL4()); +#endif + + + /*init PHY LED style*/ +#if defined(CONFIG_RTL865X_BICOLOR_LED) + #ifdef BICOLOR_LED_VENDOR_BXXX + REG32(LEDCR) |= (1 << 19); // 5 ledmode set to 1 for bi-color LED + REG32(PABCNR) &= ~0x001f0000; /* set port port b-4/3/2/1/0 to gpio */ + REG32(PABDIR) |= 0x001f0000; /* set port port b-4/3/2/1/0 gpio direction-output */ + #else + //8650B demo board default: Bi-color 5 LED + WRITE_MEM32(LEDCR, READ_MEM32(LEDCR) | 0x01180000 ); // bi-color LED + #endif + /* config LED mode */ + WRITE_MEM32(SWTAA, PORT5_PHY_CONTROL); + WRITE_MEM32(TCR0, 0x000002C2); //8651 demo board default: 15 LED boards + WRITE_MEM32(SWTACR, CMD_FORCE | ACTION_START); // force add +#else /* CONFIG_RTL865X_BICOLOR_LED */ + + /* config LED mode */ + WRITE_MEM32(LEDCR, 0x00000000 ); // 15 LED + WRITE_MEM32(SWTAA, PORT5_PHY_CONTROL); + WRITE_MEM32(TCR0, 0x000002C7); //8651 demo board default: 15 LED boards + WRITE_MEM32(SWTACR, CMD_FORCE | ACTION_START); // force add +#endif /* CONFIG_RTL865X_BICOLOR_LED */ + +/*2007-12-19*/ +#if defined(CONFIG_RTK_VLAN_SUPPORT) + //port based decision + rtl865xC_setNetDecisionPolicy(NETIF_PORT_BASED); + WRITE_MEM32(PLITIMR,0); + +#endif + + /*queue id & rx ring descriptor mapping*/ + REG32(CPUQDM0)=QUEUEID1_RXRING_MAPPING|(QUEUEID0_RXRING_MAPPING<<16); + REG32(CPUQDM2)=QUEUEID3_RXRING_MAPPING|(QUEUEID2_RXRING_MAPPING<<16); + REG32(CPUQDM4)=QUEUEID5_RXRING_MAPPING|(QUEUEID4_RXRING_MAPPING<<16); + + rtl8651_setAsicOutputQueueNumber(CPU, RTL_CPU_RX_RING_NUM); + + + +#if defined(CONFIG_RTL_HW_STP) + //Initial: disable Realtek Hardware STP + rtl865x_setSpanningEnable(FALSE); +#endif + + +#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER_L3 +#if defined (CONFIG_RTL_HARDWARE_MULTICAST) + rtl8651_setAsicMulticastEnable(TRUE); +#else + rtl8651_setAsicMulticastEnable(FALSE); +#endif +#endif + local_irq_restore(flags); + return 0; +} + +int rtl865x_reinitSwitchCore(void) +{ + /*enable switch core clock*/ + rtl865x_duringReInitSwtichCore=1; + /*disable switch core interrupt*/ + REG32(CPUICR) = 0; + REG32(CPUIIMR) = 0; + REG32(GIMR) &= ~(BSP_SW_IE); + + re865x_reProbe(); + swNic_reInit(); + rtl865x_reChangeOpMode(); + + /*enable switch core interrupt*/ + + REG32(CPUICR) = TXCMD | RXCMD | BUSBURST_32WORDS | MBUF_2048BYTES; + REG32(CPUIIMR) = RX_DONE_IE_ALL | TX_ALL_DONE_IE_ALL | LINK_CHANGE_IE; + REG32(GIMR) |= (BSP_SW_IE); + + rtl865x_duringReInitSwtichCore=0; + return 0; +} + +static struct proc_dir_entry *reInitSwitchCoreProc=NULL; + +static int rtl865x_reInitSwitchCoreReadProc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len=0; + + if (len <= off+count) + *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) + len = count; + + if (len<0) len = 0; + + return len; +} + +static int rtl865x_reInitSwitchCoreWriteProc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char tmpBuf[256]; + char *strptr; + char *tokptr; + unsigned int action; + + if (buffer && !copy_from_user(tmpBuf, buffer, count)) + { + tmpBuf[count-1]=0; + strptr=tmpBuf; + + tokptr = strsep(&strptr," "); + if (tokptr==NULL) + { + goto errOut; + } + + if(rtl865x_duringReInitSwtichCore) + { + goto errOut; + } + //printk("here to reset switch core\n"); + action=simple_strtol(tokptr, NULL, 0); + if(action==1) + { + rtl865x_reinitSwitchCore(); + } + + return count; + } + +errOut: + return -EFAULT; +} + + +int rtl865x_creatReInitSwitchCoreProc(void) +{ + reInitSwitchCoreProc = create_proc_entry("reInitSwitchCore", 0, NULL); + if(reInitSwitchCoreProc) + { + reInitSwitchCoreProc->read_proc = rtl865x_reInitSwitchCoreReadProc; + reInitSwitchCoreProc->write_proc = rtl865x_reInitSwitchCoreWriteProc; + } + + return 0; +} + +void __exit rtl865x_destroyReInitResetSwitchCore(void) +{ + if (reInitSwitchCoreProc) { + remove_proc_entry("reInitSwitchCore", reInitSwitchCoreProc); + reInitSwitchCoreProc = NULL; + } +} + +#endif + + + |