rename and renumber storm patches
[openwrt/openwrt.git] / target / linux / storm / patches / 002-gmac.patch
diff --git a/target/linux/storm/patches/002-gmac.patch b/target/linux/storm/patches/002-gmac.patch
new file mode 100644 (file)
index 0000000..d6632ba
--- /dev/null
@@ -0,0 +1,18615 @@
+--- /dev/null
++++ b/drivers/net/sl2312_emac.c
+@@ -0,0 +1,4604 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch-sl2312/irqs.h>
++#include <asm/arch/it8712.h>
++#include <asm/arch/sl2312.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/sysctl_storlink.h>
++
++#define BIG_ENDIAN    0
++
++#define GMAC_DEBUG      0
++
++#define GMAC_PHY_IF     2
++
++/* define PHY address */
++#define HPHY_ADDR   0x01
++#define GPHY_ADDR   0x02
++
++#define CONFIG_ADM_6999 1
++/* define chip information */
++#define DRV_NAME                      "SL2312"
++#define DRV_VERSION                   "0.1.1"
++#define SL2312_DRIVER_NAME  DRV_NAME " Fast Ethernet driver " DRV_VERSION
++
++/* define TX/RX descriptor parameter */
++#define MAX_ETH_FRAME_SIZE    1920
++#define TX_BUF_SIZE                   MAX_ETH_FRAME_SIZE
++#define TX_DESC_NUM                   128
++#define TX_BUF_TOT_LEN                (TX_BUF_SIZE * TX_DESC_NUM)
++#define RX_BUF_SIZE                   MAX_ETH_FRAME_SIZE
++#define RX_DESC_NUM                   256
++#define RX_BUF_TOT_LEN                (RX_BUF_SIZE * RX_DESC_NUM)
++#define MAX_ISR_WORK        20
++
++unsigned int int_status = 0;
++
++/* define GMAC base address */
++#define GMAC_PHYSICAL_BASE_ADDR           (SL2312_GMAC_BASE)
++#define GMAC_BASE_ADDR                            (IO_ADDRESS(GMAC_PHYSICAL_BASE_ADDR))
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++#define GMAC0_BASE                  (IO_ADDRESS(SL2312_GMAC0_BASE))
++#define GMAC1_BASE                  (IO_ADDRESS(SL2312_GMAC1_BASE))
++
++/* memory management utility */
++#define DMA_MALLOC(size,handle)               pci_alloc_consistent(NULL,size,handle)
++#define DMA_MFREE(mem,size,handle)    pci_free_consistent(NULL,size,mem,handle)
++
++//#define gmac_read_reg(offset)       (readl(GMAC_BASE_ADDR + offset))
++//#define gmac_write_reg(offset,data,mask)  writel( (gmac_read_reg(offset)&~mask) |(data&mask),(GMAC_BASE_ADDR+offset))
++
++/* define owner bit */
++#define CPU           0
++#define DMA           1
++
++#define ACTIVE      1
++#define NONACTIVE   0
++
++#define CONFIG_SL_NAPI
++
++#ifndef CONFIG_SL2312_MPAGE
++#define CONFIG_SL2312_MPAGE
++#endif
++
++#ifdef CONFIG_SL2312_MPAGE
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#endif
++
++#ifndef CONFIG_TXINT_DISABLE
++//#define CONFIG_TXINT_DISABLE
++#endif
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++
++/* transmit timeout value */
++#define TX_TIMEOUT  (6*HZ)
++
++/***************************************/
++/* the offset address of GMAC register */
++/***************************************/
++enum GMAC_REGISTER {
++      GMAC_STA_ADD0   = 0x0000,
++      GMAC_STA_ADD1   = 0x0004,
++      GMAC_STA_ADD2   = 0x0008,
++      GMAC_RX_FLTR    = 0x000c,
++      GMAC_MCAST_FIL0 = 0x0010,
++      GMAC_MCAST_FIL1 = 0x0014,
++      GMAC_CONFIG0    = 0x0018,
++      GMAC_CONFIG1    = 0x001c,
++      GMAC_CONFIG2    = 0x0020,
++      GMAC_BNCR               = 0x0024,
++      GMAC_RBNR               = 0x0028,
++      GMAC_STATUS             = 0x002c,
++      GMAC_IN_DISCARDS= 0x0030,
++      GMAC_IN_ERRORS  = 0x0034,
++      GMAC_IN_MCAST   = 0x0038,
++      GMAC_IN_BCAST   = 0x003c,
++      GMAC_IN_MAC1    = 0x0040,
++      GMAC_IN_MAC2    = 0x0044
++};
++
++/*******************************************/
++/* the offset address of GMAC DMA register */
++/*******************************************/
++enum GMAC_DMA_REGISTER {
++      GMAC_DMA_DEVICE_ID              = 0xff00,
++      GMAC_DMA_STATUS                 = 0xff04,
++      GMAC_TXDMA_CTRL                 = 0xff08,
++      GMAC_TXDMA_FIRST_DESC   = 0xff0c,
++      GMAC_TXDMA_CURR_DESC    = 0xff10,
++      GMAC_RXDMA_CTRL                 = 0xff14,
++      GMAC_RXDMA_FIRST_DESC   = 0xff18,
++      GMAC_RXDMA_CURR_DESC    = 0xff1c,
++};
++
++/*******************************************/
++/* the register structure of GMAC          */
++/*******************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0004
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int sta_add2_l16       : 16;   /* station MAC address2 bits 15 to 0 */
++              unsigned int sta_add1_h16       : 16;   /* station MAC address1 bits 47 to 32 */
++#else
++              unsigned int sta_add1_h16       : 16;   /* station MAC address1 bits 47 to 32 */
++              unsigned int sta_add2_l16       : 16;   /* station MAC address2 bits 15 to 0 */
++#endif
++      } bits;
++} GMAC_STA_ADD1_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_000c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 27;
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++#else
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int                            : 27;
++#endif
++      } bits;
++} GMAC_RX_FLTR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0018
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int : 10;
++              unsigned int inv_rx_clk     : 1;        /* Inverse RX Clock */
++              unsigned int rising_latch   : 1;
++        unsigned int rx_tag_remove  :  1;   /* Remove Rx VLAN tag */
++        unsigned int ipv6_tss_rx_en :  1;   /* IPv6 TSS RX enable */
++        unsigned int ipv4_tss_rx_en :  1;   /* IPv4 TSS RX enable */
++        unsigned int rgmii_en       :  1;   /* RGMII in-band status enable */
++              unsigned int tx_fc_en           :  1;   /* TX flow control enable */
++              unsigned int rx_fc_en           :  1;   /* RX flow control enable */
++              unsigned int sim_test           :  1;   /* speed up timers in simulation */
++              unsigned int dis_col            :  1;   /* disable 16 collisions abort function */
++              unsigned int dis_bkoff          :  1;   /* disable back-off function */
++              unsigned int max_len            :  3;   /* maximum receive frame length allowed */
++              unsigned int adj_ifg            :  4;   /* adjust IFG from 96+/-56 */
++        unsigned int                :  1;   /* reserved */
++              unsigned int loop_back          :  1;   /* transmit data loopback enable */
++              unsigned int dis_rx                     :  1;   /* disable receive */
++              unsigned int dis_tx                     :  1;   /* disable transmit */
++#else
++              unsigned int dis_tx                     :  1;   /* disable transmit */
++              unsigned int dis_rx                     :  1;   /* disable receive */
++              unsigned int loop_back          :  1;   /* transmit data loopback enable */
++        unsigned int                :  1;   /* reserved */
++              unsigned int adj_ifg            :  4;   /* adjust IFG from 96+/-56 */
++              unsigned int max_len            :  3;   /* maximum receive frame length allowed */
++              unsigned int dis_bkoff          :  1;   /* disable back-off function */
++              unsigned int dis_col            :  1;   /* disable 16 collisions abort function */
++              unsigned int sim_test           :  1;   /* speed up timers in simulation */
++              unsigned int rx_fc_en           :  1;   /* RX flow control enable */
++              unsigned int tx_fc_en           :  1;   /* TX flow control enable */
++        unsigned int rgmii_en       :  1;   /* RGMII in-band status enable */
++        unsigned int ipv4_tss_rx_en :  1;   /* IPv4 TSS RX enable */
++        unsigned int ipv6_tss_rx_en :  1;   /* IPv6 TSS RX enable */
++        unsigned int rx_tag_remove  :  1;   /* Remove Rx VLAN tag */
++              unsigned int rising_latch   :  1;
++              unsigned int inv_rx_clk : 1;    /* Inverse RX Clock */
++              unsigned int : 10;
++#endif
++      } bits;
++} GMAC_CONFIG0_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_001c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 28;
++              unsigned int buf_size           :  4;   /* per packet buffer size */
++#else
++              unsigned int buf_size           :  4;   /* per packet buffer size */
++              unsigned int                            : 28;
++#endif
++      } bits;
++} GMAC_CONFIG1_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG2_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0024
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 16;
++              unsigned int buf_num            : 16;   /* return buffer number from software */
++#else
++              unsigned int buf_num            : 16;   /* return buffer number from software */
++              unsigned int                            : 16;
++#endif
++      } bits;
++} GMAC_BNCR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0028
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 16;
++              unsigned int buf_remain         : 16;   /* remaining buffer number */
++#else
++              unsigned int buf_remain         : 16;   /* remaining buffer number */
++              unsigned int                            : 16;
++#endif
++      } bits;
++} GMAC_RBNR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_002c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 25;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int phy_mode           :  1;   /* PHY interface mode in 10M-bps */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int link                       :  1;   /* link status */
++#else
++              unsigned int link                       :  1;   /* link status */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int phy_mode           :  1;   /* PHY interface mode in 10M-bps */
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int                            : 25;
++#endif
++      } bits;
++} GMAC_STATUS_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_009
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 10;
++              unsigned int tx_fail            :  1;   /* Tx fail interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_underrun        :  1;   /* GMAC Tx FIFO underrun interrupt */
++              unsigned int                            :  6;
++              unsigned int m_tx_fail          :  1;   /* Tx fail interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_underrun      :  1;   /* GMAC Tx FIFO underrun interrupt mask */
++#else
++              unsigned int m_tx_underrun      :  1;   /* GMAC Tx FIFO underrun interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_tx_fail          :  1;   /* Tx fail interrupt mask */
++              unsigned int                            :  6;
++              unsigned int tx_underrun        :  1;   /* GMAC Tx FIFO underrun interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int tx_fail            :  1;   /* Tx fail interrupt */
++              unsigned int                            : 10;
++#endif
++      } bits;
++} GMAC_INT_MASK_T;
++
++
++/*******************************************/
++/* the register structure of GMAC DMA      */
++/*******************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff00
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                :  7;   /* reserved */
++              unsigned int s_ahb_err          :  1;   /* Slave AHB bus error */
++              unsigned int tx_err_code    :  4;   /* TxDMA error code */
++              unsigned int rx_err_code        :  4;   /* RxDMA error code */
++              unsigned int device_id          : 12;
++              unsigned int revision_id        :  4;
++#else
++              unsigned int revision_id        :  4;
++              unsigned int device_id          : 12;
++              unsigned int rx_err_code        :  4;   /* RxDMA error code */
++              unsigned int tx_err_code    :  4;   /* TxDMA error code */
++              unsigned int s_ahb_err          :  1;   /* Slave AHB bus error */
++              unsigned int                :  7;   /* reserved */
++#endif
++      } bits;
++} GMAC_DMA_DEVICE_ID_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff04
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++              unsigned int                    :  1;   /* Tx fail interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int link_change        :  1;   /* GMAC link changed Interrupt for RGMII mode */
++              unsigned int                    :  1;
++              unsigned int                    :  1;
++              unsigned int                            :  3;
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++              unsigned int                    :  1;   /* Tx fail interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_link_change      :  1;   /* GMAC link changed Interrupt mask for RGMII mode */
++#else
++              unsigned int m_link_change      :  1;   /* GMAC link changed Interrupt mask for RGMII mode */
++              unsigned int m_rx_overrun       :  1;   /* GMAC Rx FIFO overrun interrupt mask */
++              unsigned int m_tx_pause_off     :  1;   /* received pause off frame interrupt mask */
++              unsigned int m_rx_pause_off :  1;       /* received pause off frame interrupt mask */
++              unsigned int m_tx_pause_on  :  1;       /* transmit pause on frame interrupt mask */
++              unsigned int m_rx_pause_on      :  1;   /* received pause on frame interrupt mask */
++              unsigned int m_cnt_full         :  1;   /* MIB counters half full interrupt mask */
++              unsigned int                    :  1;   /* Tx fail interrupt mask */
++              unsigned int loop_back          :  1;   /* loopback TxDMA to RxDMA */
++              unsigned int                            :  3;
++              unsigned int                    :  1;
++              unsigned int                    :  1;
++              unsigned int link_change        :  1;   /* GMAC link changed Interrupt for RGMII mode */
++              unsigned int rx_overrun         :  1;   /* GMAC Rx FIFO overrun interrupt */
++              unsigned int tx_pause_off       :  1;   /* received pause off frame interrupt */
++              unsigned int rx_pause_off   :  1;       /* received pause off frame interrupt */
++              unsigned int tx_pause_on        :  1;   /* transmit pause on frame interrupt */
++              unsigned int rx_pause_on        :  1;   /* received pause on frame interrupt */
++              unsigned int cnt_full           :  1;   /* MIB counters half full interrupt */
++              unsigned int                    :  1;   /* Tx fail interrupt */
++              unsigned int rs_eofi            :  1;   /* RxDMA end of frame interrupt */
++              unsigned int rs_eodi            :  1;   /* RxDMA end of descriptor interrupt */
++              unsigned int rs_perr            :  1;   /* Rx Descriptor protocol error */
++              unsigned int rs_derr            :  1;   /* AHB Bus Error while rx */
++              unsigned int rs_finish          :  1;   /* finished rx interrupt */
++              unsigned int ts_eofi            :  1;   /* TxDMA end of frame interrupt */
++              unsigned int ts_eodi            :  1;   /* TxDMA end of descriptor interrupt */
++              unsigned int ts_perr            :  1;   /* Tx Descriptor protocol error */
++              unsigned int ts_derr            :  1;   /* AHB Bus Error while tx */
++              unsigned int ts_finish          :  1;   /* finished tx interrupt */
++#endif
++      } bits;
++} GMAC_DMA_STATUS_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff08
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int td_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int td_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int td_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int td_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int td_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int td_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int td_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int td_burst_size  :  2;       /* TxDMA max burst size for every AHB request */
++              unsigned int td_prot            :  4;   /* TxDMA protection control */
++              unsigned int                            :  1;
++              unsigned int td_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int td_continue        :  1;   /* Continue DMA operation */
++              unsigned int td_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} GMAC_TXDMA_CTRL_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff0c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int td_busy                    :  1;/* 1-TxDMA busy; 0-TxDMA idle */
++              unsigned int td_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} GMAC_TXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff10
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int                            :  1;
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int                            :  1;
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} GMAC_TXDMA_CURR_DESC_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff14
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int                            :  1;
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int                            : 14;
++#else
++              unsigned int                            : 14;
++              unsigned int rd_eof_en      :  1;   /* End of frame interrupt Enable;1-enable;0-mask */
++              unsigned int rd_eod_en          :  1;   /* End of Descriptor interrupt Enable;1-enable;0-mask */
++              unsigned int rd_perr_en         :  1;   /* Protocol Failure Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_fail_en         :  1;   /* DMA Fail Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_finish_en   :  1;       /* DMA Finish Event Interrupt Enable;1-enable;0-mask */
++              unsigned int rd_endian          :  1;   /* AHB Endian. 0-little endian; 1-big endian */
++              unsigned int rd_bus                 :  2;       /* peripheral bus width;0x->8 bits,10->16 bits,11->32 bits */
++              unsigned int rd_burst_size  :  2;       /* DMA max burst size for every AHB request */
++              unsigned int rd_prot            :  4;   /* DMA protection control */
++              unsigned int                            :  1;
++              unsigned int rd_chain_mode      :  1;   /* Descriptor Chain Mode;1-Descriptor Chain mode, 0-Direct DMA mode*/
++              unsigned int rd_continue        :  1;   /* Continue DMA operation */
++              unsigned int rd_start           :  1;   /* Start DMA transfer */
++#endif
++      } bits;
++} GMAC_RXDMA_CTRL_T;
++
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff18
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int                                    :  3;
++#else
++              unsigned int                                    :  3;
++              unsigned int rd_busy                    :  1;/* 1-RxDMA busy; 0-RxDMA idle */
++              unsigned int rd_first_des_ptr   : 28;/* first descriptor address */
++#endif
++      } bits;
++} GMAC_RXDMA_FIRST_DESC_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit2_ff1c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int ndar                       : 28;   /* next descriptor address */
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int                            :  1;
++              unsigned int sof_eof            :  2;
++#else
++              unsigned int sof_eof            :  2;
++              unsigned int                            :  1;
++              unsigned int eofie                      :  1;   /* end of frame interrupt enable */
++              unsigned int ndar                       : 28;   /* next descriptor address */
++#endif
++      } bits;
++} GMAC_RXDMA_CURR_DESC_T;
++
++
++/********************************************/
++/*          Descriptor Format               */
++/********************************************/
++
++typedef struct descriptor_t
++{
++      union frame_control_t
++      {
++              unsigned int bits32;
++              struct bits_0000
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int csum_state : 3;    /* checksum error status */
++                      unsigned int vlan_tag   : 1;    /* 802.1q vlan tag packet */
++                      unsigned int frame_state: 3;    /* reference Rx Status1 */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int frame_state: 3;    /* reference Rx Status1 */
++                      unsigned int vlan_tag   : 1;    /* 802.1q vlan tag packet */
++                      unsigned int csum_state : 3;    /* checksum error status */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++              } bits_rx;
++
++              struct bits_0001
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int            : 6;
++                      unsigned int success_tx : 1;    /* successful transmitted */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int success_tx : 1;    /* successful transmitted */
++                      unsigned int            : 6;
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++        } bits_tx_in;
++
++              struct bits_0002
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int            : 2;
++                      unsigned int udp_csum_en: 1;    /* TSS UDP checksum enable */
++                      unsigned int tcp_csum_en: 1;    /* TSS TCP checksum enable */
++                      unsigned int ipv6_tx_en : 1;    /* TSS IPv6 TX enable */
++                      unsigned int ip_csum_en : 1;    /* TSS IPv4 IP Header checksum enable */
++                      unsigned int vlan_enable: 1;    /* VLAN TIC insertion enable */
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++#else
++                      unsigned int buffer_size:16;    /* transfer buffer size associated with current description*/
++                      unsigned int desc_count : 6;    /* number of descriptors used for the current frame */
++                      unsigned int vlan_enable: 1;    /* VLAN TIC insertion enable */
++                      unsigned int ip_csum_en : 1;    /* TSS IPv4 IP Header checksum enable */
++                      unsigned int ipv6_tx_en : 1;    /* TSS IPv6 TX enable */
++                      unsigned int tcp_csum_en: 1;    /* TSS TCP checksum enable */
++                      unsigned int udp_csum_en: 1;    /* TSS UDP checksum enable */
++                      unsigned int            : 2;
++                      unsigned int perr               : 1;    /* protocol error during processing this descriptor */
++                      unsigned int derr               : 1;    /* data error during processing this descriptor */
++                      unsigned int own                : 1;    /* owner bit. 0-CPU, 1-DMA */
++#endif
++        } bits_tx_out;
++
++      } frame_ctrl;
++
++      union flag_status_t
++      {
++              unsigned int bits32;
++              struct bits_0004
++              {
++#if (BIG_ENDIAN==1)
++            unsigned int priority   : 3;    /* user priority extracted from receiving frame*/
++            unsigned int cfi        : 1;      /* cfi extracted from receiving frame*/
++                      unsigned int vlan_id    :12;    /* VLAN ID extracted from receiving frame */
++                      unsigned int frame_count:16;    /* received frame byte count,include CRC,not include VLAN TIC */
++#else
++                      unsigned int frame_count:16;    /* received frame byte count,include CRC,not include VLAN TIC */
++                      unsigned int vlan_id    :12;    /* VLAN ID extracted from receiving frame */
++            unsigned int cfi        : 1;      /* cfi extracted from receiving frame*/
++            unsigned int priority   : 3;    /* user priority extracted from receiving frame*/
++#endif
++              } bits_rx_status;
++
++              struct bits_0005
++              {
++#if (BIG_ENDIAN==1)
++            unsigned int priority   : 3;    /* user priority to transmit*/
++            unsigned int cfi        : 1;      /* cfi to transmit*/
++                      unsigned int vlan_id    :12;    /* VLAN ID to transmit */
++                      unsigned int frame_count:16;    /* total tx frame byte count */
++#else
++                      unsigned int frame_count:16;    /* total tx frame byte count */
++                      unsigned int vlan_id    :12;    /* VLAN ID to transmit */
++            unsigned int cfi        : 1;      /* cfi to transmit*/
++            unsigned int priority   : 3;    /* user priority to transmit*/
++#endif
++              } bits_tx_flag;
++      } flag_status;
++
++      unsigned int buf_adr;   /* data buffer address */
++
++      union next_desc_t
++      {
++              unsigned int next_descriptor;
++              struct bits_000c
++              {
++#if (BIG_ENDIAN==1)
++                      unsigned int ndar               :28;    /* next descriptor address */
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int                    : 1;
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++#else
++                      unsigned int sof_eof    : 2;    /* 00-the linking descriptor   01-the last descriptor of a frame*/
++                                                      /* 10-the first descriptor of a frame    11-only one descriptor for a frame*/
++                      unsigned int                    : 1;
++                      unsigned int eofie              : 1;    /* end of frame interrupt enable */
++                      unsigned int ndar               :28;    /* next descriptor address */
++#endif
++              } bits;
++      } next_desc;
++} GMAC_DESCRIPTOR_T;
++
++typedef struct gmac_conf {
++      struct net_device *dev;
++      int portmap;
++      int vid;
++      int flag;     /* 1: active  0: non-active */
++} sys_gmac_conf;
++
++struct gmac_private {
++      unsigned char       *tx_bufs;   /* Tx bounce buffer region. */
++      unsigned char       *rx_bufs;
++      GMAC_DESCRIPTOR_T       *tx_desc;       /* point to virtual TX descriptor address*/
++      GMAC_DESCRIPTOR_T       *rx_desc;       /* point to virtual RX descriptor address*/
++      GMAC_DESCRIPTOR_T       *tx_cur_desc;   /* point to current TX descriptor */
++      GMAC_DESCRIPTOR_T       *rx_cur_desc;   /* point to current RX descriptor */
++      GMAC_DESCRIPTOR_T   *tx_finished_desc;
++      GMAC_DESCRIPTOR_T   *rx_finished_desc;
++      unsigned long       cur_tx;
++      unsigned int        cur_rx;     /* Index into the Rx buffer of next Rx pkt. */
++      unsigned int        tx_flag;
++      unsigned long       dirty_tx;
++      unsigned char       *tx_buf[TX_DESC_NUM];       /* Tx bounce buffers */
++      dma_addr_t          tx_desc_dma; /* physical TX descriptor address */
++      dma_addr_t          rx_desc_dma;        /* physical RX descriptor address */
++      dma_addr_t          tx_bufs_dma; /* physical TX descriptor address */
++      dma_addr_t          rx_bufs_dma; /* physical RX descriptor address */
++    struct net_device_stats  stats;
++      pid_t               thr_pid;
++      wait_queue_head_t   thr_wait;
++      struct completion   thr_exited;
++    spinlock_t          lock;
++    int                 time_to_die;
++      unsigned int            tx_desc_hdr[GMAC_PHY_IF];       /* the descriptor which sw can fill */
++      unsigned int            tx_desc_tail[GMAC_PHY_IF];      /* the descriptor which is not cleaned yet */
++};
++
++
++struct reg_ioctl_data {
++    unsigned int    reg_addr;   /* the register address */
++    unsigned int    val_in;     /* data write to the register */
++    unsigned int    val_out;    /* data read from the register */
++};
++
++#ifdef CONFIG_SL2312_MPAGE
++typedef struct tx_data_t {
++      int     freeable; // 1 when it's skb. it can be freed in tx interrupt handler
++      struct sk_buff* skb; // skb
++      int     desc_in_use; // 1 when the desc is in use. 0 when desc is available.
++      long end_seq; // to find out packets are in seq.
++      // so this value is the seq of next packet.
++} tx_data;
++#endif
++
++/*************************************************************
++ *         Global Variable
++ *************************************************************/
++struct semaphore        sem_gmac;   /* semaphore for share pins issue */
++
++/*************************************************************
++ *        Static Global Variable
++ *************************************************************/
++// static unsigned int     MAC_BASE_ADDR = GMAC0_BASE;
++static unsigned int     gmac_base_addr[GMAC_PHY_IF] = {GMAC0_BASE,GMAC1_BASE};
++static unsigned int     gmac_irq[GMAC_PHY_IF] = {IRQ_GMAC0,IRQ_GMAC1};
++static struct net_device *gmac_dev[GMAC_PHY_IF];
++
++static unsigned int     FLAG_SWITCH=0;        /* if 1-->switch chip presented. if 0-->switch chip unpresented */
++static unsigned int     flow_control_enable[GMAC_PHY_IF] = {1,1};
++static unsigned int     pre_phy_status[GMAC_PHY_IF] = {LINK_DOWN,LINK_DOWN};
++static unsigned int     tx_desc_virtual_base[GMAC_PHY_IF];
++static unsigned int     rx_desc_virtual_base[GMAC_PHY_IF];
++static unsigned int     full_duplex = 1;
++static unsigned int     speed = 1;
++#ifdef CONFIG_SL2312_MPAGE
++static tx_data                    tx_skb[GMAC_PHY_IF][TX_DESC_NUM];
++#else
++static struct sk_buff   *tx_skb[GMAC_PHY_IF][TX_DESC_NUM];
++#endif
++static struct sk_buff   *rx_skb[GMAC_PHY_IF][RX_DESC_NUM];
++static unsigned int     tx_desc_start_adr[GMAC_PHY_IF];
++static unsigned int     rx_desc_start_adr[GMAC_PHY_IF];
++static unsigned char    eth0_mac[6]= {0x00,0x50,0xc2,0x2b,0xd3,0x25};
++static unsigned char    eth1_mac[6]= {0x00,0x50,0xc2,0x2b,0xdf,0xfe};
++static unsigned int     next_tick = 3 * HZ;
++
++static unsigned int     phy_addr[GMAC_PHY_IF] = {0x01,0x02};  /* define PHY address */
++
++DECLARE_WAIT_QUEUE_HEAD(gmac_queue);
++//static      wait_queue_t    wait;
++
++struct gmac_conf VLAN_conf[] = {
++#ifdef CONFIG_ADM_6999
++      { (struct net_device *)0,0x7F,1 },
++      { (struct net_device *)0,0x80,2 }
++#endif
++#ifdef CONFIG_ADM_6996
++      { (struct net_device *)0,0x0F,1 },
++      { (struct net_device *)0,0x10,2 }
++#endif
++};
++
++#define NUM_VLAN_IF   (sizeof(VLAN_conf)/sizeof(struct gmac_conf))
++
++
++/************************************************/
++/*            GMAC function declare             */
++/************************************************/
++
++unsigned int mii_read(unsigned char phyad,unsigned char regad);
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value);
++static void gmac_set_phy_status(struct net_device *dev);
++static void gmac_get_phy_status(struct net_device *dev);
++static int gmac_phy_thread (void *data);
++static int gmac_set_mac_address(struct net_device *dev, void *addr);
++static void gmac_tx_timeout(struct net_device *dev);
++static void gmac_tx_packet_complete(struct net_device *dev);
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static void gmac_set_rx_mode(struct net_device *dev);
++static void gmac_rx_packet(struct net_device *dev);
++static int gmac_open (struct net_device *dev);
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++
++static unsigned int gmac_get_dev_index(struct net_device *dev);
++static unsigned int gmac_select_interface(struct net_device *dev);
++
++#ifdef CONFIG_SL2312_MPAGE
++int printk_all(int dev_index, struct gmac_private* tp);
++#endif
++
++/****************************************/
++/*    SPI Function Declare            */
++/****************************************/
++void SPI_write(unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char table,unsigned char addr);
++void SPI_write_bit(char bit_EEDO);
++unsigned int SPI_read_bit(void);
++void SPI_default(void);
++void SPI_reset(unsigned char rstype,unsigned char port_cnt);
++void SPI_pre_st(void);
++void SPI_CS_enable(unsigned char enable);
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask);
++void SPI_Set_tag(unsigned int port,unsigned tag);
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask);
++unsigned int SPI_Get_PVID(unsigned int port);
++void SPI_mac_lock(unsigned int port, unsigned char lock);
++void SPI_get_port_state(unsigned int port);
++void SPI_port_enable(unsigned int port,unsigned char enable);
++unsigned int SPI_get_identifier(void);
++void SPI_get_status(unsigned int port);
++
++/****************************************/
++/*    VLAN Function Declare                   */
++/****************************************/
++int getVLANfromdev (struct net_device *dev );
++struct net_device * getdevfromVLAN( int VID);
++
++
++
++/************************************************/
++/*                 function body                */
++/************************************************/
++#if 0
++void hw_memcpy(void *to,const void *from,unsigned long n)
++{
++    writel(from,SL2312_DRAM_CTRL_BASE+0x20);  /* set source address */
++    writel(to,SL2312_DRAM_CTRL_BASE+0x24);    /* set destination address */
++    writel(n,SL2312_DRAM_CTRL_BASE+0x28);     /* set byte count */
++    writel(0x00000001,SL2312_DRAM_CTRL_BASE+0x2c);
++    while (readl(SL2312_DRAM_CTRL_BASE+0x2c));
++}
++#endif
++
++static unsigned int gmac_read_reg(unsigned int addr)
++{
++    unsigned int    reg_val;
++//    unsigned int    flags;
++//    spinlock_t     lock;
++
++//    spin_lock_irqsave(&lock, flags);
++    reg_val = readl(addr);    // Gary Chen
++//    spin_unlock_irqrestore(&lock, flags);
++      return (reg_val);
++}
++
++static void gmac_write_reg(unsigned int addr,unsigned int data,unsigned int bit_mask)
++{
++      unsigned int    reg_val;
++    //unsigned int    *addr;
++//    unsigned int    flags;
++//    spinlock_t     lock;
++
++//    spin_lock_irqsave(&lock, flags);
++      reg_val = ( gmac_read_reg(addr) & (~bit_mask) ) | (data & bit_mask);
++    writel(reg_val,addr);
++//    spin_unlock_irqrestore(&lock, flags);
++      return;
++}
++
++
++static void gmac_sw_reset(struct net_device *dev)
++{
++    unsigned int    index;
++    unsigned int    reg_val;
++
++    index = gmac_get_dev_index(dev);
++    if (index==0)
++        reg_val = readl(GMAC_GLOBAL_BASE_ADDR+0x0c) | 0x00000020;   /* GMAC0 S/W reset */
++    else
++        reg_val = readl(GMAC_GLOBAL_BASE_ADDR+0x0c) | 0x00000040;   /* GMAC1 S/W reset */
++
++    writel(reg_val,GMAC_GLOBAL_BASE_ADDR+0x0c);
++    return;
++}
++
++static void gmac_get_mac_address(void)
++{
++#ifdef CONFIG_MTD
++      extern int get_vlaninfo(vlaninfo* vlan);
++    static vlaninfo    vlan[2];
++
++    if (get_vlaninfo(&vlan[0]))
++    {
++        memcpy(eth0_mac,vlan[0].mac,6);
++        VLAN_conf[0].vid = vlan[0].vlanid;
++        VLAN_conf[0].portmap = vlan[0].vlanmap;
++        memcpy(eth1_mac,vlan[1].mac,6);
++        VLAN_conf[1].vid = vlan[1].vlanid;
++        VLAN_conf[1].portmap = vlan[1].vlanmap;
++    }
++#else
++    unsigned int reg_val;
++
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth0_mac[4] = (reg_val & 0xff00) >> 8;
++    eth0_mac[5] = reg_val & 0x00ff;
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth1_mac[4] = (reg_val & 0xff00) >> 8;
++    eth1_mac[5] = reg_val & 0x00ff;
++#endif
++    return;
++}
++
++static unsigned int gmac_get_dev_index(struct net_device *dev)
++{
++    unsigned int    i;
++
++    /* get device index number */
++    for (i=0;i<GMAC_PHY_IF;i++)
++    {
++        if (gmac_dev[i]==dev)
++        {
++            return(i);
++        }
++    }
++    return (0xff);
++}
++
++static unsigned int gmac_select_interface(struct net_device *dev)
++{
++    unsigned int    index;
++
++    index = gmac_get_dev_index(dev);
++    // MAC_BASE_ADDR = gmac_base_addr[index]; // Gary Chen
++    return (index);
++}
++
++
++static void gmac_dump_register(struct net_device *dev)
++{
++#if 0
++    unsigned int   i,val,index;
++
++    index = gmac_select_interface(dev);
++
++    printk("========== GMAC%d ==========\n",index);
++    for (i=0;i<=0x7c;i=i+4)
++    {
++        val = gmac_read_reg(gmac_base_addr[index] + i);
++        printk("offset = %08x   value = %08x\n",i,val);
++    }
++    for (i=0xff00;i<=0xff7c;i=i+4)
++    {
++        val = gmac_read_reg(gmac_base_addr[index] + i);
++        printk("offset = %08x   value = %08x\n",i,val);
++    }
++#endif
++}
++
++static int gmac_init_chip(struct net_device *dev)
++{
++      GMAC_RBNR_T             rbnr_val,rbnr_mask;
++      GMAC_CONFIG2_T  config2_val;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_CONFIG1_T  config1;
++      struct sockaddr sock;
++      unsigned int    status;
++      unsigned int    phy_mode;
++      unsigned int    index;
++
++    index = gmac_get_dev_index(dev);
++
++    /* set GMAC RMII mode */
++    if (index==0)
++        phy_mode = 0;   /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++    else
++        phy_mode = 2;   /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++
++    /* set PHY operation mode */
++    status = (phy_mode<<5) | 0x11 | (full_duplex<<3) | (speed<<1);
++    gmac_write_reg(gmac_base_addr[index] + GMAC_STATUS,status ,0x0000007f);
++
++      /* set station MAC address1 and address2 */
++      if (index==0)
++          memcpy(&sock.sa_data[0],&eth0_mac[0],6);
++    else
++          memcpy(&sock.sa_data[0],&eth1_mac[0],6);
++    gmac_set_mac_address(dev,(void *)&sock);
++
++    /* set RX_FLTR register to receive all multicast packet */
++    gmac_write_reg(gmac_base_addr[index] + GMAC_RX_FLTR,0x0000001F,0x0000001f);
++    //gmac_write_reg(gmac_base_addr[index] + GMAC_RX_FLTR,0x00000007,0x0000001f);
++
++      /* set per packet buffer size */
++      config1.bits32 = 0;
++    config1.bits.buf_size = 11; /* buffer size = 2048-byte */
++    gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG1,config1.bits32,0x0000000f);
++
++      /* set flow control threshold */
++      config2_val.bits32 = 0;
++      config2_val.bits.set_threshold = RX_DESC_NUM/4;
++      config2_val.bits.rel_threshold = RX_DESC_NUM*3/4;
++      gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG2,config2_val.bits32,0xffffffff);
++
++      /* init remaining buffer number register */
++      rbnr_val.bits32 = 0;
++      rbnr_val.bits.buf_remain = RX_DESC_NUM;
++      rbnr_mask.bits32 = 0;
++      rbnr_mask.bits.buf_remain = 0xffff;
++      gmac_write_reg(gmac_base_addr[index] + GMAC_RBNR,rbnr_val.bits32,rbnr_mask.bits32);
++
++    /* disable TX/RX and disable internal loop back */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.max_len = 2;
++    if (flow_control_enable[index]==1)
++    {
++        config0.bits.tx_fc_en = 1; /* enable tx flow control */
++        config0.bits.rx_fc_en = 1; /* enable rx flow control */
++        printk("Enable MAC Flow Control...\n");
++    }
++    else
++    {
++        config0.bits.tx_fc_en = 0; /* disable tx flow control */
++        config0.bits.rx_fc_en = 0; /* disable rx flow control */
++        printk("Disable MAC Flow Control...\n");
++    }
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.inv_rx_clk = 0;
++      config0.bits.rising_latch = 1;
++      config0.bits.ipv4_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++
++    config0_mask.bits.max_len = 7;
++    config0_mask.bits.tx_fc_en = 1;
++    config0_mask.bits.rx_fc_en = 1;
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    config0_mask.bits.loop_back = 1;
++    config0_mask.bits.inv_rx_clk = 1;
++      config0_mask.bits.rising_latch = 1;
++      config0_mask.bits.ipv4_tss_rx_en = 1;
++      config0_mask.bits.ipv6_tss_rx_en = 1;
++    gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++
++      return (0);
++}
++
++static void gmac_enable_tx_rx(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++      int                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++}
++
++static void gmac_disable_tx_rx(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++      int                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++}
++
++#ifdef CONFIG_SL_NAPI
++static int gmac_rx_poll_ga(struct net_device *dev, int *budget)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        index;
++      unsigned int        dev_index;
++      int                 work = 0;
++      int                 work_done = 0;
++      int                 quota = min(dev->quota, *budget);
++
++    dev_index = gmac_select_interface(dev);
++
++      for (;;)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          work_done = 1;
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++//            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++            writel(desc_count,(unsigned int *)(gmac_base_addr[dev_index] + GMAC_BNCR));
++        }
++
++              if (work++ >= quota )
++              {
++                      break;
++              }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++
++      dev->quota -= work;
++      *budget -= work;
++      if (work_done==1)
++      {
++          /* Receive descriptor is empty now */
++        netif_rx_complete(dev);
++        /* enable receive interrupt */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0x0007c000,0x0007c000);   /* enable rx interrupt */
++        return 0;
++    }
++    else
++    {
++        return -1;
++    }
++}
++
++static int gmac_rx_poll_gb(struct net_device *dev, int *budget)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        index;
++      unsigned int        dev_index;
++      int                 work = 0;
++      int                 work_done = 0;
++      int                 quota = min(dev->quota, *budget);
++
++    dev_index = gmac_select_interface(dev);
++
++      for (;;)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          work_done = 1;
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++//            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++            writel(desc_count,(unsigned int *)(gmac_base_addr[dev_index] + GMAC_BNCR));
++        }
++
++              if (work++ >= quota )
++              {
++                      break;
++              }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++
++      dev->quota -= work;
++      *budget -= work;
++      if (work_done==1)
++      {
++          /* Receive descriptor is empty now */
++        netif_rx_complete(dev);
++        /* enable receive interrupt */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0x0007c000,0x0007c000);   /* enable rx interrupt */
++        return 0;
++    }
++    else
++    {
++        return -1;
++    }
++}
++
++#endif
++
++static void gmac_rx_packet(struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++    GMAC_DESCRIPTOR_T   *rx_desc;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++    unsigned int        vid;
++//    unsigned int        priority;
++      unsigned int        own;
++      unsigned int        good_frame = 0;
++      unsigned int        i,index;
++      unsigned int        dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      for (i=0;i<256;i++)
++      {
++        own = tp->rx_cur_desc->frame_ctrl.bits32 >> 31;
++        if (own == CPU) /* check owner bit */
++        {
++              rx_desc = tp->rx_cur_desc;
++#if (GMAC_DEBUG==1)
++              /* check error interrupt */
++              if ( (rx_desc->frame_ctrl.bits_rx.derr==1)||(rx_desc->frame_ctrl.bits_rx.perr==1) )
++              {
++              printk("%s::Rx Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++          /* get frame information from the first descriptor of the frame */
++              pkt_size = rx_desc->flag_status.bits_rx_status.frame_count - 4;  /*total byte count in a frame*/
++#if (GMAC_DEBUG==1)
++            priority = rx_desc->flag_status.bits_rx_status.priority;    /* 802.1p priority */
++#endif
++            vid = rx_desc->flag_status.bits_rx_status.vlan_id;          /* 802.1q vlan id */
++            if (vid == 0)
++            {
++                vid = 1;    /* default vlan */
++            }
++              desc_count = rx_desc->frame_ctrl.bits_rx.desc_count; /* get descriptor count per frame */
++
++              if (rx_desc->frame_ctrl.bits_rx.frame_state == 0x000) /* good frame */
++              {
++                      tp->stats.rx_bytes += pkt_size;
++                      tp->stats.rx_packets++;
++                      good_frame = 1;
++              }
++              else
++              {
++                      tp->stats.rx_errors++;
++                      good_frame = 0;
++                      printk("RX status: 0x%x\n",rx_desc->frame_ctrl.bits_rx.frame_state);
++              }
++      }
++      else
++      {
++          break;  /* Rx process is completed */
++      }
++
++        if (good_frame == 1)
++        {
++            /* get rx skb buffer index */
++            index = ((unsigned int)tp->rx_cur_desc - rx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            if (rx_skb[dev_index][index])
++            {
++                skb_reserve (rx_skb[dev_index][index], 2);    /* 16 byte align the IP fields. */
++                rx_skb[dev_index][index]->dev = dev;
++                rx_skb[dev_index][index]->ip_summed = CHECKSUM_UNNECESSARY;
++                          skb_put(rx_skb[dev_index][index],pkt_size);
++                          rx_skb[dev_index][index]->protocol = eth_type_trans(rx_skb[dev_index][index],dev); /* set skb protocol */
++                          netif_rx(rx_skb[dev_index][index]);  /* socket rx */
++                          dev->last_rx = jiffies;
++
++                          /* allocate rx skb buffer */
++                if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++                {
++                    printk("%s::skb buffer allocation fail !\n",__func__);
++                }
++                rx_skb[dev_index][index] = skb;
++                tp->rx_cur_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++            }
++            else
++            {
++                printk("%s::rx skb index error !\n",__func__);
++            }
++        }
++
++          tp->rx_cur_desc->frame_ctrl.bits_rx.own = DMA; /* release rx descriptor to DMA */
++        /* point to next rx descriptor */
++        tp->rx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->rx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+rx_desc_virtual_base[dev_index]);
++
++        /* release buffer to Remaining Buffer Number Register */
++        if (flow_control_enable[dev_index] ==1)
++        {
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_BNCR,desc_count,0x0000ffff);
++        }
++    }
++
++    /* if RX DMA process is stoped , restart it */
++      rxdma_busy.bits.rd_first_des_ptr = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC);
++      if (rxdma_busy.bits.rd_busy == 0)
++      {
++          rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++          rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++          rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++          rxdma_ctrl_mask.bits.rd_continue = 1;
++          gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    }
++}
++
++#ifdef CONFIG_SL2312_MPAGE
++static inline void free_tx_buf(int dev_index, int desc_index)
++{
++      if (tx_skb[dev_index][desc_index].freeable &&
++          tx_skb[dev_index][desc_index].skb) {
++              struct sk_buff* skb = tx_skb[dev_index][desc_index].skb;
++              //printk("free_skb %x, len %d\n", skb, skb->len);
++#ifdef CONFIG_TXINT_DISABLE
++              dev_kfree_skb(skb);
++#else
++              dev_kfree_skb_irq(skb);
++#endif
++              tx_skb[dev_index][desc_index].skb = 0;
++      }
++}
++
++#ifdef CONFIG_TXINT_DISABLE
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++    GMAC_DESCRIPTOR_T     *tx_hw_complete_desc, *next_desc;
++    unsigned int desc_cnt=0;
++    unsigned int i,index,dev_index;
++    unsigned int tx_current_descriptor = 0;
++      // int own_dma = 0;
++
++    dev_index = gmac_select_interface(dev);
++
++      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      if (tx_skb[dev_index][index].desc_in_use && tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU) {
++              free_tx_buf(dev_index, index);
++              tx_skb[dev_index][index].desc_in_use = 0;
++      }
++      next_desc = (GMAC_DESCRIPTOR_T*)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++
++      for (;;) {
++              tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++              if (next_desc == tx_hw_complete_desc)
++                      break;
++              if (next_desc->frame_ctrl.bits_tx_in.own == CPU) {
++                      if (next_desc->frame_ctrl.bits_tx_in.success_tx == 1) {
++                              tp->stats.tx_bytes += next_desc->flag_status.bits_tx_flag.frame_count;
++                              tp->stats.tx_packets ++;
++                      } else {
++                              tp->stats.tx_errors++;
++                      }
++                      desc_cnt = next_desc->frame_ctrl.bits_tx_in.desc_count;
++                      for (i=1; i<desc_cnt; i++) {
++                              /* get tx skb buffer index */
++                              index = ((unsigned int)next_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                              next_desc->frame_ctrl.bits_tx_in.own = CPU;
++                              free_tx_buf(dev_index, index);
++                              tx_skb[dev_index][index].desc_in_use = 0;
++                              tp->tx_desc_tail[dev_index] = (tp->tx_desc_tail[dev_index] +1) & (TX_DESC_NUM-1);
++                              /* release Tx descriptor to CPU */
++                              next_desc = (GMAC_DESCRIPTOR_T *)((next_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                      }
++                      /* get tx skb buffer index */
++                      index = ((unsigned int)next_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                      /* free skb buffer */
++                      next_desc->frame_ctrl.bits_tx_in.own = CPU;
++                      free_tx_buf(dev_index, index);
++                      tx_skb[dev_index][index].desc_in_use = 0;
++                      tp->tx_desc_tail[dev_index] = (tp->tx_desc_tail[dev_index] +1) & (TX_DESC_NUM-1);
++                      tp->tx_finished_desc = next_desc;
++//                    printk("finish tx_desc index %d\n", index);
++                      next_desc = (GMAC_DESCRIPTOR_T *)((next_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++              }
++              else
++                      break;
++      }
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++
++}
++#else
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_DESCRIPTOR_T           *tx_hw_complete_desc;
++      unsigned int desc_cnt=0;
++      unsigned int i,index,dev_index;
++      unsigned int tx_current_descriptor = 0;
++      // int own_dma = 0;
++
++      dev_index = gmac_select_interface(dev);
++
++      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      /* check tx status and accumulate tx statistics */
++      for (;;)
++      {
++
++        for (i=0;i<1000;i++)
++        {
++            tx_current_descriptor = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC);
++            if ( ((tx_current_descriptor & 0x00000003)==0x00000003) ||  /* only one descriptor */
++                 ((tx_current_descriptor & 0x00000003)==0x00000001) )   /* the last descriptor */
++            {
++                break;
++            }
++            udelay(1);
++        }
++        if (i==1000)
++        {
++//            gmac_dump_register(dev);
++//            printk("%s: tx current descriptor = %x \n",__func__,tx_current_descriptor);
++//            printk_all(dev_index, tp);
++            continue;
++        }
++
++          /* get tx H/W completed descriptor virtual address */
++      tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((tx_current_descriptor & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++//            tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++          if (tp->tx_finished_desc == tx_hw_complete_desc ) // ||
++                  //tx_skb[dev_index][index].desc_in_use )   /* complete tx processing */
++              {
++                      break;
++              }
++
++        for (;;)
++        {
++              if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU)
++              {
++    #if (GMAC_DEBUG==1)
++                      if ( (tp->tx_finished_desc->frame_ctrl.bits_tx_in.derr) ||
++                         (tp->tx_finished_desc->frame_ctrl.bits_tx_in.perr) )
++                      {
++                              printk("%s::Descriptor Processing Error !!!\n",__func__);
++                      }
++    #endif
++                      if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.success_tx == 1)
++                      {
++                              tp->stats.tx_bytes += tp->tx_finished_desc->flag_status.bits_tx_flag.frame_count;
++                              tp->stats.tx_packets ++;
++                      }
++                      else
++                      {
++                              tp->stats.tx_errors++;
++                      }
++                      desc_cnt = tp->tx_finished_desc->frame_ctrl.bits_tx_in.desc_count;
++                      for (i=1; i<desc_cnt; i++)  /* multi-descriptor in one packet */
++                      {
++                              /* get tx skb buffer index */
++                              index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                              tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++                              free_tx_buf(dev_index, index);
++                              tx_skb[dev_index][index].desc_in_use = 0;
++                              /* release Tx descriptor to CPU */
++                              tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                      }
++                      /* get tx skb buffer index */
++                      index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                      /* free skb buffer */
++                      tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++                      free_tx_buf(dev_index, index);
++                      tx_skb[dev_index][index].desc_in_use = 0;
++                      tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++
++                  if (tp->tx_finished_desc == tx_hw_complete_desc )
++                      {
++                              break;
++                      }
++            }
++              else
++              {
++                      break;
++                      }
++              }
++      }
++
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++
++}
++#endif
++#else
++
++static void gmac_tx_packet_complete(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++    GMAC_DESCRIPTOR_T     *tx_hw_complete_desc;
++    unsigned int desc_cnt=0;
++    unsigned int i,index,dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      /* get tx H/W completed descriptor virtual address */
++      tx_hw_complete_desc = (GMAC_DESCRIPTOR_T *)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0)+ tx_desc_virtual_base[dev_index]);
++      /* check tx status and accumulate tx statistics */
++    for (;;)
++    {
++        if (tp->tx_finished_desc == tx_hw_complete_desc)   /* complete tx processing */
++        {
++            break;
++        }
++      if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.own == CPU)
++      {
++#if (GMAC_DEBUG==1)
++          if ( (tp->tx_finished_desc->frame_ctrl.bits_tx_in.derr) ||
++               (tp->tx_finished_desc->frame_ctrl.bits_tx_in.perr) )
++          {
++              printk("%s::Descriptor Processing Error !!!\n",__func__);
++          }
++#endif
++            if (tp->tx_finished_desc->frame_ctrl.bits_tx_in.success_tx == 1)
++            {
++                tp->stats.tx_bytes += tp->tx_finished_desc->flag_status.bits_tx_flag.frame_count;
++                tp->stats.tx_packets ++;
++            }
++            else
++            {
++                tp->stats.tx_errors++;
++            }
++            desc_cnt = tp->tx_finished_desc->frame_ctrl.bits_tx_in.desc_count;
++              for (i=1; i<desc_cnt; i++)  /* multi-descriptor in one packet */
++              {
++                /* get tx skb buffer index */
++                index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++                /* free skb buffer */
++                if (tx_skb[dev_index][index])
++                {
++                          dev_kfree_skb_irq(tx_skb[dev_index][index]);
++                      }
++                  /* release Tx descriptor to CPU */
++                tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++                tp->tx_finished_desc->frame_ctrl.bits_tx_in.own = CPU;
++              }
++            /* get tx skb buffer index */
++            index = ((unsigned int)tp->tx_finished_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++            /* free skb buffer */
++            if (tx_skb[dev_index][index])
++            {
++                  dev_kfree_skb_irq(tx_skb[dev_index][index]);
++              }
++            tp->tx_finished_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_finished_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++      }
++    }
++
++      if (netif_queue_stopped(dev))
++      {
++          netif_wake_queue(dev);
++      }
++
++}
++
++
++#endif
++
++#if 0
++static void gmac_weird_interrupt(struct net_device *dev)
++{
++    gmac_dump_register(dev);
++}
++#endif
++
++/* The interrupt handler does all of the Rx thread work and cleans up
++   after the Tx thread. */
++static irqreturn_t gmac_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++{
++      struct net_device       *dev = (struct net_device *)dev_instance;
++      GMAC_RXDMA_FIRST_DESC_T rxdma_busy;
++//    GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++//    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_DMA_STATUS_T           status;
++    unsigned int            i,dev_index;
++      int                     handled = 0;
++
++    dev_index = gmac_select_interface(dev);
++
++      handled = 1;
++
++#ifdef CONFIG_SL_NAPI
++      disable_irq(gmac_irq[dev_index]);   /* disable GMAC interrupt */
++
++    status.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS);        /* read DMA status */
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,status.bits32,status.bits32);    /* clear DMA status */
++
++    if (status.bits.rx_overrun == 1)
++    {
++              printk("%s::RX Overrun !!!%d\n",__func__,gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RBNR));
++         gmac_dump_register(dev);
++        /* if RX DMA process is stoped , restart it */
++        rxdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC) ;
++        if (rxdma_busy.bits.rd_busy == 0)
++        {
++            /* restart Rx DMA process */
++              rxdma_ctrl.bits32 = 0;
++              rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++            rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++            rxdma_ctrl_mask.bits32 = 0;
++              rxdma_ctrl_mask.bits.rd_start = 1;
++            rxdma_ctrl_mask.bits.rd_continue = 1;
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++        }
++    }
++
++    /* process rx packet */
++      if (netif_running(dev) && ((status.bits.rs_eofi==1)||(status.bits.rs_finish==1)))
++      {
++        if (likely(netif_rx_schedule_prep(dev)))
++        {
++            gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,0,0x0007c000);   /* disable rx interrupt */
++            __netif_rx_schedule(dev);
++        }
++    }
++#ifndef CONFIG_TXINT_DISABLE
++    /* process tx packet */
++      if (netif_running(dev) && ((status.bits.ts_eofi==1)||(status.bits.ts_finish==1)))
++      {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++
++      enable_irq(gmac_irq[dev_index]);    /* enable GMAC interrupt */
++    return IRQ_RETVAL(handled);
++#endif
++
++   /* disable GMAC interrupt */
++      disable_irq(gmac_irq[dev_index]);
++    for (i=0;i<MAX_ISR_WORK;i++)
++    {
++        /* read DMA status */
++          status.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS);
++int_status = status.bits32;
++          /* clear DMA status */
++        gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,status.bits32,status.bits32);
++
++        if ((status.bits32 & 0xffffc000)==0)
++        {
++            break;
++        }
++
++          if (status.bits.rx_overrun == 1)
++          {
++                      printk("%s::RX Overrun !!!%d\n",__func__,gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RBNR));
++              gmac_dump_register(dev);
++            /* if RX DMA process is stoped , restart it */
++              rxdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_FIRST_DESC) ;
++              if (rxdma_busy.bits.rd_busy == 0)
++              {
++                  /* restart Rx DMA process */
++              rxdma_ctrl.bits32 = 0;
++              rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++                  rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++                  rxdma_ctrl_mask.bits32 = 0;
++              rxdma_ctrl_mask.bits.rd_start = 1;
++                  rxdma_ctrl_mask.bits.rd_continue = 1;
++                  gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++            }
++          }
++
++        /* receive rx interrupt */
++      if (netif_running(dev) && ((status.bits.rs_eofi==1)||(status.bits.rs_finish==1)))
++      {
++              gmac_rx_packet(dev);
++//                    gmac_tx_packet_complete(dev);
++        }
++
++        /* receive tx interrupt */
++      // if (netif_running(dev) && (status.bits.ts_finish==1))
++#ifndef CONFIG_TXINT_DISABLE
++      if (netif_running(dev) && ((status.bits.ts_eofi==1)||
++                         (status.bits.ts_finish==1)))
++      {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++      /* check uncommon events */
++/*        if ((status.bits32 & 0x632fc000)!=0)
++        {
++            printk("%s::DMA Status = %08x \n",__func__,status.bits32);
++            gmac_weird_interrupt(dev);
++        }
++*/
++      }
++
++    /* enable GMAC interrupt */
++      enable_irq(gmac_irq[dev_index]);
++      //printk("gmac_interrupt complete!\n\n");
++      return IRQ_RETVAL(handled);
++}
++
++static void gmac_hw_start(struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_TXDMA_CURR_DESC_T  tx_desc;
++      GMAC_RXDMA_CURR_DESC_T  rx_desc;
++    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      GMAC_DMA_STATUS_T       dma_status,dma_status_mask;
++      int                                             dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++      /* program TxDMA Current Descriptor Address register for first descriptor */
++      tx_desc.bits32 = (unsigned int)(tp->tx_desc_dma);
++      tx_desc.bits.eofie = 1;
++      tx_desc.bits.sof_eof = 0x03;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC,tx_desc.bits32,0xffffffff);
++      gmac_write_reg(gmac_base_addr[dev_index] + 0xff2c,tx_desc.bits32,0xffffffff);   /* tx next descriptor address */
++
++      /* program RxDMA Current Descriptor Address register for first descriptor */
++      rx_desc.bits32 = (unsigned int)(tp->rx_desc_dma);
++      rx_desc.bits.eofie = 1;
++      rx_desc.bits.sof_eof = 0x03;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CURR_DESC,rx_desc.bits32,0xffffffff);
++      gmac_write_reg(gmac_base_addr[dev_index] + 0xff3c,rx_desc.bits32,0xffffffff);   /* rx next descriptor address */
++
++      /* enable GMAC interrupt & disable loopback */
++      dma_status.bits32 = 0;
++      dma_status.bits.loop_back = 0;  /* disable DMA loop-back mode */
++//    dma_status.bits.m_tx_fail = 1;
++      dma_status.bits.m_cnt_full = 1;
++      dma_status.bits.m_rx_pause_on = 1;
++      dma_status.bits.m_tx_pause_on = 1;
++      dma_status.bits.m_rx_pause_off = 1;
++      dma_status.bits.m_tx_pause_off = 1;
++      dma_status.bits.m_rx_overrun = 1;
++      dma_status.bits.m_link_change = 1;
++      dma_status_mask.bits32 = 0;
++      dma_status_mask.bits.loop_back = 1;
++//    dma_status_mask.bits.m_tx_fail = 1;
++      dma_status_mask.bits.m_cnt_full = 1;
++      dma_status_mask.bits.m_rx_pause_on = 1;
++      dma_status_mask.bits.m_tx_pause_on = 1;
++      dma_status_mask.bits.m_rx_pause_off = 1;
++      dma_status_mask.bits.m_tx_pause_off = 1;
++      dma_status_mask.bits.m_rx_overrun = 1;
++      dma_status_mask.bits.m_link_change = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_DMA_STATUS,dma_status.bits32,dma_status_mask.bits32);
++
++    /* program tx dma control register */
++      txdma_ctrl.bits32 = 0;
++      txdma_ctrl.bits.td_start = 0;    /* start TX DMA transfer */
++      txdma_ctrl.bits.td_continue = 0; /* continue Tx DMA operation */
++      txdma_ctrl.bits.td_chain_mode = 1;  /* chain mode */
++      txdma_ctrl.bits.td_prot = 0;
++      txdma_ctrl.bits.td_burst_size = 2;  /* DMA burst size for every AHB request */
++      txdma_ctrl.bits.td_bus = 2;         /* peripheral bus width */
++      txdma_ctrl.bits.td_endian = 0;      /* little endian */
++#ifdef CONFIG_TXINT_DISABLE
++      txdma_ctrl.bits.td_finish_en = 0;   /* DMA finish event interrupt disable */
++#else
++      txdma_ctrl.bits.td_finish_en = 1;   /* DMA finish event interrupt enable */
++#endif
++      txdma_ctrl.bits.td_fail_en = 1;     /* DMA fail interrupt enable */
++      txdma_ctrl.bits.td_perr_en = 1;     /* protocol failure interrupt enable */
++      txdma_ctrl.bits.td_eod_en = 0;      /* disable Tx End of Descriptor Interrupt */
++      //txdma_ctrl.bits.td_eod_en = 0;      /* disable Tx End of Descriptor Interrupt */
++#ifdef CONFIG_TXINT_DISABLE
++      txdma_ctrl.bits.td_eof_en = 0;      /* end of frame interrupt disable */
++#else
++      txdma_ctrl.bits.td_eof_en = 1;      /* end of frame interrupt enable */
++#endif
++      txdma_ctrl_mask.bits32 = 0;
++      txdma_ctrl_mask.bits.td_start = 1;
++      txdma_ctrl_mask.bits.td_continue = 1;
++      txdma_ctrl_mask.bits.td_chain_mode = 1;
++      txdma_ctrl_mask.bits.td_prot = 15;
++      txdma_ctrl_mask.bits.td_burst_size = 3;
++      txdma_ctrl_mask.bits.td_bus = 3;
++      txdma_ctrl_mask.bits.td_endian = 1;
++      txdma_ctrl_mask.bits.td_finish_en = 1;
++      txdma_ctrl_mask.bits.td_fail_en = 1;
++      txdma_ctrl_mask.bits.td_perr_en = 1;
++      txdma_ctrl_mask.bits.td_eod_en = 1;
++      //txdma_ctrl_mask.bits.td_eod_en = 1;
++      txdma_ctrl_mask.bits.td_eof_en = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,txdma_ctrl.bits32,txdma_ctrl_mask.bits32);
++
++    /* program rx dma control register */
++      rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 1;    /* start RX DMA transfer */
++      rxdma_ctrl.bits.rd_continue = 1; /* continue RX DMA operation */
++      rxdma_ctrl.bits.rd_chain_mode = 1;  /* chain mode */
++      rxdma_ctrl.bits.rd_prot = 0;
++      rxdma_ctrl.bits.rd_burst_size = 2;  /* DMA burst size for every AHB request */
++      rxdma_ctrl.bits.rd_bus = 2;         /* peripheral bus width */
++      rxdma_ctrl.bits.rd_endian = 0;      /* little endian */
++      rxdma_ctrl.bits.rd_finish_en = 1;   /* DMA finish event interrupt enable */
++      rxdma_ctrl.bits.rd_fail_en = 1;     /* DMA fail interrupt enable */
++      rxdma_ctrl.bits.rd_perr_en = 1;     /* protocol failure interrupt enable */
++      rxdma_ctrl.bits.rd_eod_en = 0;      /* disable Rx End of Descriptor Interrupt */
++      rxdma_ctrl.bits.rd_eof_en = 1;      /* end of frame interrupt enable */
++      rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++      rxdma_ctrl_mask.bits.rd_continue = 1;
++      rxdma_ctrl_mask.bits.rd_chain_mode = 1;
++      rxdma_ctrl_mask.bits.rd_prot = 15;
++      rxdma_ctrl_mask.bits.rd_burst_size = 3;
++      rxdma_ctrl_mask.bits.rd_bus = 3;
++      rxdma_ctrl_mask.bits.rd_endian = 1;
++      rxdma_ctrl_mask.bits.rd_finish_en = 1;
++      rxdma_ctrl_mask.bits.rd_fail_en = 1;
++      rxdma_ctrl_mask.bits.rd_perr_en = 1;
++      rxdma_ctrl_mask.bits.rd_eod_en = 1;
++      rxdma_ctrl_mask.bits.rd_eof_en = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++    return;
++}
++
++static void gmac_hw_stop(struct net_device *dev)
++{
++    GMAC_TXDMA_CTRL_T       txdma_ctrl,txdma_ctrl_mask;
++    GMAC_RXDMA_CTRL_T       rxdma_ctrl,rxdma_ctrl_mask;
++      int                                     dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* program tx dma control register */
++      txdma_ctrl.bits32 = 0;
++      txdma_ctrl.bits.td_start = 0;
++      txdma_ctrl.bits.td_continue = 0;
++      txdma_ctrl_mask.bits32 = 0;
++      txdma_ctrl_mask.bits.td_start = 1;
++      txdma_ctrl_mask.bits.td_continue = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,txdma_ctrl.bits32,txdma_ctrl_mask.bits32);
++    /* program rx dma control register */
++      rxdma_ctrl.bits32 = 0;
++      rxdma_ctrl.bits.rd_start = 0;    /* stop RX DMA transfer */
++      rxdma_ctrl.bits.rd_continue = 0; /* stop continue RX DMA operation */
++      rxdma_ctrl_mask.bits32 = 0;
++      rxdma_ctrl_mask.bits.rd_start = 1;
++      rxdma_ctrl_mask.bits.rd_continue = 1;
++      gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RXDMA_CTRL,rxdma_ctrl.bits32,rxdma_ctrl_mask.bits32);
++}
++
++static int gmac_init_desc_buf(struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      struct sk_buff          *skb;
++      dma_addr_t          tx_first_desc_dma=0;
++      dma_addr_t          rx_first_desc_dma=0;
++      dma_addr_t          rx_first_buf_dma=0;
++      unsigned int        i,index;
++
++    printk("Descriptor buffer init......\n");
++
++    /* get device index number */
++    index = gmac_get_dev_index(dev);
++#ifdef CONFIG_SL2312_MPAGE
++      for (i=0; i<TX_DESC_NUM; i++) {
++              tx_skb[index][i].freeable = 0;
++              tx_skb[index][i].skb = 0;
++              tx_skb[index][i].desc_in_use = 0;
++              tx_skb[index][i].end_seq = 0;
++      }
++#else
++    for (i=0;i<TX_DESC_NUM;i++)
++    {
++        tx_skb[index][i] = NULL;
++    }
++#endif
++    for (i=0;i<RX_DESC_NUM;i++)
++    {
++        rx_skb[index][i] = NULL;
++    }
++
++      /* allocates TX/RX descriptors */
++      tp->tx_desc = DMA_MALLOC(TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(dma_addr_t *)&tp->tx_desc_dma);
++    tx_desc_virtual_base[index] = (unsigned int)tp->tx_desc - (unsigned int)tp->tx_desc_dma;
++    memset(tp->tx_desc,0x00,TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T));
++      tp->rx_desc = DMA_MALLOC(RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(dma_addr_t *)&tp->rx_desc_dma);
++    rx_desc_virtual_base[index] = (unsigned int)tp->rx_desc - (unsigned int)tp->rx_desc_dma;
++    memset(tp->rx_desc,0x00,RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T));
++    tx_desc_start_adr[index] = (unsigned int)tp->tx_desc;   /* for tx skb index calculation */
++    rx_desc_start_adr[index] = (unsigned int)tp->rx_desc;   /* for rx skb index calculation */
++    printk("tx_desc = %08x\n",(unsigned int)tp->tx_desc);
++    printk("rx_desc = %08x\n",(unsigned int)tp->rx_desc);
++      printk("tx_desc_dma = %08x\n",tp->tx_desc_dma);
++      printk("rx_desc_dma = %08x\n",tp->rx_desc_dma);
++
++      if (tp->tx_desc==0x00 || tp->rx_desc==0x00)
++      {
++              free_irq(dev->irq, dev);
++
++              if (tp->tx_desc)
++                      DMA_MFREE(tp->tx_desc, TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),tp->tx_desc_dma);
++              if (tp->rx_desc)
++                      DMA_MFREE(tp->rx_desc, RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),tp->rx_desc_dma);
++              return -ENOMEM;
++      }
++
++      /* TX descriptors initial */
++      tp->tx_cur_desc = tp->tx_desc;  /* virtual address */
++      tp->tx_finished_desc = tp->tx_desc; /* virtual address */
++      tx_first_desc_dma = tp->tx_desc_dma; /* physical address */
++      for (i = 1; i < TX_DESC_NUM; i++)
++      {
++              tp->tx_desc->frame_ctrl.bits_tx_out.own = CPU; /* set owner to CPU */
++              tp->tx_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;  /* set tx buffer size for descriptor */
++              tp->tx_desc_dma = tp->tx_desc_dma + sizeof(GMAC_DESCRIPTOR_T); /* next tx descriptor DMA address */
++              tp->tx_desc->next_desc.next_descriptor = tp->tx_desc_dma | 0x0000000b;
++              tp->tx_desc = &tp->tx_desc[1] ; /* next tx descriptor virtual address */
++      }
++      /* the last descriptor will point back to first descriptor */
++      tp->tx_desc->frame_ctrl.bits_tx_out.own = CPU;
++      tp->tx_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;
++      tp->tx_desc->next_desc.next_descriptor = tx_first_desc_dma | 0x0000000b;
++      tp->tx_desc = tp->tx_cur_desc;
++      tp->tx_desc_dma = tx_first_desc_dma;
++
++      /* RX descriptors initial */
++      tp->rx_cur_desc = tp->rx_desc;  /* virtual address */
++      rx_first_desc_dma = tp->rx_desc_dma; /* physical address */
++      for (i = 1; i < RX_DESC_NUM; i++)
++      {
++        if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++        {
++            printk("%s::skb buffer allocation fail !\n",__func__);
++        }
++        rx_skb[index][i-1] = skb;
++        tp->rx_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++              tp->rx_desc->frame_ctrl.bits_rx.own = DMA;  /* set owner bit to DMA */
++              tp->rx_desc->frame_ctrl.bits_rx.buffer_size = RX_BUF_SIZE; /* set rx buffer size for descriptor */
++              tp->rx_bufs_dma = tp->rx_bufs_dma + RX_BUF_SIZE;    /* point to next buffer address */
++              tp->rx_desc_dma = tp->rx_desc_dma + sizeof(GMAC_DESCRIPTOR_T); /* next rx descriptor DMA address */
++              tp->rx_desc->next_desc.next_descriptor = tp->rx_desc_dma | 0x0000000b;
++              tp->rx_desc = &tp->rx_desc[1]; /* next rx descriptor virtual address */
++      }
++      /* the last descriptor will point back to first descriptor */
++    if ( (skb = dev_alloc_skb(RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++    {
++        printk("%s::skb buffer allocation fail !\n",__func__);
++    }
++    rx_skb[index][i-1] = skb;
++    tp->rx_desc->buf_adr = (unsigned int)__pa(skb->data) | 0x02;    /* insert two bytes in the beginning of rx data */
++      tp->rx_desc->frame_ctrl.bits_rx.own = DMA;
++      tp->rx_desc->frame_ctrl.bits_rx.buffer_size = RX_BUF_SIZE;
++      tp->rx_desc->next_desc.next_descriptor = rx_first_desc_dma | 0x0000000b;
++      tp->rx_desc = tp->rx_cur_desc;
++      tp->rx_desc_dma = rx_first_desc_dma;
++      tp->rx_bufs_dma = rx_first_buf_dma;
++
++      for (i=0; i<GMAC_PHY_IF; i++) {
++              tp->tx_desc_hdr[i] = 0;
++              tp->tx_desc_tail[i] = 0;
++      }
++      return (0);
++}
++
++static int gmac_clear_counter (struct net_device *dev)
++{
++      struct gmac_private *tp = dev->priv;
++      unsigned int    dev_index;
++
++    dev_index = gmac_select_interface(dev);
++//    tp = gmac_dev[index]->priv;
++    /* clear counter */
++    gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_DISCARDS);
++    gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_ERRORS);
++    tp->stats.tx_bytes = 0;
++    tp->stats.tx_packets = 0;
++      tp->stats.tx_errors = 0;
++    tp->stats.rx_bytes = 0;
++      tp->stats.rx_packets = 0;
++      tp->stats.rx_errors = 0;
++    tp->stats.rx_dropped = 0;
++      return (0);
++}
++
++static int gmac_open (struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      int    retval;
++
++    gmac_select_interface(dev);
++
++      /* chip reset */
++      gmac_sw_reset(dev);
++
++    /* allocates tx/rx descriptor and buffer memory */
++    gmac_init_desc_buf(dev);
++
++    /* get mac address from FLASH */
++    gmac_get_mac_address();
++
++    /* set PHY register to start autonegition process */
++    gmac_set_phy_status(dev);
++
++      /* GMAC initialization */
++      if (gmac_init_chip(dev))
++      {
++              printk (KERN_ERR "GMAC init fail\n");
++      }
++
++    /* start DMA process */
++      gmac_hw_start(dev);
++
++    /* enable tx/rx register */
++    gmac_enable_tx_rx(dev);
++
++    /* clear statistic counter */
++    gmac_clear_counter(dev);
++
++      netif_start_queue (dev);
++
++    /* hook ISR */
++      retval = request_irq (dev->irq, gmac_interrupt, SA_INTERRUPT, dev->name, dev);
++      if (retval)
++              return retval;
++
++      if(!FLAG_SWITCH)
++      {
++      init_waitqueue_head (&tp->thr_wait);
++      init_completion(&tp->thr_exited);
++
++      tp->time_to_die = 0;
++      tp->thr_pid = kernel_thread (gmac_phy_thread, dev, CLONE_FS | CLONE_FILES);
++      if (tp->thr_pid < 0)
++      {
++              printk (KERN_WARNING "%s: unable to start kernel thread\n",dev->name);
++      }
++    }
++      return (0);
++}
++
++static int gmac_close(struct net_device *dev)
++{
++    struct gmac_private *tp = dev->priv;
++    unsigned int        i,dev_index;
++    unsigned int        ret;
++
++    dev_index = gmac_get_dev_index(dev);
++
++    /* stop tx/rx packet */
++    gmac_disable_tx_rx(dev);
++
++    /* stop the chip's Tx and Rx DMA processes */
++      gmac_hw_stop(dev);
++
++    netif_stop_queue(dev);
++
++    /* disable interrupts by clearing the interrupt mask */
++    synchronize_irq();
++    free_irq(dev->irq,dev);
++
++      DMA_MFREE(tp->tx_desc, TX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(unsigned int)tp->tx_desc_dma);
++      DMA_MFREE(tp->rx_desc, RX_DESC_NUM*sizeof(GMAC_DESCRIPTOR_T),(unsigned int)tp->rx_desc_dma);
++
++#ifdef CONFIG_SL2312_MPAGE
++//    kfree(tx_skb);
++#endif
++
++    for (i=0;i<RX_DESC_NUM;i++)
++    {
++        if (rx_skb[dev_index][i])
++        {
++            dev_kfree_skb(rx_skb[dev_index][i]);
++        }
++    }
++      if(!FLAG_SWITCH)
++      {
++      if (tp->thr_pid >= 0)
++      {
++                  tp->time_to_die = 1;
++              wmb();
++              ret = kill_proc (tp->thr_pid, SIGTERM, 1);
++              if (ret)
++              {
++                      printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
++                      return ret;
++              }
++//                    wait_for_completion (&tp->thr_exited);
++      }
++    }
++
++    return (0);
++}
++
++#ifdef CONFIG_SL2312_MPAGE
++int printk_all(int dev_index, struct gmac_private* tp)
++{
++      int i=0;
++    unsigned int tx_current_descriptor = 0;
++    int hw_index;
++    int fi;
++    GMAC_DESCRIPTOR_T* tmp_desc;
++
++      GMAC_DESCRIPTOR_T* cur_desc=tp->tx_cur_desc;
++      fi = ((unsigned int)cur_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      printk("tmp_desc %x, id %d\n", (int)cur_desc, fi);
++
++      tmp_desc = (GMAC_DESCRIPTOR_T*)((gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC) & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++      hw_index = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index])/ sizeof(GMAC_DESCRIPTOR_T);
++      printk("hd_desc %x, ind %d, fin desc %x\n",(int)tmp_desc, hw_index, (int)tp->tx_finished_desc);
++
++      for (i=0; i<TX_DESC_NUM; i++) {
++              printk("**id %4d, hw_index %4d ==> ", fi, hw_index);
++              printk("fc %8x ", tmp_desc->frame_ctrl.bits32);
++              printk("fs %8x ", tmp_desc->flag_status.bits32);
++              printk("fb %8x ", tmp_desc->buf_adr);
++              printk("fd %8x\n",  tmp_desc->next_desc.next_descriptor);
++              tmp_desc = (GMAC_DESCRIPTOR_T*)((tmp_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              fi = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++      }
++    tx_current_descriptor = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CURR_DESC);
++    printk("%s: tx current descriptor = %x \n",__func__,tx_current_descriptor);
++    printk("%s: interrupt status = %x \n",__func__,int_status);
++    return 0;
++}
++
++int cleanup_desc(int dev_index, struct gmac_private* tp)
++{
++      int i=0;
++      int index = ((unsigned int)tp->tx_cur_desc - tx_desc_start_adr[dev_index])/sizeof(GMAC_DESCRIPTOR_T);
++      GMAC_DESCRIPTOR_T* fill_desc = tp->tx_cur_desc;
++
++      for (i=0; i< TX_DESC_NUM; i++)
++      {
++              fill_desc->frame_ctrl.bits_tx_out.own = CPU;
++              fill_desc->frame_ctrl.bits_tx_out.buffer_size = TX_BUF_SIZE;
++              tx_skb[dev_index][index].desc_in_use = 0;
++              free_tx_buf(dev_index, index);
++              printk("cleanup di %d\n", index);
++              fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              index++;
++              if (index > TX_DESC_NUM)
++                      index = 0;
++      }
++      return 1;
++}
++
++size_t get_available_tx_desc(struct net_device* dev, int dev_index)
++{
++      struct gmac_private *tp = dev->priv;
++      unsigned int desc_hdr = tp->tx_desc_hdr[dev_index];
++      unsigned int desc_tail = tp->tx_desc_tail[dev_index];
++      int available_desc_num = (TX_DESC_NUM - desc_hdr + desc_tail) & (TX_DESC_NUM-1);
++      if (!available_desc_num) {
++              if (tx_skb[dev_index][desc_hdr].desc_in_use)
++                      return 0;
++              else
++                      return TX_DESC_NUM;
++      }
++      return available_desc_num;
++}
++
++int check_free_tx_desc(int dev_index, int n, GMAC_DESCRIPTOR_T* desc)
++{
++      int i,index;
++      GMAC_DESCRIPTOR_T* tmp_desc = desc;
++
++      if (n > TX_DESC_NUM)
++              return 0;
++
++      index = ((unsigned int)tmp_desc - tx_desc_start_adr[dev_index])/sizeof(GMAC_DESCRIPTOR_T);
++      for (i=0; i<n; i++)
++      {
++              if (tx_skb[dev_index][index].desc_in_use)
++              {
++                      printk("sw desc %d is in use\n", index);
++                      /* cleanup all the descriptors to check if DMA still running */
++                      return 0;
++              }
++              index++;
++              if (index == TX_DESC_NUM)
++                      index = 0;
++      }
++      return 1;
++}
++
++#define TCPHDRLEN(tcp_hdr)  ((ntohs(*((__u16 *)tcp_hdr + 6)) >> 12) & 0x000F)
++
++inline int fill_in_desc(int dev_index, GMAC_DESCRIPTOR_T *desc, char* data, int len, int total_len, int sof, int freeable, int ownership, struct sk_buff* skb)
++{
++      int index = ((unsigned int)desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      if (desc->frame_ctrl.bits_tx_in.own == CPU)
++      {
++              tx_skb[dev_index][index].freeable = freeable;
++              if ((sof & 0x01) && skb) {
++                      tx_skb[dev_index][index].skb = skb;
++              }
++              else
++                      tx_skb[dev_index][index].skb = 0;
++
++              if (sof != 2)
++                      tx_skb[dev_index][index].desc_in_use = 1;
++              else
++                      tx_skb[dev_index][index].desc_in_use = 0;
++
++              consistent_sync(data, len, PCI_DMA_TODEVICE);
++              desc->buf_adr = (unsigned int)__pa(data);
++              desc->frame_ctrl.bits_tx_out.buffer_size = len;
++              desc->flag_status.bits_tx_flag.frame_count = total_len;
++              desc->next_desc.bits.eofie = 1;
++              desc->next_desc.bits.sof_eof = sof;
++              desc->frame_ctrl.bits_tx_out.vlan_enable = 0;
++              desc->frame_ctrl.bits_tx_out.ip_csum_en = 1;     /* TSS IPv4 IP header checksum enable */
++              desc->frame_ctrl.bits_tx_out.ipv6_tx_en = 1;    /* TSS IPv6 tx enable */
++              desc->frame_ctrl.bits_tx_out.tcp_csum_en = 1;    /* TSS TCP checksum enable */
++              desc->frame_ctrl.bits_tx_out.udp_csum_en = 1;    /* TSS UDP checksum enable */
++        wmb();
++              desc->frame_ctrl.bits_tx_out.own = ownership;
++//            consistent_sync(desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++      }
++      return 0;
++}
++#endif
++
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct gmac_private     *tp = dev->priv;
++      GMAC_TXDMA_CTRL_T               tx_ctrl,tx_ctrl_mask;
++      GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++      unsigned int            len = skb->len;
++      unsigned int            dev_index;
++      static unsigned int     pcount = 0;
++#ifdef CONFIG_SL2312_MPAGE
++    GMAC_DESCRIPTOR_T *fill_desc;
++      int snd_pages = skb_shinfo(skb)->nr_frags;  /* get number of descriptor */
++      int desc_needed = 1; // for jumbo packet, one descriptor is enough.
++      int header_len = skb->len;
++    struct iphdr      *ip_hdr;
++    struct tcphdr     *tcp_hdr;
++    int             tcp_hdr_len;
++    int             data_len;
++    int             prv_index;
++    long            seq_num;
++    int             first_desc_index;
++    int             ownership, freeable;
++    int             eof;
++      int             i=0;
++#endif
++#ifdef CONFIG_TXINT_DISABLE
++      int                             available_desc_cnt = 0;
++#endif
++
++    dev_index = gmac_select_interface(dev);
++
++#ifdef CONFIG_TXINT_DISABLE
++      available_desc_cnt = get_available_tx_desc(dev, dev_index);
++
++      if (available_desc_cnt < (TX_DESC_NUM >> 2)) {
++              gmac_tx_packet_complete(dev);
++      }
++#endif
++
++#ifdef CONFIG_SL2312_MPAGE
++
++      fill_desc = tp->tx_cur_desc;
++      if(!fill_desc) {
++              printk("cur_desc is NULL!\n");
++              return -1;
++      }
++
++      if (storlink_ctl.recvfile==2)
++      {
++          printk("snd_pages=%d skb->len=%d\n",snd_pages,skb->len);
++      }
++
++      if (snd_pages)
++              desc_needed += snd_pages;   /* decriptors needed for this large packet */
++
++      if (!check_free_tx_desc(dev_index, desc_needed, fill_desc)) {
++              printk("no available desc!\n");
++        gmac_dump_register(dev);
++              printk_all(dev_index, tp);
++              tp->stats.tx_dropped++;
++              if (pcount++ > 10)
++              {
++                  for (;;);
++              }
++              return -1;
++      }
++
++      first_desc_index = ((unsigned int)fill_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++      /* check if the tcp packet is in order*/
++      ip_hdr = (struct iphdr*) &(skb->data[14]);
++      tcp_hdr = (struct tcphdr*) &(skb->data[14+ip_hdr->ihl * 4]);
++      tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++      data_len = skb->len - 14 - ip_hdr->ihl *4 - tcp_hdr_len;
++
++      prv_index = first_desc_index-1;
++      if (prv_index <0)
++          prv_index += TX_DESC_NUM;
++      seq_num = ntohl(tcp_hdr->seq);
++
++      if (snd_pages)
++      {
++              // calculate header length
++              // check fragment total length and header len = skb len - frag len
++              // or parse the header.
++              for (i=0; i<snd_pages; i++) {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                      header_len -= frag->size;
++              }
++              ownership = CPU;
++              freeable = 0;
++              /* fill header into first descriptor */
++              fill_in_desc(dev_index, fill_desc, skb->data, header_len, len, 2, freeable, ownership, 0);
++              fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              tx_skb[dev_index][first_desc_index].end_seq = seq_num + data_len;
++
++              eof = 0;
++              ownership = DMA;
++              for (i=0; i<snd_pages; i++)
++              {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                      int start_pos = frag->page_offset;
++                      char* data_buf = page_address(frag->page);
++                      int data_size = frag->size;
++                      int cur_index;
++
++                      if (i == snd_pages-1)
++                      {
++                              eof=1;
++                              freeable = 1;
++                      }
++                      fill_in_desc(dev_index, fill_desc, data_buf+(start_pos), data_size,
++                                   len, eof, freeable, ownership, skb);
++                      cur_index = ((unsigned int)fill_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++
++                      fill_desc = (GMAC_DESCRIPTOR_T*)((fill_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              }
++              /* pass the ownership of the first descriptor to hardware */
++//        disable_irq(gmac_irq[dev_index]);
++              tx_skb[dev_index][first_desc_index].desc_in_use = 1;
++        wmb();
++              tp->tx_cur_desc->frame_ctrl.bits_tx_out.own = DMA;
++//            consistent_sync(tp->tx_cur_desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++              tp->tx_cur_desc = fill_desc;
++              dev->trans_start = jiffies;
++//        enable_irq(gmac_irq[dev_index]);
++      }
++      else if ( tp->tx_cur_desc->frame_ctrl.bits_tx_out.own == CPU )
++      {
++//            tx_skb[dev_index][first_desc_index].end_seq = seq_num + data_len;
++//        disable_irq(gmac_irq[dev_index]);
++              fill_in_desc(dev_index, tp->tx_cur_desc, skb->data, skb->len, skb->len, 3, 1, DMA, skb);
++//        enable_irq(gmac_irq[dev_index]);
++              //consistent_sync(tp->tx_cur_desc, sizeof(GMAC_DESCRIPTOR_T), PCI_DMA_TODEVICE);
++              tp->tx_cur_desc = (GMAC_DESCRIPTOR_T*)((tp->tx_cur_desc->next_desc.next_descriptor & 0xfffffff0) + tx_desc_virtual_base[dev_index]);
++              dev->trans_start = jiffies;
++      }
++      else
++      {
++              printk("gmac tx drop!\n");
++              tp->stats.tx_dropped++;
++              return -1;
++      }
++
++#ifdef CONFIG_TXINT_DISABLE
++      tp->tx_desc_hdr[dev_index] = (tp->tx_desc_hdr[dev_index] + desc_needed) & (TX_DESC_NUM-1);
++#endif
++
++#else
++    if ((tp->tx_cur_desc->frame_ctrl.bits_tx_out.own == CPU) && (len < TX_BUF_SIZE))
++      {
++        index = ((unsigned int)tp->tx_cur_desc - tx_desc_start_adr[dev_index]) / sizeof(GMAC_DESCRIPTOR_T);
++        tx_skb[dev_index][index] = skb;
++        consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE);
++        tp->tx_cur_desc->buf_adr = (unsigned int)__pa(skb->data);
++      tp->tx_cur_desc->flag_status.bits_tx_flag.frame_count = len;    /* total frame byte count */
++      tp->tx_cur_desc->next_desc.bits.sof_eof = 0x03;                 /*only one descriptor*/
++              tp->tx_cur_desc->frame_ctrl.bits_tx_out.buffer_size = len;      /* descriptor byte count */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.vlan_enable = 0;
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.ip_csum_en = 0;     /* TSS IPv4 IP header checksum enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.ipv6_tx_en = 0 ;    /* TSS IPv6 tx enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.tcp_csum_en = 0;    /* TSS TCP checksum enable */
++        tp->tx_cur_desc->frame_ctrl.bits_tx_out.udp_csum_en = 0;    /* TSS UDP checksum enable */
++        wmb();
++      tp->tx_cur_desc->frame_ctrl.bits_tx_out.own = DMA;              /* set owner bit */
++      tp->tx_cur_desc = (GMAC_DESCRIPTOR_T *)((tp->tx_cur_desc->next_desc.next_descriptor & 0xfffffff0)+tx_desc_virtual_base[dev_index]);
++      dev->trans_start = jiffies;
++      }
++      else
++      {
++              /* no free tx descriptor */
++              dev_kfree_skb(skb);
++          netif_stop_queue(dev);
++              tp->stats.tx_dropped++;
++              return (-1);
++      }
++#endif
++      /* if TX DMA process is stoped , restart it */
++      txdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_FIRST_DESC);
++      if (txdma_busy.bits.td_busy == 0)
++      {
++              /* restart DMA process */
++              tx_ctrl.bits32 = 0;
++              tx_ctrl.bits.td_start = 1;
++              tx_ctrl.bits.td_continue = 1;
++              tx_ctrl_mask.bits32 = 0;
++              tx_ctrl_mask.bits.td_start = 1;
++              tx_ctrl_mask.bits.td_continue = 1;
++              gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,tx_ctrl.bits32,tx_ctrl_mask.bits32);
++      }
++      return (0);
++}
++
++
++struct net_device_stats * gmac_get_stats(struct net_device *dev)
++{
++    struct gmac_private *tp = dev->priv;
++    unsigned long       flags;
++    unsigned int        pkt_drop;
++    unsigned int        pkt_error;
++    unsigned int        dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++//    if (storlink_ctl.recvfile==3)
++//    {
++//        printk("GMAC_GLOBAL_BASE_ADDR=%x\n", readl(GMAC_GLOBAL_BASE_ADDR+0x30));
++//        gmac_dump_register(dev);
++//        printk_all(0, dev);
++//    }
++
++    if (netif_running(dev))
++    {
++        /* read H/W counter */
++        spin_lock_irqsave(&tp->lock,flags);
++        pkt_drop = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_DISCARDS);
++        pkt_error = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_IN_ERRORS);
++        tp->stats.rx_dropped = tp->stats.rx_dropped + pkt_drop;
++        tp->stats.rx_errors = tp->stats.rx_errors + pkt_error;
++        spin_unlock_irqrestore(&tp->lock,flags);
++    }
++    return &tp->stats;
++}
++
++static unsigned const ethernet_polynomial = 0x04c11db7U;
++static inline u32 ether_crc (int length, unsigned char *data)
++{
++      int crc = -1;
++      unsigned int i;
++      unsigned int crc_val=0;
++
++      while (--length >= 0) {
++              unsigned char current_octet = *data++;
++              int bit;
++              for (bit = 0; bit < 8; bit++, current_octet >>= 1)
++                      crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
++                           ethernet_polynomial : 0);
++      }
++      crc = ~crc;
++      for (i=0;i<32;i++)
++      {
++              crc_val = crc_val + (((crc << i) & 0x80000000) >> (31-i));
++      }
++      return crc_val;
++}
++
++static void gmac_set_rx_mode(struct net_device *dev)
++{
++    GMAC_RX_FLTR_T      filter;
++      unsigned int        mc_filter[2];       /* Multicast hash filter */
++    int                 bit_nr;
++      unsigned int        i, dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++//    printk("%s : dev->flags = %x \n",__func__,dev->flags);
++//    dev->flags |= IFF_ALLMULTI;  /* temp */
++    filter.bits32 = 0;
++    filter.bits.error = 0;
++      if (dev->flags & IFF_PROMISC)
++      {
++          filter.bits.error = 1;
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else if (dev->flags & IFF_ALLMULTI)
++      {
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else
++      {
++              struct dev_mc_list *mclist;
++
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0;
++              for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;i++, mclist = mclist->next)
++              {
++            bit_nr = ether_crc(ETH_ALEN,mclist->dmi_addr) & 0x0000003f;
++            if (bit_nr < 32)
++            {
++                mc_filter[0] = mc_filter[0] | (1<<bit_nr);
++            }
++            else
++            {
++                mc_filter[1] = mc_filter[1] | (1<<(bit_nr-32));
++            }
++              }
++      }
++    filter.bits32 = 0x1f;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_RX_FLTR,filter.bits32,0xffffffff);
++
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_MCAST_FIL0,mc_filter[0],0xffffffff);
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_MCAST_FIL1,mc_filter[1],0xffffffff);
++    return;
++}
++
++static int gmac_set_mac_address(struct net_device *dev, void *addr)
++{
++      struct sockaddr *sock;
++      unsigned int    reg_val;
++      unsigned int    dev_index;
++    unsigned int    i;
++
++    dev_index = gmac_select_interface(dev);
++
++      sock = (struct sockaddr *) addr;
++      for (i = 0; i < 6; i++)
++      {
++              dev->dev_addr[i] = sock->sa_data[i];
++      }
++
++    reg_val = dev->dev_addr[0] + (dev->dev_addr[1]<<8) + (dev->dev_addr[2]<<16) + (dev->dev_addr[3]<<24);
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_STA_ADD0,reg_val,0xffffffff);
++    reg_val = dev->dev_addr[4] + (dev->dev_addr[5]<<8) ;
++    gmac_write_reg(gmac_base_addr[dev_index] + GMAC_STA_ADD1,reg_val,0x0000ffff);
++    memcpy(&eth0_mac[0],&dev->dev_addr[0],6);
++    printk("Storlink %s address = ",dev->name);
++    printk("%02x",dev->dev_addr[0]);
++    printk("%02x",dev->dev_addr[1]);
++    printk("%02x",dev->dev_addr[2]);
++    printk("%02x",dev->dev_addr[3]);
++    printk("%02x",dev->dev_addr[4]);
++    printk("%02x\n",dev->dev_addr[5]);
++
++    return (0);
++}
++
++static void gmac_tx_timeout(struct net_device *dev)
++{
++      GMAC_TXDMA_CTRL_T               tx_ctrl,tx_ctrl_mask;
++    GMAC_TXDMA_FIRST_DESC_T     txdma_busy;
++    int                                                       dev_index;
++
++    dev_index = gmac_select_interface(dev);
++
++    /* if TX DMA process is stoped , restart it */
++      txdma_busy.bits32 = gmac_read_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_FIRST_DESC);
++      if (txdma_busy.bits.td_busy == 0)
++      {
++              /* restart DMA process */
++              tx_ctrl.bits32 = 0;
++              tx_ctrl.bits.td_start = 1;
++              tx_ctrl.bits.td_continue = 1;
++              tx_ctrl_mask.bits32 = 0;
++              tx_ctrl_mask.bits.td_start = 1;
++              tx_ctrl_mask.bits.td_continue = 1;
++              gmac_write_reg(gmac_base_addr[dev_index] + GMAC_TXDMA_CTRL,tx_ctrl.bits32,tx_ctrl_mask.bits32);
++      }
++      netif_wake_queue(dev);
++    return;
++}
++
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      int rc = 0;
++    unsigned char *hwa = rq->ifr_ifru.ifru_hwaddr.sa_data;
++
++      if (!netif_running(dev))
++      {
++          printk("Before changing the H/W address,please down the device.\n");
++              return -EINVAL;
++    }
++
++      switch (cmd) {
++      case SIOCETHTOOL:
++        break;
++
++    case SIOCSIFHWADDR:
++        gmac_set_mac_address(dev,hwa);
++        break;
++
++      case SIOCGMIIPHY:       /* Get the address of the PHY in use. */
++      case SIOCDEVPRIVATE:    /* binary compat, remove in 2.5 */
++        break;
++
++      case SIOCGMIIREG:       /* Read the specified MII register. */
++      case SIOCDEVPRIVATE+1:
++              break;
++
++      case SIOCSMIIREG:       /* Write the specified MII register */
++      case SIOCDEVPRIVATE+2:
++              break;
++
++      default:
++              rc = -EOPNOTSUPP;
++              break;
++      }
++
++      return rc;
++}
++
++static void gmac_cleanup_module(void)
++{
++    int i;
++
++    for (i=0;i<GMAC_PHY_IF;i++)
++    {
++        unregister_netdev(gmac_dev[i]);
++    }
++      return ;
++}
++
++static int __init gmac_init_module(void)
++{
++      struct gmac_private *tp;
++      struct net_device *dev[GMAC_PHY_IF];
++      unsigned int i;
++
++#ifdef MODULE
++      printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
++#endif
++//    init_waitqueue_entry(&wait, current);
++
++      printk("GMAC Init......\n");
++      for(i = 0; i<GMAC_PHY_IF; i++)
++      {
++              dev[i] = alloc_etherdev(sizeof(struct gmac_private));
++              if (dev[i] == NULL)
++              {
++                      printk (KERN_ERR "Can't allocate ethernet device #%d .\n",i);
++                      return -ENOMEM;
++              }
++        gmac_dev[i] = dev[i];
++
++              SET_MODULE_OWNER(dev[i]);
++
++              tp = dev[i]->priv;
++
++              dev[i]->base_addr = gmac_base_addr[i];
++              dev[i]->irq = gmac_irq[i];
++          dev[i]->open = gmac_open;
++          dev[i]->stop = gmac_close;
++              dev[i]->hard_start_xmit = gmac_start_xmit;
++              dev[i]->get_stats = gmac_get_stats;
++              dev[i]->set_multicast_list = gmac_set_rx_mode;
++              dev[i]->set_mac_address = gmac_set_mac_address;
++              dev[i]->do_ioctl = gmac_netdev_ioctl;
++              dev[i]->tx_timeout = gmac_tx_timeout;
++              dev[i]->watchdog_timeo = TX_TIMEOUT;
++              dev[i]->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_TSO;
++#ifdef CONFIG_SL_NAPI
++        printk("NAPI driver is enabled.\n");
++        if (i==0)
++        {
++              dev[i]->poll = gmac_rx_poll_ga;
++              dev[i]->weight = 64;
++          }
++          else
++          {
++              dev[i]->poll = gmac_rx_poll_gb;
++              dev[i]->weight = 64;
++          }
++#endif
++
++              if (register_netdev(dev[i]))
++              {
++                      gmac_cleanup_module();
++                      return(-1);
++              }
++      }
++
++#ifdef CONFIG_SL3516_ASIC
++{
++    unsigned int    val;
++
++    /* set GMAC global register */
++    val = readl(GMAC_GLOBAL_BASE_ADDR+0x10);
++    val = val | 0x005a0000;
++    writel(val,GMAC_GLOBAL_BASE_ADDR+0x10);
++    writel(0x07f007f0,GMAC_GLOBAL_BASE_ADDR+0x1c);
++    writel(0x77770000,GMAC_GLOBAL_BASE_ADDR+0x20);
++    writel(0x77770000,GMAC_GLOBAL_BASE_ADDR+0x24);
++      val = readl(GMAC_GLOBAL_BASE_ADDR+0x04);
++      if((val&(1<<20))==0){           // GMAC1 enable
++              val = readl(GMAC_GLOBAL_BASE_ADDR+0x30);
++              val = (val & 0xe7ffffff) | 0x08000000;
++              writel(val,GMAC_GLOBAL_BASE_ADDR+0x30);
++      }
++
++}
++#endif
++
++//    printk("%s: dev0=%x  dev1=%x \n",__func__,dev[0],dev[1]);
++//    FLAG_SWITCH = 0 ;
++//    FLAG_SWITCH = SPI_get_identifier();
++//    if(FLAG_SWITCH)
++//    {
++//            printk("Configure ADM699X...\n");
++//            SPI_default();  //Add by jason for ADM699X configuration
++//    }
++      return (0);
++}
++
++
++module_init(gmac_init_module);
++module_exit(gmac_cleanup_module);
++
++static int gmac_phy_thread (void *data)
++{
++      struct net_device   *dev = data;
++      struct gmac_private *tp = dev->priv;
++      unsigned long       timeout;
++
++    daemonize("%s", dev->name);
++      allow_signal(SIGTERM);
++//    reparent_to_init();
++//    spin_lock_irq(&current->sigmask_lock);
++//    sigemptyset(&current->blocked);
++//    recalc_sigpending(current);
++//    spin_unlock_irq(&current->sigmask_lock);
++//    strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
++//    current->comm[sizeof(current->comm) - 1] = '\0';
++
++      while (1)
++      {
++          timeout = next_tick;
++              do
++              {
++                      timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
++              } while (!signal_pending (current) && (timeout > 0));
++
++              if (signal_pending (current))
++              {
++//                    spin_lock_irq(&current->sigmask_lock);
++                      flush_signals(current);
++//                    spin_unlock_irq(&current->sigmask_lock);
++              }
++
++              if (tp->time_to_die)
++                      break;
++
++//        printk("%s : Polling PHY Status...%x\n",__func__,dev);
++              rtnl_lock ();
++        gmac_get_phy_status(dev);
++              rtnl_unlock ();
++      }
++      complete_and_exit (&tp->thr_exited, 0);
++}
++
++static void gmac_set_phy_status(struct net_device *dev)
++{
++    GMAC_STATUS_T   status;
++    unsigned int    reg_val;
++    unsigned int    i = 0;
++    unsigned int    index;
++
++    if (FLAG_SWITCH==1)
++    {
++        return; /* GMAC connects to a switch chip, not PHY */
++    }
++
++    index = gmac_get_dev_index(dev);
++
++    if (index == 0)
++    {
++//            mii_write(phy_addr[index],0x04,0x0461); /* advertisement 10M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x0421); /* advertisement 10M half duplex, pause capable on */
++      mii_write(phy_addr[index],0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x04a1); /* advertisement 100M half duplex, pause capable on */
++#ifdef CONFIG_SL3516_ASIC
++      mii_write(phy_addr[index],0x09,0x0300); /* advertisement 1000M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x09,0x0000); /* advertisement 1000M full duplex, pause capable on */
++#endif
++    }
++    else
++    {
++//            mii_write(phy_addr[index],0x04,0x0461); /* advertisement 10M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x0421); /* advertisement 10M half duplex, pause capable on */
++      mii_write(phy_addr[index],0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++//            mii_write(phy_addr[index],0x04,0x04a1); /* advertisement 100M half duplex, pause capable on */
++#ifdef CONFIG_SL3516_ASIC
++//            mii_write(phy_addr[index],0x09,0x0000); /* advertisement no 1000M */
++      mii_write(phy_addr[index],0x09,0x0300); /* advertisement 1000M full duplex, pause capable on */
++#endif
++      }
++
++    mii_write(phy_addr[index],0x00,0x1200); /* Enable and Restart Auto-Negotiation */
++    mii_write(phy_addr[index],0x18,0x0041); /* Enable Active led */
++    while (((reg_val=mii_read(phy_addr[index],0x01)) & 0x00000004)!=0x04)
++    {
++        i++;
++        if (i > 30)
++        {
++            break;
++        }
++      msleep(100);
++    }
++    if (i>30)
++    {
++        pre_phy_status[index] = LINK_DOWN;
++              clear_bit(__LINK_STATE_START, &dev->state);
++        netif_stop_queue(dev);
++        storlink_ctl.link = 0;
++        printk("Link Down (%04x) ",reg_val);
++    }
++    else
++    {
++        pre_phy_status[index] = LINK_UP;
++              set_bit(__LINK_STATE_START, &dev->state);
++        netif_wake_queue(dev);
++        storlink_ctl.link = 1;
++        printk("Link Up (%04x) ",reg_val);
++    }
++
++    status.bits32 = 0;
++    reg_val = mii_read(phy_addr[index],10);
++    printk("reg_val0 = %x \n",reg_val);
++    if ((reg_val & 0x0800) == 0x0800)
++    {
++        status.bits.duplex = 1;
++        status.bits.speed = 2;
++        printk(" 1000M/Full \n");
++    }
++    else if ((reg_val & 0x0400) == 0x0400)
++    {
++        status.bits.duplex = 0;
++        status.bits.speed = 2;
++        printk(" 1000M/Half \n");
++    }
++    else
++    {
++        reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++        printk("reg_val1 = %x \n",reg_val);
++        if ((reg_val & 0x08)==0x08) /* 100M full duplex */
++        {
++                status.bits.duplex = 1;
++                status.bits.speed = 1;
++                printk(" 100M/Full \n");
++        }
++        else if ((reg_val & 0x04)==0x04) /* 100M half duplex */
++        {
++                status.bits.duplex = 0;
++                status.bits.speed = 1;
++                printk(" 100M/Half \n");
++        }
++        else if ((reg_val & 0x02)==0x02) /* 10M full duplex */
++        {
++                status.bits.duplex = 1;
++                status.bits.speed = 0;
++                printk(" 10M/Full \n");
++        }
++        else if ((reg_val & 0x01)==0x01) /* 10M half duplex */
++        {
++                status.bits.duplex = 0;
++                status.bits.speed = 0;
++                printk(" 100M/Half \n");
++        }
++    }
++
++    reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++    if ((reg_val & 0x20)==0x20)
++    {
++        flow_control_enable[index] = 1;
++        printk("Flow Control Enable. \n");
++    }
++    else
++    {
++        flow_control_enable[index] = 0;
++        printk("Flow Control Disable. \n");
++    }
++    full_duplex = status.bits.duplex;
++    speed = status.bits.speed;
++}
++
++static void gmac_get_phy_status(struct net_device *dev)
++{
++      GMAC_CONFIG0_T  config0,config0_mask;
++    GMAC_STATUS_T   status;
++    unsigned int    reg_val;
++    unsigned int    index;
++
++    index = gmac_select_interface(dev);
++
++    status.bits32 = 0;
++    status.bits.phy_mode = 1;
++
++#ifdef CONFIG_SL3516_ASIC
++    status.bits.mii_rmii = 2;   /* default value for ASIC version */
++//    status.bits.speed = 1;
++#else
++    if (index==0)
++        status.bits.mii_rmii = 0;
++    else
++        status.bits.mii_rmii = 2;
++#endif
++
++    /* read PHY status register */
++    reg_val = mii_read(phy_addr[index],0x01);
++    if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++    {
++        /* read PHY Auto-Negotiation Link Partner Ability Register */
++        reg_val = mii_read(phy_addr[index],10);
++        if ((reg_val & 0x0800) == 0x0800)
++        {
++            status.bits.mii_rmii = 3;  /* RGMII 1000Mbps mode */
++            status.bits.duplex = 1;
++            status.bits.speed = 2;
++        }
++        else if ((reg_val & 0x0400) == 0x0400)
++        {
++            status.bits.mii_rmii = 3;  /* RGMII 1000Mbps mode */
++            status.bits.duplex = 0;
++            status.bits.speed = 2;
++        }
++        else
++        {
++            reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++            if ((reg_val & 0x08)==0x08) /* 100M full duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 1;
++                    status.bits.speed = 1;
++            }
++            else if ((reg_val & 0x04)==0x04) /* 100M half duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 0;
++                    status.bits.speed = 1;
++            }
++            else if ((reg_val & 0x02)==0x02) /* 10M full duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 1;
++                    status.bits.speed = 0;
++            }
++            else if ((reg_val & 0x01)==0x01) /* 10M half duplex */
++            {
++                    status.bits.mii_rmii = 2;  /* RGMII 10/100Mbps mode */
++                    status.bits.duplex = 0;
++                    status.bits.speed = 0;
++            }
++        }
++        status.bits.link = LINK_UP; /* link up */
++        netif_wake_queue(dev);
++
++        reg_val = (mii_read(phy_addr[index],0x05) & 0x05E0) >> 5;
++        if ((reg_val & 0x20)==0x20)
++        {
++            if (flow_control_enable[index] == 0)
++            {
++                config0.bits32 = 0;
++                config0_mask.bits32 = 0;
++                config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                config0_mask.bits.tx_fc_en = 1;
++                config0_mask.bits.rx_fc_en = 1;
++                gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++//                printk("eth%d Flow Control Enable. \n",index);
++            }
++            flow_control_enable[index] = 1;
++        }
++        else
++        {
++            if (flow_control_enable[index] == 1)
++            {
++                config0.bits32 = 0;
++                config0_mask.bits32 = 0;
++                config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                config0_mask.bits.tx_fc_en = 1;
++                config0_mask.bits.rx_fc_en = 1;
++                gmac_write_reg(gmac_base_addr[index] + GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++//                printk("eth%d Flow Control Disable. \n",index);
++            }
++            flow_control_enable[index] = 0;
++        }
++
++        if (pre_phy_status[index] == LINK_DOWN)
++        {
++            gmac_enable_tx_rx(dev);
++            pre_phy_status[index] = LINK_UP;
++                      set_bit(__LINK_STATE_START, &dev->state);
++                      storlink_ctl.link = 1;
++//                    printk("eth%d Link Up ...\n",index);
++        }
++    }
++    else
++    {
++        status.bits.link = LINK_DOWN; /* link down */
++        netif_stop_queue(dev);
++        flow_control_enable[index] = 0;
++        storlink_ctl.link = 0;
++        if (pre_phy_status[index] == LINK_UP)
++        {
++            gmac_disable_tx_rx(dev);
++            pre_phy_status[index] = LINK_DOWN;
++                      clear_bit(__LINK_STATE_START, &dev->state);
++//                    printk("eth%d Link Down ...\n",index);
++      }
++
++    }
++
++    reg_val = gmac_read_reg(gmac_base_addr[index] + GMAC_STATUS);
++    if (reg_val != status.bits32)
++    {
++        gmac_write_reg(gmac_base_addr[index] + GMAC_STATUS,status.bits32,0x0000007f);
++    }
++}
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_BASE_ADDR  (IO_ADDRESS(SL2312_GPIO_BASE))
++
++/* define GPIO pin for MDC/MDIO */
++
++// for gemini ASIC
++#ifdef CONFIG_SL3516_ASIC
++#define H_MDC_PIN           22
++#define H_MDIO_PIN          21
++#define G_MDC_PIN           22
++#define G_MDIO_PIN          21
++#else
++#define H_MDC_PIN           3
++#define H_MDIO_PIN          2
++#define G_MDC_PIN           0
++#define G_MDIO_PIN          1
++#endif
++
++//#define GPIO_MDC             0x80000000
++//#define GPIO_MDIO            0x00400000
++
++static unsigned int GPIO_MDC = 0;
++static unsigned int GPIO_MDIO = 0;
++static unsigned int GPIO_MDC_PIN = 0;
++static unsigned int GPIO_MDIO_PIN = 0;
++
++// For PHY test definition!!
++#define LPC_EECK              0x02
++#define LPC_EDIO              0x04
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR         IO_ADDRESS(IT8712_IO_BASE)
++#define inb_gpio(x)           inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++/***********************/
++/*    MDC : GPIO[31]   */
++/*    MDIO: GPIO[22]   */
++/***********************/
++
++/***************************************************
++* All the commands should have the frame structure:
++*<PRE><ST><OP><PHYAD><REGAD><TA><DATA><IDLE>
++****************************************************/
++
++/*****************************************************************
++* Inject a bit to NWay register through CSR9_MDC,MDIO
++*******************************************************************/
++void mii_serial_write(char bit_MDO) // write data into mii PHY
++{
++#if 0 //def CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (LPC_EECK|LPC_EDIO) ;                         // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_MDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= LPC_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(LPC_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++    unsigned int addr;
++    unsigned int value;
++
++    addr = GPIO_BASE_ADDR + GPIO_PIN_DIR;
++    value = readl(addr) | GPIO_MDC | GPIO_MDIO; /* set MDC/MDIO Pin to output */
++    writel(value,addr);
++    if(bit_MDO)
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDIO,addr); /* set MDIO to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++    else
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDIO,addr); /* set MDIO to 0 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++
++#endif
++}
++
++/**********************************************************************
++* read a bit from NWay register through CSR9_MDC,MDIO
++***********************************************************************/
++unsigned int mii_serial_read(void) // read data from mii PHY
++{
++#if 0 //def CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(LPC_EDIO) ;         // Set EDIO input
++      iomode |= (LPC_EECK) ;          // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++
++#else
++    unsigned int *addr;
++    unsigned int value;
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_PIN_DIR);
++    value = readl(addr) & ~GPIO_MDIO; //0xffbfffff;   /* set MDC to output and MDIO to input */
++    writel(value,addr);
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_SET);
++    writel(GPIO_MDC,addr); /* set MDC to 1 */
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++    writel(GPIO_MDC,addr); /* set MDC to 0 */
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_IN);
++    value = readl(addr);
++    value = (value & (1<<GPIO_MDIO_PIN)) >> GPIO_MDIO_PIN;
++    return(value);
++
++#endif
++}
++
++/***************************************
++* preamble + ST
++***************************************/
++void mii_pre_st(void)
++{
++    unsigned char i;
++
++    for(i=0;i<32;i++) // PREAMBLE
++        mii_serial_write(1);
++    mii_serial_write(0); // ST
++    mii_serial_write(1);
++}
++
++
++/******************************************
++* Read MII register
++* phyad -> physical address
++* regad -> register address
++***************************************** */
++unsigned int mii_read(unsigned char phyad,unsigned char regad)
++{
++    unsigned int i,value;
++    unsigned int bit;
++
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(1); // OP
++    mii_serial_write(0);
++
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    mii_serial_read(); // TA_Z
++//    if((bit=mii_serial_read()) !=0 ) // TA_0
++//    {
++//        return(0);
++//    }
++    value=0;
++    for (i=0;i<16;i++) { // READ DATA
++        bit=mii_serial_read();
++        value += (bit<<(15-i)) ;
++    }
++
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++//printk("%s: phy_addr=%x reg_addr=%x value=%x \n",__func__,phyad,regad,value);
++    return(value);
++}
++
++/******************************************
++* Write MII register
++* phyad -> physical address
++* regad -> register address
++* value -> value to be write
++***************************************** */
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value)
++{
++    unsigned int i;
++    char bit;
++
++printk("%s: phy_addr=%x reg_addr=%x value=%x \n",__func__,phyad,regad,value);
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(0); // OP
++    mii_serial_write(1);
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(1); // TA_1
++    mii_serial_write(0); // TA_0
++
++    for (i=0;i<16;i++) { // OUT DATA
++        bit= ((value>>(15-i)) & 0x01) ? 1 : 0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++}
++
++
++
++
++
++
++
++
++
++/*                            NOTES
++ *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
++ *
++ *               Start  OP        *
++ *     Function   Bit  Code  Address**  Data     Description
++ *     -------------------------------------------------------------------
++ *     READ        1    10   A7 - A0             Reads data stored in memory,
++ *                                               starting at specified address
++ *     EWEN        1    00   11XXXXXX            Write enable must precede
++ *                                               all programming modes
++ *     ERASE       1    11   A7 - A0             Erase register A7A6A5A4A3A2A1A0
++ *     WRITE       1    01   A7 - A0   D15 - D0  Writes register
++ *     ERAL        1    00   10XXXXXX            Erase all registers
++ *     WRAL        1    00   01XXXXXX  D15 - D0  Writes to all registers
++ *     EWDS        1    00   00XXXXXX            Disables all programming
++ *                                               instructions
++ *    *Note: A value of X for address is a don't care condition.
++ *    **Note: There are 8 address bits for the 93C56/66 chips unlike
++ *          the 93C46/26/06 chips which have 6 address bits.
++ *
++ *   The 93Cx6 has a four wire interface: clock, chip select, data in, and
++ *   data out.While the ADM6996 uning three interface: clock, chip select,and data line.
++ *   The input and output are the same pin. ADM6996 can only recognize the write cmd.
++ *   In order to perform above functions, you need
++ *   1. to enable the chip select .
++ *   2. send one clock of dummy clock
++ *   3. send start bit and opcode
++ *   4. send 8 bits address and 16 bits data
++ *   5. to disable the chip select.
++ *                                                    Jason Lee 2003/07/30
++ */
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_EECS          0x00400000         /*   EECS: GPIO[22]   */
++//#define GPIO_MOSI        0x20000000         /*   EEDO: GPIO[29]   send to 6996*/
++#define GPIO_MISO          0x40000000         /*   EEDI: GPIO[30]   receive from 6996*/
++#define GPIO_EECK          0x80000000         /*   EECK: GPIO[31]   */
++
++#define ADM_EECS              0x01
++#define ADM_EECK              0x02
++#define ADM_EDIO              0x04
++/*************************************************************
++* SPI protocol for ADM6996 control
++**************************************************************/
++#define SPI_OP_LEN         0x03               // the length of start bit and opcode
++#define SPI_OPWRITE        0X05               // write
++#define SPI_OPREAD         0X06               // read
++#define SPI_OPERASE        0X07               // erase
++#define SPI_OPWTEN         0X04               // write enable
++#define SPI_OPWTDIS        0X04               // write disable
++#define SPI_OPERSALL       0X04               // erase all
++#define SPI_OPWTALL        0X04               // write all
++
++#define SPI_ADD_LEN        8                  // bits of Address
++#define SPI_DAT_LEN        16                 // bits of Data
++#define ADM6996_PORT_NO            6                  // the port number of ADM6996
++#define ADM6999_PORT_NO            9                  // the port number of ADM6999
++#ifdef CONFIG_ADM_6996
++      #define ADM699X_PORT_NO         ADM6996_PORT_NO
++#endif
++#ifdef CONFIG_ADM_6999
++      #define ADM699X_PORT_NO         ADM6999_PORT_NO
++#endif
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR                 IO_ADDRESS(IT8712_IO_BASE)
++
++extern int it8712_exist;
++
++#define inb_gpio(x)                   inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++/****************************************/
++/*    Function Declare                */
++/****************************************/
++/*
++void SPI_write(unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char table,unsigned char addr);
++void SPI_write_bit(char bit_EEDO);
++unsigned int SPI_read_bit(void);
++void SPI_default(void);
++void SPI_reset(unsigned char rstype,unsigned char port_cnt);
++void SPI_pre_st(void);
++void SPI_CS_enable(unsigned char enable);
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask);
++void SPI_Set_tag(unsigned int port,unsigned tag);
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask);
++void SPI_mac_lock(unsigned int port, unsigned char lock);
++void SPI_get_port_state(unsigned int port);
++void SPI_port_enable(unsigned int port,unsigned char enable);
++
++void SPI_get_status(unsigned int port);
++*/
++
++struct PORT_CONFIG
++{
++      unsigned char auto_negotiation; // 0:Disable    1:Enable
++      unsigned char speed;            // 0:10M        1:100M
++      unsigned char duplex;           // 0:Half       1:Full duplex
++      unsigned char Tag;              // 0:Untag      1:Tag
++      unsigned char port_disable;     // 0:port enable        1:disable
++      unsigned char pvid;             // port VLAN ID 0001
++      unsigned char mdix;             // Crossover judgement. 0:Disable 1:Enable
++      unsigned char mac_lock;         // MAC address Lock 0:Disable 1:Enable
++};
++
++struct PORT_STATUS
++{
++      unsigned char link;             // 0:not link   1:link established
++      unsigned char speed;            // 0:10M        1:100M
++      unsigned char duplex;           // 0:Half       1:Full duplex
++      unsigned char flow_ctl;         // 0:flow control disable 1:enable
++      unsigned char mac_lock;         // MAC address Lock 0:Disable 1:Enable
++      unsigned char port_disable;     // 0:port enable        1:disable
++
++      // Serial Management
++      unsigned long rx_pac_count;             //receive packet count
++      unsigned long rx_pac_byte;              //receive packet byte count
++      unsigned long tx_pac_count;             //transmit packet count
++      unsigned long tx_pac_byte;              //transmit packet byte count
++      unsigned long collision_count;          //error count
++      unsigned long error_count ;
++
++      unsigned long rx_pac_count_overflow;            //overflow flag
++      unsigned long rx_pac_byte_overflow;
++      unsigned long tx_pac_count_overflow;
++      unsigned long tx_pac_byte_overflow;
++      unsigned long collision_count_overflow;
++      unsigned long error_count_overflow;
++};
++
++struct PORT_CONFIG port_config[ADM699X_PORT_NO];      // 0~3:LAN , 4:WAN , 5:MII
++static struct PORT_STATUS port_state[ADM699X_PORT_NO];
++
++/******************************************
++* SPI_write
++* addr -> Write Address
++* value -> value to be write
++***************************************** */
++void SPI_write(unsigned char addr,unsigned int value)
++{
++      int     i;
++      char    bit;
++#ifdef CONFIG_IT8712_GPIO
++      char    status;
++#else
++    int     ad1;
++#endif
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++      SPI_CS_enable(1);
++
++      SPI_write_bit(0);       //dummy clock
++
++      //send write command (0x05)
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (SPI_OPWRITE>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 16 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = (value>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      SPI_CS_enable(0);       // CS low
++
++      for(i=0;i<0xFFF;i++) ;
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++}
++
++
++/************************************
++* SPI_write_bit
++* bit_EEDO -> 1 or 0 to be written
++************************************/
++void SPI_write_bit(char bit_EEDO)
++{
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (ADM_EECK|ADM_EDIO|ADM_EECS) ;                                // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_EEDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= ADM_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(ADM_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECK |GPIO_MISO ;   /* set EECK/MISO Pin to output */
++      writel(value,addr);
++      if(bit_EEDO)
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_MISO,addr); /* set MISO to 1 */
++              writel(GPIO_EECK,addr); /* set EECK to 1 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_MISO,addr); /* set MISO to 0 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++
++      return ;
++#endif
++}
++
++/**********************************************************************
++* read a bit from ADM6996 register
++***********************************************************************/
++unsigned int SPI_read_bit(void) // read data from
++{
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(ADM_EDIO) ;         // Set EDIO input
++      iomode |= (ADM_EECS|ADM_EECK) ;         // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++#else
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) & (~GPIO_MISO);   // set EECK to output and MISO to input
++      writel(value,addr);
++
++      addr =(GPIO_BASE_ADDR + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); // set EECK to 1
++      addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); // set EECK to 0
++
++      addr = (GPIO_BASE_ADDR + GPIO_DATA_IN);
++      value = readl(addr) ;
++      value = value >> 30;
++      return value ;
++#endif
++}
++
++/******************************************
++* SPI_default
++* EEPROM content default value
++*******************************************/
++void SPI_default(void)
++{
++      int i;
++#ifdef CONFIG_ADM_6999
++      SPI_write(0x11,0xFF30);
++      for(i=1;i<8;i++)
++              SPI_write(i,0x840F);
++
++      SPI_write(0x08,0x880F);                 //port 8 Untag, PVID=2
++      SPI_write(0x09,0x881D);                 //port 9 Tag, PVID=2 ,10M
++      SPI_write(0x14,0x017F);                 //Group 0~6,8 as VLAN 1
++      SPI_write(0x15,0x0180);                 //Group 7,8 as VLAN 2
++#endif
++
++#ifdef CONFIG_ADM_6996
++      SPI_write(0x11,0xFF30);
++      SPI_write(0x01,0x840F);                 //port 0~3 Untag ,PVID=1 ,100M ,duplex
++      SPI_write(0x03,0x840F);
++      SPI_write(0x05,0x840F);
++      SPI_write(0x07,0x840F);
++      SPI_write(0x08,0x880F);                 //port 4 Untag, PVID=2
++      SPI_write(0x09,0x881D);                 //port 5 Tag, PVID=2 ,10M
++      SPI_write(0x14,0x0155);                 //Group 0~3,5 as VLAN 1
++      SPI_write(0x15,0x0180);                 //Group 4,5 as VLAN 2
++
++#endif
++
++      for(i=0x16;i<=0x22;i++)
++              SPI_write((unsigned char)i,0x0000);             // clean VLAN¡@map 3~15
++
++      for (i=0;i<NUM_VLAN_IF;i++)                             // Set VLAN ID map 1,2
++              SPI_Set_PVID( VLAN_conf[i].vid,  VLAN_conf[i].portmap);
++
++      for(i=0;i<ADM699X_PORT_NO;i++)                          // reset count
++              SPI_reset(0,i);
++}
++
++/*************************************************
++* SPI_reset
++* rstype -> reset type
++*         0:reset all count for 'port_cnt' port
++*         1:reset specified count 'port_cnt'
++* port_cnt   ->  port number or counter index
++***************************************************/
++void SPI_reset(unsigned char rstype,unsigned char port_cnt)
++{
++
++      int i;
++#ifdef CONFIG_IT8712_GPIO
++    char status;
++#else
++      int ad1;
++#endif
++      char bit;
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      SPI_CS_enable(0);       // CS low
++
++      SPI_pre_st(); // PRE+ST
++      SPI_write_bit(0); // OP
++      SPI_write_bit(1);
++
++      SPI_write_bit(1);               // Table select, must be 1 -> reset Counter
++
++      SPI_write_bit(0);               // Device Address
++      SPI_write_bit(0);
++
++      rstype &= 0x01;
++      SPI_write_bit(rstype);          // Reset type 0:clear dedicate port's all counters 1:clear dedicate counter
++
++      for (i=5;i>=0;i--)              // port or cnt index
++      {
++              bit = port_cnt >> i ;
++              bit &= 0x01 ;
++              SPI_write_bit(bit);
++      }
++
++      SPI_write_bit(0);               // dumy clock
++      SPI_write_bit(0);               // dumy clock
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++}
++
++/*****************************************************
++* SPI_pre_st
++* preambler: 32 bits '1'   start bit: '01'
++*****************************************************/
++void SPI_pre_st(void)
++{
++      int i;
++
++      for(i=0;i<32;i++) // PREAMBLE
++              SPI_write_bit(1);
++      SPI_write_bit(0); // ST
++      SPI_write_bit(1);
++}
++
++
++/***********************************************************
++* SPI_CS_enable
++* before access ,you have to enable Chip Select. (pull high)
++* When fisish, you should pull low !!
++*************************************************************/
++void SPI_CS_enable(unsigned char enable)
++{
++#ifdef CONFIG_IT8712_GPIO
++
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (ADM_EECK|ADM_EDIO|ADM_EECS) ;                                // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++
++      status = inb_gpio( LPC_GPIO_SET);
++      if(enable)
++              status |= ADM_EECS ;            //EECS high
++      else
++              status &= ~(ADM_EECS) ; //EECS low
++
++      outb_gpio(LPC_GPIO_SET, status);
++
++
++      status |= ADM_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(ADM_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECS |GPIO_EECK;   /* set EECS/EECK Pin to output */
++      writel(value,addr);
++
++      if(enable)
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECS,addr); /* set EECS to 1 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECS,addr); /* set EECS to 0 */
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */     // at least one clock after CS low
++              addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */
++      }
++#endif
++}
++
++/*********************************************************
++* SPI_Set_VLAN: group ports as VLAN
++* LAN  -> VLAN number : 0~16
++* port_mask -> ports which would group as LAN
++*            ex. 0x03 = 0000 0011
++*                     port 0 and port 1
++*********************************************************/
++void SPI_Set_VLAN(unsigned char LAN,unsigned int port_mask)
++{
++      unsigned int i,value=0;
++      unsigned reg_add = 0x13 + LAN ;
++
++      for(i=0;i<ADM6996_PORT_NO;i++)
++      {       if(port_mask&0x01)
++              {
++                      switch(i)
++                      {
++                              case 0: value|=0x0001;  break;  //port0:bit[0]
++                              case 1: value|=0x0004;  break;  //port1:bit[2]
++                              case 2: value|=0x0010;  break;  //port2:bit[4]
++                              case 3: value|=0x0040;  break;  //port3:bit[6]
++                              case 4: value|=0x0080;  break;  //port4:bit[7]
++                              case 5: value|=0x0100;  break;  //port5:bit[8]
++                      }
++              }
++              port_mask >>= 1;
++      }
++
++      SPI_write(reg_add,value);
++}
++
++
++/*******************************************
++* SPI_Set_tag
++* port -> port number to set tag or untag
++* tag  -> 0/set untag,  1/set tag
++* In general, tag is for MII port. LAN and
++* WAN port is configed as untag!!
++********************************************/
++void SPI_Set_tag(unsigned int port,unsigned tag)
++{
++      unsigned int regadd,value;
++
++      // mapping port's register !! (0,1,2,3,4,5) ==> (1,3,5,7,8,9)
++      if(port<=3)
++              regadd=2*port+1;
++      else if(port==4) regadd = 8 ;
++      else regadd = 9 ;
++
++
++      value = SPI_read(0,regadd);             //read original setting
++
++      if(tag)
++              value |= 0x0010 ;               // set tag
++      else
++              value &= 0xFFEF ;               // set untag
++
++      SPI_write(regadd,value);                // write back!!
++}
++
++/************************************************
++* SPI_Set_PVID
++* PVID -> PVID number :
++* port_mask -> ports which would group as LAN
++*            ex. 0x0F = 0000 1111 ==> port 0~3
++************************************************/
++void SPI_Set_PVID(unsigned int PVID,unsigned int port_mask)
++{
++      unsigned int i,value=0;
++
++      PVID &= 0x000F ;
++
++      for(i=0;i<ADM699X_PORT_NO;i++)
++      {       if(port_mask&0x01)
++              {
++#ifdef CONFIG_ADM_6996
++                      switch(i)
++                      {
++                              case 0:
++                                      value = SPI_read(0,0x01);       // read original value
++                                      value &= 0xC3FF ;                       //set PVIC column as 0 first
++                                      value |= PVID << 10 ;           //Set PVID column as PVID
++                                      SPI_write(0x01,value);          //write back
++                                      break;
++                              case 1:
++                                      value = SPI_read(0,0x03);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x03,value);
++                                      break;
++                              case 2:
++                                      value = SPI_read(0,0x05);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x05,value);
++                                      break;
++                              case 3:
++                                      value = SPI_read(0,0x07);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x07,value);
++                                      break;
++                              case 4:
++                                      value = SPI_read(0,0x08);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x08,value);
++                                      break;
++                              case 5:
++                                      value = SPI_read(0,0x09);
++                                      value &= 0xC3FF ;
++                                      value |= PVID << 10 ;
++                                      SPI_write(0x09,value);
++                                      break;
++                      }
++#endif
++#ifdef CONFIG_ADM_6999
++                      value = SPI_read(0,(unsigned char)i+1);
++                      value &= 0xC3FF ;
++                      value |= PVID << 10 ;
++                      SPI_write((unsigned char)i+1,value);
++#endif
++              }
++              port_mask >>= 1;
++      }
++}
++
++
++/************************************************
++* SPI_get_PVID
++* port -> which ports to VID
++************************************************/
++unsigned int SPI_Get_PVID(unsigned int port)
++{
++      unsigned int value=0;
++
++      if (port>=ADM6996_PORT_NO)
++              return 0;
++
++      switch(port)
++      {
++              case 0:
++                      value = SPI_read(0,0x01);       // read original value
++                      value &= 0x3C00 ;               // get VID
++                      value = value >> 10 ;           // Shift
++                      break;
++              case 1:
++                      value = SPI_read(0,0x03);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 2:
++                      value = SPI_read(0,0x05);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 3:
++                      value = SPI_read(0,0x07);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 4:
++                      value = SPI_read(0,0x08);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++              case 5:
++                      value = SPI_read(0,0x09);
++                      value &= 0x3C00 ;
++                      value = value >> 10 ;
++                      break;
++      }
++      return value ;
++}
++
++
++/**********************************************
++* SPI_mac_clone
++* port -> the port which will lock or unlock
++* lock -> 0/the port will be unlock
++*       1/the port will be locked
++**********************************************/
++void SPI_mac_lock(unsigned int port, unsigned char lock)
++{
++      unsigned int i,value=0;
++
++      value = SPI_read(0,0x12);               // read original
++
++      for(i=0;i<ADM6996_PORT_NO;i++)
++      {       if(lock)                                // lock port
++              {
++                      switch(port)
++                      {
++                              case 0: value|=0x0001;  break;  //port0:bit[0]
++                              case 1: value|=0x0004;  break;  //port1:bit[2]
++                              case 2: value|=0x0010;  break;  //port2:bit[4]
++                              case 3: value|=0x0040;  break;  //port3:bit[6]
++                              case 4: value|=0x0080;  break;  //port4:bit[7]
++                              case 5: value|=0x0100;  break;  //port5:bit[8]
++                      }
++              }
++              else
++              {
++                      switch(i)                       // unlock port
++                      {
++                              case 0: value&=0xFFFE;  break;
++                              case 1: value&=0xFFFB;  break;
++                              case 2: value&=0xFFEF;  break;
++                              case 3: value&=0xFFBF;  break;
++                              case 4: value&=0xFF7F;  break;
++                              case 5: value&=0xFEFF;  break;
++                      }
++              }
++      }
++
++      SPI_write(0x12,value);
++}
++
++
++/***************************************************
++* SPI_learn_pause
++* pause = 01-80-c2-00-00-01
++* DA=distination address
++* forward -> 0: if DA == pause then drop and stop mac learning
++*          1: if DA == pause ,then forward it
++***************************************************/
++void SPI_pause_cmd_forward(unsigned char forward)
++{
++      unsigned int value=0;
++
++      value = SPI_read(0,0x2C);               // read original setting
++      if(forward)
++              value |= 0x2000;                // set bit[13] '1'
++      else
++              value &= 0xDFFF;                // set bit[13] '0'
++
++      SPI_write(0x2C,value);
++
++}
++
++
++/************************************************
++* SPI_read
++* table -> which table to be read: 1/count  0/EEPROM
++* addr  -> Address to be read
++* return : Value of the register
++*************************************************/
++unsigned int SPI_read(unsigned char table,unsigned char addr)
++{
++      int i ;
++      unsigned int value=0;
++      unsigned int bit;
++#ifdef CONFIG_IT8712_GPIO
++      unsigned char status;
++#else
++    unsigned int ad1;
++#endif
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      SPI_CS_enable(0);
++
++      SPI_pre_st(); // PRE+ST
++      SPI_write_bit(1); // OPCODE '10' for read
++      SPI_write_bit(0);
++
++      (table==1) ? SPI_write_bit(1) : SPI_write_bit(0) ;      // table select
++
++      SPI_write_bit(0);               // Device Address
++      SPI_write_bit(0);
++
++
++      // send 7 bits address to be read
++      for (i=6;i>=0;i--) {
++              bit= ((addr>>i) & 0x01) ? 1 :0 ;
++              SPI_write_bit(bit);
++      }
++
++
++      // turn around
++      SPI_read_bit(); // TA_Z
++
++      value=0;
++      for (i=31;i>=0;i--) { // READ DATA
++              bit=SPI_read_bit();
++              value |= bit << i ;
++      }
++
++      SPI_read_bit(); // dumy clock
++      SPI_read_bit(); // dumy clock
++
++      if(!table)                                      // EEPROM, only fetch 16 bits data
++      {
++          if(addr&0x01)                               // odd number content (register,register-1)
++                  value >>= 16 ;                      // so we remove the rear 16bits
++          else                                        // even number content (register+1,register),
++                  value &= 0x0000FFFF ;               // so we keep the rear 16 bits
++      }
++
++
++      SPI_CS_enable(0);
++
++#ifdef CONFIG_IT8712_GPIO
++      status = inb_gpio(LPC_GPIO_SET);
++      status &= ~(ADM_EDIO) ;         //EDIO low
++      outb_gpio(LPC_GPIO_SET, status);
++#else
++      ad1 = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++      writel(GPIO_MISO,ad1); /* set MISO to 0 */
++#endif
++
++      return(value);
++
++}
++
++
++
++/**************************************************
++* SPI_port_en
++* port -> Number of port to config
++* enable -> 1/ enable this port
++*         0/ disable this port
++**************************************************/
++void SPI_port_enable(unsigned int port,unsigned char enable)
++{
++      unsigned int reg_val ;
++      unsigned char reg_add ;
++
++      if(port<=3)
++              reg_add=2*port+1;
++      else if(port==4) reg_add = 8 ;
++      else reg_add = 9 ;
++
++      reg_val = SPI_read(0,reg_add);
++      if(enable)
++      {
++              reg_val &= 0xFFDF ;
++              SPI_write(reg_add,reg_val);
++      }
++      else
++      {
++              reg_val |= 0x0020 ;
++              SPI_write(reg_add,reg_val);
++      }
++}
++
++/********************************************************
++* get port status
++* port -> specify the port number to get configuration
++*********************************************************/
++void SPI_get_status(unsigned int port)
++{
++/*    unsigned int reg_val,add_offset[6];
++      struct PORT_STATUS *status;
++      status = &port_state[port];
++
++      if(port>(ADM6996_PORT_NO-1))
++              return ;
++
++      // Link estabilish , speed, deplex, flow control ?
++      if(port < 5 )
++      {
++              reg_val = SPI_read(1, 1) ;
++              if(port < 4)
++                      reg_val >>= port*8 ;
++              else
++                      reg_val >>=28 ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000004 ;
++              status->flow_ctl = reg_val & 0x00000008 ;
++      }
++      else if(port ==5 )
++      {
++              reg_val = SPI_read(1, 2) ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000008 ;
++              status->flow_ctl = reg_val & 0x00000010 ;
++      }
++
++      //   Mac Lock ?
++      reg_val = SPI_read(0,0x12);
++      switch(port)
++      {
++              case 0: status->mac_lock = reg_val & 0x00000001;
++              case 1: status->mac_lock = reg_val & 0x00000004;
++              case 2: status->mac_lock = reg_val & 0x00000010;
++              case 3: status->mac_lock = reg_val & 0x00000040;
++              case 4: status->mac_lock = reg_val & 0x00000080;
++              case 5: status->mac_lock = reg_val & 0x00000100;
++      }
++
++      // port enable ?
++      add_offset[0] = 0x01 ;          add_offset[1] = 0x03 ;
++      add_offset[2] = 0x05 ;          add_offset[3] = 0x07 ;
++      add_offset[4] = 0x08 ;          add_offset[5] = 0x09 ;
++      reg_val = SPI_read(0,add_offset[port]);
++      status->port_disable = reg_val & 0x0020;
++
++
++      //  Packet Count ...
++      add_offset[0] = 0x04 ;          add_offset[1] = 0x06 ;
++      add_offset[2] = 0x08 ;          add_offset[3] = 0x0a ;
++      add_offset[4] = 0x0b ;          add_offset[5] = 0x0c ;
++
++      reg_val = SPI_read(1,add_offset[port]);
++      status->rx_pac_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+9);
++      status->rx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+18);
++      status->tx_pac_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+27);
++      status->tx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+36);
++      status->collision_count = reg_val ;
++      reg_val = SPI_read(1,add_offset[port]+45);
++      status->error_count = reg_val ;
++      reg_val = SPI_read(1, 0x3A);
++      switch(port)
++      {
++              case 0: status->rx_pac_count_overflow = reg_val & 0x00000001;
++                      status->rx_pac_byte_overflow = reg_val & 0x00000200 ;
++              case 1: status->rx_pac_count_overflow = reg_val & 0x00000004;
++                      status->rx_pac_byte_overflow = reg_val & 0x00000800 ;
++              case 2: status->rx_pac_count_overflow = reg_val & 0x00000010;
++                      status->rx_pac_byte_overflow = reg_val & 0x00002000 ;
++              case 3: status->rx_pac_count_overflow = reg_val & 0x00000040;;
++                      status->rx_pac_byte_overflow = reg_val & 0x00008000 ;
++              case 4: status->rx_pac_count_overflow = reg_val & 0x00000080;
++                      status->rx_pac_byte_overflow = reg_val & 0x00010000 ;
++              case 5: status->rx_pac_count_overflow = reg_val & 0x00000100;
++                      status->rx_pac_byte_overflow = reg_val & 0x00020000 ;
++      }
++
++      reg_val = SPI_read(1, 0x3B);
++      switch(port)
++      {
++              case 0: status->tx_pac_count_overflow = reg_val & 0x00000001;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00000200 ;
++              case 1: status->tx_pac_count_overflow  = reg_val & 0x00000004;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00000800 ;
++              case 2: status->tx_pac_count_overflow  = reg_val & 0x00000010;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00002000 ;
++              case 3: status->tx_pac_count_overflow  = reg_val & 0x00000040;;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00008000 ;
++              case 4: status->tx_pac_count_overflow  = reg_val & 0x00000080;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00010000 ;
++              case 5: status->tx_pac_count_overflow  = reg_val & 0x00000100;
++                      status->tx_pac_byte_overflow  = reg_val & 0x00020000 ;
++      }
++*/
++
++      unsigned int reg_val;
++      struct PORT_STATUS *status;
++      status = &port_state[port];
++
++      if(port>=ADM6999_PORT_NO)
++              return ;
++
++      // Link estabilish , speed, deplex, flow control ?
++      if(port < ADM6999_PORT_NO-1 )
++      {
++              reg_val = SPI_read(1, 0x01) ;
++              reg_val = reg_val >> port*4 ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000004 ;
++              status->flow_ctl = reg_val & 0x00000008 ;
++      }
++      else if(port == (ADM6999_PORT_NO-1) )
++      {
++              reg_val = SPI_read(1, 0x02) ;
++              status->link = reg_val & 0x00000001 ;
++              status->speed = reg_val  & 0x00000002 ;
++              status->duplex = reg_val & 0x00000008 ;
++              status->flow_ctl = reg_val & 0x00000010 ;
++      }
++
++      // Mac Lock ?
++      reg_val = SPI_read(0,0x12);
++      reg_val = reg_val >> port ;
++      reg_val = reg_val & 0x01 ;
++      status->mac_lock = reg_val ? 0x01:0x00 ;
++
++      // port enable ?
++      reg_val = SPI_read(0,(unsigned char)port+1);
++      status->port_disable = reg_val & 0x0020;
++
++      //  Packet Count ...
++      reg_val = SPI_read(1,(unsigned char)port+0x04);
++      status->rx_pac_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x0D);
++      status->rx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x16);
++      status->tx_pac_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x1F);
++      status->tx_pac_byte = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x28);
++      status->collision_count = reg_val ;
++      reg_val = SPI_read(1,(unsigned char)port+0x31);
++      status->error_count = reg_val ;
++      reg_val = SPI_read(1, 0x3A);
++      reg_val = reg_val >> port ;
++      status->rx_pac_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->rx_pac_byte_overflow = reg_val & 0x00000001 ;
++
++      reg_val = SPI_read(1, 0x3B);
++      reg_val = reg_val >> port ;
++      status->tx_pac_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->tx_pac_byte_overflow  = reg_val & 0x00000001 ;
++
++      reg_val = SPI_read(1, 0x3C);
++      reg_val = reg_val >> port ;
++      status->collision_count_overflow = reg_val & 0x00000001;
++      reg_val = reg_val >> 0x09 ;
++      status->error_count_overflow  = reg_val & 0x00000001 ;
++
++}
++
++unsigned int SPI_get_identifier(void)
++{
++      unsigned int flag=0;
++
++#ifdef CONFIG_IT8712_GPIO
++
++      if (!it8712_exist) {
++              return -ENODEV;
++      }
++      printk("it8712_gpio init\n");
++
++      /* initialize registers */
++      // switch all multi-function pins to GPIO
++      LPCSetConfig(LDN_GPIO, 0x28, 0xff);
++
++      // set simple I/O base address
++      LPCSetConfig(LDN_GPIO, 0x62, IT8712_GPIO_BASE >> 8);
++      LPCSetConfig(LDN_GPIO, 0x63, (unsigned char) IT8712_GPIO_BASE >> 8);
++
++      // select GPIO to simple I/O
++      LPCSetConfig(LDN_GPIO, 0xc3, 0xff);
++
++      // enable internal pull-up
++      LPCSetConfig(LDN_GPIO, 0xbb, 0xff);
++
++#endif
++
++      flag = SPI_read(1,0x00);
++      printk("Get ADM identifier %6x\n",flag);
++      if ((flag & 0xFFFF0) == 0x21120) {
++              printk("ADM699X Found\n");
++              return 1;
++      }
++      else {
++              printk("ADM699X not Found\n");
++              return 0;
++      }
++}
++
+--- /dev/null
++++ b/drivers/net/sl351x_crc16.c
+@@ -0,0 +1,93 @@
++/****************************************************************************
++* Name                        : sl351x_crc16.c
++* Description :
++*             Implement CRC16
++*             refer to RFC1662
++* History
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     09/14/2005      Gary Chen       Create
++*
++****************************************************************************/
++
++#define INITFCS16             0xffff  /* Initial FCS value */
++#define GOODFCS16             0xf0b8  /* Good final FCS value */
++#define SWAP_WORD(x)  (unsigned short)((((unsigned short)x & 0x00FF) << 8) |  \
++                                                                               (((unsigned short)x & 0xFF00) >> 8))
++
++/*----------------------------------------------------------------------
++*     x**0 + x**5 + x**12 + x**16
++*----------------------------------------------------------------------*/
++static const unsigned short crc16_tbl[256] = {
++      0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++      0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++      0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++      0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++      0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++      0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++      0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++      0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++      0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++      0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++      0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++      0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++      0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++      0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++      0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++      0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++      0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++      0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++      0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++      0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++      0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++      0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++      0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++      0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++      0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++      0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++      0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++      0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++      0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++      0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++      0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++      0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++/*----------------------------------------------------------------------
++* hash_crc16
++*----------------------------------------------------------------------*/
++unsigned short hash_crc16(unsigned short crc, unsigned char *datap, unsigned long len)
++{
++    while (len--)
++    {
++        crc = (crc >> 8) ^ crc16_tbl[(crc ^ (*datap++)) & 0xff];
++    }
++
++    return (crc);
++
++}
++
++/*----------------------------------------------------------------------
++* hash_check_crc16
++*----------------------------------------------------------------------*/
++unsigned long hash_check_crc16(unsigned char *datap, unsigned long len)
++{
++    unsigned short crc;
++
++    crc = hash_crc16(INITFCS16, datap, len );
++    return (crc == GOODFCS16) ?  0 : 1;
++}
++
++/*----------------------------------------------------------------------
++* hash_gen_crc16
++*----------------------------------------------------------------------*/
++unsigned short hash_gen_crc16(unsigned char *datap, unsigned long len)
++{
++    unsigned short crc;
++
++    crc = hash_crc16(INITFCS16, datap, len);
++    crc ^= 0xffff;
++
++    return(SWAP_WORD(crc));
++}
+--- /dev/null
++++ b/drivers/net/sl351x_gmac.c
+@@ -0,0 +1,5622 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_gmac.c
++* Description :
++*             Ethernet device driver for Storlink SL351x FPGA
++*
++* History
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     08/22/2005      Gary Chen       Create and implement
++*   27/10/2005  CH Hsu      Porting to Linux
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++
++#include <linux/mtd/kvctl.h>
++
++#define        MIDWAY
++#define        SL_LEPUS
++#define VITESSE_G5SWITCH      1
++
++#ifndef CONFIG_SL351x_RXTOE
++//#define CONFIG_SL351x_RXTOE 1
++#endif
++#undef CONFIG_SL351x_RXTOE
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++
++#ifdef CONFIG_SL351x_SYSCTL
++#include <linux/sysctl_storlink.h>
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++#include <asm/arch/sl351x_toe.h>
++#include <net/tcp.h>
++#include <linux/tcp.h>
++#include <linux/ip.h>
++#endif
++
++// #define SL351x_TEST_WORKAROUND
++#ifdef CONFIG_SL351x_NAT
++#define CONFIG_SL_NAPI                                        1
++#endif
++#define GMAX_TX_INTR_DISABLED                 1
++#define DO_HW_CHKSUM                                  1
++#define ENABLE_TSO                                            1
++#define GMAC_USE_TXQ0                                 1
++// #define NAT_WORKAROUND_BY_RESET_GMAC       1
++// #define HW_RXBUF_BY_KMALLOC                        1
++//#define _DUMP_TX_TCP_CONTENT        1
++#define       br_if_ioctl                                             1
++#define GMAC_LEN_1_2_ISSUE                            1
++
++#define GMAC_EXISTED_FLAG                     0x5566abcd
++#define CONFIG_MAC_NUM                                GMAC_NUM
++#define GMAC0_BASE                                    TOE_GMAC0_BASE
++#define GMAC1_BASE                                    TOE_GMAC1_BASE
++#define PAUSE_SET_HW_FREEQ                    (TOE_HW_FREEQ_DESC_NUM / 2)
++#define PAUSE_REL_HW_FREEQ                    ((TOE_HW_FREEQ_DESC_NUM / 2) + 10)
++#define DEFAULT_RXQ_MAX_CNT                   256
++#ifdef        L2_jumbo_frame
++#define TCPHDRLEN(tcp_hdr)  ((ntohs(*((__u16 *)tcp_hdr + 6)) >> 12) & 0x000F)
++#endif
++
++/* define chip information */
++#define DRV_NAME                                      "SL351x"
++#define DRV_VERSION                                   "0.1.4"
++#define SL351x_DRIVER_NAME            DRV_NAME " Giga Ethernet driver " DRV_VERSION
++
++#define toe_gmac_enable_interrupt(irq)        enable_irq(irq)
++#define toe_gmac_disable_interrupt(irq)       disable_irq(irq)
++
++#ifdef SL351x_GMAC_WORKAROUND
++#define GMAC_SHORT_FRAME_THRESHOLD            10
++static struct timer_list gmac_workround_timer_obj;
++void sl351x_poll_gmac_hanged_status(u32 data);
++#ifdef CONFIG_SL351x_NAT
++//#define IxscriptMate_1518                           1
++      void sl351x_nat_workaround_init(void);
++      #ifndef NAT_WORKAROUND_BY_RESET_GMAC
++              static void sl351x_nat_workaround_handler(void);
++      #endif
++#endif
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++      #define _DEBUG_PREFETCH_NUM     256
++static        int     _debug_prefetch_cnt;
++static        char _debug_prefetch_buf[_DEBUG_PREFETCH_NUM][4] __attribute__((aligned(4)));
++#endif
++/*************************************************************
++ *         Global Variable
++ *************************************************************/
++static int    gmac_initialized = 0;
++TOE_INFO_T toe_private_data;
++//static int          do_again = 0;
++spinlock_t gmac_fq_lock;
++unsigned int FLAG_SWITCH;
++
++static unsigned int           next_tick = 3 * HZ;
++static unsigned char          eth_mac[CONFIG_MAC_NUM][6]= {{0x00,0x11,0x11,0x87,0x87,0x87}, {0x00,0x22,0x22,0xab,0xab,0xab}};
++
++#undef CONFIG_SL351x_RXTOE
++extern NAT_CFG_T nat_cfg;
++
++/************************************************/
++/*                 function declare             */
++/************************************************/
++static int gmac_set_mac_address(struct net_device *dev, void *addr);
++static unsigned int gmac_get_phy_vendor(int phy_addr);
++static void gmac_set_phy_status(struct net_device *dev);
++void gmac_get_phy_status(struct net_device *dev);
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++static void gmac_tx_timeout(struct net_device *dev);
++static int gmac_phy_thread (void *data);
++struct net_device_stats * gmac_get_stats(struct net_device *dev);
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static void gmac_set_rx_mode(struct net_device *dev);
++static irqreturn_t toe_gmac_interrupt (int irq, void *dev_instance);
++static void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp);
++unsigned int mii_read(unsigned char phyad,unsigned char regad);
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value);
++void mac_init_drv(void);
++
++static void toe_init_free_queue(void);
++static void toe_init_swtx_queue(void);
++static void toe_init_default_queue(void);
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_init_interrupt_queue(void);
++#endif
++static void toe_init_interrupt_config(void);
++static void toe_gmac_sw_reset(void);
++static int toe_gmac_init_chip(struct net_device *dev);
++static void toe_gmac_enable_tx_rx(struct net_device* dev);
++static void toe_gmac_disable_tx_rx(struct net_device *dev);
++static void toe_gmac_hw_start(struct net_device *dev);
++static void toe_gmac_hw_stop(struct net_device *dev);
++static int toe_gmac_clear_counter(struct net_device *dev);
++static void toe_init_gmac(struct net_device *dev);
++static  void toe_gmac_tx_complete(GMAC_INFO_T *tp, unsigned int tx_qid, struct net_device *dev, int interrupt);
++#ifdef CONFIG_SL_NAPI
++static int gmac_rx_poll(struct net_device *dev, int *budget);
++// static void toe_gmac_disable_rx(struct net_device *dev);
++// static void toe_gmac_enable_rx(struct net_device *dev);
++#endif
++
++u32 mac_read_dma_reg(int mac, unsigned int offset);
++void mac_write_dma_reg(int mac, unsigned int offset, u32 data);
++void mac_stop_txdma(struct net_device *dev);
++void mac_get_sw_tx_weight(struct net_device *dev, char *weight);
++void mac_set_sw_tx_weight(struct net_device *dev, char *weight);
++void mac_get_hw_tx_weight(struct net_device *dev, char *weight);
++void mac_set_hw_tx_weight(struct net_device *dev, char *weight);
++static inline void toe_gmac_fill_free_q(void);
++
++#ifdef VITESSE_G5SWITCH
++extern int Get_Set_port_status(void);
++extern int SPI_default(void);
++extern unsigned int SPI_get_identifier(void);
++void gmac_get_switch_status(struct net_device *dev);
++unsigned int Giga_switch=0;
++unsigned int switch_port_no=0;
++unsigned int ever_dwon=0;
++#endif
++
++/************************************************/
++/*            GMAC function declare             */
++/************************************************/
++static int gmac_open (struct net_device *dev);
++static int gmac_close (struct net_device *dev);
++static void gmac_cleanup_module(void);
++static void gmac_get_mac_address(void);
++
++#ifdef CONFIG_SL351x_NAT
++static void toe_init_hwtx_queue(void);
++extern void sl351x_nat_init(void);
++extern void sl351x_nat_input(struct sk_buff *skb, int port, void *l3off, void *l4off);
++extern int sl351x_nat_output(struct sk_buff *skb, int port);
++extern int sl351x_nat_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++extern void set_toeq_hdr(struct toe_conn* connection, TOE_INFO_T* toe, struct net_device *dev);
++extern void sl351x_toe_init(void);
++extern void toe_gmac_handle_toeq(struct net_device *dev, GMAC_INFO_T* tp, __u32 status);
++extern struct toe_conn* init_toeq(int ipver, void* iph, struct tcphdr* tcp_hdr, TOE_INFO_T* toe, unsigned char* l2hdr);
++#endif
++
++int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++void mac_set_rule_enable_bit(int mac, int rule, int data);
++int mac_set_rule_action(int mac, int rule, int data);
++int mac_get_MRxCRx(int mac, int rule, int ctrlreg);
++void mac_set_MRxCRx(int mac, int rule, int ctrlreg, u32 data);
++
++/*----------------------------------------------------------------------
++*     Ethernet Driver init
++*----------------------------------------------------------------------*/
++
++static int __init gmac_init_module(void)
++{
++      GMAC_INFO_T             *tp;
++      struct net_device       *dev;
++      int             i,j;
++      unsigned int    chip_id;
++//    unsigned int chip_version;
++
++#ifdef CONFIG_SL3516_ASIC
++{
++    unsigned int    val;
++    /* set GMAC global register */
++    val = readl(GMAC_GLOBAL_BASE_ADDR+0x10);
++    val = val | 0x005f0000;
++    writel(val,GMAC_GLOBAL_BASE_ADDR+0x10);
++//    writel(0xb737b737,GMAC_GLOBAL_BASE_ADDR+0x1c); //For Socket Board
++    writel(0x77777777,GMAC_GLOBAL_BASE_ADDR+0x20);
++//    writel(0xa737b747,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++
++      //debug_Aaron
++    //writel(0xa7f0a7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++    writel(0xa7f0b7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For Mounting Board
++
++    writel(0x77777777,GMAC_GLOBAL_BASE_ADDR+0x24);
++      writel(0x09200030,GMAC_GLOBAL_BASE_ADDR+0x2C);
++      val = readl(GMAC_GLOBAL_BASE_ADDR+0x04);
++      if((val&(1<<20))==0){           // GMAC1 enable
++              val = readl(GMAC_GLOBAL_BASE_ADDR+0x30);
++              val = (val & 0xe7ffffff) | 0x08000000;
++              writel(val,GMAC_GLOBAL_BASE_ADDR+0x30);
++      }
++}
++#endif
++
++#ifdef VITESSE_G5SWITCH
++      Giga_switch = SPI_get_identifier();
++      if(Giga_switch)
++              switch_port_no = SPI_default();
++#endif
++
++      chip_id = readl(GMAC_GLOBAL_BASE_ADDR+0x0);
++      if (chip_id == 0x3512C1)
++      {
++              writel(0x5787a5f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For 3512 Switch Board
++              writel(0x55557777,GMAC_GLOBAL_BASE_ADDR+0x20);//For 3512 Switch Board
++      }
++//#endif
++
++      mac_init_drv();
++
++      printk (KERN_INFO SL351x_DRIVER_NAME " built at %s %s\n", __DATE__, __TIME__);
++
++//    init_waitqueue_entry(&wait, current);
++
++      // printk("GMAC Init......\n");
++
++      i = 0;
++      for(j = 0; i<CONFIG_MAC_NUM; j++)
++      {
++              i=j;
++              if(Giga_switch){                // if gswitch present, swap eth0/1
++                      if(j==0)
++                              i=1;
++                      else if(j==1)
++                              i=0;
++              }
++
++              tp = (GMAC_INFO_T *)&toe_private_data.gmac[i];
++              tp->dev = NULL;
++              if (tp->existed != GMAC_EXISTED_FLAG) continue;
++
++              dev = alloc_etherdev(0);
++              if (dev == NULL)
++              {
++                      printk (KERN_ERR "Can't allocate ethernet device #%d .\n",i);
++                      return -ENOMEM;
++              }
++
++              dev->priv=tp;
++              tp->dev = dev;
++
++              SET_MODULE_OWNER(dev);
++
++              // spin_lock_init(&tp->lock);
++              spin_lock_init(&gmac_fq_lock);
++              dev->base_addr = tp->base_addr;
++              dev->irq = tp->irq;
++          dev->open = gmac_open;
++          dev->stop = gmac_close;
++              dev->hard_start_xmit = gmac_start_xmit;
++              dev->get_stats = gmac_get_stats;
++              dev->set_multicast_list = gmac_set_rx_mode;
++              dev->set_mac_address = gmac_set_mac_address;
++              dev->do_ioctl = gmac_netdev_ioctl;
++              dev->tx_timeout = gmac_tx_timeout;
++              dev->watchdog_timeo = GMAC_DEV_TX_TIMEOUT;
++#ifdef        L2_jumbo_frame
++              dev->mtu = 2018; //2002  ,2018
++#endif
++              if (tp->port_id == 0)
++                      dev->tx_queue_len = TOE_GMAC0_SWTXQ_DESC_NUM;
++              else
++                      dev->tx_queue_len = TOE_GMAC1_SWTXQ_DESC_NUM;
++
++#ifdef DO_HW_CHKSUM
++              dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
++#ifdef ENABLE_TSO
++              dev->features |= NETIF_F_TSO;
++#endif
++#endif
++#ifdef CONFIG_SL_NAPI
++        dev->poll = gmac_rx_poll;
++        dev->weight = 64;
++#endif
++
++              if (register_netdev(dev))
++              {
++                      gmac_cleanup_module();
++                      return(-1);
++              }
++      }
++
++
++//    FLAG_SWITCH = 0 ;
++//    FLAG_SWITCH = SPI_get_identifier();
++//    if(FLAG_SWITCH)
++//    {
++//            printk("Configure ADM699X...\n");
++//            SPI_default();  //Add by jason for ADM699X configuration
++//    }
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++*     gmac_cleanup_module
++*----------------------------------------------------------------------*/
++
++static void gmac_cleanup_module(void)
++{
++    int i;
++
++#ifdef SL351x_GMAC_WORKAROUND
++      del_timer(&gmac_workround_timer_obj);
++#endif
++
++    for (i=0;i<CONFIG_MAC_NUM;i++)
++    {
++      if (toe_private_data.gmac[i].dev)
++      {
++              unregister_netdev(toe_private_data.gmac[i].dev);
++              toe_private_data.gmac[i].dev = NULL;
++        }
++    }
++      return ;
++}
++
++module_init(gmac_init_module);
++module_exit(gmac_cleanup_module);
++
++
++/*----------------------------------------------------------------------
++*     gmac_read_reg
++*----------------------------------------------------------------------*/
++static inline unsigned int gmac_read_reg(unsigned int base, unsigned int offset)
++//static unsigned int gmac_read_reg(unsigned int base, unsigned int offset)
++{
++    volatile unsigned int reg_val;
++
++    reg_val = readl(base + offset);
++      return (reg_val);
++}
++
++/*----------------------------------------------------------------------
++*     gmac_write_reg
++*----------------------------------------------------------------------*/
++static inline void gmac_write_reg(unsigned int base, unsigned int offset,unsigned int data,unsigned int bit_mask)
++//static void gmac_write_reg(unsigned int base, unsigned int offset,unsigned int data,unsigned int bit_mask)
++{
++      volatile unsigned int reg_val;
++    unsigned int *addr;
++
++      reg_val = ( gmac_read_reg(base, offset) & (~bit_mask) ) | (data & bit_mask);
++      addr = (unsigned int *)(base + offset);
++    writel(reg_val,addr);
++      return;
++}
++
++/*----------------------------------------------------------------------
++*     mac_init_drv
++*----------------------------------------------------------------------*/
++void mac_init_drv(void)
++{
++      TOE_INFO_T                      *toe;
++      int                                     i;
++      QUEUE_THRESHOLD_T       threshold;
++      u32                                     *destp;
++      unsigned int            chip_id,chip_version;
++
++      chip_id = readl(GMAC_GLOBAL_BASE_ADDR+0x0);
++      chip_version = chip_id & 0x1 ;
++
++      if (!gmac_initialized)
++      {
++              gmac_initialized = 1;
++
++              // clear non TOE Queue Header Area
++              destp = (u32 *)TOE_NONTOE_QUE_HDR_BASE;
++              for (; destp < (u32 *)NONTOE_Q_HDR_AREA_END; destp++)
++                      *destp = 0x00;
++
++              // clear TOE Queue Header Area
++              destp = (u32 *)TOE_TOE_QUE_HDR_BASE;
++              for (; destp < (u32 *)TOE_Q_HDR_AREA_END; destp++)
++                      *destp = 0x00;
++
++              // init private data
++              toe = (TOE_INFO_T *)&toe_private_data;
++              memset((void *)toe, 0, sizeof(TOE_INFO_T));
++              toe->gmac[0].base_addr = GMAC0_BASE;
++              toe->gmac[1].base_addr = GMAC1_BASE;
++              toe->gmac[0].dma_base_addr = TOE_GMAC0_DMA_BASE;
++              toe->gmac[1].dma_base_addr = TOE_GMAC1_DMA_BASE;
++        toe->gmac[0].auto_nego_cfg = 1;
++        toe->gmac[1].auto_nego_cfg = 1;
++#ifdef CONFIG_SL3516_ASIC
++        toe->gmac[0].speed_cfg = GMAC_SPEED_1000;
++        toe->gmac[1].speed_cfg = GMAC_SPEED_1000;
++#else
++              toe->gmac[0].speed_cfg = GMAC_SPEED_100;
++        toe->gmac[1].speed_cfg = GMAC_SPEED_100;
++#endif
++        toe->gmac[0].full_duplex_cfg = 1;
++        toe->gmac[1].full_duplex_cfg = 1;
++#ifdef CONFIG_SL3516_ASIC
++        toe->gmac[0].phy_mode = GMAC_PHY_RGMII_1000;
++        toe->gmac[1].phy_mode = GMAC_PHY_RGMII_1000;
++#else
++              toe->gmac[0].phy_mode = GMAC_PHY_RGMII_100;
++        toe->gmac[1].phy_mode = GMAC_PHY_RGMII_100;
++#endif
++        toe->gmac[0].port_id = GMAC_PORT0;
++        toe->gmac[1].port_id = GMAC_PORT1;
++        toe->gmac[0].phy_addr = 0x1;
++        toe->gmac[1].phy_addr = 2;
++//      toe->gmac[0].irq = SL2312_INTERRUPT_GMAC0;
++              toe->gmac[0].irq =1;
++//      toe->gmac[1].irq = SL2312_INTERRUPT_GMAC1;
++              toe->gmac[1].irq =2;
++        toe->gmac[0].mac_addr1 = &eth_mac[0][0];
++        toe->gmac[1].mac_addr1 = &eth_mac[1][0];
++
++              for (i=0; i<CONFIG_MAC_NUM; i++)
++              {
++                      unsigned int data, phy_vendor;
++                      gmac_write_reg(toe->gmac[i].base_addr, GMAC_STA_ADD2, 0x55aa55aa, 0xffffffff);
++                      data = gmac_read_reg(toe->gmac[i].base_addr, GMAC_STA_ADD2);
++                      if (data == 0x55aa55aa)
++                      {
++#ifdef VITESSE_G5SWITCH
++                              if(Giga_switch && (i==1)){
++                                      toe->gmac[i].existed = GMAC_EXISTED_FLAG;
++                                      break;
++                              }
++#endif
++                              phy_vendor = gmac_get_phy_vendor(toe->gmac[i].phy_addr);
++                              if (phy_vendor != 0 && phy_vendor != 0xffffffff)
++                                      toe->gmac[i].existed = GMAC_EXISTED_FLAG;
++                      }
++              }
++
++              // Write GLOBAL_QUEUE_THRESHOLD_REG
++              threshold.bits32 = 0;
++              threshold.bits.swfq_empty = (TOE_SW_FREEQ_DESC_NUM > 256) ? 255 :
++                                                      TOE_SW_FREEQ_DESC_NUM/2;
++              threshold.bits.hwfq_empty = (TOE_HW_FREEQ_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_HW_FREEQ_DESC_NUM/4;
++              threshold.bits.toe_class = (TOE_TOE_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_TOE_DESC_NUM/4;
++              threshold.bits.intrq = (TOE_INTR_DESC_NUM > 256) ? 256/4 :
++                                                      TOE_INTR_DESC_NUM/4;
++              writel(threshold.bits32, TOE_GLOBAL_BASE + GLOBAL_QUEUE_THRESHOLD_REG);
++
++              FLAG_SWITCH = 0;
++              toe_gmac_sw_reset();
++              toe_init_free_queue();
++              toe_init_swtx_queue();
++#ifdef CONFIG_SL351x_NAT
++              toe_init_hwtx_queue();
++#endif
++              toe_init_default_queue();
++#ifdef CONFIG_SL351x_RXTOE
++              toe_init_interrupt_queue();
++#endif
++              toe_init_interrupt_config();
++
++#if defined(CONFIG_SL351x_NAT) || defined(CONFIG_SL351x_RXTOE)
++              sl351x_hash_init();
++#else
++      {
++              volatile u32 *dp1, *dp2, dword;
++
++              dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++              dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++              for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++              {
++                      *dp1++ = 0;
++                      dword = *dp2++; // read-clear
++              }
++      }
++#endif
++      }
++
++#ifdef SL351x_GMAC_WORKAROUND
++#ifdef CONFIG_SL351x_NAT
++      sl351x_nat_workaround_init();
++#endif
++      init_timer(&gmac_workround_timer_obj);
++      if (chip_version == 1)
++      {
++              gmac_workround_timer_obj.expires = jiffies * 50;
++      }
++      else
++      {
++              gmac_workround_timer_obj.expires = jiffies + 2;
++      }
++      gmac_workround_timer_obj.data = (unsigned long)&gmac_workround_timer_obj;
++      gmac_workround_timer_obj.function = (void *)&sl351x_poll_gmac_hanged_status;
++      add_timer(&gmac_workround_timer_obj);
++#endif
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_free_queue
++*     (1) Initialize the Free Queue Descriptor Base Address & size
++*             Register: TOE_GLOBAL_BASE + 0x0004
++*     (2) Initialize DMA Read/Write pointer for
++*             SW Free Queue and HW Free Queue
++*     (3)     Initialize DMA Descriptors for
++*             SW Free Queue and HW Free Queue,
++*----------------------------------------------------------------------*/
++static void toe_init_free_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++//    unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++      GMAC_RXDESC_T           *sw_desc_ptr;
++      struct sk_buff          *skb;
++#ifdef CONFIG_SL351x_NAT
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++#endif
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&toe->sw_freeq_desc_base_dma) ;
++      sw_desc_ptr = (GMAC_RXDESC_T *)desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return;
++      }
++      memset((void *)desc_buf, 0, TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((toe->sw_freeq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_SW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_SW_FREEQ_BASE_SIZE_REG);
++
++      // init descriptor base
++      toe->swfq_desc_base = desc_buf;
++
++      // SW Free Queue Read/Write Pointer
++      rwptr_reg.bits.wptr = TOE_SW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      toe->fq_rx_rwptr.bits32 = rwptr_reg.bits32;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++      // SW Free Queue Descriptors
++      for (i=0; i<TOE_SW_FREEQ_DESC_NUM; i++)
++      {
++              sw_desc_ptr->word0.bits.buffer_size = SW_RX_BUF_SIZE;
++              sw_desc_ptr->word1.bits.sw_id = i;      // used to locate skb
++              if ( (skb = dev_alloc_skb(SW_RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++              {
++                      printk("%s::skb buffer allocation fail !\n",__func__); while(1);
++              }
++              REG32(skb->data) = (unsigned int)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++              // toe->rx_skb[i] = skb;
++              sw_desc_ptr->word2.buf_adr = (unsigned int)__pa(skb->data);
++//            consistent_sync((unsigned int)desc_ptr, sizeof(GMAC_RXDESC_T), PCI_DMA_TODEVICE);
++              sw_desc_ptr++;
++      }
++
++#ifdef CONFIG_SL351x_NAT
++      if (sizeof(skb->cb) < 64)
++      {
++                      printk("==> %s:: sk structure is incorrect -->Change to cb[64] !\n",__func__); while(1);
++      }
++      // init hardware free queues
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&toe->hw_freeq_desc_base_dma) ;
++      desc_ptr = (GMAC_RXDESC_T *)desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return;
++      }
++      memset((void *)desc_buf, 0, TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((toe->hw_freeq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_HW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_HW_FREEQ_BASE_SIZE_REG);
++
++      // init descriptor base
++      toe->hwfq_desc_base = desc_buf;
++
++      // HW Free Queue Read/Write Pointer
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++#ifndef HW_RXBUF_BY_KMALLOC
++      buf_ptr = (unsigned int)DMA_MALLOC(TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE,
++                                              (dma_addr_t *)&toe->hwfq_buf_base_dma);
++#else
++      buf_ptr = (unsigned int)kmalloc(TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE, GFP_KERNEL);
++      toe->hwfq_buf_base_dma = __pa(buf_ptr);
++#endif
++      if (!buf_ptr)
++      {
++              printk("===> %s::Failed to allocate HW TxQ Buffers!\n",__func__);
++              while(1);       // could not be happened, if happened, adjust the buffer descriptor number
++              return;
++      }
++
++      toe->hwfq_buf_base = buf_ptr;
++      toe->hwfq_buf_end_dma = toe->hwfq_buf_base_dma + (TOE_HW_FREEQ_DESC_NUM * HW_RX_BUF_SIZE);
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++//            consistent_sync((unsigned int)desc_ptr, sizeof(GMAC_RXDESC_T), PCI_DMA_TODEVICE);
++              // consistent_sync((unsigned int)buf_ptr, HW_RX_BUF_SIZE, PCI_DMA_TODEVICE);
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++#else
++      // DMA Queue Base & Size
++      writel((0) | TOE_SW_FREEQ_DESC_POWER,
++                      TOE_GLOBAL_BASE + GLOBAL_HW_FREEQ_BASE_SIZE_REG);
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++
++#endif
++}
++/*----------------------------------------------------------------------
++*     toe_init_swtx_queue
++*     (2) Initialize the GMAC 0/1 SW TXQ Queue Descriptor Base Address & sizeup
++*             GMAC_SW_TX_QUEUE_BASE_REG(0x0050)
++*     (2) Initialize DMA Read/Write pointer for
++*             GMAC 0/1 SW TX Q0-5
++*----------------------------------------------------------------------*/
++static void toe_init_swtx_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++      unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // GMAC-0, SW-TXQ
++      // The GMAC-0 and GMAC-0 maybe have different descriptor number
++      // so, not use for instruction
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[0].swtxq_desc_base_dma) ;
++      toe->gmac[0].swtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[0].swtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC0_SWTXQ_DESC_POWER,
++                      TOE_GMAC0_DMA_BASE+ GMAC_SW_TX_QUEUE_BASE_REG);
++
++      // GMAC0 SW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_SW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_SW_TXQ_NUM; i++)
++      {
++              toe->gmac[0].swtxq[i].rwptr_reg = rwptr_addr;
++              toe->gmac[0].swtxq[i].desc_base = desc_buf;
++              toe->gmac[0].swtxq[i].total_desc_num = TOE_GMAC0_SWTXQ_DESC_NUM;
++              desc_buf += TOE_GMAC0_SWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++
++      // GMAC-1, SW-TXQ
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC1_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[1].swtxq_desc_base_dma) ;
++      toe->gmac[1].swtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC1_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[1].swtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC1_SWTXQ_DESC_POWER,
++                      TOE_GMAC1_DMA_BASE+ GMAC_SW_TX_QUEUE_BASE_REG);
++
++
++      // GMAC1 SW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_SW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_SW_TXQ_NUM; i++)
++      {
++              toe->gmac[1].swtxq[i].rwptr_reg = rwptr_addr;
++              toe->gmac[1].swtxq[i].desc_base = desc_buf;
++              toe->gmac[1].swtxq[i].total_desc_num = TOE_GMAC1_SWTXQ_DESC_NUM;
++              desc_buf += TOE_GMAC1_SWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_hwtx_queue
++*     (2) Initialize the GMAC 0/1 HW TXQ Queue Descriptor Base Address & size
++*             GMAC_HW_TX_QUEUE_BASE_REG(0x0054)
++*     (2) Initialize DMA Read/Write pointer for
++*             GMAC 0/1 HW TX Q0-5
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void toe_init_hwtx_queue(void)
++{
++      int                             i;
++      TOE_INFO_T                      *toe;
++      DMA_RWPTR_T                     rwptr_reg;
++      unsigned int            rwptr_addr;
++      unsigned int            desc_buf;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      // GMAC-0, HW-TXQ
++      // The GMAC-0 and GMAC-0 maybe have different descriptor number
++      // so, not use for instruction
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[0].hwtxq_desc_base_dma) ;
++      toe->gmac[0].hwtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[0].hwtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC0_HWTXQ_DESC_POWER,
++                      TOE_GMAC0_DMA_BASE+ GMAC_HW_TX_QUEUE_BASE_REG);
++
++      // GMAC0 HW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              toe->gmac[0].hwtxq[i].desc_base = desc_buf;
++              desc_buf += TOE_GMAC0_HWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++
++      // GMAC-1, HW-TXQ
++      desc_buf = (unsigned int)DMA_MALLOC((TOE_GMAC1_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T)),
++                                              (dma_addr_t *)&toe->gmac[1].hwtxq_desc_base_dma) ;
++      toe->gmac[1].hwtxq_desc_base = desc_buf;
++      if (!desc_buf)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_buf, 0,     TOE_GMAC1_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T));
++      writel((toe->gmac[1].hwtxq_desc_base_dma & DMA_Q_BASE_MASK) | TOE_GMAC1_HWTXQ_DESC_POWER,
++                      TOE_GMAC1_DMA_BASE+ GMAC_HW_TX_QUEUE_BASE_REG);
++
++      // GMAC1 HW TX Q0-Q5
++      rwptr_reg.bits.wptr = 0;
++      rwptr_reg.bits.rptr = 0;
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              toe->gmac[1].hwtxq[i].desc_base = desc_buf;
++              desc_buf += TOE_GMAC1_HWTXQ_DESC_NUM * sizeof(GMAC_TXDESC_T);
++              writel(rwptr_reg.bits32, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++*     toe_init_default_queue
++*     (1) Initialize the default 0/1 Queue Header
++*             Register: TOE_DEFAULT_Q0_HDR_BASE (0x60002000)
++*                               TOE_DEFAULT_Q1_HDR_BASE (0x60002008)
++*     (2)     Initialize Descriptors of Default Queue 0/1
++*----------------------------------------------------------------------*/
++static void toe_init_default_queue(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile NONTOE_QHDR_T  *qhdr;
++      GMAC_RXDESC_T                   *desc_ptr;
++      DMA_SKB_SIZE_T                  skb_size;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                                                                      (dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_ptr, 0, TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_RXDESC_T));
++      toe->gmac[0].default_desc_base = (unsigned int)desc_ptr;
++      toe->gmac[0].default_desc_num = TOE_DEFAULT_Q0_DESC_NUM;
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_DEFAULT_Q0_HDR_BASE;
++      qhdr->word0.base_size = ((unsigned int)toe->gmac[0].default_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_DEFAULT_Q0_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      toe->gmac[0].rx_rwptr.bits32 = 0;
++      toe->gmac[0].default_qhdr = (NONTOE_QHDR_T *)qhdr;
++      desc_ptr = (GMAC_RXDESC_T *)DMA_MALLOC((TOE_DEFAULT_Q1_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                                                                      (dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC fail !\n",__func__);
++              return  ;
++      }
++      memset((void *)desc_ptr, 0, TOE_DEFAULT_Q1_DESC_NUM * sizeof(GMAC_RXDESC_T));
++      toe->gmac[1].default_desc_base = (unsigned int)desc_ptr;
++      toe->gmac[1].default_desc_num = TOE_DEFAULT_Q1_DESC_NUM;
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_DEFAULT_Q1_HDR_BASE;
++      qhdr->word0.base_size = ((unsigned int)toe->gmac[1].default_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_DEFAULT_Q1_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      toe->gmac[1].rx_rwptr.bits32 = 0;
++      toe->gmac[1].default_qhdr = (NONTOE_QHDR_T *)qhdr;
++
++      skb_size.bits.hw_skb_size = HW_RX_BUF_SIZE;
++      skb_size.bits.sw_skb_size = SW_RX_BUF_SIZE;
++      writel(skb_size.bits32, TOE_GLOBAL_BASE + GLOBAL_DMA_SKB_SIZE_REG);
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_interrupt_queue
++*     (1) Initialize the Interrupt Queue Header
++*             Register: TOE_INTR_Q_HDR_BASE (0x60002080)
++*     (2)     Initialize Descriptors of Interrupt Queues
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_init_interrupt_queue(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile NONTOE_QHDR_T  *qhdr;
++      INTR_QHDR_T                             *desc_ptr;
++      // unsigned int                 desc_buf_addr;
++      int                                             i;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (INTR_QHDR_T *)DMA_MALLOC((TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(INTR_QHDR_T)),
++                                                                                      (dma_addr_t *)&toe->intr_desc_base_dma);
++      if (!desc_ptr)
++      {
++              printk("%s::DMA_MALLOC interrupt queue fail !\n",__func__);
++              return  ;
++      }
++      /*
++      desc_buf_addr = (unsigned int)DMA_MALLOC((TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T)),
++                                                                                              (dma_addr_t *)&toe->intr_buf_base_dma);
++      if (!desc_buf_addr)
++      {
++              printk("%s::DMA_MALLOC interrupt desc fail !\n",__func__);
++              return  ;
++      }*/
++      printk("#### %s::Intr Q desc %x\n", __func__, (u32)desc_ptr);
++
++      memset((void *)desc_ptr, 0, TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(INTR_QHDR_T));
++//    memset((void *)desc_buf_addr, 0, TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T));
++      toe->intr_desc_base = (unsigned int)desc_ptr;
++      toe->intr_desc_num = TOE_INTR_DESC_NUM;
++
++      qhdr = (volatile NONTOE_QHDR_T *)TOE_INTR_Q_HDR_BASE;
++//    intrq = (INTRQ_INFO_T*) &toe->intrq[0];
++      for (i=0; i<TOE_INTR_QUEUE_NUM; i++, qhdr++)
++      {
++              qhdr->word0.base_size = ((unsigned int)toe->intr_desc_base_dma & NONTOE_QHDR0_BASE_MASK) | TOE_INTR_DESC_POWER;
++              qhdr->word1.bits32 = 0;
++              desc_ptr += TOE_INTR_DESC_NUM;
++      }
++}
++
++#endif
++
++/*----------------------------------------------------------------------
++*     toe_init_interrupt_config
++*     Interrupt Select Registers are used to map interrupt to int0 or int1
++*     Int0 and int1 are wired to CPU 0/1 GMAC 0/1
++*     Interrupt Device Inteface data are used to pass device info to
++*             upper device deiver or store status/statistics
++*     ISR handler
++*             (1) If status bit ON but masked, the prinf error message (bug issue)
++*             (2) If select bits are for me, handle it, else skip to let
++*                     the other ISR handles it.
++*  Notes:
++*             GMACx init routine (for eCOS) or open routine (for Linux)
++*       enable the interrupt bits only which are selected for him.
++*
++*     Default Setting:
++*             GMAC0 intr bits ------> int0 ----> eth0
++*             GMAC1 intr bits ------> int1 ----> eth1
++*             TOE intr -------------> int0 ----> eth0
++*             Classification Intr --> int0 ----> eth0
++*             Default Q0 -----------> int0 ----> eth0
++*             Default Q1 -----------> int1 ----> eth1
++*----------------------------------------------------------------------*/
++static void toe_init_interrupt_config(void)
++{
++      // clear all status bits
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      // Init select registers
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++
++      // disable all interrupt
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_0_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_2_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_3_REG);
++      writel(0, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_4_REG);
++}
++
++/*----------------------------------------------------------------------
++*     toe_init_gmac
++*----------------------------------------------------------------------*/
++static void toe_init_gmac(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      TOE_INFO_T              *toe;
++      u32                     data;
++
++      if (!gmac_initialized)
++              return ;
++
++      if (!tp->existed)
++              return;
++
++      tp->dev = dev;
++      tp->flow_control_enable = 1;
++      tp->pre_phy_status = LINK_DOWN;
++      tp->full_duplex_status = tp->full_duplex_cfg;
++      tp->speed_status = tp->speed_status;
++
++#if 0
++   /* get mac address from FLASH */
++    gmac_get_mac_address();
++#endif
++
++    /* set PHY register to start autonegition process */
++    gmac_set_phy_status(dev);
++
++      /* GMAC initialization */
++      if ( toe_gmac_init_chip(dev) )
++      {
++              printk ("GMAC %d init fail\n", tp->port_id);
++      }
++
++    /* clear statistic counter */
++    toe_gmac_clear_counter(dev);
++
++      memset((void *)&tp->ifStatics, 0, sizeof(struct net_device_stats));
++
++      /* -----------------------------------------------------------
++      Enable GMAC interrupt & disable loopback
++      Notes:
++              GMACx init routine (for eCOS) or open routine (for Linux)
++              enable the interrupt bits only which are selected for him.
++      --------------------------------------------------------------*/
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // Enable Interrupt Bits
++      if (tp->port_id == 0)
++      {
++              tp->intr0_selected =    GMAC0_TXDERR_INT_BIT     | GMAC0_TXPERR_INT_BIT         |
++                                      GMAC0_RXDERR_INT_BIT     | GMAC0_RXPERR_INT_BIT         |
++                                  GMAC0_SWTQ05_FIN_INT_BIT | GMAC0_SWTQ05_EOF_INT_BIT |
++                                  GMAC0_SWTQ04_FIN_INT_BIT | GMAC0_SWTQ04_EOF_INT_BIT |
++                                  GMAC0_SWTQ03_FIN_INT_BIT | GMAC0_SWTQ03_EOF_INT_BIT |
++                                  GMAC0_SWTQ02_FIN_INT_BIT | GMAC0_SWTQ02_EOF_INT_BIT |
++                                  GMAC0_SWTQ01_FIN_INT_BIT | GMAC0_SWTQ01_EOF_INT_BIT |
++                                  GMAC0_SWTQ00_FIN_INT_BIT | GMAC0_SWTQ00_EOF_INT_BIT;
++
++#ifdef GMAX_TX_INTR_DISABLED
++          tp->intr0_enabled =         0;
++#else
++          tp->intr0_enabled =         GMAC0_SWTQ00_FIN_INT_BIT | GMAC0_SWTQ00_EOF_INT_BIT;
++#endif
++
++          tp->intr1_selected =        TOE_IQ_ALL_BITS                  | TOE_CLASS_RX_INT_BITS        |
++                                                      GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT |
++                                                      GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT |
++                                                      DEFAULT_Q0_INT_BIT;
++          tp->intr1_enabled =         DEFAULT_Q0_INT_BIT | TOE_IQ_ALL_BITS;
++          tp->intr2_selected =        0xffffffff;      // TOE Queue 32-63 FUUL Intr
++          tp->intr2_enabled =         0xffffffff;
++          tp->intr3_selected =        0xffffffff;      // TOE Queue 0-31 FUUL Intr
++          tp->intr3_enabled =         0xffffffff;
++          tp->intr4_selected =        GMAC0_INT_BITS | CLASS_RX_FULL_INT_BITS |
++                                                      HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
++          tp->intr4_enabled =         GMAC0_INT_BITS | SWFQ_EMPTY_INT_BIT;
++
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) & ~tp->intr0_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG) & ~tp->intr1_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG) & ~tp->intr2_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG) & ~tp->intr3_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG) & ~tp->intr4_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++      }
++      else
++      {
++              tp->intr0_selected =    GMAC1_TXDERR_INT_BIT     | GMAC1_TXPERR_INT_BIT         |
++                                      GMAC1_RXDERR_INT_BIT     | GMAC1_RXPERR_INT_BIT         |
++                                  GMAC1_SWTQ15_FIN_INT_BIT | GMAC1_SWTQ15_EOF_INT_BIT |
++                                  GMAC1_SWTQ14_FIN_INT_BIT | GMAC1_SWTQ14_EOF_INT_BIT |
++                                  GMAC1_SWTQ13_FIN_INT_BIT | GMAC1_SWTQ13_EOF_INT_BIT |
++                                  GMAC1_SWTQ12_FIN_INT_BIT | GMAC1_SWTQ12_EOF_INT_BIT |
++                                  GMAC1_SWTQ11_FIN_INT_BIT | GMAC1_SWTQ11_EOF_INT_BIT |
++                                  GMAC1_SWTQ10_FIN_INT_BIT | GMAC1_SWTQ10_EOF_INT_BIT;
++#ifdef GMAX_TX_INTR_DISABLED
++          tp->intr0_enabled =         0;
++#else
++          tp->intr0_enabled =         GMAC1_SWTQ10_FIN_INT_BIT | GMAC1_SWTQ10_EOF_INT_BIT;
++#endif
++
++          tp->intr1_selected =        DEFAULT_Q1_INT_BIT;
++          tp->intr1_enabled =         DEFAULT_Q1_INT_BIT | TOE_IQ_ALL_BITS;
++          tp->intr2_selected =        0;       // TOE Queue 32-63 FUUL Intr
++          tp->intr2_enabled =         0;
++          tp->intr3_selected =        0;       // TOE Queue 0-31 FUUL Intr
++          tp->intr3_enabled =         0;
++          tp->intr4_selected =        GMAC1_INT_BITS;
++          tp->intr4_enabled =         GMAC1_INT_BITS;
++
++          if (toe->gmac[0].existed != GMAC_EXISTED_FLAG)
++          {
++              tp->intr1_selected      |=      TOE_IQ_ALL_BITS | TOE_CLASS_RX_INT_BITS |
++                                                              GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT |
++                                                              GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT;
++              tp->intr1_enabled       |=      TOE_IQ_ALL_BITS;
++              tp->intr2_selected      |=      0xffffffff;      // TOE Queue 32-63 FUUL Intr
++              tp->intr2_enabled       |=      0xffffffff;
++              tp->intr3_selected      |=      0xffffffff;      // TOE Queue 0-31 FUUL Intr
++              tp->intr3_enabled       |=      0xffffffff;
++              tp->intr4_selected      |=      CLASS_RX_FULL_INT_BITS |
++                                                              HWFQ_EMPTY_INT_BIT | SWFQ_EMPTY_INT_BIT;
++              tp->intr4_enabled       |=      SWFQ_EMPTY_INT_BIT;
++              }
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG) | tp->intr0_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_0_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG) | tp->intr1_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_1_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG) | tp->intr2_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_2_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG) | tp->intr3_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_3_REG);
++          data = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG) | tp->intr4_selected;
++          writel(data, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_SELECT_4_REG);
++      }
++
++      // enable only selected bits
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_0_REG,
++                                      tp->intr0_enabled, tp->intr0_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_1_REG,
++                                      tp->intr1_enabled, tp->intr1_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_2_REG,
++                                      tp->intr2_enabled, tp->intr2_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_3_REG,
++                                      tp->intr3_enabled, tp->intr3_selected);
++      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                                      tp->intr4_enabled, tp->intr4_selected);
++
++    /* start DMA process */
++      toe_gmac_hw_start(dev);
++
++    /* enable tx/rx register */
++    toe_gmac_enable_tx_rx(dev);
++
++//    toe_gmac_enable_interrupt(tp->irq);
++
++    return ;
++}
++
++
++/*----------------------------------------------------------------------
++* toe_gmac_sw_reset
++*----------------------------------------------------------------------*/
++static void toe_gmac_sw_reset(void)
++{
++      unsigned int    reg_val;
++      reg_val = readl(GMAC_GLOBAL_BASE_ADDR+GLOBAL_RESET_REG) | 0x00000060;   /* GMAC0 S/W reset */
++    writel(reg_val,GMAC_GLOBAL_BASE_ADDR+GLOBAL_RESET_REG);
++    udelay(100);
++    return;
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_init_chip
++*----------------------------------------------------------------------*/
++static int toe_gmac_init_chip(struct net_device *dev)
++{
++      GMAC_INFO_T     *tp = dev->priv;
++      GMAC_CONFIG2_T  config2_val;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_CONFIG1_T  config1;
++      #ifdef CONFIG_SL351x_NAT
++      GMAC_CONFIG3_T  config3_val;
++      #endif
++      GMAC_TX_WCR0_T  hw_weigh;
++      GMAC_TX_WCR1_T  sw_weigh;
++//    GMAC_HASH_ENABLE_REG0_T hash_ctrl;
++//
++#if 0 /* mac address will be set in late_initcall */
++      struct sockaddr sock;
++      // GMAC_AHB_WEIGHT_T    ahb_weight, ahb_weight_mask;
++
++
++      /* set station MAC address1 and address2 */
++      memcpy(&sock.sa_data[0],&eth_mac[tp->port_id][0],6);
++      gmac_set_mac_address(dev,(void *)&sock);
++#endif
++
++      /* set RX_FLTR register to receive all multicast packet */
++      gmac_write_reg(tp->base_addr, GMAC_RX_FLTR, 0x00000007,0x0000001f);
++      //    gmac_write_reg(tp->base_addr, GMAC_RX_FLTR, 0x00000007,0x0000001f);
++      //gmac_write_reg(tp->base_addr, GMAC_RX_FLTR,0x00000007,0x0000001f);
++
++      /* set per packet buffer size */
++      //      config1.bits32 = 0x002004;      //next version
++      /* set flow control threshold */
++      config1.bits32 = 0;
++      config1.bits.set_threshold = 32 / 2;
++      config1.bits.rel_threshold = 32 / 4 * 3;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG1, config1.bits32, 0xffffffff);
++
++      /* set flow control threshold */
++      config2_val.bits32 = 0;
++      config2_val.bits.set_threshold = TOE_SW_FREEQ_DESC_NUM/2;
++      config2_val.bits.rel_threshold = TOE_SW_FREEQ_DESC_NUM*3/4;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG2, config2_val.bits32,0xffffffff);
++
++      #ifdef CONFIG_SL351x_NAT
++      /* set HW free queue flow control threshold */
++      config3_val.bits32 = 0;
++      config3_val.bits.set_threshold = PAUSE_SET_HW_FREEQ;
++      config3_val.bits.rel_threshold = PAUSE_REL_HW_FREEQ;
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG3, config3_val.bits32,0xffffffff);
++      #endif
++      /* set_mcast_filter mask*/
++      //      gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL0,0x0,0xffffffff);
++      //  gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL1,0x0,0xffffffff);
++
++      /* disable TX/RX and disable internal loop back */
++      config0.bits32 = 0;
++      config0_mask.bits32 = 0;
++
++      //debug_Aaron
++#ifdef        L2_jumbo_frame
++      config0.bits.max_len = 5;
++#else
++      config0.bits.max_len = 2;
++#endif
++
++      if (tp->flow_control_enable==1)
++      {
++              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++              printk("Enable MAC Flow Control...\n");
++      }
++      else
++      {
++              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++              printk("Disable MAC Flow Control...\n");
++      }
++      config0.bits.dis_rx = 1;  /* disable rx */
++      config0.bits.dis_tx = 1;  /* disable tx */
++      config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.rx_err_detect = 1;
++      config0.bits.rgmii_en = 0;
++      config0.bits.rgmm_edge = 1;
++      config0.bits.rxc_inv = 0;
++      config0.bits.ipv4_rx_chksum = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_rx_chksum = 1;  /* enable H/W to check ip checksum */
++      config0.bits.port0_chk_hwq = 1; // GaryChen 3/24/2006 2:26PM
++      config0.bits.port1_chk_hwq = 1; // GaryChen 3/24/2006 2:26PM
++      config0.bits.port0_chk_toeq = 1;
++      config0.bits.port1_chk_toeq = 1;
++      config0.bits.port0_chk_classq = 1;
++      config0.bits.port1_chk_classq = 1;
++
++      config0_mask.bits.max_len = 7;
++      config0_mask.bits.tx_fc_en = 1;
++      config0_mask.bits.rx_fc_en = 1;
++      config0_mask.bits.dis_rx = 1;
++      config0_mask.bits.dis_tx = 1;
++      config0_mask.bits.loop_back = 1;
++      config0_mask.bits.rgmii_en = 1;
++      config0_mask.bits.rgmm_edge = 1;
++      config0_mask.bits.rxc_inv = 1;
++      config0_mask.bits.ipv4_rx_chksum = 1;
++      config0_mask.bits.ipv6_rx_chksum = 1;
++      config0_mask.bits.port0_chk_hwq = 1;
++      config0_mask.bits.port1_chk_hwq = 1;
++      config0_mask.bits.port0_chk_toeq = 1;
++      config0_mask.bits.port1_chk_toeq = 1;
++      config0_mask.bits.port0_chk_classq = 1;
++      config0_mask.bits.port1_chk_classq = 1;
++      config0_mask.bits.rx_err_detect = 1;
++
++      #if 0
++      config0.bits.dis_rx = 1;  /* disable rx */
++      config0.bits.dis_tx = 1;  /* disable tx */
++      config0.bits.loop_back = 0; /* enable/disable GMAC loopback */
++      config0.bits.txc_inv = 0;
++      config0.bits.rgmii_en = 0;
++      config0.bits.rgmm_edge = 1;
++      config0.bits.rxc_inv = 1;
++      config0.bits.ipv4_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++      config0.bits.ipv6_tss_rx_en = 1;  /* enable H/W to check ip checksum */
++
++      config0_mask.bits.max_len = 3;
++      config0_mask.bits.tx_fc_en = 1;
++      config0_mask.bits.rx_fc_en = 1;
++      config0_mask.bits.dis_rx = 1;
++      config0_mask.bits.dis_tx = 1;
++      config0_mask.bits.loop_back = 1;
++      config0_mask.bits.rgmii_en = 1;
++      config0_mask.bits.rgmm_edge = 1;
++      config0_mask.bits.txc_inv = 1;
++      config0_mask.bits.rxc_inv = 1;
++      config0_mask.bits.ipv4_tss_rx_en = 1;
++      config0_mask.bits.ipv6_tss_rx_en = 1;
++      #endif
++
++      gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++
++      #if 1
++      hw_weigh.bits32 = 0;
++      hw_weigh.bits.hw_tq3 = 1;
++      hw_weigh.bits.hw_tq2 = 1;
++      hw_weigh.bits.hw_tq1 = 1;
++      hw_weigh.bits.hw_tq0 = 1;
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG, hw_weigh.bits32, 0xffffffff);
++
++      sw_weigh.bits32 = 0;
++      sw_weigh.bits.sw_tq5 = 1;
++      sw_weigh.bits.sw_tq4 = 1;
++      sw_weigh.bits.sw_tq3 = 1;
++      sw_weigh.bits.sw_tq2 = 1;
++      sw_weigh.bits.sw_tq1 = 1;
++      sw_weigh.bits.sw_tq0 = 1;
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG, sw_weigh.bits32, 0xffffffff);
++      #endif
++
++      #if 0
++      ahb_weight.bits32 = 0;
++      ahb_weight_mask.bits32 = 0;
++      ahb_weight.bits.rx_weight = 1;
++      ahb_weight.bits.tx_weight = 1;
++      ahb_weight.bits.hash_weight = 1;
++      ahb_weight.bits.pre_req = 0x1f;
++      ahb_weight.bits.tqDV_threshold = 0;
++      ahb_weight_mask.bits.rx_weight = 0x1f;
++      ahb_weight_mask.bits.tx_weight = 0x1f;
++      ahb_weight_mask.bits.hash_weight = 0x1f;
++      ahb_weight_mask.bits.pre_req = 0x1f;
++      ahb_weight_mask.bits.tqDV_threshold = 0x1f;
++      gmac_write_reg(tp->dma_base_addr, GMAC_AHB_WEIGHT_REG, ahb_weight.bits32, ahb_weight_mask.bits32);
++      #endif
++
++      #if defined(CONFIG_SL351x_NAT) || defined(CONFIG_SL351x_RXTOE)
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR0, IPPROTO_TCP, 0xffffffff);
++      #endif
++      #ifdef CONFIG_SL351x_NAT
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR1, IPPROTO_UDP, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR2, IPPROTO_GRE, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR3, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR4, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR5, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR6, 0xff, 0xffffffff);
++      gmac_write_reg(tp->dma_base_addr, GMAC_SPR7, 0xff, 0xffffffff);
++
++      sl351x_nat_init();
++      #endif
++
++      #ifdef CONFIG_SL351x_RXTOE
++      /* setup matching rule to TOE */
++      sl351x_toe_init();
++      #endif
++
++      // for A1 ASIC version
++//    hash_ctrl.bits32 = 0;
++//    hash_ctrl.bits.timing = 6;
++//    gmac_write_reg(tp->dma_base_addr, GMAC_HASH_ENGINE_REG0, hash_ctrl.bits32, 0xffffffff);
++
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_enable_tx_rx
++*----------------------------------------------------------------------*/
++static void toe_gmac_enable_tx_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++/*----------------------------------------------------------------------
++*     toe_gmac_disable_rx
++*----------------------------------------------------------------------*/
++#if 0
++static void toe_gmac_disable_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++//    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++//     config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++#endif
++/*----------------------------------------------------------------------
++*     toe_gmac_enable_rx
++*----------------------------------------------------------------------*/
++#if 0
++static void toe_gmac_enable_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 0;  /* enable rx */
++//    config0.bits.dis_tx = 0;  /* enable tx */
++    config0_mask.bits.dis_rx = 1;
++//    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++#endif
++/*----------------------------------------------------------------------
++*     toe_gmac_disable_tx_rx
++*----------------------------------------------------------------------*/
++static void toe_gmac_disable_tx_rx(struct net_device *dev)
++{
++      GMAC_INFO_T             *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++
++    /* enable TX/RX */
++    config0.bits32 = 0;
++    config0_mask.bits32 = 0;
++    config0.bits.dis_rx = 1;  /* disable rx */
++    config0.bits.dis_tx = 1;  /* disable tx */
++    config0_mask.bits.dis_rx = 1;
++    config0_mask.bits.dis_tx = 1;
++    gmac_write_reg(tp->base_addr, GMAC_CONFIG0, config0.bits32,config0_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_hw_start
++*----------------------------------------------------------------------*/
++static void toe_gmac_hw_start(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T                 dma_ctrl, dma_ctrl_mask;
++
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 1;
++      dma_ctrl.bits.td_enable = 1;
++      dma_ctrl.bits.loopback = 0;
++      dma_ctrl.bits.drop_small_ack = 0;
++      dma_ctrl.bits.rd_prot = 0;
++      dma_ctrl.bits.rd_burst_size = 3;
++      dma_ctrl.bits.rd_insert_bytes = RX_INSERT_BYTES;
++      dma_ctrl.bits.rd_bus = 3;
++      dma_ctrl.bits.td_prot = 0;
++      dma_ctrl.bits.td_burst_size = 3;
++      dma_ctrl.bits.td_bus = 3;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++      dma_ctrl_mask.bits.loopback = 1;
++      dma_ctrl_mask.bits.drop_small_ack = 1;
++      dma_ctrl_mask.bits.rd_prot = 3;
++      dma_ctrl_mask.bits.rd_burst_size = 3;
++      dma_ctrl_mask.bits.rd_insert_bytes = 3;
++      dma_ctrl_mask.bits.rd_bus = 3;
++      dma_ctrl_mask.bits.td_prot = 0x0f;
++      dma_ctrl_mask.bits.td_burst_size = 3;
++      dma_ctrl_mask.bits.td_bus = 3;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++
++    return;
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_hw_stop
++*----------------------------------------------------------------------*/
++static void toe_gmac_hw_stop(struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T         dma_ctrl, dma_ctrl_mask;
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_clear_counter
++*----------------------------------------------------------------------*/
++static int toe_gmac_clear_counter (struct net_device *dev)
++{
++      GMAC_INFO_T     *tp = (GMAC_INFO_T *)dev->priv;
++
++    /* clear counter */
++    gmac_read_reg(tp->base_addr, GMAC_IN_DISCARDS);
++    gmac_read_reg(tp->base_addr, GMAC_IN_ERRORS);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MCAST);
++    gmac_read_reg(tp->base_addr, GMAC_IN_BCAST);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MAC1);
++    gmac_read_reg(tp->base_addr, GMAC_IN_MAC2);
++              tp->ifStatics.tx_bytes = 0;
++              tp->ifStatics.tx_packets = 0;
++              tp->ifStatics.tx_errors = 0;
++              tp->ifStatics.rx_bytes = 0;
++              tp->ifStatics.rx_packets = 0;
++              tp->ifStatics.rx_errors = 0;
++              tp->ifStatics.rx_dropped = 0;
++      return (0);
++}
++
++
++/*----------------------------------------------------------------------
++*     toe_gmac_tx_complete
++*----------------------------------------------------------------------*/
++static  void toe_gmac_tx_complete(GMAC_INFO_T *tp, unsigned int tx_qid,
++                                                                              struct net_device *dev, int interrupt)
++{
++      volatile GMAC_TXDESC_T  *curr_desc;
++      GMAC_TXDESC_0_T                 word0;
++      GMAC_TXDESC_1_T                 word1;
++      unsigned int                    desc_count;
++//    struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      GMAC_SWTXQ_T                    *swtxq;
++      DMA_RWPTR_T                             rwptr;
++
++      /* get tx H/W completed descriptor virtual address */
++      /* check tx status and accumulate tx statistics */
++      swtxq = &tp->swtxq[tx_qid];
++      swtxq->intr_cnt++;
++      for (;;)
++      {
++              rwptr.bits32 = readl(swtxq->rwptr_reg);
++              if (rwptr.bits.rptr == swtxq->finished_idx)
++                      break;
++      curr_desc = (volatile GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_FROMDEVICE);
++              word0.bits32 = curr_desc->word0.bits32;
++              word1.bits32 = curr_desc->word1.bits32;
++
++              if (word0.bits.status_tx_ok)
++              {
++                      tp->ifStatics.tx_bytes += word1.bits.byte_count;
++                      desc_count = word0.bits.desc_count;
++                      if (desc_count==0)
++                      {
++                              printk("%s::Desc 0x%x = 0x%x, desc_count=%d\n",__func__, (u32)curr_desc, word0.bits32, desc_count);
++                              while(1);
++                      }
++                      while (--desc_count)
++                      {
++                              word0.bits.status_tx_ok = 0;
++                              curr_desc->word0.bits32 = word0.bits32;
++                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                              word0.bits32 = curr_desc->word0.bits32;
++#ifdef _DUMP_TX_TCP_CONTENT
++                              if (curr_desc->word0.bits.buffer_size < 16)
++                              {
++                                      int a;
++                                      char *datap;
++                                      printk("\t Tx Finished Desc 0x%x Len %d Addr 0x%08x: ", (u32)curr_desc, curr_desc->word0.bits.buffer_size, curr_desc->word2.buf_adr);
++                                      datap = (char *)__va(curr_desc->word2.buf_adr);
++                                      for (a=0; a<8 && a<curr_desc->word0.bits.buffer_size; a++, datap++)
++                                      {
++                                              printk("0x%02x ", *datap);
++                                      }
++                                      printk("\n");
++                              }
++#endif
++                      }
++
++                      word0.bits.status_tx_ok = 0;
++                      if (swtxq->tx_skb[swtxq->finished_idx])
++                      {
++                              if (interrupt)
++                                      dev_kfree_skb_irq(swtxq->tx_skb[swtxq->finished_idx]);
++                              else
++                                      dev_kfree_skb(swtxq->tx_skb[swtxq->finished_idx]);
++                              swtxq->tx_skb[swtxq->finished_idx] = NULL;
++                      }
++                      curr_desc->word0.bits32 = word0.bits32;
++                      swtxq->curr_finished_desc = (GMAC_TXDESC_T *)curr_desc;
++                      swtxq->total_finished++;
++                      tp->ifStatics.tx_packets++;
++                      swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++              }
++              else
++              {
++                      // tp->ifStatics.tx_errors++;
++                      // printk("%s::Tx Descriptor is !!!\n",__func__);
++                      // wait ready by breaking
++                      break;
++              }
++      }
++
++      if (netif_queue_stopped(dev))
++      {
++              netif_wake_queue(dev);
++      }
++}
++
++/*----------------------------------------------------------------------
++*     gmac_start_xmit
++*----------------------------------------------------------------------*/
++static int gmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp= dev->priv;
++//    static unsigned int     pcount = 0;
++//    unsigned int                    tx_qid;
++    DMA_RWPTR_T                               rwptr;
++      volatile GMAC_TXDESC_T  *curr_desc;
++      int                                     snd_pages = skb_shinfo(skb)->nr_frags + 1;  /* get number of descriptor */
++      int                                     frag_id = 0;
++      int                                     len, total_len = skb->len;
++      struct net_device_stats *isPtr;
++      unsigned int                    free_desc;
++      GMAC_SWTXQ_T                    *swtxq;
++      register unsigned long  word0, word1, word2, word3;
++      unsigned short                  wptr, rptr;
++#ifdef        L2_jumbo_frame
++      int header_len = skb->len;
++      struct iphdr    *ip_hdr;
++    struct tcphdr     *tcp_hdr;
++    int             tcp_hdr_len;
++    unsigned char     *ptr;
++    int             data_len,a;
++    unsigned int    val;
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++      int                                             total_pages;
++      total_pages = snd_pages;
++#endif
++
++      isPtr = (struct net_device_stats *)&tp->ifStatics;
++#if 1
++      if (skb->len >= 0x10000)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++              printk("%s::[GMAC %d] skb->len %d >= 64K\n", __func__, tp->port_id, skb->len);
++              netif_stop_queue(dev);
++              return 1;
++    }
++#endif
++
++#if 0
++      if (storlink_ctl.recvfile==2)
++      {
++          printk("snd_pages=%d skb->len=%d\n",snd_pages,skb->len);
++      }
++#endif
++
++#ifdef GMAC_USE_TXQ0
++      #define tx_qid  0
++#endif
++
++      swtxq = &tp->swtxq[tx_qid];
++
++//    spin_lock(&tp->tx_mutex);
++    rwptr.bits32 = readl(swtxq->rwptr_reg);
++      wptr = rwptr.bits.wptr;
++      rptr = rwptr.bits.rptr;
++
++      // check finished desc or empty BD
++      // cannot check by read ptr of RW PTR register,
++      // because the HW complete to send but the SW may NOT handle it
++#ifndef       GMAX_TX_INTR_DISABLED
++      if (wptr >= swtxq->finished_idx)
++              free_desc = swtxq->total_desc_num - wptr - 1 + swtxq->finished_idx;
++      else
++              free_desc = swtxq->finished_idx - wptr - 1;
++
++      if (free_desc < snd_pages)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++//            printk("GMAC %d No available descriptor!\n", tp->port_id);
++              netif_stop_queue(dev);
++              return 1;
++    }
++#else
++      toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++
++      if (wptr >= swtxq->finished_idx)
++              free_desc = swtxq->total_desc_num - wptr - 1 + swtxq->finished_idx;
++      else
++              free_desc = swtxq->finished_idx - wptr - 1;
++      if (free_desc < snd_pages)
++      {
++//            spin_unlock(&tp->tx_mutex);
++              isPtr->tx_dropped++;
++//            printk("GMAC %d No available descriptor!\n", tp->port_id);
++              netif_stop_queue(dev);
++              return 1;
++    }
++
++#if 0
++      printk("1: free_desc=%d, wptr=%d, finished_idx=%d\n", free_desc, wptr, swtxq->finished_idx);
++      if ((free_desc < (snd_pages << 2)) ||
++          (free_desc < (swtxq->total_desc_num >> 2)))
++      {
++              printk("2: free_desc = %d\n", free_desc);
++              toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++              rwptr.bits32 = readl(swtxq->rwptr_reg);
++              wptr = rwptr.bits.wptr;
++              if (wptr>= swtxq->finished_idx)
++                      free_desc = swtxq->total_desc_num - wptr -1 + swtxq->finished_idx;
++              else
++                      free_desc = swtxq->finished_idx - wptr - 1;
++      }
++#endif
++#endif
++
++#ifdef        L2_jumbo_frame
++//            data_len = skb->len - 14 - ip_hdr->ihl *4 - tcp_hdr_len;
++//            if ((skb->nh.iph->protocol == __constant_htons(ETH_P_IP)) && ((skb->nh.iph->protocol & 0x00ff)  == IPPROTO_TCP))
++//            if (skb->nh.iph->protocol == 0x006 && (skb->nh.iph->protocol == __constant_htons(ETH_P_IP)))
++              if (((skb->nh.iph->protocol & 0x00ff)  == IPPROTO_TCP))
++              {
++                              ip_hdr = (struct iphdr*)(skb->nh.iph);
++                              tcp_hdr = (struct tcphdr*)(skb->h.th);
++                              tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++                              tcp_hdr_len = TCPHDRLEN(tcp_hdr) * 4;
++
++                              if ((skb->h.th->syn) && (tcp_hdr_len > 20))
++                              {
++                                      ptr = (unsigned char *)(tcp_hdr+1);
++                                      if ((ptr[0] == 0x02) && (ptr[1] == 0x04) && (ptr[2] == 0x07) && (ptr[3] == 0xba)) // 0x07 aa=2016-54=1962  ,0x07ba=2032-54=1978
++                                      {
++                                              ptr[2]=0x20;    //23
++                                              ptr[3]=0x00;    //00
++                                              printk("-----> Change MSS to 8K \n" );
++                                      }
++                              }
++              }
++//            if ((ip_hdr->protocol & 0x00ff) != IPPROTO_TCP)
++//            if ((tcp_hdr_len > 20) && (skb->h.th->syn))
++#endif
++
++
++#if 0
++      if (snd_pages > 1)
++              printk("-----> snd_pages=%d\n", snd_pages);
++      if (total_len > 1514)
++      {
++              printk("-----> total_len=%d\n", total_len);
++      }
++#endif
++
++    while (snd_pages)
++    {
++      char *pkt_datap;
++
++      curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + wptr;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_FROMDEVICE);
++#if 0
++//#if (GMAC_DEBUG==1)
++      // if curr_desc->word2.buf_adr !=0 means that the ISR does NOT handle it
++      // if (curr_desc->word2.buf_adr)
++      if (swtxq->tx_skb[wptr])
++      {
++              printk("Error! Stop due to TX descriptor's buffer is not freed!\n");
++              while(1);
++              dev_kfree_skb(swtxq->tx_skb[wptr]);
++              swtxq->tx_skb[wptr] = NULL;
++              }
++#endif
++
++              if (frag_id == 0)
++              {
++#if 0
++                      int i;
++                      pkt_datap = skb->data;
++                      len = total_len;
++                      for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
++                      {
++                              skb_frag_t* frag = &skb_shinfo(skb)->frags[i];
++                              len -= frag->size;
++                      }
++#else
++                      pkt_datap = skb->data;
++                      len = total_len - skb->data_len;
++#endif
++              }
++              else
++              {
++                      skb_frag_t* frag = &skb_shinfo(skb)->frags[frag_id-1];
++                      pkt_datap = page_address(frag->page) + frag->page_offset;
++                      len = frag->size;
++                      if (len > total_len)
++                      {
++                              printk("===> Fatal Error! Send Frag size %d > Total Size %d!!!!!\n",
++                                      len, total_len);
++                      }
++              }
++
++              /* set TX descriptor */
++              /* copy packet to descriptor buffer address */
++              // curr_desc->word0.bits32 = len;    /* total frame byte count */
++              word0 = len;
++#ifdef        L2_jumbo_frame
++              word3 = (dev->mtu+14) | EOFIE_BIT;  //2016 ,2032
++#else
++              word3 = 1514 | EOFIE_BIT;
++#endif
++
++#ifdef DO_HW_CHKSUM
++#ifdef        L2_jumbo_frame
++              if (total_len >= (dev->mtu+14) && (skb->nh.iph->protocol == 0x011) && skb->nh.iph && (skb->nh.iph->frag_off & __constant_htons(0x3fff)))
++#else
++              if (total_len <= 1514 && ip_hdr(skb) && (ip_hdr(skb)->frag_off & __constant_htons(0x3fff)))
++#endif
++                      word1  = total_len |
++                                      TSS_IP_CHKSUM_BIT  |
++                                      TSS_IPV6_ENABLE_BIT |
++                                      TSS_MTU_ENABLE_BIT;
++              else
++                      word1 = total_len |
++                                      TSS_UDP_CHKSUM_BIT |
++                                      TSS_TCP_CHKSUM_BIT |
++                                      TSS_IP_CHKSUM_BIT  |
++                                      TSS_IPV6_ENABLE_BIT |
++                                      TSS_MTU_ENABLE_BIT;
++#else
++              word1 = total_len | TSS_MTU_ENABLE_BIT;
++#endif
++              word2 = (unsigned long)__pa(pkt_datap);
++
++              if (frag_id == 0)
++              {
++                      word3 |= SOF_BIT;       // SOF
++              }
++
++              if (snd_pages == 1)
++              {
++                      word3 |= EOF_BIT;       // EOF
++                      swtxq->tx_skb[wptr] = skb;
++#ifdef CONFIG_SL351x_NAT
++                      if (nat_cfg.enabled && sl351x_nat_output(skb, tp->port_id))
++                              word1 |= TSS_IP_FIXED_LEN_BIT;
++#endif
++              }
++              else
++                      swtxq->tx_skb[wptr] = NULL;
++              // word1 |= TSS_IP_FIXED_LEN_BIT;
++#if 1
++#ifdef CONFIG_SL351x_RXTOE
++              // check if this frame has the mission to enable toe hash entry..
++              // if rx_max_pktsize ==0, do not enable RXTOE
++              if (TCP_SKB_CB(skb)->connection && storlink_ctl.rx_max_pktsize) {
++                      set_toeq_hdr(TCP_SKB_CB(skb)->connection, &toe_private_data, dev);
++              }
++#endif
++#endif
++#ifdef _DUMP_TX_TCP_CONTENT
++              if (len < 16 && frag_id && skb->h.th && (skb->h.th->source == __constant_htons(445) || skb->h.th->source == __constant_htons(139)))
++              {
++                      int a;
++                      char *datap;
++                      printk("Tx Desc 0x%x Frag %d Len %d [IP-ID 0x%x] 0x%08x: ", (u32)curr_desc, frag_id, len, htons(skb->nh.iph->id), (u32)pkt_datap);
++                      datap = (char *)pkt_datap;
++                      for (a=0; a<8 && a<len; a++, datap++)
++                      {
++                              printk("0x%02x ", *datap);
++                      }
++                      printk("\n");
++              }
++#endif
++
++#ifdef GMAC_LEN_1_2_ISSUE
++              if ((total_pages!=snd_pages) && (len == 1 || len == 2 ) && ((u32)pkt_datap & 0x03))
++              {
++                      memcpy((void *)&_debug_prefetch_buf[_debug_prefetch_cnt][0], pkt_datap, len);
++                      pkt_datap = (char *)&_debug_prefetch_buf[_debug_prefetch_cnt][0];
++                      word2 = (unsigned long)__pa(pkt_datap);
++                      _debug_prefetch_cnt++;
++                      if (_debug_prefetch_cnt >= _DEBUG_PREFETCH_NUM)
++                              _debug_prefetch_cnt = 0;
++              }
++#endif
++
++              consistent_sync((void *)pkt_datap, len, PCI_DMA_TODEVICE);
++              wmb();
++              curr_desc->word0.bits32 = word0;
++              curr_desc->word1.bits32 = word1;
++              curr_desc->word2.bits32 = word2;
++              curr_desc->word3.bits32 = word3;
++              swtxq->curr_tx_desc = (GMAC_TXDESC_T *)curr_desc;
++//            consistent_sync((void *)curr_desc, sizeof(GMAC_TXDESC_T), PCI_DMA_TODEVICE);
++#ifdef _DUMP_TX_TCP_CONTENT
++              if (len < 16 && frag_id && skb->h.th && (skb->h.th->source == __constant_htons(445) || skb->h.th->source == __constant_htons(139)))
++              {
++                      int a;
++                      char *datap;
++                      printk("\t 0x%08x: ", (u32)pkt_datap);
++                      datap = (char *)pkt_datap;
++                      for (a=0; a<8 && a<len; a++, datap++)
++                      {
++                              printk("0x%02x ", *datap);
++                      }
++                      printk("\n");
++              }
++#endif
++              free_desc--;
++              wmb();
++              wptr = RWPTR_ADVANCE_ONE(wptr, swtxq->total_desc_num);
++              frag_id++;
++              snd_pages--;
++      }
++
++    swtxq->total_sent++;
++      SET_WPTR(swtxq->rwptr_reg, wptr);
++      dev->trans_start = jiffies;
++
++
++      // printk("MAC %d Qid %d rwptr = 0x%x, curr_desc=0x%x\n", skb->tx_port_id, tx_qid, rwptr.bits32, curr_desc);
++//#ifdef      GMAX_TX_INTR_DISABLED
++//            toe_gmac_tx_complete(tp, tx_qid, dev, 0);
++//#endif
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_mac_address
++*----------------------------------------------------------------------*/
++
++static int gmac_set_mac_address(struct net_device *dev, void *addr)
++{
++      GMAC_INFO_T             *tp= dev->priv;
++      struct sockaddr *sock;
++      unsigned int    reg_val;
++    unsigned int    i;
++
++      sock = (struct sockaddr *) addr;
++      for (i = 0; i < 6; i++)
++      {
++              dev->dev_addr[i] = sock->sa_data[i];
++      }
++
++    reg_val = dev->dev_addr[0] + (dev->dev_addr[1]<<8) + (dev->dev_addr[2]<<16) + (dev->dev_addr[3]<<24);
++    gmac_write_reg(tp->base_addr,GMAC_STA_ADD0,reg_val,0xffffffff);
++    reg_val = dev->dev_addr[4] + (dev->dev_addr[5]<<8);
++    gmac_write_reg(tp->base_addr,GMAC_STA_ADD1,reg_val,0x0000ffff);
++      memcpy(&eth_mac[tp->port_id][0],&dev->dev_addr[0],6);
++
++    printk("Storlink %s address = ",dev->name);
++    printk("%02x",dev->dev_addr[0]);
++    printk("%02x",dev->dev_addr[1]);
++    printk("%02x",dev->dev_addr[2]);
++    printk("%02x",dev->dev_addr[3]);
++    printk("%02x",dev->dev_addr[4]);
++    printk("%02x\n",dev->dev_addr[5]);
++
++    return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_mac_address
++*     get mac address from FLASH
++*----------------------------------------------------------------------*/
++static void gmac_get_mac_address(void)
++{
++#ifdef CONFIG_MTD
++      extern int get_vlaninfo(vlaninfo* vlan);
++    static vlaninfo    vlan[2];
++
++    if (get_vlaninfo(&vlan[0]))
++    {
++        memcpy((void *)&eth_mac[0][0],vlan[0].mac,6);
++        // VLAN_conf[0].vid = vlan[0].vlanid;
++        // VLAN_conf[0].portmap = vlan[0].vlanmap;
++        memcpy((void *)&eth_mac[1][0],vlan[1].mac,6);
++        // VLAN_conf[1].vid = vlan[1].vlanid;
++        // VLAN_conf[1].portmap = vlan[1].vlanmap;
++    }
++#else
++    unsigned int reg_val;
++
++    reg_val = readl(IO_ADDRESS(TOE_GMAC0_BASE)+0xac);
++    eth_mac[0][4] = (reg_val & 0xff00) >> 8;
++    eth_mac[0][5] = reg_val & 0x00ff;
++    reg_val = readl(IO_ADDRESS(SL2312_SECURITY_BASE)+0xac);
++    eth_mac[1][4] = (reg_val & 0xff00) >> 8;
++    eth_mac[1][5] = reg_val & 0x00ff;
++#endif
++    return;
++}
++
++
++/*----------------------------------------------------------------------
++* mac_stop_txdma
++*----------------------------------------------------------------------*/
++void mac_stop_txdma(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T                 dma_ctrl, dma_ctrl_mask;
++      GMAC_TXDMA_FIRST_DESC_T txdma_busy;
++
++      // wait idle
++      do
++      {
++              txdma_busy.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_DMA_TX_FIRST_DESC_REG);
++      } while (txdma_busy.bits.td_busy);
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++/*----------------------------------------------------------------------
++* mac_start_txdma
++*----------------------------------------------------------------------*/
++void mac_start_txdma(struct net_device *dev)
++{
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      GMAC_DMA_CTRL_T         dma_ctrl, dma_ctrl_mask;
++
++    /* program dma control register */
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.rd_enable = 1;
++      dma_ctrl.bits.td_enable = 1;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.rd_enable = 1;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++}
++
++
++/*----------------------------------------------------------------------
++* gmac_get_stats
++*----------------------------------------------------------------------*/
++
++struct net_device_stats * gmac_get_stats(struct net_device *dev)
++{
++    GMAC_INFO_T *tp = (GMAC_INFO_T *)dev->priv;
++    // unsigned int        flags;
++    unsigned int        pkt_drop;
++    unsigned int        pkt_error;
++
++    if (netif_running(dev))
++    {
++        /* read H/W counter */
++        // spin_lock_irqsave(&tp->lock,flags);
++        pkt_drop = gmac_read_reg(tp->base_addr,GMAC_IN_DISCARDS);
++        pkt_error = gmac_read_reg(tp->base_addr,GMAC_IN_ERRORS);
++        tp->ifStatics.rx_dropped = tp->ifStatics.rx_dropped + pkt_drop;
++        tp->ifStatics.rx_errors = tp->ifStatics.rx_errors + pkt_error;
++        // spin_unlock_irqrestore(&tp->lock,flags);
++    }
++    return &tp->ifStatics;
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_get_sw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_get_sw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR1_T  sw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      sw_weigh.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG);
++
++      weight[0] = sw_weigh.bits.sw_tq0;
++      weight[1] = sw_weigh.bits.sw_tq1;
++      weight[2] = sw_weigh.bits.sw_tq2;
++      weight[3] = sw_weigh.bits.sw_tq3;
++      weight[4] = sw_weigh.bits.sw_tq4;
++      weight[5] = sw_weigh.bits.sw_tq5;
++}
++
++/*----------------------------------------------------------------------
++* mac_set_sw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_set_sw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR1_T  sw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      sw_weigh.bits32 = 0;
++      sw_weigh.bits.sw_tq0 = weight[0];
++      sw_weigh.bits.sw_tq1 = weight[1];
++      sw_weigh.bits.sw_tq2 = weight[2];
++      sw_weigh.bits.sw_tq3 = weight[3];
++      sw_weigh.bits.sw_tq4 = weight[4];
++      sw_weigh.bits.sw_tq5 = weight[5];
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_1_REG, sw_weigh.bits32, 0xffffffff);
++}
++
++/*----------------------------------------------------------------------
++* mac_get_hw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_get_hw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR0_T  hw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      hw_weigh.bits32 = gmac_read_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG);
++
++      weight[0] = hw_weigh.bits.hw_tq0;
++      weight[1] = hw_weigh.bits.hw_tq1;
++      weight[2] = hw_weigh.bits.hw_tq2;
++      weight[3] = hw_weigh.bits.hw_tq3;
++}
++
++/*----------------------------------------------------------------------
++* mac_set_hw_tx_weight
++*----------------------------------------------------------------------*/
++void mac_set_hw_tx_weight(struct net_device *dev, char *weight)
++{
++      GMAC_TX_WCR0_T  hw_weigh;
++    GMAC_INFO_T               *tp = (GMAC_INFO_T *)dev->priv;
++
++      hw_weigh.bits32 = 0;
++      hw_weigh.bits.hw_tq0 = weight[0];
++      hw_weigh.bits.hw_tq1 = weight[1];
++      hw_weigh.bits.hw_tq2 = weight[2];
++      hw_weigh.bits.hw_tq3 = weight[3];
++
++      gmac_write_reg(tp->dma_base_addr, GMAC_TX_WEIGHTING_CTRL_0_REG, hw_weigh.bits32, 0xffffffff);
++}
++
++/*----------------------------------------------------------------------
++* mac_start_tx_dma
++*----------------------------------------------------------------------*/
++int mac_start_tx_dma(int mac)
++{
++      GMAC_DMA_CTRL_T dma_ctrl, dma_ctrl_mask;
++
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.td_enable = 1;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      if (mac == 0)
++      gmac_write_reg(TOE_GMAC0_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      else
++      gmac_write_reg(TOE_GMAC1_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      return  1;
++}
++
++/*----------------------------------------------------------------------
++* mac_stop_tx_dma
++*----------------------------------------------------------------------*/
++int mac_stop_tx_dma(int mac)
++{
++      GMAC_DMA_CTRL_T dma_ctrl, dma_ctrl_mask;
++
++      dma_ctrl.bits32 = 0;
++      dma_ctrl.bits.td_enable = 0;
++
++      dma_ctrl_mask.bits32 = 0;
++      dma_ctrl_mask.bits.td_enable = 1;
++
++      if (mac == 0)
++      gmac_write_reg(TOE_GMAC0_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      else
++      gmac_write_reg(TOE_GMAC1_DMA_BASE, GMAC_DMA_CTRL_REG, dma_ctrl.bits32, dma_ctrl_mask.bits32);
++      return  1;
++}
++
++/*----------------------------------------------------------------------
++* mac_read_reg(int mac, unsigned int offset)
++*----------------------------------------------------------------------*/
++unsigned int mac_read_reg(int mac, unsigned int offset)
++{
++      switch (mac)
++      {
++              case 0:
++                      return gmac_read_reg(TOE_GMAC0_BASE, offset);
++              case 1:
++                      return gmac_read_reg(TOE_GMAC1_BASE, offset);
++              default:
++                      return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_write_reg
++*----------------------------------------------------------------------*/
++void mac_write_reg(int mac, unsigned int offset, unsigned data)
++{
++      switch (mac)
++      {
++              case 0:
++                      gmac_write_reg(GMAC0_BASE, offset, data, 0xffffffff);
++                      break;
++              case 1:
++                      gmac_write_reg(GMAC1_BASE, offset, data, 0xffffffff);
++                      break;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_read_dma_reg(int mac, unsigned int offset)
++*----------------------------------------------------------------------*/
++u32 mac_read_dma_reg(int mac, unsigned int offset)
++{
++      switch (mac)
++      {
++              case 0:
++                      return gmac_read_reg(TOE_GMAC0_DMA_BASE, offset);
++              case 1:
++                      return gmac_read_reg(TOE_GMAC1_DMA_BASE, offset);
++              default:
++                      return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_write_dma_reg
++*----------------------------------------------------------------------*/
++void mac_write_dma_reg(int mac, unsigned int offset, u32 data)
++{
++      switch (mac)
++      {
++              case 0:
++                      gmac_write_reg(TOE_GMAC0_DMA_BASE, offset, data, 0xffffffff);
++                      break;
++              case 1:
++                      gmac_write_reg(TOE_GMAC1_DMA_BASE, offset, data, 0xffffffff);
++                      break;
++      }
++}
++
++/*----------------------------------------------------------------------
++* ether_crc
++*----------------------------------------------------------------------*/
++static unsigned const ethernet_polynomial = 0x04c11db7U;
++static unsigned int ether_crc (int length, unsigned char *data)
++{
++      int crc = -1;
++      unsigned int i;
++      unsigned int crc_val=0;
++
++      while (--length >= 0) {
++              unsigned char current_octet = *data++;
++              int bit;
++              for (bit = 0; bit < 8; bit++, current_octet >>= 1)
++                      crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
++                           ethernet_polynomial : 0);
++      }
++      crc = ~crc;
++      for (i=0;i<32;i++)
++      {
++              crc_val = crc_val + (((crc << i) & 0x80000000) >> (31-i));
++      }
++      return crc_val;
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_set_rx_mode
++*----------------------------------------------------------------------*/
++void mac_set_rx_mode(int pid, unsigned int data)
++{
++      unsigned int    base;
++
++      base = (pid == 0) ? GMAC0_BASE : GMAC1_BASE;
++
++    gmac_write_reg(base, GMAC_RX_FLTR, data, 0x0000001f);
++    return;
++}
++
++
++/*----------------------------------------------------------------------
++* gmac_open
++*----------------------------------------------------------------------*/
++
++static int gmac_open (struct net_device *dev)
++{
++      GMAC_INFO_T  *tp = (GMAC_INFO_T *)dev->priv;
++      int                                     retval;
++      TOE_INFO_T                              *toe;
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++    /* hook ISR */
++      retval = request_irq (dev->irq, toe_gmac_interrupt, IRQF_DISABLED, dev->name, dev);
++      if (retval)
++              return retval;
++
++      toe_init_gmac(dev);
++
++      if(!FLAG_SWITCH)
++      {
++      init_waitqueue_head (&tp->thr_wait);
++      init_completion(&tp->thr_exited);
++
++      tp->time_to_die = 0;
++      tp->thr_pid = kernel_thread (gmac_phy_thread, dev, CLONE_FS | CLONE_FILES);
++      if (tp->thr_pid < 0)
++      {
++              printk (KERN_WARNING "%s: unable to start kernel thread\n",dev->name);
++      }
++    }
++
++      tp->operation = 1;
++
++      netif_start_queue (dev);
++
++      return (0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_close
++*----------------------------------------------------------------------*/
++static int gmac_close(struct net_device *dev)
++{
++    TOE_INFO_T                        *toe;
++//    GMAC_RXDESC_T           *sw_desc_ptr,*desc_ptr;
++//    unsigned int            buf_ptr;
++      GMAC_INFO_T     *tp = dev->priv;
++      unsigned int            ret;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      tp->operation = 0;
++
++    netif_stop_queue(dev);
++    mdelay(20);
++
++    /* stop tx/rx packet */
++    toe_gmac_disable_tx_rx(dev);
++    mdelay(20);
++
++    /* stop the chip's Tx and Rx DMA processes */
++      toe_gmac_hw_stop(dev);
++
++      toe_gmac_disable_interrupt(tp->irq);
++
++    /* disable interrupts by clearing the interrupt mask */
++    synchronize_irq();
++    free_irq(dev->irq,dev);
++
++//    DMA_MFREE(sw_desc_ptr, (TOE_SW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->sw_freeq_desc_base_dma);
++//    DMA_MFREE(desc_ptr, TOE_HW_FREEQ_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->hw_freeq_desc_base_dma);
++//    DMA_MFREE(buf_ptr, TOE_HW_FREEQ_DESC_NUM) * HW_RX_BUF_SIZE),(dma_addr_t *)&toe->hwfq_buf_base_dma);
++//    DMA_MFREE(toe->gmac[0].swtxq_desc_base , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].swtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].swtxq_desc_base , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_SW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].swtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[0].hwtxq_desc_base_dma , TOE_GMAC0_HWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].hwtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].hwtxq_desc_base_dma , TOE_GMAC0_SWTXQ_DESC_NUM * TOE_HW_TXQ_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].hwtxq_desc_base_dma);
++//    DMA_MFREE(toe->gmac[0].default_desc_base_dma ,TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[0].default_desc_base_dma);
++//    DMA_MFREE(toe->gmac[1].default_desc_base_dma , TOE_DEFAULT_Q0_DESC_NUM * sizeof(GMAC_TXDESC_T),(dma_addr_t *)&toe->gmac[1].default_desc_base_dma);
++//    DMA_MFREE(toe->intr_desc_base_dma , TOE_INTR_QUEUE_NUM * TOE_INTR_DESC_NUM * sizeof(GMAC_RXDESC_T),(dma_addr_t *)&toe->intr_desc_base_dma);
++//    DMA_MFREE(toe->intr_buf_base_dma , TOE_INTR_DESC_NUM * sizeof(TOE_QHDR_T),(dma_addr_t *)&toe->intr_buf_base_dma);
++
++      if(!FLAG_SWITCH)
++      {
++      if (tp->thr_pid >= 0)
++      {
++                  tp->time_to_die = 1;
++              wmb();
++              ret = kill_proc (tp->thr_pid, SIGTERM, 1);
++              if (ret)
++              {
++                      printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
++                      return ret;
++              }
++//                    wait_for_completion (&tp->thr_exited);
++      }
++    }
++
++    return (0);
++}
++
++/*----------------------------------------------------------------------
++* toe_gmac_fill_free_q
++* allocate buffers for free queue.
++*----------------------------------------------------------------------*/
++static inline void toe_gmac_fill_free_q(void)
++{
++      struct sk_buff  *skb;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      volatile GMAC_RXDESC_T  *fq_desc;
++      unsigned long   flags;
++      // unsigned short max_cnt=TOE_SW_FREEQ_DESC_NUM>>1;
++
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      spin_lock_irqsave(&gmac_fq_lock, flags);
++      //while ((max_cnt--) && (unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++      //                              TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
++      while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++                                      TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr) {
++              if ((skb = dev_alloc_skb(SW_RX_BUF_SIZE)) == NULL) {
++                      printk("%s::skb allocation fail!\n", __func__);
++                      //while(1);
++                      break;
++              }
++              REG32(skb->data) = (unsigned int)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++              // fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr,
++                      TOE_SW_FREEQ_DESC_NUM);
++              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base+fq_rwptr.bits.wptr;
++              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++              toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++      }
++      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++}
++// EXPORT_SYMBOL(toe_gmac_fill_free_q);
++
++/*----------------------------------------------------------------------
++* toe_gmac_interrupt
++*----------------------------------------------------------------------*/
++static irqreturn_t toe_gmac_interrupt (int irq, void *dev_instance)
++{
++      struct net_device   *dev = (struct net_device *)dev_instance;
++      TOE_INFO_T                      *toe;
++      GMAC_INFO_T             *tp = (GMAC_INFO_T *)dev->priv;
++      unsigned int            status0;
++      unsigned int            status1;
++      unsigned int            status2;
++      unsigned int            status3;
++      unsigned int            status4;
++
++//    struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      toe = (TOE_INFO_T *)&toe_private_data;
++//    handle NAPI
++#ifdef CONFIG_SL_NAPI
++if (storlink_ctl.pauseoff == 1)
++{
++/* disable GMAC interrupt */
++    //toe_gmac_disable_interrupt(tp->irq);
++
++//    isPtr->interrupts++;
++      /* read Interrupt status */
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      // prompt warning if status bit ON but not enabled
++#if 0
++      if (status0 & ~tp->intr0_enabled)
++              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
++                              status0, tp->intr0_enabled);
++      if (status1 & ~tp->intr1_enabled)
++              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
++                              status1, tp->intr1_enabled);
++      if (status2 & ~tp->intr2_enabled)
++              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
++                              status2, tp->intr2_enabled);
++      if (status3 & ~tp->intr3_enabled)
++              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
++                              status3, tp->intr3_enabled);
++      if (status4 & ~tp->intr4_enabled)
++              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
++                              status4, tp->intr4_enabled);
++#endif
++
++      if (status0)
++              writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
++      if (status1)
++              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
++      if (status2)
++              writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
++      if (status3)
++              writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
++      if (status4)
++              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++#if 0
++      /* handle freeq interrupt first */
++      if (status4 & tp->intr4_enabled) {
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
++                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
++                      printk("\nfreeq int\n");
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++              }
++      }
++#endif
++      // Interrupt Status 1
++      if (status1 & tp->intr1_enabled)
++      {
++              #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
++              #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
++              // Handle GMAC 0/1 HW Tx queue 0-3 EOF events
++              // Only count
++              // TOE, Classification, and default queues interrupts are handled by ISR
++              // because they should pass packets to upper layer
++              if (tp->port_id == 0)
++              {
++                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
++                      {
++                              if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ02_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ01_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++                      }
++                              if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
++                              {
++                                      if (likely(netif_rx_schedule_prep(dev)))
++                              {
++                                      unsigned int data32;
++                                      // disable GMAC-0 rx interrupt
++                                      // class-Q & TOE-Q are implemented in future
++                                      //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //data32 &= ~DEFAULT_Q0_INT_BIT;
++                                              //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                              //printk("\%s: DEFAULT_Q0_INT_BIT===================>>>>>>>>>>>>\n",__func__);
++                                              writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                              //tp->total_q_cnt_napi=0;
++                                              //rx_time = jiffies;
++                                              //rx_old_bytes = isPtr->rx_bytes;
++                              __netif_rx_schedule(dev);
++                              }
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
++                      {
++                              if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ12_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ11_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ10_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++                      }
++
++                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
++                      {
++                              if (likely(netif_rx_schedule_prep(dev)))
++                      {
++                              unsigned int data32;
++                              // disable GMAC-0 rx interrupt
++                              // class-Q & TOE-Q are implemented in future
++                              //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                              //data32 &= ~DEFAULT_Q1_INT_BIT;
++                                      //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //printk("\%s: 1111111111--->DEFAULT_Q1_INT_BIT===================>>>>>>>>>>>>\n",__func__);
++                                      writel(0x0, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++                                      //tp->total_q_cnt_napi=0;
++                                      //rx_time = jiffies;
++                                      //rx_old_bytes = isPtr->rx_bytes;
++                              __netif_rx_schedule(dev);
++                      }
++                      }
++              }
++      }
++
++      // Interrupt Status 0
++      if (status0 & tp->intr0_enabled)
++      {
++              #define ERR_INTR_BITS   (GMAC0_TXDERR_INT_BIT | GMAC0_TXPERR_INT_BIT |  \
++                                                               GMAC1_TXDERR_INT_BIT | GMAC1_TXPERR_INT_BIT |  \
++                                                               GMAC0_RXDERR_INT_BIT | GMAC0_RXPERR_INT_BIT |  \
++                                                               GMAC1_RXDERR_INT_BIT | GMAC1_RXPERR_INT_BIT)
++
++              if (status0 &  ERR_INTR_BITS)
++              {
++                      if ((status0 & GMAC0_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[0]++;
++                              printk("GMAC0 TX AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[0]++;
++                              printk("GMAC0 Tx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[1]++;
++                              printk("GMAC1 Tx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[1]++;
++                              printk("GMAC1 Tx Descriptor Protocol Error!\n");
++                      }
++
++                      if ((status0 & GMAC0_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[0]++;
++                              printk("GMAC0 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[0]++;
++                              printk("GMAC0 Rx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[1]++;
++                              printk("GMAC1 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[1]++;
++                              printk("GMAC1 Rx Descriptor Protocol Error!\n");
++                      }
++              }
++
++#ifndef       GMAX_TX_INTR_DISABLED
++              if (tp->port_id == 1 && netif_running(dev) &&
++                      (((status0 & GMAC1_SWTQ10_FIN_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC1_SWTQ10_EOF_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[1], 0, dev, 1);
++              }
++
++              if (tp->port_id == 0 && netif_running(dev) &&
++                      (((status0 & GMAC0_SWTQ00_FIN_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC0_SWTQ00_EOF_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
++              }
++#endif
++      }
++      // Interrupt Status 4
++      if (status4 & tp->intr4_enabled)
++      {
++              #define G1_INTR4_BITS           (0xff000000)
++              #define G0_INTR4_BITS           (0x00ff0000)
++
++              if (tp->port_id == 0)
++              {
++                      if ((status4 & G0_INTR4_BITS) && (tp->intr4_enabled & G0_INTR4_BITS))
++                      {
++                              if (status4 & GMAC0_RESERVED_INT_BIT)
++                                      printk("GMAC0_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC0_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_ON_INT_BIT)
++                                      tp->rx_pause_on_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_ON_INT_BIT)
++                                      tp->tx_pause_on_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
++                                      tp->rx_overrun_cnt++;
++                              if (status4 & GMAC0_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if ((status4 & G1_INTR4_BITS) && (tp->intr4_enabled & G1_INTR4_BITS))
++                      {
++                              if (status4 & GMAC1_RESERVED_INT_BIT)
++                                      printk("GMAC1_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC1_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC1_RX_PAUSE_ON_INT_BIT)
++                              {
++                                      printk("Gmac pause on\n");
++                                      tp->rx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_ON_INT_BIT)
++                              {
++                                      printk("Gmac pause on\n");
++                                      tp->tx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_PAUSE_OFF_INT_BIT)
++                              {
++                                      printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_OFF_INT_BIT)
++                              {
++                                      printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_OVERRUN_INT_BIT)
++                              {
++                                      //printk("Gmac Rx Overrun \n");
++                                      tp->rx_overrun_cnt++;
++                              }
++                              if (status4 & GMAC1_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++      }
++
++      //toe_gmac_enable_interrupt(tp->irq);
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++//     enable_irq(gmac_irq[dev_index]);
++      //printk("gmac_interrupt complete!\n\n");
++//    return IRQ_RETVAL(handled);
++      return  IRQ_RETVAL(1);
++}
++else
++{
++#endif        //endif NAPI
++
++
++      /* disable GMAC interrupt */
++    toe_gmac_disable_interrupt(tp->irq);
++
++//    isPtr->interrupts++;
++      /* read Interrupt status */
++      status0 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      status1 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      status2 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      status3 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++      // prompt warning if status bit ON but not enabled
++#if 0
++      if (status0 & ~tp->intr0_enabled)
++              printk("Intr 0 Status error. status = 0x%X, enable = 0x%X\n",
++                              status0, tp->intr0_enabled);
++      if (status1 & ~tp->intr1_enabled)
++              printk("Intr 1 Status error. status = 0x%X, enable = 0x%X\n",
++                              status1, tp->intr1_enabled);
++      if (status2 & ~tp->intr2_enabled)
++              printk("Intr 2 Status error. status = 0x%X, enable = 0x%X\n",
++                              status2, tp->intr2_enabled);
++      if (status3 & ~tp->intr3_enabled)
++              printk("Intr 3 Status error. status = 0x%X, enable = 0x%X\n",
++                              status3, tp->intr3_enabled);
++      if (status4 & ~tp->intr4_enabled)
++              printk("Intr 4 Status error. status = 0x%X, enable = 0x%X\n",
++                              status4, tp->intr4_enabled);
++#endif
++#define       INTERRUPT_SELECT                        1
++      if (status0)
++              writel(status0 & tp->intr0_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_0_REG);
++      if (status1)
++              writel(status1 & tp->intr1_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_1_REG);
++      if (status2)
++              writel(status2 & tp->intr2_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_2_REG);
++      if (status3)
++              writel(status3 & tp->intr3_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_3_REG);
++      if (status4)
++              writel(status4 & tp->intr4_enabled, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_STATUS_4_REG);
++
++      /* handle freeq interrupt first */
++      if (status4 & tp->intr4_enabled) {
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                      //      tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
++                      //      SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++                      if (toe->gmac[0].dev && netif_running(toe->gmac[0].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[0].dev,&toe->gmac[0]);
++                      if (toe->gmac[1].dev && netif_running(toe->gmac[1].dev))
++                              toe_gmac_handle_default_rxq(toe->gmac[1].dev,&toe->gmac[1]);
++                      printk("\nfreeq int\n");
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                              SWFQ_EMPTY_INT_BIT);
++              }
++      }
++
++      // Interrupt Status 1
++      if (status1 & tp->intr1_enabled)
++      {
++              #define G1_INTR0_BITS   (GMAC1_HWTQ13_EOF_INT_BIT | GMAC1_HWTQ12_EOF_INT_BIT | GMAC1_HWTQ11_EOF_INT_BIT | GMAC1_HWTQ10_EOF_INT_BIT)
++              #define G0_INTR0_BITS   (GMAC0_HWTQ03_EOF_INT_BIT | GMAC0_HWTQ02_EOF_INT_BIT | GMAC0_HWTQ01_EOF_INT_BIT | GMAC0_HWTQ00_EOF_INT_BIT)
++              // Handle GMAC 0/1 HW Tx queue 0-3 EOF events
++              // Only count
++              // TOE, Classification, and default queues interrupts are handled by ISR
++              // because they should pass packets to upper layer
++              if (tp->port_id == 0)
++              {
++#ifndef       INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & G0_INTR0_BITS) && (tp->intr1_enabled & G0_INTR0_BITS))
++                      {
++                              if (status1 & GMAC0_HWTQ03_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ02_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ01_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC0_HWTQ00_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++#endif        //INTERRUPT_SELECT
++#ifndef       INTERRUPT_SELECT
++                      }
++#endif        //INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & DEFAULT_Q0_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q0_INT_BIT))
++                      {
++                              tp->default_q_intr_cnt++;
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      }
++#ifdef CONFIG_SL351x_RXTOE
++                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
++                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
++                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
++                              toe_gmac_handle_toeq(dev, tp, status1);
++                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
++                      }
++#endif
++              }
++              else if (tp->port_id == 1)
++              {
++#ifndef       INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & G1_INTR0_BITS) && (tp->intr1_enabled & G1_INTR0_BITS))
++                      {
++                              if (status1 & GMAC1_HWTQ13_EOF_INT_BIT)
++                                      tp->hwtxq[3].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ12_EOF_INT_BIT)
++                                      tp->hwtxq[2].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ11_EOF_INT_BIT)
++                                      tp->hwtxq[1].eof_cnt++;
++                              if (status1 & GMAC1_HWTQ10_EOF_INT_BIT)
++                                      tp->hwtxq[0].eof_cnt++;
++#endif        //INTERRUPT_SELECT
++#ifndef       INTERRUPT_SELECT
++                      }
++#endif        //INTERRUPT_SELECT
++                      if (netif_running(dev) && (status1 & DEFAULT_Q1_INT_BIT) && (tp->intr1_enabled & DEFAULT_Q1_INT_BIT))
++                      {
++                              tp->default_q_intr_cnt++;
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      }
++#ifdef CONFIG_SL351x_RXTOE
++                      if (netif_running(dev) && (status1 & TOE_IQ_ALL_BITS) &&
++                          (tp->intr1_enabled & TOE_IQ_ALL_BITS)) {
++                              //printk("status %x, bits %x, slct %x\n", status1, TOE_IQ_ALL_BITS, tp->intr1_selected);
++                              toe_gmac_handle_toeq(dev, tp, status1);
++                              //toe_gmac_handle_toeq(dev, toe, tp, status1);
++                      }
++#endif
++              }
++      }
++
++
++      // Interrupt Status 0
++      if (status0 & tp->intr0_enabled)
++      {
++
++              #define ERR_INTR_BITS   (GMAC0_TXDERR_INT_BIT | GMAC0_TXPERR_INT_BIT |  \
++                                                               GMAC1_TXDERR_INT_BIT | GMAC1_TXPERR_INT_BIT |  \
++                                                               GMAC0_RXDERR_INT_BIT | GMAC0_RXPERR_INT_BIT |  \
++                                                               GMAC1_RXDERR_INT_BIT | GMAC1_RXPERR_INT_BIT)
++#ifndef       INTERRUPT_SELECT
++              if (status0 &  ERR_INTR_BITS)
++              {
++                      if ((status0 & GMAC0_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[0]++;
++                              printk("GMAC0 TX AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[0]++;
++                              printk("GMAC0 Tx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXDERR_INT_BIT))
++                      {
++                              tp->txDerr_cnt[1]++;
++                              printk("GMAC1 Tx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_TXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_TXPERR_INT_BIT))
++                      {
++                              tp->txPerr_cnt[1]++;
++                              printk("GMAC1 Tx Descriptor Protocol Error!\n");
++                      }
++
++                      if ((status0 & GMAC0_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[0]++;
++                              printk("GMAC0 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC0_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC0_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[0]++;
++                              printk("GMAC0 Rx Descriptor Protocol Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXDERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXDERR_INT_BIT))
++                      {
++                              tp->RxDerr_cnt[1]++;
++                              printk("GMAC1 Rx AHB Bus Error!\n");
++                      }
++                      if ((status0 & GMAC1_RXPERR_INT_BIT) && (tp->intr0_enabled & GMAC1_RXPERR_INT_BIT))
++                      {
++                              tp->RxPerr_cnt[1]++;
++                              printk("GMAC1 Rx Descriptor Protocol Error!\n");
++                      }
++              }
++#endif        //INTERRUPT_SELECT
++#ifndef       GMAX_TX_INTR_DISABLED
++              if (tp->port_id == 1 && netif_running(dev) &&
++                      (((status0 & GMAC1_SWTQ10_FIN_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC1_SWTQ10_EOF_INT_BIT) && (tp->intr0_enabled & GMAC1_SWTQ10_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[1], 0, dev, 1);
++              }
++
++              if (tp->port_id == 0 && netif_running(dev) &&
++                      (((status0 & GMAC0_SWTQ00_FIN_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_FIN_INT_BIT))
++                      ||
++                      ((status0 & GMAC0_SWTQ00_EOF_INT_BIT) && (tp->intr0_enabled & GMAC0_SWTQ00_EOF_INT_BIT))))
++              {
++                      toe_gmac_tx_complete(&toe_private_data.gmac[0], 0, dev, 1);
++              }
++#endif
++              // clear enabled status bits
++      }
++      // Interrupt Status 4
++#ifndef       INTERRUPT_SELECT
++      if (status4 & tp->intr4_enabled)
++      {
++              #define G1_INTR4_BITS           (0xff000000)
++              #define G0_INTR4_BITS           (0x00ff0000)
++
++              if (tp->port_id == 0)
++              {
++                      if ((status4 & G0_INTR4_BITS) && (tp->intr4_enabled & G0_INTR4_BITS))
++                      {
++                              if (status4 & GMAC0_RESERVED_INT_BIT)
++                                      printk("GMAC0_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC0_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_ON_INT_BIT)
++                                      tp->rx_pause_on_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_ON_INT_BIT)
++                                      tp->tx_pause_on_cnt++;
++                              if (status4 & GMAC0_RX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_TX_PAUSE_OFF_INT_BIT)
++                                      tp->rx_pause_off_cnt++;
++                              if (status4 & GMAC0_RX_OVERRUN_INT_BIT)
++                                      tp->rx_overrun_cnt++;
++                              if (status4 & GMAC0_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++              else if (tp->port_id == 1)
++              {
++                      if ((status4 & G1_INTR4_BITS) && (tp->intr4_enabled & G1_INTR4_BITS))
++                      {
++                              if (status4 & GMAC1_RESERVED_INT_BIT)
++                                      printk("GMAC1_RESERVED_INT_BIT is ON\n");
++                              if (status4 & GMAC1_MIB_INT_BIT)
++                                      tp->mib_full_cnt++;
++                              if (status4 & GMAC1_RX_PAUSE_ON_INT_BIT)
++                              {
++                                      //printk("Gmac pause on\n");
++                                      tp->rx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_ON_INT_BIT)
++                              {
++                                      //printk("Gmac pause on\n");
++                                      tp->tx_pause_on_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_PAUSE_OFF_INT_BIT)
++                              {
++                                      //printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_TX_PAUSE_OFF_INT_BIT)
++                              {
++                                      //printk("Gmac pause off\n");
++                                      tp->rx_pause_off_cnt++;
++                              }
++                              if (status4 & GMAC1_RX_OVERRUN_INT_BIT)
++                              {
++                                      //printk("Gmac Rx Overrun \n");
++                                      tp->rx_overrun_cnt++;
++                              }
++                              if (status4 & GMAC1_STATUS_CHANGE_INT_BIT)
++                                      tp->status_changed_cnt++;
++                      }
++              }
++#if 0
++              if ((status4 & SWFQ_EMPTY_INT_BIT) && (tp->intr4_enabled & SWFQ_EMPTY_INT_BIT))
++              {
++                      // unsigned long data = REG32(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++//                    mac_stop_rxdma(tp->sc);
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_ENABLE_4_REG,
++                              tp->intr4_enabled & ~SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG,
++                              SWFQ_EMPTY_INT_BIT, SWFQ_EMPTY_INT_BIT);
++                      toe_gmac_fill_free_q();
++                      tp->sw_fq_empty_cnt++;
++
++                      gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                              SWFQ_EMPTY_INT_BIT);
++//#if 0
++/*                    if (netif_running(dev))
++                              toe_gmac_handle_default_rxq(dev, tp);
++                      printk("SWFQ_EMPTY_INT_BIT is ON!\n");  // should not be happened */
++//#endif
++              }
++#endif
++      }
++#endif        //INTERRUPT_SELECT
++      toe_gmac_enable_interrupt(tp->irq);
++//enable gmac rx function when do RFC 2544
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 0;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++      //printk("gmac_interrupt complete!\n\n");
++//    return IRQ_RETVAL(handled);
++      return  IRQ_RETVAL(1);
++#ifdef CONFIG_SL_NAPI
++}
++#endif
++}
++
++/*----------------------------------------------------------------------
++*     toe_gmac_handle_default_rxq
++*     (1) Get rx Buffer for default Rx queue
++*     (2) notify or call upper-routine to handle it
++*     (3) get a new buffer and insert it into SW free queue
++*     (4) Note: The SW free queue Read-Write Pointer should be locked when accessing
++*----------------------------------------------------------------------*/
++//static inline void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
++static void toe_gmac_handle_default_rxq(struct net_device *dev, GMAC_INFO_T *tp)
++{
++      TOE_INFO_T                      *toe;
++    GMAC_RXDESC_T     *curr_desc;
++      struct sk_buff          *skb;
++    DMA_RWPTR_T                       rwptr;
++      unsigned int            pkt_size;
++      int                                     max_cnt;
++      unsigned int        desc_count;
++      unsigned int        good_frame, chksum_status, rx_status;
++      struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++
++//when do ixia RFC 2544 test and packet size is select 1518 bytes,disable gmace rx function immediately after one interrupt come in.
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++      {
++              GMAC_CONFIG0_T config0;
++              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 1;
++              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++              config0.bits.dis_rx = 1;
++              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++      }
++#endif
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++#if 0
++      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
++      {
++              mac_stop_txdma((struct net_device *)tp->dev);
++              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
++                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
++              while(1);
++      }
++#endif
++      toe = (TOE_INFO_T *)&toe_private_data;
++      max_cnt = DEFAULT_RXQ_MAX_CNT;
++      while ((--max_cnt) && rwptr.bits.rptr != rwptr.bits.wptr)
++//    while (rwptr.bits.rptr != rwptr.bits.wptr)
++      {
++//if packet size is not 1518 for RFC 2544,enable gmac rx function.The other packet size have RX workaround.
++#ifdef IxscriptMate_1518
++      if (storlink_ctl.pauseoff == 1)
++              {
++                      if (pkt_size != 1514)
++                      {
++                                              GMAC_CONFIG0_T config0;
++                                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                              config0.bits.dis_rx = 0;
++                                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                              config0.bits.dis_rx = 0;
++                                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++              }
++#endif
++      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++//            consistent_sync(curr_desc, sizeof(GMAC_RXDESC_T), PCI_DMA_FROMDEVICE);
++              tp->default_q_cnt++;
++      tp->rx_curr_desc = (unsigned int)curr_desc;
++      rx_status = curr_desc->word0.bits.status;
++      chksum_status = curr_desc->word0.bits.chksum_status;
++      tp->rx_status_cnt[rx_status]++;
++      tp->rx_chksum_cnt[chksum_status]++;
++        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
++              desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
++              good_frame=1;
++              if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
++                      || (pkt_size < 60)
++                  || (chksum_status & 0x4)
++                      || rx_status)
++              {
++                      good_frame = 0;
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
++                              printk("%s::derr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_perr)
++                              printk("%s::perr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (rx_status)
++                      {
++                              if (rx_status == 4 || rx_status == 7)
++                                      isPtr->rx_crc_errors++;
++//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
++                      }
++#ifdef SL351x_GMAC_WORKAROUND
++                      else if (pkt_size < 60)
++                      {
++                              if (tp->short_frames_cnt < GMAC_SHORT_FRAME_THRESHOLD)
++                                      tp->short_frames_cnt++;
++                              if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                              {
++                                      GMAC_CONFIG0_T config0;
++                                      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              }
++                      }
++#endif
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++              }
++              if (good_frame)
++              {
++                      if (curr_desc->word0.bits.drop)
++                              printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++
++              /* get frame information from the first descriptor of the frame */
++#ifdef SL351x_GMAC_WORKAROUND
++                      if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              GMAC_CONFIG0_T config0;
++                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++                      tp->short_frames_cnt = 0;
++#endif
++                      isPtr->rx_packets++;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr - SKB_RESERVE_BYTES)));
++                      if (!skb)
++                      {
++                              printk("Fatal Error!!skb==NULL\n");
++                              goto next_rx;
++                      }
++                      tp->curr_rx_skb = skb;
++                      // consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
++
++      //              curr_desc->word2.buf_adr = 0;
++
++                      skb_reserve (skb, RX_INSERT_BYTES);     /* 16 byte align the IP fields. */
++                      skb_put(skb, pkt_size);
++                      skb->dev = dev;
++                      if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++#if 0
++#ifdef CONFIG_SL351x_RXTOE
++                              if (storlink_ctl.rx_max_pktsize) {
++                                      struct iphdr    *ip_hdr;
++                                      struct tcphdr   *tcp_hdr;
++                                      int ip_hdrlen;
++
++                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
++                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
++                                              ip_hdrlen = ip_hdr->ihl << 2;
++                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++                                              if (tcp_hdr->syn) {
++                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
++                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
++                                                      TCP_SKB_CB(skb)->connection = connection;
++                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
++                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
++                                                      //                      __func__, skb->data, connection, connection->mode);
++                                              }
++                                      }
++                              }
++#endif
++#endif
++                      }
++                      else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr            *ip_hdr;
++                                      //struct tcphdr         *tcp_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      //tcp_hdr = (struct tcphdr *)&(skb->data[curr_desc->word3.bits.l4_offset]);
++                                      if (ip_hdr->protocol == IPPROTO_UDP)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                              tp->port_id,
++                                                                              (void *)curr_desc->word3.bits.l3_offset,
++                                                                              (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                                      else if (ip_hdr->protocol == IPPROTO_GRE)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      else
++                      {
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++
++                      netif_rx(skb);  /* socket rx */
++                      dev->last_rx = jiffies;
++
++                      isPtr->rx_bytes += pkt_size;
++
++        }
++
++next_rx:
++              // advance one for Rx default Q 0/1
++              rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      tp->rx_rwptr.bits32 = rwptr.bits32;
++
++              toe_gmac_fill_free_q();
++      }
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_phy_vendor
++*----------------------------------------------------------------------*/
++static unsigned int gmac_get_phy_vendor(int phy_addr)
++{
++    unsigned int      reg_val;
++    reg_val=(mii_read(phy_addr,0x02) << 16) + mii_read(phy_addr,0x03);
++    return reg_val;
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_phy_status
++*----------------------------------------------------------------------*/
++void gmac_set_phy_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_STATUS_T   status;
++      unsigned int    reg_val, ability,wan_port_id;
++      unsigned int    i = 0;
++
++#ifdef VITESSE_G5SWITCH
++      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1)){
++#if 0
++              rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
++              rcv_mask |= 0x4F;
++              for(i=0;i<4;i++){
++                      reg_val = BIT(26)|(i<<21)|(10<<16);
++                      SPI_write(3,0,1,reg_val);
++                      msleep(10);
++                      reg_val = SPI_read(3,0,2);
++                      if(reg_val & 0x0c00){
++                              printk("Port%d:Giga mode\n",i);
++                              SPI_write(1,i,0x00,0x300701B1);
++                              SPI_write(1,i,0x00,0x10070181);
++                              switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_1000;
++                      }
++                      else{
++                              reg_val = BIT(26)|(i<<21)|(5<<16);
++                              SPI_write(3,0,1,reg_val);
++                              msleep(10);
++                              ability = (reg_val = SPI_read(3,0,2)&0x5e0) >>5;
++                              if ((ability & 0x0C)) /* 100M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050472);
++                                      SPI_write(1,i,0x00,0x10050442);
++                                      printk("Port%d:100M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                              switch_pre_speed[i]=GMAC_SPEED_100;
++                              }
++                              else if((ability & 0x03)) /* 10M full duplex */
++                              {
++                                      SPI_write(1,i,0x00,0x30050473);
++                                      SPI_write(1,i,0x00,0x10050443);
++                                      printk("Port%d:10M\n",i);
++                                      switch_pre_link[i]=LINK_UP;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                              }
++                              else{
++                                      SPI_write(1,i,0x00,BIT(16));                    // disable RX
++                                      SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
++                                      while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
++                                              msleep(1);
++
++                                      SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
++                                      switch_pre_link[i]=LINK_DOWN;
++                                      switch_pre_speed[i]=GMAC_SPEED_10;
++                                      rcv_mask &= ~BIT(i);
++                                      SPI_write(2,0,0x10,rcv_mask);                   // Disable Receive
++                              }
++                      }
++              }
++#endif
++              gmac_get_switch_status(dev);
++              gmac_write_reg(tp->base_addr, GMAC_STATUS, 0x7d, 0x0000007f);
++//            SPI_write(2,0,0x10,rcv_mask);                   // Enable Receive
++              return ;
++      }
++#endif
++
++      reg_val = gmac_get_phy_vendor(tp->phy_addr);
++      printk("GMAC-%d Addr %d Vendor ID: 0x%08x\n", tp->port_id, tp->phy_addr, reg_val);
++
++      switch (tp->phy_mode)
++      {
++              case GMAC_PHY_GMII:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              #ifdef CONFIG_SL3516_ASIC
++              mii_write(tp->phy_addr,0x09,0x0300); /* advertise 1000M full/half duplex */
++              #else
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M full/half duplex */
++              #endif
++              break;
++              case GMAC_PHY_RGMII_100:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M */
++              break;
++              case GMAC_PHY_RGMII_1000:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              #ifdef CONFIG_SL3516_ASIC
++              mii_write(tp->phy_addr,0x09,0x0300); /* advertise 1000M full/half duplex */
++              #else
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M full/half duplex */
++              #endif
++              break;
++              case GMAC_PHY_MII:
++              default:
++              mii_write(tp->phy_addr,0x04,0x05e1); /* advertisement 100M full duplex, pause capable on */
++              mii_write(tp->phy_addr,0x09,0x0000); /* advertise no 1000M */
++              break;
++      }
++
++      mii_write(tp->phy_addr,0x18,0x0041);    // Phy active led
++      if (tp->auto_nego_cfg)
++      {
++              reg_val = 0x1200 | (1 << 15);
++              mii_write(tp->phy_addr,0x00,reg_val); /* Enable and Restart Auto-Negotiation */
++              mdelay(500);
++              reg_val &= ~(1 << 15);
++              mii_write(tp->phy_addr, 0x00, reg_val);
++      }
++      else
++      {
++              reg_val = 0;
++              reg_val |= (tp->full_duplex_cfg) ? (1 << 8) : 0;
++              reg_val |= (tp->speed_cfg == GMAC_SPEED_1000) ? (1 << 6) : 0;
++              reg_val |= (tp->speed_cfg == GMAC_SPEED_100) ? (1 << 13) : 0;
++              mii_write(tp->phy_addr, 0x00, reg_val);
++              mdelay(100);
++
++              reg_val |= (1 << 15);   // Reset PHY;
++              mii_write(tp->phy_addr, 0x00, reg_val);
++      }
++
++      status.bits32 = 0;
++      /* set PHY operation mode */
++      status.bits.mii_rmii = tp->phy_mode;
++      status.bits.reserved = 1;
++      mdelay(100);
++      while (((reg_val=mii_read(tp->phy_addr,0x01)) & 0x00000004)!=0x04)
++      {
++              msleep(100);
++              i++;
++              if (i > 30)
++              break;
++      }
++      if (i>30)
++      {
++              tp->pre_phy_status = LINK_DOWN;
++              status.bits.link = LINK_DOWN;
++              //              clear_bit(__LINK_STATE_START, &dev->state);
++              printk("Link Down (0x%04x) ", reg_val);
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 0;
++#endif
++              }
++              else
++              {
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ tp->port_id] = 0;
++#endif
++              }
++      }
++      else
++      {
++              tp->pre_phy_status = LINK_UP;
++              status.bits.link = LINK_UP;
++              //              set_bit(__LINK_STATE_START, &dev->state);
++              printk("Link Up (0x%04x) ",reg_val);
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 1;
++#endif
++              }
++              else
++              {
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ tp->port_id] = 1;
++#endif
++              }
++      }
++      //    value = mii_read(PHY_ADDR,0x05);
++
++      ability = (mii_read(tp->phy_addr,0x05) & 0x05E0) >> 5;
++
++      //#ifdef CONFIG_SL3516_ASIC
++      reg_val = mii_read(tp->phy_addr,10);
++      printk("MII REG 10 = 0x%x\n",reg_val);
++
++      if ((reg_val & 0x0800) == 0x0800)
++      {
++              status.bits.duplex = 1;
++              status.bits.speed = 2;
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++
++              printk(" 1000M/Full \n");
++      }
++      else if ((reg_val & 0x0400) == 0x0400)
++      {
++              status.bits.duplex = 0;
++              status.bits.speed = 2;
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++
++              printk(" 1000M/Half \n");
++      }
++      //#endif
++      else
++      {
++              #ifdef CONFIG_SL3516_ASIC
++              if (status.bits.mii_rmii == GMAC_PHY_RGMII_1000)
++              status.bits.mii_rmii = GMAC_PHY_RGMII_100;
++              #endif
++              printk("MII REG 5 (bit 5:15) = 0x%x\n", ability);
++              if ((ability & 0x08)==0x08) /* 100M full duplex */
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 1;
++                      printk(" 100M/Full\n");
++
++              }
++              else if ((ability & 0x04)==0x04) /* 100M half duplex */
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 1;
++                      printk(" 100M/Half\n");
++
++              }
++              else if ((ability & 0x02)==0x02) /* 10M full duplex */
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 0;
++                      printk(" 10M/Full\n");
++
++              }
++              else if ((ability & 0x01)==0x01) /* 10M half duplex */
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 0;
++                      printk(" 10M/Half\n");
++
++              }
++      }
++      if ((ability & 0x20)==0x20)
++      {
++              tp->flow_control_enable = 1;
++              printk("Flow Control Enable.\n");
++      }
++      else
++      {
++              tp->flow_control_enable = 0;
++              printk("Flow Control Disable.\n");
++      }
++      tp->full_duplex_status = status.bits.duplex;
++      tp->speed_status = status.bits.speed;
++      if (!tp->auto_nego_cfg)
++      {
++              status.bits.duplex = tp->full_duplex_cfg;
++              status.bits.speed = tp->speed_cfg;
++      }
++      toe_gmac_disable_tx_rx(dev);
++      mdelay(10);
++      gmac_write_reg(tp->base_addr, GMAC_STATUS, status.bits32, 0x0000007f);
++      toe_gmac_enable_tx_rx(dev);
++}
++
++/*----------------------------------------------------------------------
++* gmac_phy_thread
++*----------------------------------------------------------------------*/
++static int gmac_phy_thread (void *data)
++{
++      struct net_device   *dev = data;
++      GMAC_INFO_T *tp = dev->priv;
++      unsigned long       timeout;
++
++    daemonize("%s", dev->name);
++      allow_signal(SIGTERM);
++//    reparent_to_init();
++//    spin_lock_irq(&current->sigmask_lock);
++//    sigemptyset(&current->blocked);
++//    recalc_sigpending(current);
++//    spin_unlock_irq(&current->sigmask_lock);
++//    strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
++//    current->comm[sizeof(current->comm) - 1] = '\0';
++
++      while (1)
++      {
++          timeout = next_tick;
++              do
++              {
++                      timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
++              } while (!signal_pending (current) && (timeout > 0));
++
++              if (signal_pending (current))
++              {
++//                    spin_lock_irq(&current->sigmask_lock);
++                      flush_signals(current);
++//                    spin_unlock_irq(&current->sigmask_lock);
++              }
++
++              if (tp->time_to_die)
++                      break;
++
++              // printk("%s : Polling MAC %d PHY Status...\n",__func__, tp->port_id);
++              rtnl_lock ();
++              if (tp->auto_nego_cfg){
++#ifdef VITESSE_G5SWITCH
++                      if((tp->port_id == GMAC_PORT1)&&(Giga_switch==1))
++                              gmac_get_switch_status(dev);
++                      else
++#endif
++                              gmac_get_phy_status(dev); //temp remove
++              }
++              rtnl_unlock ();
++      }
++      complete_and_exit (&tp->thr_exited, 0);
++}
++
++/*----------------------------------------------------------------------
++* gmac_get_switch_status
++*----------------------------------------------------------------------*/
++#ifdef VITESSE_G5SWITCH
++void gmac_get_switch_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      unsigned int    switch_port_id;
++      int get_link=0;
++
++      get_link = Get_Set_port_status();
++      if(get_link){                           // link
++              if(ever_dwon){
++                      ever_dwon = 0;
++                      toe_gmac_enable_tx_rx(dev);
++                      netif_wake_queue(dev);
++                      set_bit(__LINK_STATE_START, &dev->state);
++              }
++      }
++      else{                                   // all down
++              //printk("All link down\n");
++              ever_dwon=1;
++              netif_stop_queue(dev);
++              toe_gmac_disable_tx_rx(dev);
++              clear_bit(__LINK_STATE_START, &dev->state);
++      }
++
++      if ( tp->port_id == 1 )
++              switch_port_id = 0;
++#ifdef CONFIG_SL351x_SYSCTL
++      if (get_link)
++      {
++              storlink_ctl.link[switch_port_id] = 1;
++      }
++      else
++      {
++              storlink_ctl.link[switch_port_id] = 0;
++      }
++      if (storlink_ctl.pauseoff == 1)
++              {
++                      if (tp->flow_control_enable == 1)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("Disable SWITCH Flow Control...\n");
++                      }
++                              tp->flow_control_enable = 0;
++              }
++              else
++#endif
++              {
++                      if (tp->flow_control_enable == 0)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("Enable SWITCH Flow Control...\n");
++                      }
++                      tp->flow_control_enable = 1;
++              }
++      return ;
++
++}
++#endif
++
++/*----------------------------------------------------------------------
++* gmac_get_phy_status
++*----------------------------------------------------------------------*/
++void gmac_get_phy_status(struct net_device *dev)
++{
++      GMAC_INFO_T *tp = dev->priv;
++      GMAC_CONFIG0_T  config0,config0_mask;
++      GMAC_STATUS_T   status, old_status;
++      unsigned int    reg_val,ability,wan_port_id;
++
++      old_status.bits32 = status.bits32 = gmac_read_reg(tp->base_addr, GMAC_STATUS);
++
++
++      /* read PHY status register */
++      reg_val = mii_read(tp->phy_addr,0x01);
++      if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++      {
++              ability = (mii_read(tp->phy_addr,0x05) & 0x05E0) >> 5;
++              /* read PHY Auto-Negotiation Link Partner Ability Register */
++              #ifdef CONFIG_SL3516_ASIC
++              reg_val = mii_read(tp->phy_addr,10);
++              if ((reg_val & 0x0800) == 0x0800)
++              {
++                      status.bits.duplex = 1;
++                      status.bits.speed = 2;
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++              }
++              else if ((reg_val & 0x0400) == 0x0400)
++              {
++                      status.bits.duplex = 0;
++                      status.bits.speed = 2;
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_100)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_1000;
++              }
++              else
++              #endif
++              {
++                      #ifdef CONFIG_SL3516_ASIC
++                      if (status.bits.mii_rmii == GMAC_PHY_RGMII_1000)
++                      status.bits.mii_rmii = GMAC_PHY_RGMII_100;
++                      #endif
++                      if ((ability & 0x08)==0x08) /* 100M full duplex */
++                      {
++                              status.bits.duplex = 1;
++                              status.bits.speed = 1;
++                      }
++                      else if ((ability & 0x04)==0x04) /* 100M half duplex */
++                      {
++                              status.bits.duplex = 0;
++                              status.bits.speed = 1;
++                      }
++                      else if ((ability & 0x02)==0x02) /* 10M full duplex */
++                      {
++                              status.bits.duplex = 1;
++                              status.bits.speed = 0;
++                      }
++                      else if ((ability & 0x01)==0x01) /* 10M half duplex */
++                      {
++                              status.bits.duplex = 0;
++                              status.bits.speed = 0;
++                      }
++              }
++              status.bits.link = LINK_UP; /* link up */
++              if(Giga_switch==1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 1;
++              }
++              else
++              {
++                              storlink_ctl.link[ tp->port_id] = 1;
++#endif
++              }
++              if ((ability & 0x20)==0x20)
++              {
++                      if (tp->flow_control_enable == 0)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 1; /* enable tx flow control */
++                              config0.bits.rx_fc_en = 1; /* enable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("GMAC-%d Flow Control Enable.\n", tp->port_id);
++                      }
++                      tp->flow_control_enable = 1;
++              }
++              else
++              {
++                      if (tp->flow_control_enable == 1)
++                      {
++                              config0.bits32 = 0;
++                              config0_mask.bits32 = 0;
++                              config0.bits.tx_fc_en = 0; /* disable tx flow control */
++                              config0.bits.rx_fc_en = 0; /* disable rx flow control */
++                              config0_mask.bits.tx_fc_en = 1;
++                              config0_mask.bits.rx_fc_en = 1;
++                              gmac_write_reg(tp->base_addr, GMAC_CONFIG0,config0.bits32,config0_mask.bits32);
++                              printk("GMAC-%d Flow Control Disable.\n", tp->port_id);
++                      }
++                      tp->flow_control_enable = 0;
++              }
++
++              if (tp->pre_phy_status == LINK_DOWN)
++              {
++                      printk("GMAC-%d LINK_UP......\n",tp->port_id);
++                      tp->pre_phy_status = LINK_UP;
++              }
++      }
++      else
++      {
++              status.bits.link = LINK_DOWN; /* link down */
++              if(Giga_switch == 1)
++              {
++                              wan_port_id = 1;
++#ifdef CONFIG_SL351x_SYSCTL
++                              storlink_ctl.link[ wan_port_id] = 0;
++              }
++              else
++              {
++                              storlink_ctl.link[ tp->port_id] = 0;
++#endif
++              }
++              if (tp->pre_phy_status == LINK_UP)
++              {
++                      printk("GMAC-%d LINK_Down......\n",tp->port_id);
++                      tp->pre_phy_status = LINK_DOWN;
++              }
++      }
++
++      tp->full_duplex_status = status.bits.duplex;
++      tp->speed_status = status.bits.speed;
++      if (!tp->auto_nego_cfg)
++      {
++              status.bits.duplex = tp->full_duplex_cfg;
++              status.bits.speed = tp->speed_cfg;
++      }
++
++      if (old_status.bits32 != status.bits32)
++      {
++              netif_stop_queue(dev);
++              toe_gmac_disable_tx_rx(dev);
++              clear_bit(__LINK_STATE_START, &dev->state);
++              printk("GMAC-%d Change Status Bits 0x%x-->0x%x\n",tp->port_id, old_status.bits32, status.bits32);
++              mdelay(10); // let GMAC consume packet
++              gmac_write_reg(tp->base_addr, GMAC_STATUS, status.bits32, 0x0000007f);
++              if (status.bits.link == LINK_UP)
++              {
++                      toe_gmac_enable_tx_rx(dev);
++                      netif_wake_queue(dev);
++                      set_bit(__LINK_STATE_START, &dev->state);
++              }
++      }
++}
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_BASE_ADDR  (IO_ADDRESS(SL2312_GPIO_BASE))
++#define GPIO_BASE_ADDR1  (IO_ADDRESS(SL2312_GPIO_BASE1))
++
++/* define GPIO pin for MDC/MDIO */
++#ifdef CONFIG_SL3516_ASIC
++#define H_MDC_PIN           22
++#define H_MDIO_PIN          21
++#define G_MDC_PIN           22
++#define G_MDIO_PIN          21
++#else
++#define H_MDC_PIN           3
++#define H_MDIO_PIN          2
++#define G_MDC_PIN           0
++#define G_MDIO_PIN          1
++#endif
++
++//#define GPIO_MDC             0x80000000
++//#define GPIO_MDIO            0x00400000
++
++static unsigned int GPIO_MDC = 0;
++static unsigned int GPIO_MDIO = 0;
++static unsigned int GPIO_MDC_PIN = 0;
++static unsigned int GPIO_MDIO_PIN = 0;
++
++// For PHY test definition!!
++#define LPC_EECK              0x02
++#define LPC_EDIO              0x04
++#define LPC_GPIO_SET          3
++#define LPC_BASE_ADDR         IO_ADDRESS(IT8712_IO_BASE)
++#define inb_gpio(x)           inb(LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++#define outb_gpio(x, y)               outb(y, LPC_BASE_ADDR + IT8712_GPIO_BASE + x)
++
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++/***********************/
++/*    MDC : GPIO[31]   */
++/*    MDIO: GPIO[22]   */
++/***********************/
++
++/***************************************************
++* All the commands should have the frame structure:
++*<PRE><ST><OP><PHYAD><REGAD><TA><DATA><IDLE>
++****************************************************/
++
++/*****************************************************************
++* Inject a bit to NWay register through CSR9_MDC,MDIO
++*******************************************************************/
++void mii_serial_write(char bit_MDO) // write data into mii PHY
++{
++#ifdef CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode |= (LPC_EECK|LPC_EDIO) ;                         // Set EECK,EDIO,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      if(bit_MDO)
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status |= LPC_EDIO ;            //EDIO high
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++      else
++      {
++              status = inb_gpio( LPC_GPIO_SET);
++              status &= ~(LPC_EDIO) ;         //EDIO low
++              outb_gpio(LPC_GPIO_SET, status);
++      }
++
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++#else
++    unsigned int addr;
++    unsigned int value;
++
++    addr = GPIO_BASE_ADDR + GPIO_PIN_DIR;
++    value = readl(addr) | GPIO_MDC | GPIO_MDIO; /* set MDC/MDIO Pin to output */
++    writel(value,addr);
++    if(bit_MDO)
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDIO,addr); /* set MDIO to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++    else
++    {
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDIO,addr); /* set MDIO to 0 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_SET);
++        writel(GPIO_MDC,addr); /* set MDC to 1 */
++        addr = (GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++        writel(GPIO_MDC,addr); /* set MDC to 0 */
++    }
++
++#endif
++}
++
++/**********************************************************************
++* read a bit from NWay register through CSR9_MDC,MDIO
++***********************************************************************/
++unsigned int mii_serial_read(void) // read data from mii PHY
++{
++#ifdef CONFIG_SL2312_LPC_IT8712
++      unsigned char iomode,status;
++      unsigned int value ;
++
++      iomode = LPCGetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET);
++      iomode &= ~(LPC_EDIO) ;         // Set EDIO input
++      iomode |= (LPC_EECK) ;          // Set EECK,EECS output
++      LPCSetConfig(LDN_GPIO, 0xc8 + LPC_GPIO_SET, iomode);
++
++      status = inb_gpio( LPC_GPIO_SET);
++      status |= LPC_EECK ;            //EECK high
++      outb_gpio(LPC_GPIO_SET, status);
++
++      status &= ~(LPC_EECK) ;         //EECK low
++      outb_gpio(LPC_GPIO_SET, status);
++
++      value = inb_gpio( LPC_GPIO_SET);
++
++      value = value>>2 ;
++      value &= 0x01;
++
++      return value ;
++
++#else
++    unsigned int *addr;
++    unsigned int value;
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_PIN_DIR);
++    value = readl(addr) & ~GPIO_MDIO; //0xffbfffff;   /* set MDC to output and MDIO to input */
++    writel(value,addr);
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_SET);
++    writel(GPIO_MDC,addr); /* set MDC to 1 */
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_CLEAR);
++    writel(GPIO_MDC,addr); /* set MDC to 0 */
++
++    addr = (unsigned int *)(GPIO_BASE_ADDR + GPIO_DATA_IN);
++    value = readl(addr);
++    value = (value & (1<<GPIO_MDIO_PIN)) >> GPIO_MDIO_PIN;
++    return(value);
++
++#endif
++}
++
++/***************************************
++* preamble + ST
++***************************************/
++void mii_pre_st(void)
++{
++    unsigned char i;
++
++    for(i=0;i<32;i++) // PREAMBLE
++        mii_serial_write(1);
++    mii_serial_write(0); // ST
++    mii_serial_write(1);
++}
++
++
++/******************************************
++* Read MII register
++* phyad -> physical address
++* regad -> register address
++***************************************** */
++unsigned int mii_read(unsigned char phyad,unsigned char regad)
++{
++    unsigned int i,value;
++    unsigned int bit;
++
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(1); // OP
++    mii_serial_write(0);
++
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    mii_serial_read(); // TA_Z
++//    if((bit=mii_serial_read()) !=0 ) // TA_0
++//    {
++//        return(0);
++//    }
++    value=0;
++    for (i=0;i<16;i++) { // READ DATA
++        bit=mii_serial_read();
++        value += (bit<<(15-i)) ;
++    }
++
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++
++      //printk("%s: phy_addr=0x%x reg_addr=0x%x value=0x%x \n",__func__,phyad,regad,value);
++    return(value);
++}
++
++/******************************************
++* Write MII register
++* phyad -> physical address
++* regad -> register address
++* value -> value to be write
++***************************************** */
++void mii_write(unsigned char phyad,unsigned char regad,unsigned int value)
++{
++    unsigned int i;
++    char bit;
++
++      printk("%s: phy_addr=0x%x reg_addr=0x%x value=0x%x \n",__func__,phyad,regad,value);
++    if (phyad == GPHY_ADDR)
++    {
++        GPIO_MDC_PIN = G_MDC_PIN;   /* assigned MDC pin for giga PHY */
++        GPIO_MDIO_PIN = G_MDIO_PIN; /* assigned MDIO pin for giga PHY */
++    }
++    else
++    {
++        GPIO_MDC_PIN = H_MDC_PIN;   /* assigned MDC pin for 10/100 PHY */
++        GPIO_MDIO_PIN = H_MDIO_PIN; /* assigned MDIO pin for 10/100 PHY */
++    }
++    GPIO_MDC = (1<<GPIO_MDC_PIN);
++    GPIO_MDIO = (1<<GPIO_MDIO_PIN);
++
++    mii_pre_st(); // PRE+ST
++    mii_serial_write(0); // OP
++    mii_serial_write(1);
++    for (i=0;i<5;i++) { // PHYAD
++        bit= ((phyad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++
++    for (i=0;i<5;i++) { // REGAD
++        bit= ((regad>>(4-i)) & 0x01) ? 1 :0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(1); // TA_1
++    mii_serial_write(0); // TA_0
++
++    for (i=0;i<16;i++) { // OUT DATA
++        bit= ((value>>(15-i)) & 0x01) ? 1 : 0 ;
++        mii_serial_write(bit);
++    }
++    mii_serial_write(0); // dumy clock
++    mii_serial_write(0); // dumy clock
++}
++
++/*----------------------------------------------------------------------
++* gmac_set_rx_mode
++*----------------------------------------------------------------------*/
++static void gmac_set_rx_mode(struct net_device *dev)
++{
++    GMAC_RX_FLTR_T      filter;
++      unsigned int        mc_filter[2];       /* Multicast hash filter */
++    int                 bit_nr;
++      unsigned int        i;
++      GMAC_INFO_T             *tp = dev->priv;
++
++//    printk("%s : dev->flags = %x \n",__func__,dev->flags);
++//    dev->flags |= IFF_ALLMULTI;  /* temp */
++    filter.bits32 = 0;
++    filter.bits.error = 0;
++      if (dev->flags & IFF_PROMISC)
++      {
++          filter.bits.error = 1;
++        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else if (dev->flags & IFF_ALLMULTI)
++      {
++//        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0xffffffff;
++      }
++      else
++      {
++              struct dev_mc_list *mclist;
++
++//        filter.bits.promiscuous = 1;
++        filter.bits.broadcast = 1;
++        filter.bits.multicast = 1;
++        filter.bits.unicast = 1;
++              mc_filter[1] = mc_filter[0] = 0;
++              for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;i++, mclist = mclist->next)
++              {
++            bit_nr = ether_crc(ETH_ALEN,mclist->dmi_addr) & 0x0000003f;
++            if (bit_nr < 32)
++            {
++                mc_filter[0] = mc_filter[0] | (1<<bit_nr);
++            }
++            else
++            {
++                mc_filter[1] = mc_filter[1] | (1<<(bit_nr-32));
++            }
++              }
++      }
++    gmac_write_reg(tp->base_addr,GMAC_RX_FLTR,filter.bits32,0xffffffff);  //chech base address!!!
++    gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL0,mc_filter[0],0xffffffff);
++    gmac_write_reg(tp->base_addr,GMAC_MCAST_FIL1,mc_filter[1],0xffffffff);
++    return;
++}
++
++#ifdef CONFIG_SL_NAPI
++/*----------------------------------------------------------------------
++* gmac_rx_poll
++*----------------------------------------------------------------------*/
++static int gmac_rx_poll(struct net_device *dev, int *budget)
++{
++      TOE_INFO_T                      *toe;
++    GMAC_RXDESC_T     *curr_desc;
++      struct sk_buff          *skb;
++    DMA_RWPTR_T                       rwptr;
++      unsigned int            pkt_size;
++      unsigned int        desc_count;
++      unsigned int        good_frame, chksum_status, rx_status;
++      int                 rx_pkts_num = 0;
++      int                 quota = min(dev->quota, *budget);
++      GMAC_INFO_T                     *tp = (GMAC_INFO_T *)dev->priv;
++      unsigned int            status4;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      int                                     max_cnt = TOE_SW_FREEQ_DESC_NUM;//TOE_SW_FREEQ_DESC_NUM = 64
++      //unsigned long         rx_old_bytes;
++      struct net_device_stats *isPtr = (struct net_device_stats *)&tp->ifStatics;
++      //unsigned long long    rx_time;
++
++
++
++#if 1
++      if (do_again)
++      {
++                      toe_gmac_fill_free_q();
++                      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++                      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                      //printk("\n%s:: do_again toe_gmac_fill_free_q =======>status4=0x%x =====fq_rwptr =0x%8x======>JKJKJKJKJKJKJKJKJ \n", __func__,status4,fq_rwptr.bits32);
++                      if (fq_rwptr.bits.wptr != fq_rwptr.bits.rptr)
++                      {
++                                              //status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++                                              do_again =0;
++                                              //netif_rx_complete(dev);
++                                              gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4, 0x1);
++                                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                                              rwptr.bits32 = readl(&tp->default_qhdr->word1);
++                      }
++                      else
++                              return 1;
++      }
++#endif
++      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++#if 0
++      if (rwptr.bits.rptr != tp->rx_rwptr.bits.rptr)
++      {
++              mac_stop_txdma((struct net_device *)tp->dev);
++              printk("Default Queue HW RD ptr (0x%x) != SW RD Ptr (0x%x)\n",
++                              rwptr.bits32, tp->rx_rwptr.bits.rptr);
++              while(1);
++      }
++#endif
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      //printk("%s:---Before-------------->Default Queue HW RW ptr (0x%8x),   fq_rwptr =0x%8x \n",__func__,rwptr.bits32,fq_rwptr.bits32 );
++      //printk("%s:---Before while   rx_pkts_num=%d------rx_finished_idx=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rx_finished_idx,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++//    while ((--max_cnt) && (rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
++
++      while ((rwptr.bits.rptr != rwptr.bits.wptr) && (rx_pkts_num < quota))
++      {
++
++      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++              tp->default_q_cnt++;
++      tp->rx_curr_desc = (unsigned int)curr_desc;
++      rx_status = curr_desc->word0.bits.status;
++      chksum_status = curr_desc->word0.bits.chksum_status;
++      tp->rx_status_cnt[rx_status]++;
++      tp->rx_chksum_cnt[chksum_status]++;
++        pkt_size = curr_desc->word1.bits.byte_count;  /*total byte count in a frame*/
++              desc_count = curr_desc->word0.bits.desc_count; /* get descriptor count per frame */
++              good_frame=1;
++              if ((curr_desc->word0.bits32 & (GMAC_RXDESC_0_T_derr | GMAC_RXDESC_0_T_perr))
++                      || (pkt_size < 60)
++                  || (chksum_status & 0x4)
++                  || rx_status )
++//                    || rx_status || (rwptr.bits.rptr > rwptr.bits.wptr ))
++              {
++                      good_frame = 0;
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_derr)
++                              printk("%s::derr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (curr_desc->word0.bits32 & GMAC_RXDESC_0_T_perr)
++                              printk("%s::perr (GMAC-%d)!!!\n", __func__, tp->port_id);
++                      if (rx_status)
++                      {
++                              if (rx_status == 4 || rx_status == 7)
++                                      isPtr->rx_crc_errors++;
++//                            printk("%s::Status=%d (GMAC-%d)!!!\n", __func__, rx_status, tp->port_id);
++                      }
++#ifdef SL351x_GMAC_WORKAROUND
++                      else if (pkt_size < 60)
++                      {
++                              if (tp->short_frames_cnt < GMAC_SHORT_FRAME_THRESHOLD)
++                                      tp->short_frames_cnt++;
++                              if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                              {
++                                      GMAC_CONFIG0_T config0;
++                                      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                                      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                                      config0.bits.dis_rx = 1;
++                                      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              }
++                      }
++#endif
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++              }
++              if (good_frame)
++              {
++                      if (curr_desc->word0.bits.drop)
++                              printk("%s::Drop (GMAC-%d)!!!\n", __func__, tp->port_id);
++//                    if (chksum_status)
++//                            printk("%s::Checksum Status=%d (GMAC-%d)!!!\n", __func__, chksum_status, tp->port_id);
++
++#ifdef SL351x_GMAC_WORKAROUND
++                      if (tp->short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              GMAC_CONFIG0_T config0;
++                              config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              config0.bits.dis_rx = 0;
++                              writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                      }
++                      tp->short_frames_cnt = 0;
++#endif
++              /* get frame information from the first descriptor of the frame */
++                      isPtr->rx_packets++;
++                      //consistent_sync((void *)__va(curr_desc->word2.buf_adr), pkt_size, PCI_DMA_FROMDEVICE);
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      tp->curr_rx_skb = skb;
++      //              curr_desc->word2.buf_adr = 0;
++
++                  //skb_reserve (skb, SKB_RESERVE_BYTES);
++                      skb_reserve (skb, RX_INSERT_BYTES);     /* 2 byte align the IP fields. */
++                      //if ((skb->tail+pkt_size) > skb->end )
++                      //printk("%s::------------->Here skb->len=%d,pkt_size= %d,skb->head=0x%x,skb->tail= 0x%x, skb->end= 0x%x\n", __func__, skb->len, pkt_size,skb->head,skb->tail,skb->end);
++                      skb_put(skb, pkt_size);
++
++
++                      skb->dev = dev;
++                      if (chksum_status == RX_CHKSUM_IP_UDP_TCP_OK)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++#if 0
++#ifdef CONFIG_SL351x_RXTOE
++                              if (storlink_ctl.rx_max_pktsize) {
++                                      struct iphdr    *ip_hdr;
++                                      struct tcphdr   *tcp_hdr;
++                                      int ip_hdrlen;
++
++                                      ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if ((skb->protocol == __constant_htons(ETH_P_IP)) &&
++                                         ((ip_hdr->protocol & 0x00ff) == IPPROTO_TCP)) {
++                                              ip_hdrlen = ip_hdr->ihl << 2;
++                                              tcp_hdr = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++                                              if (tcp_hdr->syn) {
++                                                      struct toe_conn* connection = init_toeq(ip_hdr->version,
++                                                                      ip_hdr, tcp_hdr, toe, &(skb->data[0]) - 14);
++                                                      TCP_SKB_CB(skb)->connection = connection;
++                                                      //      hash_dump_entry(TCP_SKB_CB(skb)->connection->hash_entry_index);
++                                                      //              printk("%s::skb data %x, conn %x, mode %x\n",
++                                                      //                      __func__, skb->data, connection, connection->mode);
++                                              }
++                                      }
++                              }
++#endif
++#endif
++                      }
++                      else if (chksum_status == RX_CHKSUM_IP_OK_ONLY)
++                      {
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++#ifdef CONFIG_SL351x_NAT
++                              if (nat_cfg.enabled && curr_desc->word3.bits.l3_offset && curr_desc->word3.bits.l4_offset)
++                              {
++                                      struct iphdr    *ip_hdr;
++                                      ip_hdr = (struct iphdr *)&(skb->data[curr_desc->word3.bits.l3_offset]);
++                                      if (ip_hdr->protocol == IPPROTO_UDP)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                              tp->port_id,
++                                                                              (void *)curr_desc->word3.bits.l3_offset,
++                                                                              (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                                      else if (ip_hdr->protocol == IPPROTO_GRE)
++                                      {
++                                              sl351x_nat_input(skb,
++                                                                      tp->port_id,
++                                                                      (void *)curr_desc->word3.bits.l3_offset,
++                                                                      (void *)curr_desc->word3.bits.l4_offset);
++                                      }
++                              }
++#endif
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      else
++                      {
++                              skb->protocol = eth_type_trans(skb,dev); /* set skb protocol */
++                      }
++                      //netif_rx(skb);  /* socket rx */
++                      netif_receive_skb(skb); //For NAPI
++                      dev->last_rx = jiffies;
++
++                      isPtr->rx_bytes += pkt_size;
++                      //printk("------------------->isPtr->rx_bytes = %d\n",isPtr->rx_bytes);
++
++
++        }
++              // advance one for Rx default Q 0/1
++              rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      tp->rx_rwptr.bits32 = rwptr.bits32;
++              rx_pkts_num++;
++              //rwptr.bits32 = readl(&tp->default_qhdr->word1);//try read default_qhdr again
++              //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++              //printk("%s:---Loop  -------->rx_pkts_num=%d------------>Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits32,fq_rwptr.bits32 );
++#if 0
++              if ((status4 & 0x1) == 0)
++              {
++                      //if (!((dev->last_rx <= (rx_time + 2)) &&  (isPtr->rx_bytes > (rx_old_bytes + 1000000 ))))
++                      if (tp->total_q_cnt_napi < 1024)
++                      {
++                              tp->total_q_cnt_napi++;
++                              toe_gmac_fill_free_q();  //for iperf test disable
++                      }
++                      //else
++                              //printk("%s:---isPtr->rx_bytes =%u , rx_old_bytes =%u\n",__func__,isPtr->rx_bytes,rx_old_bytes );
++
++              }
++#endif
++              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              //printk("%s:---Loop  -------->rx_pkts_num=%d----rwptr.bits.rptr=0x%x-------->Default Queue HW RW ptr = (0x%8x),   fq_rwptr =0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits32,fq_rwptr.bits32 );
++              //printk("%s:---Loop  rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++      }
++      // advance one for Rx default Q 0/1
++
++              //rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++              //SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++      //tp->rx_rwptr.bits32 = rwptr.bits32;
++      //rwptr.bits.rptr = rwptr.bits.rptr;
++
++      dev->quota -= rx_pkts_num;
++      *budget -= rx_pkts_num;
++
++      status4 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);//try read SWFQ empty again
++      //fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      rwptr.bits32 = readl(&tp->default_qhdr->word1); //try read default_qhdr again
++      //printk("%s:---After    rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++//    if (rwptr.bits.rptr > rwptr.bits.wptr )
++//                    {
++                              //toe_gmac_disable_rx(dev);
++                              //wait_event_interruptible_timeout(freeq_wait,
++                                      //(rx_pkts_num == 100), CMTP_INTEROP_TIMEOUT);
++                              //printk("\n%s:: return 22222=======> rx_pkts_num =%d,   rwptr.bits.rptr=%d,   rwptr.bits.wptr = %d ====---------=======>JKJKJKJKJK\n",
++                                      //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++//                            return 1;
++//                    }
++
++      if (rwptr.bits.rptr == rwptr.bits.wptr)
++      {
++              unsigned int data32;
++                      //printk("%s:---[rwptr.bits.rptr == rwptr.bits.wptr]   rx_pkts_num=%d------rwptr.bits.rptr=0x%x------->Default_Q [rwptr.bits.rptr(SW)=0x%x,   rwptr.bits.wptr(HW) = 0x%x ]---->Free_Q(SW_HW) = 0x%8x \n",__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.rptr,rwptr.bits.wptr,fq_rwptr.bits32 );
++
++          /* Receive descriptor is empty now */
++#if 1
++     if (status4 & 0x1)
++                      {
++                              do_again =1;
++                              //writel(0x40400000, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_4_REG); //disable SWFQ empty interrupt
++                              //toe_gmac_disable_interrupt(tp->irq);
++                              tp->sw_fq_empty_cnt++;
++                              //toe_gmac_disable_rx(dev);
++                              writel(0x07960202, TOE_GMAC0_BASE+GMAC_CONFIG0);
++                              writel(0x07960202, TOE_GMAC1_BASE+GMAC_CONFIG0);
++                              //printk("\n%s ::  freeq int-----tp->sw_fq_empty_cnt  =%d---------====================----------------->\n",__func__,tp->sw_fq_empty_cnt);
++                              //while ((fq_rwptr.bits.wptr >= (fq_rwptr.bits.rptr+256)) || (fq_rwptr.bits.wptr <= (fq_rwptr.bits.rptr+256)))
++                              //{
++                                      //gmac_write_reg(TOE_GLOBAL_BASE, GLOBAL_INTERRUPT_STATUS_4_REG, status4,
++                                      //0x1);
++                              //printk("\n%s::fq_rwptr.wrptr = %x =======> ===========>here \n", __func__,fq_rwptr.bits32);
++                              //if ((status4 & 0x1) == 0)
++                                      //break;
++                               return 1;
++                              //}
++
++                      }
++#endif
++        //toe_gmac_fill_free_q();
++        netif_rx_complete(dev);
++        // enable GMAC-0 rx interrupt
++        // class-Q & TOE-Q are implemented in future
++        //data32 = readl(TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++        //if (tp->port_id == 0)
++              //data32 |= DEFAULT_Q0_INT_BIT;
++        //else
++              //data32 |= DEFAULT_Q1_INT_BIT;
++        //writel(data32, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_ENABLE_1_REG);
++              writel(0x3, TOE_GLOBAL_BASE+GLOBAL_INTERRUPT_ENABLE_1_REG);
++              //printk("\n%s::netif_rx_complete-->  rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x ====---------=======>JKJKJKJKJK\n",
++              //__func__,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++        writel(0x07960200, TOE_GMAC0_BASE+GMAC_CONFIG0);
++              writel(0x07960200, TOE_GMAC1_BASE+GMAC_CONFIG0);
++        return 0;
++    }
++    else
++    {
++        //printk("\n%s:: return 1 -->status4= 0x%x,rx_pkts_num =%d,   rwptr.bits.rptr=0x%x,   rwptr.bits.wptr = 0x%x  ======> \n", __func__,status4,rx_pkts_num,rwptr.bits.rptr,rwptr.bits.wptr);
++        return 1;
++    }
++}
++#endif
++
++/*----------------------------------------------------------------------
++* gmac_tx_timeout
++*----------------------------------------------------------------------*/
++void gmac_tx_timeout(struct net_device *dev)
++{
++      GMAC_INFO_T                             *tp = (GMAC_INFO_T *)dev->priv;
++
++#ifdef CONFIG_SL351x_SYSCTL
++      if (tp->operation && storlink_ctl.link[tp->port_id])
++#else
++      if (tp->operation)
++#endif
++      {
++              netif_wake_queue(dev);
++      }
++}
++
++
++
++/*----------------------------------------------------------------------
++* mac_set_rule_reg
++*----------------------------------------------------------------------*/
++int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2)
++{
++      int             total_key_dwords;
++
++      total_key_dwords = 1;
++
++      if (reg0 & MR_L2_BIT)
++      {
++              if (reg0 & MR_DA_BIT) total_key_dwords += 2;
++              if (reg0 & MR_SA_BIT) total_key_dwords += 2;
++              if ((reg0 & MR_DA_BIT) && ( reg0 & MR_SA_BIT)) total_key_dwords--;
++              if (reg0 & (MR_PPPOE_BIT | MR_VLAN_BIT)) total_key_dwords++;
++      }
++      if (reg0 & MR_L3_BIT)
++      {
++              if (reg0 & (MR_IP_HDR_LEN_BIT | MR_TOS_TRAFFIC_BIT | MR_SPR_BITS))
++                      total_key_dwords++;
++              if (reg0 & MR_FLOW_LABLE_BIT) total_key_dwords++;
++              if ((reg0 & MR_IP_VER_BIT) == 0) // IPv4
++              {
++                      if (reg1 & 0xff000000) total_key_dwords += 1;
++                      if (reg1 & 0x00ff0000) total_key_dwords += 1;
++              }
++              else
++              {
++                      if (reg1 & 0xff000000) total_key_dwords += 4;
++                      if (reg1 & 0x00ff0000) total_key_dwords += 4;
++              }
++      }
++      if (reg0 & MR_L4_BIT)
++      {
++              if (reg1 & 0x0000f000) total_key_dwords += 1;
++              if (reg1 & 0x00000f00) total_key_dwords += 1;
++              if (reg1 & 0x000000f0) total_key_dwords += 1;
++              if (reg1 & 0x0000000f) total_key_dwords += 1;
++              if (reg2 & 0xf0000000) total_key_dwords += 1;
++              if (reg2 & 0x0f000000) total_key_dwords += 1;
++      }
++      if (reg0 & MR_L7_BIT)
++      {
++              if (reg2 & 0x00f00000) total_key_dwords += 1;
++              if (reg2 & 0x000f0000) total_key_dwords += 1;
++              if (reg2 & 0x0000f000) total_key_dwords += 1;
++              if (reg2 & 0x00000f00) total_key_dwords += 1;
++              if (reg2 & 0x000000f0) total_key_dwords += 1;
++              if (reg2 & 0x0000000f) total_key_dwords += 1;
++      }
++
++      if (total_key_dwords > HASH_MAX_KEY_DWORD)
++              return -1;
++
++      if (total_key_dwords == 0 && enabled)
++              return -2;
++
++      mac_set_rule_enable_bit(mac, rule, 0);
++      if (enabled)
++      {
++              mac_set_MRxCRx(mac, rule, 0, reg0);
++              mac_set_MRxCRx(mac, rule, 1, reg1);
++              mac_set_MRxCRx(mac, rule, 2, reg2);
++              mac_set_rule_action(mac, rule, total_key_dwords);
++              mac_set_rule_enable_bit(mac, rule, enabled);
++      }
++      else
++      {
++              mac_set_rule_action(mac, rule, 0);
++      }
++      return total_key_dwords;
++}
++
++/*----------------------------------------------------------------------
++* mac_get_rule_enable_bit
++*----------------------------------------------------------------------*/
++int mac_get_rule_enable_bit(int mac, int rule)
++{
++      switch (rule)
++      {
++              case 0: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) >> 15) & 1);
++              case 1: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) >> 31) & 1);
++              case 2: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) >> 15) & 1);
++              case 3: return ((mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) >> 31) & 1);
++              default: return 0;
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_enable_bit
++*----------------------------------------------------------------------*/
++void mac_set_rule_enable_bit(int mac, int rule, int data)
++{
++      u32 reg;
++
++      if (data & ~1)
++              return;
++
++      switch (rule)
++      {
++              case 0:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(1<<15)) | (data << 15);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg);
++                      break;
++              case 1:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(1<<31)) | (data << 31);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg);
++                      break;
++              case 2:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(1<<15)) | (data << 15);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg);
++                      break;
++              case 3:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(1<<31)) | (data << 31);
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg);
++      }
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_action
++*----------------------------------------------------------------------*/
++int mac_set_rule_action(int mac, int rule, int data)
++{
++      u32 reg;
++
++      if (data > 32)
++              return -1;
++
++      if (data)
++              data = (data << 6) | (data + HASH_ACTION_DWORDS);
++      switch (rule)
++      {
++              case 0:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(0x7ff));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg | data);
++                      break;
++              case 1:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG0) & ~(0x7ff<<16));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG0, reg | (data << 16));
++                      break;
++              case 2:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(0x7ff));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1,  reg | data);
++                      break;
++              case 3:
++                      reg = (mac_read_dma_reg(mac, GMAC_HASH_ENGINE_REG1) & ~(0x7ff<<16));
++                      mac_write_dma_reg(mac, GMAC_HASH_ENGINE_REG1, reg | (data << 16));
++                      break;
++              default:
++                      return -1;
++      }
++
++      return 0;
++}
++/*----------------------------------------------------------------------
++* mac_get_MRxCRx
++*----------------------------------------------------------------------*/
++int mac_get_MRxCRx(int mac, int rule, int ctrlreg)
++{
++      int reg;
++
++      switch (rule)
++      {
++              case 0: reg = GMAC_MR0CR0 + ctrlreg * 4; break;
++              case 1: reg = GMAC_MR1CR0 + ctrlreg * 4; break;
++              case 2: reg = GMAC_MR2CR0 + ctrlreg * 4; break;
++              case 3: reg = GMAC_MR3CR0 + ctrlreg * 4; break;
++              default: return 0;
++      }
++      return mac_read_dma_reg(mac, reg);
++}
++
++/*----------------------------------------------------------------------
++* mac_set_MRxCRx
++*----------------------------------------------------------------------*/
++void mac_set_MRxCRx(int mac, int rule, int ctrlreg, u32 data)
++{
++      int reg;
++
++      switch (rule)
++      {
++              case 0: reg = GMAC_MR0CR0 + ctrlreg * 4; break;
++              case 1: reg = GMAC_MR1CR0 + ctrlreg * 4; break;
++              case 2: reg = GMAC_MR2CR0 + ctrlreg * 4; break;
++              case 3: reg = GMAC_MR3CR0 + ctrlreg * 4; break;
++              default: return;
++      }
++      mac_write_dma_reg(mac, reg, data);
++}
++
++/*----------------------------------------------------------------------
++* mac_set_rule_priority
++*----------------------------------------------------------------------*/
++void mac_set_rule_priority(int mac, int p0, int p1, int p2, int p3)
++{
++      int                     i;
++      GMAC_MRxCR0_T   reg[4];
++
++      for (i=0; i<4; i++)
++              reg[i].bits32 = mac_get_MRxCRx(mac, i, 0);
++
++      reg[0].bits.priority = p0;
++      reg[1].bits.priority = p1;
++      reg[2].bits.priority = p2;
++      reg[3].bits.priority = p3;
++
++      for (i=0; i<4; i++)
++              mac_set_MRxCRx(mac, i, 0, reg[i].bits32);
++}
++
++/*----------------------------------------------------------------------
++* gmac_netdev_ioctl
++*----------------------------------------------------------------------*/
++static int gmac_netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      int                             rc = 0;
++    unsigned char             *hwa = rq->ifr_ifru.ifru_hwaddr.sa_data;
++
++#ifdef br_if_ioctl
++    struct                            ethtool_cmd ecmd;       //br_if.c will call this ioctl
++      GMAC_INFO_T             *tp = dev->priv;
++#endif
++
++#ifdef        CONFIG_SL351x_NAT
++      if (cmd == SIOCDEVPRIVATE)
++              return sl351x_nat_ioctl(dev, rq, cmd);
++#endif
++
++      switch (cmd) {
++      case SIOCETHTOOL:
++#ifdef br_if_ioctl    //br_if.c will call this ioctl
++              if (!netif_running(dev))
++              {
++                      printk("Before changing the H/W address,please down the device.\n");
++                      return -EINVAL;
++              }
++              memset((void *) &ecmd, 0, sizeof (ecmd));
++                  ecmd.supported =
++                      SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
++                    SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++                    SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
++                          ecmd.port = PORT_TP;
++                  ecmd.transceiver = XCVR_EXTERNAL;
++                  ecmd.phy_address = tp->phy_addr;
++                  switch (tp->speed_status)
++                  {
++                  case GMAC_SPEED_10: ecmd.speed = SPEED_10; break;
++                  case GMAC_SPEED_100: ecmd.speed = SPEED_100; break;
++                  case GMAC_SPEED_1000: ecmd.speed = SPEED_1000; break;
++                  default: ecmd.speed = SPEED_10; break;
++                 }
++                  ecmd.duplex = tp->full_duplex_status ? DUPLEX_FULL : DUPLEX_HALF;
++                  ecmd.advertising = ADVERTISED_TP;
++                  ecmd.advertising |= ADVERTISED_Autoneg;
++                  ecmd.autoneg = AUTONEG_ENABLE;
++                    if (copy_to_user(rq->ifr_data, &ecmd, sizeof (ecmd)))
++                      return -EFAULT;
++#endif
++
++        break;
++
++    case SIOCSIFHWADDR:
++              if (!netif_running(dev))
++              {
++                      printk("Before changing the H/W address,please down the device.\n");
++                      return -EINVAL;
++              }
++        gmac_set_mac_address(dev,hwa);
++        break;
++
++      case SIOCGMIIPHY:       /* Get the address of the PHY in use. */
++        break;
++
++      case SIOCGMIIREG:       /* Read the specified MII register. */
++              break;
++
++      case SIOCSMIIREG:       /* Write the specified MII register */
++              break;
++
++      default:
++              rc = -EOPNOTSUPP;
++              break;
++      }
++
++      return rc;
++}
++
++#ifdef SL351x_GMAC_WORKAROUND
++
++#define GMAC_TX_STATE_OFFSET  0x60
++#define GMAC_RX_STATE_OFFSET  0x64
++#define GMAC_POLL_HANGED_NUM  200
++#define GMAC_RX_HANGED_STATE  0x4b2000
++#define GMAC_RX_HANGED_MASK           0xdff000
++#define GMAC_TX_HANGED_STATE  0x34012
++#define GMAC_TX_HANGED_MASK           0xfffff
++#define TOE_GLOBAL_REG_SIZE           (0x78/sizeof(u32))
++#define TOE_DMA_REG_SIZE              (0xd0/sizeof(u32))
++#define TOE_GMAC_REG_SIZE             (0x30/sizeof(u32))
++#define GMAC0_RX_HANG_BIT             (1 << 0)
++#define GMAC0_TX_HANG_BIT             (1 << 1)
++#define GMAC1_RX_HANG_BIT             (1 << 2)
++#define GMAC1_TX_HANG_BIT             (1 << 3)
++
++int           gmac_in_do_workaround;
++#if 0
++int           debug_cnt, poll_max_cnt;
++#endif
++u32           gmac_workaround_cnt[4];
++u32           toe_global_reg[TOE_GLOBAL_REG_SIZE];
++u32           toe_dma_reg[GMAC_NUM][TOE_DMA_REG_SIZE];
++u32           toe_gmac_reg[GMAC_NUM][TOE_GMAC_REG_SIZE];
++u32           gmac_short_frame_workaround_cnt[2];
++
++static void sl351x_gmac_release_buffers(void);
++static void sl351x_gmac_release_swtx_q(void);
++static void sl351x_gmac_release_rx_q(void);
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_class_q(void);
++static void sl351x_gmac_release_toe_q(void);
++static void sl351x_gmac_release_intr_q(void);
++#endif
++static void sl351x_gmac_release_sw_free_q(void);
++static void sl351x_gmac_release_hw_free_q(void);
++#ifdef CONFIG_SL351x_NAT
++static int get_free_desc_cnt(unsigned long rwptr, int total);
++static void sl351x_gmac_release_hwtx_q(void);
++u32     sl351x_nat_workaround_cnt;
++#endif
++void sl351x_gmac_save_reg(void);
++void sl351x_gmac_restore_reg(void);
++
++
++/*----------------------------------------------------------------------
++*     sl351x_poll_gmac_hanged_status
++*     - Called by timer routine, period 10ms
++*     - If (state != 0 && state == prev state && )
++*----------------------------------------------------------------------*/
++void sl351x_poll_gmac_hanged_status(u32 data)
++{
++      int                     i;
++      u32                     state;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      u32                             hanged_state;
++      // int                          old_operation[GMAC_NUM];
++#ifdef CONFIG_SL351x_NAT
++      u32                             hw_free_cnt;
++#endif
++
++      if (gmac_in_do_workaround)
++              return;
++
++      gmac_in_do_workaround = 1;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      hanged_state = 0;
++
++#ifdef SL351x_TEST_WORKAROUND
++      if (toe->gmac[0].operation || toe->gmac[1].operation)
++      {
++              debug_cnt++;
++              if (debug_cnt == (30 * HZ))
++              {
++                      debug_cnt = 0;
++                      hanged_state = GMAC0_RX_HANG_BIT;
++                      goto do_workaround;
++              }
++      }
++#endif
++      if (toe->gmac[0].operation)
++              hanged_state |= GMAC0_RX_HANG_BIT | GMAC0_TX_HANG_BIT;
++
++#if (GMAC_NUM > 1)
++      if (toe->gmac[1].operation)
++              hanged_state |= GMAC1_RX_HANG_BIT | GMAC1_TX_HANG_BIT;
++#endif
++
++      for (i=0; i<GMAC_POLL_HANGED_NUM; i++)
++      {
++              if (hanged_state & GMAC0_RX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC0_BASE + GMAC_RX_STATE_OFFSET) & GMAC_RX_HANGED_MASK;
++                      if (state != GMAC_RX_HANGED_STATE)
++                              hanged_state &= ~GMAC0_RX_HANG_BIT;
++              }
++              if (hanged_state & GMAC0_TX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC0_BASE + GMAC_TX_STATE_OFFSET) & GMAC_TX_HANGED_MASK;
++                      if (state != GMAC_TX_HANGED_STATE)
++                              hanged_state &= ~GMAC0_TX_HANG_BIT;
++              }
++#if (GMAC_NUM > 1)
++              if (hanged_state & GMAC1_RX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC1_BASE + GMAC_RX_STATE_OFFSET) & GMAC_RX_HANGED_MASK;
++                      if (state != GMAC_RX_HANGED_STATE)
++                              hanged_state &= ~GMAC1_RX_HANG_BIT;
++              }
++              if (hanged_state & GMAC1_TX_HANG_BIT)
++              {
++                      state = readl(TOE_GMAC1_BASE + GMAC_TX_STATE_OFFSET) & GMAC_TX_HANGED_MASK;
++                      if (state != GMAC_TX_HANGED_STATE)
++                              hanged_state &= ~GMAC1_TX_HANG_BIT;
++              }
++#endif
++              if (!hanged_state)
++              {
++#if 0
++                      if (i < poll_max_cnt)
++                              poll_max_cnt = i;
++#endif
++                      if (toe->gmac[0].short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              gmac_short_frame_workaround_cnt[0]++;
++                              toe->gmac[0].short_frames_cnt = 0;
++                              goto do_workaround;
++                      }
++#if (GMAC_NUM > 1)
++                      if (toe->gmac[1].short_frames_cnt >= GMAC_SHORT_FRAME_THRESHOLD)
++                      {
++                              gmac_short_frame_workaround_cnt[1]++;
++                              toe->gmac[1].short_frames_cnt = 0;
++                              goto do_workaround;
++                      }
++#endif
++
++#ifdef CONFIG_SL351x_NAT
++                      hw_free_cnt = readl(TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++                      hw_free_cnt = get_free_desc_cnt(hw_free_cnt, TOE_HW_FREEQ_DESC_NUM);
++#ifdef NAT_WORKAROUND_BY_RESET_GMAC
++                      if (readl(TOE_GLOBAL_BASE + 0x4084) && (hw_free_cnt <= PAUSE_SET_HW_FREEQ))
++                      {
++                              sl351x_nat_workaround_cnt++;
++                              goto do_workaround;
++                      }
++#else
++                      if (readl(TOE_GLOBAL_BASE + 0x4084) && (hw_free_cnt <= (PAUSE_SET_HW_FREEQ*2)))
++                      {
++                              sl351x_nat_workaround_cnt++;
++                              sl351x_nat_workaround_handler();
++                      }
++#endif
++#endif
++                      gmac_in_do_workaround = 0;
++                      add_timer(&gmac_workround_timer_obj);
++                      return;
++              }
++      }
++
++do_workaround:
++
++      gmac_initialized = 0;
++      if (hanged_state)
++      {
++              if (hanged_state & GMAC0_RX_HANG_BIT) gmac_workaround_cnt[0]++;
++              if (hanged_state & GMAC0_TX_HANG_BIT) gmac_workaround_cnt[1]++;
++              if (hanged_state & GMAC1_RX_HANG_BIT) gmac_workaround_cnt[2]++;
++              if (hanged_state & GMAC1_TX_HANG_BIT) gmac_workaround_cnt[3]++;
++      }
++
++      for (i=0; i<GMAC_NUM; i++)
++      {
++              tp=(GMAC_INFO_T *)&toe->gmac[i];
++              // old_operation[i] = tp->operation;
++              if (tp->operation)
++              {
++                      netif_stop_queue(tp->dev);
++                      clear_bit(__LINK_STATE_START, &tp->dev->state);
++                      toe_gmac_disable_interrupt(tp->irq);
++                      toe_gmac_disable_tx_rx(tp->dev);
++                      toe_gmac_hw_stop(tp->dev);
++              }
++      }
++
++      // clear all status bits
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_0_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_1_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_2_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_3_REG);
++      writel(0xffffffff, TOE_GLOBAL_BASE + GLOBAL_INTERRUPT_STATUS_4_REG);
++
++#if 0
++      if ((hanged_state & GMAC0_RX_HANG_BIT) &&
++              (readl(TOE_GMAC0_DMA_BASE + 0xdc) & 0xf0))
++      {
++              struct sk_buff *skb;
++              unsigned int buf;
++              buf = readl(TOE_GMAC0_DMA_BASE + 0x68) & ~3;
++#ifdef CONFIG_SL351x_NAT
++              if (buf < toe->hwfq_buf_base_dma || buf > toe->hwfq_buf_end_dma)
++#endif
++              {
++                      skb = (struct sk_buff *)(REG32(buf - SKB_RESERVE_BYTES));
++                      printk("GMAC-0 free a loss SKB 0x%x\n", (u32)skb);
++                      dev_kfree_skb(skb);
++              }
++      }
++      if ((hanged_state & GMAC1_RX_HANG_BIT)  &&
++              (readl(TOE_GMAC1_DMA_BASE + 0xdc) & 0xf0))
++      {
++              struct sk_buff *skb;
++              unsigned int buf;
++              buf = readl(TOE_GMAC1_DMA_BASE + 0x68) & ~3;
++#ifdef CONFIG_SL351x_NAT
++              if (buf < toe->hwfq_buf_base_dma || buf > toe->hwfq_buf_end_dma)
++#endif
++              {
++                      skb = (struct sk_buff *)(REG32(buf - SKB_RESERVE_BYTES));
++                      printk("GMAC-1 free a loss SKB 0x%x\n", (u32)skb);
++                      dev_kfree_skb(skb);
++              }
++      }
++#endif
++
++      sl351x_gmac_release_buffers();
++      sl351x_gmac_save_reg();
++      toe_gmac_sw_reset();
++      sl351x_gmac_restore_reg();
++
++      if (toe->gmac[0].default_qhdr->word1.bits32)
++      {
++              // printk("===> toe->gmac[0].default_qhdr->word1 = 0x%x\n", toe->gmac[0].default_qhdr->word1);
++              sl351x_gmac_release_rx_q();
++              writel(0, &toe->gmac[0].default_qhdr->word1);
++      }
++      if (toe->gmac[1].default_qhdr->word1.bits32)
++      {
++              // printk("===> toe->gmac[1].default_qhdr->word1 = 0x%x\n", toe->gmac[1].default_qhdr->word1);
++              sl351x_gmac_release_rx_q();
++              writel(0, &toe->gmac[1].default_qhdr->word1);
++      }
++
++      gmac_initialized = 1;
++
++#ifdef        CONFIG_SL351x_NAT
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++#endif
++
++      for (i=0; i<GMAC_NUM; i++)
++      {
++              tp=(GMAC_INFO_T *)&toe->gmac[i];
++              if (tp->operation)
++              {
++                      toe_gmac_enable_interrupt(tp->irq);
++                      toe_gmac_hw_start(tp->dev);
++                      toe_gmac_enable_tx_rx(tp->dev);
++                      netif_wake_queue(tp->dev);
++                      set_bit(__LINK_STATE_START, &tp->dev->state);
++              }
++      }
++
++      gmac_in_do_workaround = 0;
++      add_timer(&gmac_workround_timer_obj);
++}
++
++/*----------------------------------------------------------------------
++*     get_free_desc_cnt
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int get_free_desc_cnt(unsigned long rwptr, int total)
++{
++      unsigned short wptr = rwptr & 0xffff;
++      unsigned short rptr = rwptr >> 16;
++
++      if (wptr >= rptr)
++              return (total - wptr + rptr);
++      else
++              return (rptr - wptr);
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_buffers
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_buffers(void)
++{
++      // Free buffers & Descriptors in all SW Tx Queues
++      sl351x_gmac_release_swtx_q();
++
++      // Free buffers in Default Rx Queues
++      sl351x_gmac_release_rx_q();
++
++#ifdef _TOEQ_CLASSQ_READY_
++      // Free buffers in Classification Queues
++      sl351x_gmac_release_class_q();
++
++      // Free buffers in TOE Queues
++      sl351x_gmac_release_toe_q();
++
++      // Free buffers in Interrupt Queues
++      sl351x_gmac_release_intr_q();
++#endif
++
++      // Free buffers & descriptors in SW free queue
++      sl351x_gmac_release_sw_free_q();
++
++      // Free buffers & descriptors in HW free queue
++      sl351x_gmac_release_hw_free_q();
++
++#ifdef CONFIG_SL351x_NAT
++      // Free buffers & descriptors in HW free queue
++      sl351x_gmac_release_hwtx_q();
++#endif
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_swtx_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_swtx_q(void)
++{
++      int                             i, j;
++      GMAC_TXDESC_T   *curr_desc;
++      unsigned int    desc_count;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      GMAC_SWTXQ_T    *swtxq;
++      DMA_RWPTR_T             rwptr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      tp = (GMAC_INFO_T *)&toe->gmac[0];
++      for (i=0; i<GMAC_NUM; i++, tp++)
++      {
++              if (!tp->existed) continue;
++              swtxq = (GMAC_SWTXQ_T *)&tp->swtxq[0];
++              for (j=0; j<TOE_SW_TXQ_NUM; j++, swtxq++)
++              {
++                      for (;;)
++                      {
++                              rwptr.bits32 = readl(swtxq->rwptr_reg);
++                              if (rwptr.bits.rptr == swtxq->finished_idx)
++                              break;
++                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                              // if (curr_desc->word0.bits.status_tx_ok)
++                              {
++                                      desc_count = curr_desc->word0.bits.desc_count;
++                                      while (--desc_count)
++                                      {
++                                              curr_desc->word0.bits.status_tx_ok = 0;
++                                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                                              curr_desc = (GMAC_TXDESC_T *)swtxq->desc_base + swtxq->finished_idx;
++                                      }
++
++                                      curr_desc->word0.bits.status_tx_ok = 0;
++                                      if (swtxq->tx_skb[swtxq->finished_idx])
++                                      {
++                                              dev_kfree_skb_irq(swtxq->tx_skb[swtxq->finished_idx]);
++                                              swtxq->tx_skb[swtxq->finished_idx] = NULL;
++                                      }
++                              }
++                              swtxq->finished_idx = RWPTR_ADVANCE_ONE(swtxq->finished_idx, swtxq->total_desc_num);
++                      }
++                      writel(0, swtxq->rwptr_reg);
++                      swtxq->finished_idx = 0;
++              }
++      }
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_rx_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_rx_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      GMAC_INFO_T             *tp;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      tp = (GMAC_INFO_T *)&toe->gmac[0];
++      for (i=0; i<GMAC_NUM; i++, tp++)
++      {
++              if (!tp->existed) continue;
++              rwptr.bits32 = readl(&tp->default_qhdr->word1);
++              while (rwptr.bits.rptr != rwptr.bits.wptr)
++              {
++                      curr_desc = (GMAC_RXDESC_T *)tp->default_desc_base + rwptr.bits.rptr;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, tp->default_desc_num);
++                      SET_RPTR(&tp->default_qhdr->word1, rwptr.bits.rptr);
++                      rwptr.bits32 = readl(&tp->default_qhdr->word1);
++              }  // while
++              writel(0, &tp->default_qhdr->word1);
++              tp->rx_rwptr.bits32 = 0;
++      } // for
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_class_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_class_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      CLASSQ_INFO_T   *classq;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      classq = (CLASSQ_INFO_T *)&toe->classq[0];
++      for (i=0; i<TOE_CLASS_QUEUE_NUM; i++, classq++)
++      {
++              rwptr.bits32 = readl(&classq->qhdr->word1);
++              while (rwptr.bits.rptr != rwptr.bits.wptr)
++              {
++                      curr_desc = (GMAC_RXDESC_T *)classq->desc_base + rwptr.bits.rptr;
++                      skb = (struct sk_buff *)(REG32(__va(curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rwptr.bits.rptr = RWPTR_ADVANCE_ONE(rwptr.bits.rptr, classq->desc_num);
++                      SET_RPTR(&classq->qhdr->word1, rwptr.bits.rptr);
++                      rwptr.bits32 = readl(&classq->qhdr->word1);
++              }  // while
++              writel(0, &classq->qhdr->word1);
++              classq->rwptr.bits32 = 0;
++      } // for
++
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_toe_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_toe_q(void)
++{
++      int                             i;
++      TOE_INFO_T              *toe;
++      TOEQ_INFO_T             *toeq_info;
++      TOE_QHDR_T              *toe_qhdr;
++      DMA_RWPTR_T             rwptr;
++      volatile GMAC_RXDESC_T  *curr_desc;
++      unsigned int    rptr, wptr;
++      GMAC_RXDESC_T   *toe_curr_desc;
++      struct sk_buff                  *skb;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      toe_qhdr = (TOE_QHDR_T *)TOE_TOE_QUE_HDR_BASE;
++      for (i=0; i<TOE_TOE_QUEUE_NUM; i++, toe_qhdr++)
++      {
++              toeq_info = (TOEQ_INFO_T *)&toe->toeq[i];
++              wptr = toe_qhdr->word1.bits.wptr;
++              rptr = toe_qhdr->word1.bits.rptr;
++              while (rptr != wptr)
++              {
++                      toe_curr_desc = (GMAC_RXDESC_T *)toeq_info->desc_base + rptr;
++                      skb = (struct sk_buff *)(REG32(__va(toe_curr_desc->word2.buf_adr) - SKB_RESERVE_BYTES));
++                      dev_kfree_skb_irq(skb);
++                      rptr = RWPTR_ADVANCE_ONE(rptr, toeq_info->desc_num);
++                      SET_RPTR(&toe_qhdr->word1.bits32, rptr);
++                      wptr = toe_qhdr->word1.bits.wptr;
++                      rptr = toe_qhdr->word1.bits.rptr;
++              }
++              toe_qhdr->word1.bits32 = 0;
++              toeq_info->rwptr.bits32 = 0;
++      }
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_intr_q
++*----------------------------------------------------------------------*/
++#ifdef _TOEQ_CLASSQ_READY_
++static void sl351x_gmac_release_intr_q(void)
++{
++}
++#endif
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_sw_free_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_sw_free_q(void)
++{
++      TOE_INFO_T                              *toe;
++      volatile DMA_RWPTR_T    fq_rwptr;
++      volatile GMAC_RXDESC_T  *fq_desc;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++      while ((unsigned short)RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM) != fq_rwptr.bits.rptr)
++      {
++              struct sk_buff *skb;
++              if ((skb = dev_alloc_skb(SW_RX_BUF_SIZE))==NULL)  /* allocate socket buffer */
++              {
++                      printk("%s::skb buffer allocation fail !\n",__func__); while(1);
++              }
++              // *(unsigned int *)(skb->data) = (unsigned int)skb;
++              REG32(skb->data) = (unsigned long)skb;
++              skb_reserve(skb, SKB_RESERVE_BYTES);
++
++              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++              fq_desc = (volatile GMAC_RXDESC_T *)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++              SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++      }
++
++      toe->fq_rx_rwptr.bits.wptr = TOE_SW_FREEQ_DESC_NUM - 1;
++      toe->fq_rx_rwptr.bits.rptr = 0;
++      writel(toe->fq_rx_rwptr.bits32, TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++
++}
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_hw_free_q
++*----------------------------------------------------------------------*/
++static void sl351x_gmac_release_hw_free_q(void)
++{
++      DMA_RWPTR_T                     rwptr_reg;
++
++#ifdef CONFIG_SL351x_NAT
++      int                                     i;
++      TOE_INFO_T                      *toe;
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++      desc_ptr = (GMAC_RXDESC_T *)toe->hwfq_desc_base;
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++#endif
++      rwptr_reg.bits.wptr = TOE_HW_FREEQ_DESC_NUM - 1;
++      rwptr_reg.bits.rptr = 0;
++      writel(rwptr_reg.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_release_hw_free_q
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void sl351x_gmac_release_hwtx_q(void)
++{
++      int                             i;
++      unsigned int    rwptr_addr;
++
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              writel(0, rwptr_addr);
++              rwptr_addr+=4;
++      }
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              writel(0, rwptr_addr);
++              rwptr_addr+=4;
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_save_reg
++*----------------------------------------------------------------------*/
++void sl351x_gmac_save_reg(void)
++{
++      int     i;
++      volatile u32    *destp;
++      unsigned int    srce_addr;
++
++      srce_addr = TOE_GLOBAL_BASE;
++      destp = (volatile u32 *)toe_global_reg;
++      for (i=0; i<TOE_GLOBAL_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++
++      srce_addr = TOE_GMAC0_DMA_BASE;
++      destp = (volatile u32 *)&toe_dma_reg[0][0];
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, destp++, srce_addr+=4)
++      {
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x38))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x58))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              *destp = readl(srce_addr);
++      }
++      srce_addr = TOE_GMAC1_DMA_BASE;
++      destp = (volatile u32 *)&toe_dma_reg[1][0];
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, destp++, srce_addr+=4)
++      {
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x38))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (srce_addr ==  (TOE_GMAC0_DMA_BASE+0x58))
++                      srce_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              *destp = readl(srce_addr);
++      }
++
++      srce_addr = TOE_GMAC0_BASE;
++      destp = (volatile u32 *)&toe_gmac_reg[0][0];
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++
++      srce_addr = TOE_GMAC1_BASE;
++      destp = (volatile u32 *)&toe_gmac_reg[1][0];
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, destp++, srce_addr+=4)
++              *destp = readl(srce_addr);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_gmac_restore_reg
++*----------------------------------------------------------------------*/
++void sl351x_gmac_restore_reg(void)
++{
++      int     i;
++      volatile u32    *srcep;
++      unsigned int    dest_addr;
++
++      srcep = (volatile u32 *)&toe_dma_reg[0][0];
++      dest_addr = TOE_GMAC0_DMA_BASE;
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, dest_addr+=4, srcep++)
++      {
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x38))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x58))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              writel(*srcep, dest_addr);
++              // gmac_write_reg(dest_addr, 0, *srcep, 0xffffffff);
++      }
++      srcep = (volatile u32 *)&toe_dma_reg[1][0];
++      dest_addr = TOE_GMAC1_DMA_BASE;
++      for (i=0; i<TOE_DMA_REG_SIZE; i++, dest_addr+=4, srcep++)
++      {
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x38))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x50);
++              if (dest_addr == (TOE_GMAC0_DMA_BASE+0x58))
++                      dest_addr = (TOE_GMAC0_DMA_BASE+0x70);
++
++              writel(*srcep, dest_addr);
++              // gmac_write_reg(dest_addr, 0, *srcep, 0xffffffff);
++      }
++
++      srcep = (volatile u32 *)&toe_gmac_reg[0][0];
++      dest_addr = TOE_GMAC0_BASE;
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++      srcep = (volatile u32 *)&toe_gmac_reg[1][0];
++      dest_addr = TOE_GMAC1_BASE;
++      for (i=0; i<TOE_GMAC_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++      srcep = (volatile u32 *)toe_global_reg;
++      dest_addr = TOE_GLOBAL_BASE;
++      for (i=0; i<TOE_GLOBAL_REG_SIZE; i++, dest_addr+=4, srcep++)
++              writel(*srcep, dest_addr);
++
++}
++
++#ifdef CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++*     sl351x_nat_workaround_init
++*----------------------------------------------------------------------*/
++#define NAT_WORAROUND_DESC_POWER      (6)
++#define NAT_WORAROUND_DESC_NUM                (2 << NAT_WORAROUND_DESC_POWER)
++dma_addr_t sl351x_nat_workaround_desc_dma;
++void sl351x_nat_workaround_init(void)
++{
++      unsigned int    desc_buf;
++
++      desc_buf = (unsigned int)DMA_MALLOC((NAT_WORAROUND_DESC_NUM * sizeof(GMAC_RXDESC_T)),
++                                              (dma_addr_t *)&sl351x_nat_workaround_desc_dma) ;
++      memset((void *)desc_buf, 0, NAT_WORAROUND_DESC_NUM * sizeof(GMAC_RXDESC_T));
++
++      // DMA Queue Base & Size
++      writel((sl351x_nat_workaround_desc_dma & DMA_Q_BASE_MASK) | NAT_WORAROUND_DESC_POWER,
++                      TOE_GLOBAL_BASE + 0x4080);
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++}
++
++/*----------------------------------------------------------------------
++*     sl351x_nat_workaround_handler
++*----------------------------------------------------------------------*/
++#ifndef NAT_WORKAROUND_BY_RESET_GMAC
++static void sl351x_nat_workaround_handler(void)
++{
++      int                                     i;
++      DMA_RWPTR_T                     rwptr;
++      GMAC_RXDESC_T           *desc_ptr;
++      unsigned int            buf_ptr;
++      TOE_INFO_T                      *toe;
++      GMAC_CONFIG0_T          config0;
++      unsigned int            rwptr_addr;
++
++      toe = (TOE_INFO_T *)&toe_private_data;
++
++      // disable Rx of GMAC-0 & 1
++      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 1;
++      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 1;
++      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++
++      // wait GMAC-0 HW Tx finished
++      rwptr_addr = TOE_GMAC0_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              rwptr.bits32 = readl(rwptr_addr);
++              if (rwptr.bits.rptr != rwptr.bits.wptr)
++                      return; // wait the HW to send packets and release buffers
++              rwptr_addr+=4;
++      }
++      rwptr_addr = TOE_GMAC1_DMA_BASE + GMAC_HW_TX_QUEUE0_PTR_REG;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              rwptr.bits32 = readl(rwptr_addr);
++              if (rwptr.bits.rptr != rwptr.bits.wptr)
++                      return; // wait the HW to send packets and release buffers
++              rwptr_addr+=4;
++      }
++
++      // printk("sl351x_nat_workaround_handler %d\n", sl351x_nat_workaround_cnt);
++      desc_ptr = (GMAC_RXDESC_T *)toe->hwfq_desc_base;
++      buf_ptr = (unsigned int)toe->hwfq_buf_base_dma;
++      for (i=0; i<TOE_HW_FREEQ_DESC_NUM; i++)
++      {
++              desc_ptr->word0.bits.buffer_size = HW_RX_BUF_SIZE;
++              desc_ptr->word1.bits.sw_id = i;
++              desc_ptr->word2.buf_adr = (unsigned int)buf_ptr;
++              desc_ptr++;
++              buf_ptr += HW_RX_BUF_SIZE;
++      }
++      rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++      rwptr.bits.wptr = RWPTR_RECEDE_ONE(rwptr.bits.rptr, TOE_HW_FREEQ_DESC_NUM);
++      writel(rwptr.bits32, TOE_GLOBAL_BASE + GLOBAL_HWFQ_RWPTR_REG);
++      writel(0, TOE_GLOBAL_BASE + 0x4084);
++
++      // Enable Rx of GMAC-0 & 1
++      config0.bits32 = readl(TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 0;
++      writel(config0.bits32, TOE_GMAC0_BASE+GMAC_CONFIG0);
++      config0.bits32 = readl(TOE_GMAC1_BASE+GMAC_CONFIG0);
++      config0.bits.dis_rx = 0;
++      writel(config0.bits32, TOE_GMAC1_BASE+GMAC_CONFIG0);
++}
++#endif
++#endif // CONFIG_SL351x_NAT
++
++#endif // SL351x_GMAC_WORKAROUND
++
++/* get the mac addresses from flash
++ *can't do this in module_init because mtd driver is initialized after ethernet
++ */
++static __init int sl351x_mac_address_init(void)
++{
++      GMAC_INFO_T             *tp;
++      struct sockaddr sock;
++      int i;
++
++      /* get mac address from FLASH */
++      gmac_get_mac_address();
++
++      for (i = 0; i < GMAC_NUM; i++) {
++              tp = (GMAC_INFO_T *)&toe_private_data.gmac[i];
++              memcpy(&sock.sa_data[0],&eth_mac[tp->port_id][0],6);
++              gmac_set_mac_address(tp->dev,(void *)&sock);
++      }
++
++        return 0;
++}
++late_initcall(sl351x_mac_address_init);
++
++
+--- /dev/null
++++ b/drivers/net/sl351x_hash.c
+@@ -0,0 +1,713 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_hash.c
++* Description :
++*             Handle Storlink SL351x Hash Functions
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++
++#ifndef RXTOE_DEBUG
++#define RXTOE_DEBUG
++#endif
++#undef RXTOE_DEBUG
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       hash_printf                             printk
++
++#define HASH_TIMER_PERIOD             (30)    // seconds
++#define HASH_ILLEGAL_INDEX            0xffff
++
++/*----------------------------------------------------------------------
++* Variables
++*----------------------------------------------------------------------*/
++u32                                   hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++char                          hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++static struct timer_list hash_timer_obj;
++LIST_HEAD(hash_timeout_list);
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length);
++static void hash_timer_func(u32 data);
++
++/*----------------------------------------------------------------------
++* hash_init
++*----------------------------------------------------------------------*/
++void sl351x_hash_init(void)
++{
++      int i;
++      volatile u32 *dp1, *dp2, dword;
++
++      dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++      dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++      for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++      {
++              *dp1++ = 0;
++              dword = *dp2++; // read-clear
++      }
++      memset((void *)&hash_nat_owner_bits, 0, sizeof(hash_nat_owner_bits));
++      memset((void *)&hash_tables, 0, sizeof(hash_tables));
++
++      init_timer(&hash_timer_obj);
++      hash_timer_obj.expires = jiffies + (HASH_TIMER_PERIOD * HZ);
++      hash_timer_obj.data = (unsigned long)&hash_timer_obj;
++      hash_timer_obj.function = (void *)&hash_timer_func;
++      add_timer(&hash_timer_obj);
++
++#if (HASH_MAX_BYTES == 128)
++      writel((unsigned long)__pa(&hash_tables) | 3,   // 32 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#elif (HASH_MAX_BYTES == 64)
++      writel((unsigned long)__pa(&hash_tables) | 2,   // 16 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#else
++      #error Incorrect setting for HASH_MAX_BYTES
++#endif
++
++}
++/*----------------------------------------------------------------------
++* hash_add_entry
++*----------------------------------------------------------------------*/
++int hash_add_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++      rc = hash_build_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++/*----------------------------------------------------------------------
++* hash_set_valid_flag
++*----------------------------------------------------------------------*/
++void hash_set_valid_flag(int index, int valid)
++{
++      register u32 reg32;
++
++      reg32 = TOE_V_BIT_BASE + (index/32) * 4;
++
++      if (valid)
++      {
++              writel(readl(reg32) | (1 << (index%32)), reg32);
++      }
++      else
++      {
++              writel(readl(reg32) & ~(1 << (index%32)), reg32);
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_set_nat_owner_flag
++*----------------------------------------------------------------------*/
++void hash_set_nat_owner_flag(int index, int valid)
++{
++      if (valid)
++      {
++              hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++      }
++      else
++      {
++              hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++      }
++}
++
++
++/*----------------------------------------------------------------------
++* hash_build_keys
++*----------------------------------------------------------------------*/
++int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      u32     data;
++      unsigned char   *cp;
++      int                             i, j;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char *)destp;
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++      {
++              HASH_PUSH_WORD(cp, entry->key.Ethertype);               // word 0
++              HASH_PUSH_BYTE(cp, entry->key.port);                    // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++      else
++      {
++              HASH_PUSH_DWORD(cp, 0);
++      }
++
++      if (entry->key_present.da || entry->key_present.sa)
++      {
++              unsigned char mac[4];
++              if (entry->key_present.da)
++              {
++                      for (i=0; i<4; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.da[i]);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa)
++              {
++                      for (i=2; i<6; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.sa[i]);
++              }
++      }
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++      if (entry->key_present.ipv4_hdrlen || entry->key_present.ip_tos || entry->key_present.ip_protocol)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.ip_protocol);             // Byte 0
++              HASH_PUSH_BYTE(cp, entry->key.ip_tos);                  // Byte 1
++              HASH_PUSH_BYTE(cp, entry->key.ipv4_hdrlen);             // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++
++      if (entry->key_present.ipv6_flow_label)
++      {
++              HASH_PUSH_DWORD(cp, entry->key.ipv6_flow_label);        // low word
++      }
++      if (entry->key_present.sip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.sip[j]);
++                      }
++              }
++      }
++      if (entry->key_present.dip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.dip[j]);
++                      }
++              }
++      }
++
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++      }
++      if (entry->key_present.l4_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[7]);
++      }
++      if (entry->key_present.l4_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[11]);
++      }
++      if (entry->key_present.l4_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[15]);
++      }
++      if (entry->key_present.l4_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[19]);
++      }
++      if (entry->key_present.l4_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[23]);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[3]);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[7]);
++      }
++      if (entry->key_present.l7_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[11]);
++      }
++      if (entry->key_present.l7_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[15]);
++      }
++      if (entry->key_present.l7_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[19]);
++      }
++      if (entry->key_present.l7_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[23]);
++      }
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      if (total > HASH_MAX_KEY_DWORD)
++      {
++              //hash_printf("Total key words (%d) is too large (> %d)!\n",
++              //                              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++              index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      else
++      {
++              if (total == 1)
++              {
++                      hash_printf("No key is assigned!\n");
++                      return -1;
++              }
++
++              index = hash_gen_crc16((unsigned char *)(destp+1), (total-1) * 4);
++      }
++
++      entry->index = index & HASH_BITS_MASK;
++
++      //hash_printf("Total key words = %d, Hash Index= %d\n",
++      //                              total, entry->index);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_nat_keys
++*----------------------------------------------------------------------*/
++void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned char   *cp;
++      int                             i;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++
++      cp = (unsigned char *)destp + 2;
++      HASH_PUSH_BYTE(cp, entry->key.port);
++      cp++;
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++
++      HASH_PUSH_BYTE(cp, entry->key.ip_protocol);
++      cp+=3;
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      entry->index = index & ((1 << HASH_BITS) - 1);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_toe_keys
++*----------------------------------------------------------------------*/
++int hash_build_toe_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned long   data;
++      unsigned char   *cp;
++      unsigned short  index;
++      int     i;
++      int total;
++      //printk("%s\n", __func__);
++      memset((void*)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char*)destp;
++
++      if(entry->key_present.port || entry->key_present.Ethertype) {
++              data = (entry->key.port << 16) + entry->key.Ethertype;
++              HASH_PUSH_DWORD(cp, data);
++      } else
++              HASH_PUSH_DWORD(cp, 0);
++
++      if (entry->key_present.da || entry->key_present.sa) {
++              unsigned char   mac[4];
++              if (entry->key_present.da) {
++                      data = (entry->key.da[0]) + (entry->key.da[1] << 8) +
++                                 (entry->key.da[2] << 16) + (entry->key.da[3] <<24);
++                      HASH_PUSH_DWORD(cp, data);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa) {
++                      data = (entry->key.sa[2]) + (entry->key.sa[3] << 8) +
++                                 (entry->key.sa[4] << 16) + (entry->key.sa[5] <<24);
++                      HASH_PUSH_DWORD(cp, data);
++              }
++      }
++
++      if (entry->key_present.ip_protocol) {
++              unsigned char ip_protocol;
++              ip_protocol = entry->key.ip_protocol;
++              data = ip_protocol;
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      if (entry->key_present.ipv6_flow_label) {
++              unsigned long flow_label;
++              flow_label  = entry->key.ipv6_flow_label;
++              data = flow_label & 0xfffff;
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      if (entry->key_present.sip)     {
++              {
++                      data = IPIV(entry->key.sip[0], entry->key.sip[1],
++                                      entry->key.sip[2], entry->key.sip[3]);
++                      HASH_PUSH_DWORD(cp, data);
++                      if (entry->key.ipv6) {
++                              for (i=4; i<16; i+=4) {
++                                      data = IPIV(entry->key.sip[i+0], entry->key.sip[i+1],
++                                                      entry->key.sip[i+2], entry->key.sip[i+3]);
++                                      HASH_PUSH_DWORD(cp, data);
++                              }
++                      }
++              }
++      }
++
++      if (entry->key_present.dip)     {
++              {
++                      data = IPIV(entry->key.dip[0], entry->key.dip[1],
++                                              entry->key.dip[2], entry->key.dip[3]);
++                      HASH_PUSH_DWORD(cp, data);
++                      if (entry->key.ipv6) {
++                              for (i=4; i<16; i+=4) {
++                                      data = IPIV(entry->key.dip[i+0], entry->key.dip[i+1],
++                                                              entry->key.dip[i+2], entry->key.dip[i+3]);
++                                      HASH_PUSH_DWORD(cp, data);
++                              }
++                      }
++              }
++      }
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l4_bytes[0];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l7_bytes[0];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              unsigned char *datap;
++              datap = &entry->key.l7_bytes[4];
++              data =  datap[0] +      (datap[1] << 8) + (datap[2] << 16) + (datap[3] << 24);
++              HASH_PUSH_DWORD(cp, data);
++      }
++
++      total = (unsigned long)((unsigned long)cp - (unsigned long)destp) / (sizeof(u32));
++      if (total > HASH_MAX_KEY_DWORD) {
++              //printf("Total key words (%d) is too large (> %d)!\n",
++              //              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++      index = hash_gen_crc16((unsigned char*)(destp + 1), (total-1)*4);
++      entry->index = index & ((1 << HASH_BITS)-1);
++
++      cp = (unsigned char*) destp;
++      cp += 3;
++      HASH_PUSH_BYTE(cp, entry->rule);
++      entry->total_dwords = total;
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_add_toe_entry
++*----------------------------------------------------------------------*/
++int hash_add_toe_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++
++      rc = hash_build_toe_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++      //hash_dump_entry(entry->index);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++
++/*----------------------------------------------------------------------
++* hash_write_entry
++*----------------------------------------------------------------------*/
++int hash_write_entry(HASH_ENTRY_T *entry, unsigned char *key)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)key;
++      destp2 = destp = (u32 *)&hash_tables[entry->index][0];
++
++      for (i=0; i<(entry->total_dwords); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      srcep = (u32 *)&entry->action;
++      *destp++ = *srcep;
++
++      srcep = (u32 *)&entry->param;
++      for (i=0; i<(sizeof(ENTRY_PARAM_T)/sizeof(*destp)); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      memset(destp, 0, (HASH_MAX_DWORDS-entry->total_dwords-HASH_ACTION_DWORDS) * sizeof(u32));
++
++      consistent_sync(destp2, (entry->total_dwords+HASH_ACTION_DWORDS) * 4, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* hash_timer_func
++*----------------------------------------------------------------------*/
++static void hash_timer_func(u32 data)
++{
++      int                                     i, j, idx;
++      volatile u32            *own_p, *valid_p;
++      u32                                     own_bits, a_bits;
++      int                                     period = HASH_TIMER_PERIOD;
++
++      valid_p = (volatile u32 *)TOE_V_BIT_BASE;
++      own_p = (volatile u32 *)hash_nat_owner_bits;
++      for (i=0, idx=0; i<(HASH_TOTAL_ENTRIES/32); i++, own_p++, valid_p++, idx+=32)
++      {
++              a_bits = readl(TOE_A_BIT_BASE + (i*4));
++              own_bits = *own_p;
++              if (own_bits)
++              {
++                      for (j=0; own_bits && j<32; j++)
++                      {
++                              if (own_bits & 1)
++                              {
++                                      short *counter_p, *interval_p;
++                                      NAT_HASH_ENTRY_T        *nat_entry;
++                                      GRE_HASH_ENTRY_T        *gre_entry;
++                                      nat_entry = (NAT_HASH_ENTRY_T *)hash_get_entry(idx+j);
++                                      gre_entry = (GRE_HASH_ENTRY_T *)nat_entry;
++                                      if (nat_entry->key.ip_protocol == IPPROTO_GRE)
++                                      {
++                                              counter_p = (short *)&gre_entry->tmo.counter;
++                                              interval_p = (short *)&gre_entry->tmo.interval;
++                                      }
++                                      else
++                                      {
++                                              counter_p = (short *)&nat_entry->tmo.counter;
++                                              interval_p = (short *)&nat_entry->tmo.interval;
++                                      }
++                                      if (a_bits & 1)
++                                      {
++                                              *counter_p = *interval_p;
++                                      }
++                                      else
++                                      {
++                                              *counter_p -= HASH_TIMER_PERIOD;
++                                              if (*counter_p <= 0)
++                                              {
++                                                      *valid_p &= ~(1 << j);          // invalidate it
++                                                      *own_p &= ~(1 << j);            // release ownership for NAT
++                                                      *counter_p = 0;
++                                                      // hash_printf("%lu %s: Clear hash index: %d\n", jiffies/HZ, __func__, i*32+j);
++                                              }
++                                              else if (period > *counter_p)
++                                              {
++                                                      period = *counter_p;
++                                              }
++                                      }
++                              }
++                              a_bits >>= 1;
++                              own_bits >>=1;
++                      }
++              }
++      }
++
++      hash_timer_obj.expires = jiffies + (period * HZ);
++      add_timer((struct timer_list *)data);
++}
++
++/*----------------------------------------------------------------------
++* dm_long
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              hash_printf("0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               hash_printf("         ");
++                      else
++                      {
++                              data = *datap;
++                              hash_printf("%08X ", data);
++                      }
++                      if (i==1)
++              hash_printf("- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        hash_printf("\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_dump_entry
++*----------------------------------------------------------------------*/
++void hash_dump_entry(int index)
++{
++      hash_printf("Hash Index %d:\n", index);
++      dm_long((u32)&hash_tables[index][0], HASH_MAX_DWORDS);
++}
++
++
+--- /dev/null
++++ b/drivers/net/sl351x_nat.c
+@@ -0,0 +1,1736 @@
++/****************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*----------------------------------------------------------------------------
++* Name                        : sl351x_nat.c
++* Description :
++*             Handle Storlink SL351x NAT Functions
++*
++*
++* Packet Flow:
++*
++*            (xmit)+<--- SW NAT -->+(xmit)
++*                  |       ^^      |
++*                  |       ||      |
++*                  |       ||      |
++*   Client <---> GMAC-x  HW-NAT  GMAC-y  <---> Server
++*
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/if_ether.h>
++#include <linux/if_pppox.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/ppp_defs.h>
++
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++#ifdef CONFIG_NETFILTER
++// #include <linux/netfilter/nf_conntrack.h>
++#include <linux/netfilter/nf_conntrack_tcp.h>
++#endif
++
++//#define NAT_DEBUG_MSG               1
++#define _NOT_CHECK_SIP_DIP
++//#define     SL351x_NAT_TEST_BY_SMARTBITS            1       // Initialize 32 hash entries and test by SmartBITS
++#define VITESSE_G5SWITCH      1
++
++#ifdef CONFIG_SL351x_NAT
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL3516_ASIC
++#define CONFIG_SL351x_NAT_TCP_UDP
++#define CONFIG_SL351x_NAT_GRE
++#define CONFIG_SL351x_TCP_UDP_RULE_ID 0
++#define CONFIG_SL351x_GRE_RULE_ID             1
++#else
++#define CONFIG_SL351x_NAT_TCP_UDP
++//#define CONFIG_SL351x_NAT_GRE
++#define CONFIG_SL351x_TCP_UDP_RULE_ID 0
++#define CONFIG_SL351x_GRE_RULE_ID             0
++#endif
++
++#define       nat_printf                                      printk
++#define NAT_FTP_CTRL_PORT                     (21)    // TCP
++#define NAT_H323_PORT                         (1720)  // TCP
++#define NAT_T120_PORT                         (1503)  // TCP
++#define NAT_PPTP_PORT                         (1723)  // TCP
++#define NAT_TFTP_PORT                                 (69)    // UDP
++#define NAT_DNS_PORT                          (53)    // UDP
++#define NAT_NTP_PORT                          (123)   // UDP
++#define NAT_RAS_PORT                          (1719)  // UDP
++#define NAT_BOOTP67_PORT                      (67)    // UDP
++#define NAT_BOOTP68_PORT                      (68)    // UDP
++
++#define NAT_TCP_PORT_MAX                      64
++#define NAT_UDP_PORT_MAX                      64
++
++#define GRE_PROTOCOL                          (0x880b)
++#define GRE_PROTOCOL_SWAP                     __constant_htons(0x880b)
++
++#ifdef VITESSE_G5SWITCH
++extern int Giga_switch;
++#endif
++
++typedef struct
++{
++      u16             flags_ver;
++      u16             protocol;
++      u16             payload_length;
++      u16             call_id;
++      u32             seq;
++      u32             ack;
++} GRE_PKTHDR_T;
++
++/*----------------------------------------------------------------------
++* NAT Configuration
++*
++* Note: Any change for network setting, the NAT configuration should
++*       be changed also.
++*     cfg->lan_port   0 if GMAC-0, 1: if GMAC-1
++*     cfg->wan_port   0 if GMAC-0, 1: if GMAC-1
++*     cfg->lan_ipaddr, cfg->lan_gateway, cfg->lan_netmask
++*     cfg->wan_ipaddr, cfg->wan_gateway, cfg->wan_netmask
++*
++*----------------------------------------------------------------------*/
++NAT_CFG_T             nat_cfg;
++static int            nat_initialized;
++u32                   nat_collision;
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++static u16            fixed_tcp_port_list[]={NAT_FTP_CTRL_PORT,
++                                                                              NAT_H323_PORT,
++                                                                              // NAT_T120_PORT,
++                                                                              NAT_PPTP_PORT,
++                                                                              0};
++static u16            fixed_udp_port_list[]={NAT_DNS_PORT,
++                                                                              NAT_NTP_PORT,
++                                                                              NAT_TFTP_PORT,
++                                                                              NAT_RAS_PORT,
++                                                                              NAT_BOOTP67_PORT,
++                                                                              NAT_BOOTP68_PORT,
++                                                                              0};
++#endif
++
++// #define _HAVE_DYNAMIC_PORT_LIST
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++static u16            dynamic_tcp_port_list[NAT_TCP_PORT_MAX+1];
++static u16            dynamic_udp_port_list[NAT_UDP_PORT_MAX+1]};
++#endif
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++int sl351x_nat_tcp_udp_output(struct sk_buff *skb, int port);
++int sl351x_nat_udp_output(struct sk_buff *skb, int port);
++int sl351x_nat_gre_output(struct sk_buff *skb, int port);
++
++extern int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++extern void hash_dump_entry(int index);
++extern void mac_get_hw_tx_weight(struct net_device *dev, char *weight);
++extern void mac_set_hw_tx_weight(struct net_device *dev, char *weight);
++
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++static void nat_init_test_entry(void);
++#endif
++/*----------------------------------------------------------------------
++* sl351x_nat_init
++*     initialize a NAT matching rule
++*     Called by SL351x Driver
++*             key             : port, protocol, Sip, Dip, Sport, Dport
++*             Action  : Srce Q: HW Free Queue,
++*                               Dest Q: HW TxQ
++*                               Change DA
++*                               Change SA
++*                 Change Sip or Dip
++*                       Change Sport or Dport
++*----------------------------------------------------------------------*/
++void sl351x_nat_init(void)
++{
++      int                                     rc;
++      GMAC_MRxCR0_T           mrxcr0;
++      GMAC_MRxCR1_T           mrxcr1;
++      GMAC_MRxCR2_T           mrxcr2;
++      NAT_CFG_T                       *cfg;
++
++      if (nat_initialized)
++              return;
++
++      nat_initialized = 1;
++
++      if ((sizeof(NAT_HASH_ENTRY_T) > HASH_MAX_BYTES) ||
++              (sizeof(GRE_HASH_ENTRY_T) > HASH_MAX_BYTES))
++      {
++              nat_printf("NAT_HASH_ENTRY_T structure Size is too larger!\n");
++              while(1);
++      }
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      memset((void *)cfg, 0, sizeof(NAT_CFG_T));
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++      memset((void *)dynamic_tcp_port_list, 0, sizeof(dynamic_tcp_port_list));
++      memset((void *)dynamic_udp_port_list, 0, sizeof(dynamic_udp_port_list));
++#endif
++
++#ifdef VITESSE_G5SWITCH
++      if(Giga_switch)
++      {
++              cfg->enabled                    = 1;
++              cfg->tcp_udp_rule_id    = CONFIG_SL351x_TCP_UDP_RULE_ID;
++              cfg->gre_rule_id                = CONFIG_SL351x_GRE_RULE_ID;
++              cfg->lan_port                   = 1;
++              cfg->wan_port                   = 0;
++              cfg->default_hw_txq     = 3;
++              cfg->tcp_tmo_interval   = 60;
++              cfg->udp_tmo_interval   = 180;
++              cfg->gre_tmo_interval   = 60;
++      }
++      else
++      {
++              cfg->enabled                    = 1;
++              cfg->tcp_udp_rule_id    = CONFIG_SL351x_TCP_UDP_RULE_ID;
++              cfg->gre_rule_id                = CONFIG_SL351x_GRE_RULE_ID;
++              cfg->lan_port                   = 0;
++              cfg->wan_port                   = 1;
++              cfg->default_hw_txq     = 3;
++              cfg->tcp_tmo_interval   = 60;
++              cfg->udp_tmo_interval   = 180;
++              cfg->gre_tmo_interval   = 60;
++
++      }
++#endif
++
++#if 1 //      debug purpose
++      cfg->ipcfg[0].total                             = 1;
++      cfg->ipcfg[0].entry[0].ipaddr   = IPIV(192,168,2,92);
++      cfg->ipcfg[0].entry[0].netmask  = IPIV(255,255,255,0);
++      cfg->ipcfg[1].total                             = 1;
++      cfg->ipcfg[1].entry[0].ipaddr   = IPIV(192,168,1,200);
++      cfg->ipcfg[1].entry[0].netmask  = IPIV(255,255,255,0);
++#endif
++
++#if 1
++      cfg->xport.total = 0;
++#else
++      cfg->xport.total = 4;
++
++      // H.323/H.225 Call setup
++      cfg->xport.entry[0].protocol = IPPROTO_TCP;
++      cfg->xport.entry[0].sport_start = 0;
++      cfg->xport.entry[0].sport_end = 0;
++      cfg->xport.entry[0].dport_start = 1720;
++      cfg->xport.entry[0].dport_end = 1720;
++      cfg->xport.entry[1].protocol = IPPROTO_TCP;
++      cfg->xport.entry[1].sport_start = 1720;
++      cfg->xport.entry[1].sport_end = 1720;
++      cfg->xport.entry[1].dport_start = 0;
++      cfg->xport.entry[1].dport_end = 0;
++
++      // RAS Setup
++      cfg->xport.entry[2].protocol = IPPROTO_UDP;
++      cfg->xport.entry[2].sport_start = 0;
++      cfg->xport.entry[2].sport_end = 0;
++      cfg->xport.entry[2].dport_start = 1719;
++      cfg->xport.entry[2].dport_end = 1719;
++      cfg->xport.entry[3].protocol = IPPROTO_UDP;
++      cfg->xport.entry[3].sport_start = 1719;
++      cfg->xport.entry[3].sport_end = 1719;
++      cfg->xport.entry[3].dport_start = 0;
++      cfg->xport.entry[3].dport_end = 0;
++#endif
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.port = 1;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0x0f; // Byte 0-3
++      mrxcr0.bits.sprx = 3;
++
++      rc = mac_set_rule_reg(cfg->lan_port, cfg->tcp_udp_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++      if (rc < 0)
++      {
++              nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->lan_port, cfg->tcp_udp_rule_id);
++      }
++
++      if (cfg->lan_port != cfg->wan_port)
++      {
++              rc = mac_set_rule_reg(cfg->wan_port, cfg->tcp_udp_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++              if (rc < 0)
++              {
++                      nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->wan_port, cfg->tcp_udp_rule_id);
++              }
++      }
++#endif
++
++#ifdef CONFIG_SL351x_NAT_GRE
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.port = 1;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0xcc; // Byte 2, 3, 6, 7
++      mrxcr0.bits.sprx = 4;                   // see GMAC driver about SPR
++
++      rc = mac_set_rule_reg(cfg->lan_port, cfg->gre_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++      if (rc < 0)
++      {
++              nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->lan_port, cfg->gre_rule_id);
++      }
++
++      if (cfg->lan_port != cfg->wan_port)
++      {
++              rc = mac_set_rule_reg(cfg->wan_port, cfg->gre_rule_id, 1, mrxcr0.bits32, mrxcr1.bits32, mrxcr2.bits32);
++              if (rc < 0)
++              {
++                      nat_printf("NAT Failed to set MAC-%d Rule %d!\n", cfg->wan_port, cfg->gre_rule_id);
++              }
++      }
++#endif
++
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++      nat_init_test_entry();
++#endif
++}
++
++/*----------------------------------------------------------------------
++* nat_build_keys
++*     Note: To call this routine, the key->rule_id MUST be zero
++*----------------------------------------------------------------------*/
++static inline int nat_build_keys(NAT_KEY_T *key)
++{
++      return hash_gen_crc16((unsigned char *)key, NAT_KEY_SIZE) & HASH_BITS_MASK;
++}
++
++/*----------------------------------------------------------------------
++* gre_build_keys
++*     Note: To call this routine, the key->rule_id MUST be zero
++*----------------------------------------------------------------------*/
++static inline int gre_build_keys(GRE_KEY_T *key)
++{
++      return hash_gen_crc16((unsigned char *)key, GRE_KEY_SIZE) & HASH_BITS_MASK;
++}
++
++/*----------------------------------------------------------------------
++* nat_write_hash_entry
++*----------------------------------------------------------------------*/
++static inline int nat_write_hash_entry(int index, void *hash_entry)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)hash_entry;
++      destp = destp2 = (u32 *)&hash_tables[index][0];
++
++      for (i=0; i<(NAT_HASH_ENTRY_SIZE/sizeof(u32)); i++)
++              *destp++ = *srcep++;
++
++      consistent_sync(destp2, NAT_HASH_ENTRY_SIZE, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* gre_write_hash_entry
++*----------------------------------------------------------------------*/
++static inline int gre_write_hash_entry(int index, void *hash_entry)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)hash_entry;
++      destp = destp2 = (u32 *)&hash_tables[index][0];
++
++      for (i=0; i<(GRE_HASH_ENTRY_SIZE/sizeof(u32)); i++)
++              *destp++ = *srcep++;
++
++      consistent_sync(destp2, GRE_HASH_ENTRY_SIZE, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_find_ipcfg
++*     return NULL if not found
++*----------------------------------------------------------------------*/
++static NAT_IP_ENTRY_T *sl351x_nat_find_ipcfg(u32 ipaddr, int port)
++{
++      int                             i;
++      NAT_IP_ENTRY_T  *ipcfg;
++
++      ipcfg = (NAT_IP_ENTRY_T *)&nat_cfg.ipcfg[port].entry[0];
++      for (i=0; i<nat_cfg.ipcfg[port].total; i++, ipcfg++)
++      {
++              if (ipaddr == ipcfg->ipaddr)
++              {
++                      return ipcfg;
++              }
++      }
++      return NULL;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_assign_qid
++*----------------------------------------------------------------------*/
++static int sl351x_nat_assign_qid(u8 proto, u32 sip, u32 dip, u16 sport, u16 dport)
++{
++      int                             i, total, qid;
++      NAT_WRULE_ENTRY_T       *entry;
++
++      for (qid = 0; qid<CONFIG_NAT_TXQ_NUM; qid++)
++      {
++              if (qid == nat_cfg.default_hw_txq)
++                      continue;
++
++              entry = (NAT_WRULE_ENTRY_T *)&nat_cfg.wrule[qid].entry[0];
++              total = nat_cfg.wrule[qid].total;
++              for (i=0; i<total; i++, entry++)
++              {
++                      if (!entry->protocol || entry->protocol==proto)
++                      {
++                              //if (!entry->sip_start && !entry->dip_start && !entry->sport_start && !entry->dport_start)
++                              //      continue; // UI take care
++                              if (entry->sip_start && !((sip >= entry->sip_start) &&
++                                                                         (sip <= entry->sip_end)))
++                                      continue;
++                              if (entry->dip_start && !((dip >= entry->dip_start) &&
++                                                                         (dip <= entry->dip_end)))
++                                      continue;
++                              if (entry->sport_start && !((sport >= entry->sport_start) &&
++                                                                         (sport <= entry->sport_end)))
++                                      continue;
++                              if (entry->dport_start && !((dport >= entry->dport_start)
++                                                                     && (dport <= entry->dport_end)))
++                                      continue;
++                              return qid;
++                      }
++              }
++      }
++      return nat_cfg.default_hw_txq;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_input
++*     Handle NAT input frames
++*     Called by SL351x Driver - Handle Default Rx Queue
++*     Notes: The caller must make sure that the l3off & l4offset should not be zero.
++*     SL351x NAT Frames should meet the following conditions:
++*     1. TCP or UDP frame
++*     2. Cannot be special ALGs ports which TCP/UDP data is updated
++*     3. LAN-IN Frames:
++*             Source IP is in the LAN subnet and Destination is not in the LAN subnet
++*     4. WAN-IN Frames
++*             Destination IP is in the WAN port IP
++*
++*     Example Ports
++*     1. TCP/UDP data is updated
++*             (a) FTP Control Packet
++*             (b) VoIP Packets
++*             (c) etc. (add in future)
++*     2. UDP Low packet rate, not worth
++*             (b) TFTP Destination Port is 69
++*             (b) DNS  53
++*             (c) NTP  123
++*             (d) etc. (add in future)
++*----------------------------------------------------------------------*/
++void sl351x_nat_input(struct sk_buff *skb, int port, void *l3off, void *l4off)
++{
++      int                             i, found;
++      u32                                     sip, dip;
++      u16                                     sport, dport;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct tcphdr           *tcp_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      NAT_CB_T                        *nat_cb;
++      u8                                      proto, pppoe_frame=0;
++      NAT_CFG_T                       *cfg;
++      u16                                     ppp_proto;
++      NAT_IP_ENTRY_T          *ipcfg;
++      NAT_XPORT_ENTRY_T       *xentry;
++      GRE_PKTHDR_T            *gre_hdr;
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      u16                             *port_ptr;
++#endif
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      if (!cfg->enabled || !cfg->ipcfg[port].total)
++              return;
++
++      ip_hdr = (struct iphdr *)&(skb->data[(u32)l3off]);
++      proto = ip_hdr->protocol;
++
++      tcp_hdr = (struct tcphdr *)&(skb->data[(u32)l4off]);
++      gre_hdr = (GRE_PKTHDR_T *)tcp_hdr;
++      sport = ntohs(tcp_hdr->source);
++      dport = ntohs(tcp_hdr->dest);
++
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++
++      if (dip == IPIV(255,255,255,255))
++              return;
++
++      if (port == cfg->lan_port)
++      {
++              ipcfg = (NAT_IP_ENTRY_T *)&cfg->ipcfg[port].entry[0];
++              for (i=0, found=0; i<cfg->ipcfg[port].total; i++, ipcfg++)
++              {
++                      u32 subnet = ipcfg->ipaddr & ipcfg->netmask;
++                      if (((sip & ipcfg->netmask) == subnet) &&
++                              ((dip & ipcfg->netmask) != subnet))
++                      {
++                              found = 1;
++                              break;
++                      }
++              }
++              if (!found)
++                      return;
++      }
++      else
++      {
++#ifndef _NOT_CHECK_SIP_DIP    // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(dip, port))
++              {
++                      printk("WAN->LAN Incorrect Dip %d.%d.%d.%d\n", HIPQUAD(dip));
++                      return;
++              }
++#endif
++              ether_hdr = (struct ethhdr *)skb->data;
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      pppoe_frame = 1;
++              }
++      }
++
++#ifdef CONFIG_SL351x_NAT_TCP_UDP
++      if (proto == IPPROTO_TCP)
++      {
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X TCP %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_SYN) nat_printf(" SYN");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_FIN) nat_printf(" FIN");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_RST) nat_printf(" RST");
++              if (tcp_flag_word(tcp_hdr) & TCP_FLAG_ACK) nat_printf(" ACK");
++              nat_printf("\n");
++#endif
++              // if (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST))
++              if (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN))
++              {
++                      return;
++              }
++              port_ptr = fixed_tcp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++              port_ptr = dynamic_tcp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#endif
++      }
++      else if (proto == IPPROTO_UDP)
++      {
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X UDP %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              nat_printf("\n");
++#endif
++              port_ptr = fixed_udp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++              port_ptr = dynamic_udp_port_list;
++              for (i=0; *port_ptr; i++, port_ptr++)
++              {
++                      if (sport == *port_ptr || dport == *port_ptr)
++                              return;
++              }
++#endif
++      }
++      else
++#endif        // CONFIG_SL351x_NAT_TCP_UDP
++#ifdef CONFIG_SL351x_NAT_GRE
++      if (proto == IPPROTO_GRE)
++      {
++              if (gre_hdr->protocol != GRE_PROTOCOL_SWAP)
++                      return;
++#ifdef        NAT_DEBUG_MSG
++              nat_printf("From   GMAC-%d: 0x%-4X GRE %d.%d.%d.%d [%d] --> %d.%d.%d.%d",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), ntohs(gre_hdr->call_id),
++                              NIPQUAD(ip_hdr->daddr));
++              nat_printf("\n");
++#endif
++      }
++      else
++#endif
++              return;
++
++
++      // check xport list
++      xentry = (NAT_XPORT_ENTRY_T *)&cfg->xport.entry[0];
++      for (i=0; i<cfg->xport.total; i++, xentry++)
++      {
++              if (!xentry->protocol || xentry->protocol == proto)
++              {
++                      //if (!xentry->sport_start && !xentry->dport_start) // UI take care
++                      //      continue;
++                      if (xentry->sport_start && !((sport >= xentry->sport_start) &&
++                                                                         (sport <= xentry->sport_end)))
++                              continue;
++                      if (xentry->dport_start && !((dport >= xentry->dport_start)
++                                                                     && (dport <= xentry->dport_end)))
++                              continue;
++                      return;
++              }
++      }
++
++      nat_cb = NAT_SKB_CB(skb);
++      if (((u32)nat_cb & 3))
++      {
++              nat_printf("%s ERROR! nat_cb is not alignment!!!!!!\n", __func__);
++              return;
++      }
++      nat_cb->tag = NAT_CB_TAG;
++      memcpy(nat_cb->sa, skb->data+6, 6);
++      nat_cb->sip = ip_hdr->saddr;
++      nat_cb->dip = ip_hdr->daddr;
++      if (proto == IPPROTO_GRE)
++      {
++              nat_cb->sport = gre_hdr->protocol;
++              nat_cb->dport = gre_hdr->call_id;
++      }
++      else
++      {
++              nat_cb->sport = tcp_hdr->source;
++              nat_cb->dport = tcp_hdr->dest;
++      }
++      nat_cb->pppoe_frame = pppoe_frame;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_output
++*     Handle NAT output frames
++*     Called by SL351x Driver - Transmit
++*
++*     1. If not SL351x NAT frames, return FALSE
++*     2. LAN-to-WAN frames
++*             (1) Sip must be WAN IP
++*     3. If TCP SY/RST/FIN frame, return
++*     4. Build the hash key and get the hash index
++*     5. If V-Bit is ON, return.
++*     6. Write hash entry and validate it
++*
++*----------------------------------------------------------------------*/
++int sl351x_nat_output(struct sk_buff *skb, int port)
++{
++      struct iphdr            *ip_hdr;
++      u8                                      proto;
++      NAT_CB_T                        *nat_cb;
++
++      nat_cb = NAT_SKB_CB(skb);
++      if (nat_cb->tag != NAT_CB_TAG)
++              return 0;
++
++      if (((u32)nat_cb & 3))
++      {
++              nat_printf("%s ERROR! nat_cb is not alignment!!!!!!\n", __func__);
++              return 0;
++      }
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      proto = ip_hdr->protocol;
++
++      switch (proto)
++      {
++              case IPPROTO_TCP:
++              case IPPROTO_UDP:
++                      return sl351x_nat_tcp_udp_output(skb, port);
++              case IPPROTO_GRE:
++                      return sl351x_nat_gre_output(skb, port);
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_tcp_udp_output
++*     Handle NAT TCP/UDP output frames
++*----------------------------------------------------------------------*/
++int sl351x_nat_tcp_udp_output(struct sk_buff *skb, int port)
++{
++      u32                                     sip, dip;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct tcphdr           *tcp_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      NAT_CB_T                        *nat_cb;
++      NAT_CFG_T                       *cfg;
++      u8                                      proto;
++      u16                                     sport, dport, ppp_proto;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      NAT_HASH_ENTRY_T        *hash_entry;
++      int                                     hash_index;
++      struct ip_conntrack *nat_ip_conntrack;
++      enum ip_conntrack_info ctinfo;
++
++      nat_cb = NAT_SKB_CB(skb);
++      cfg = (NAT_CFG_T *)&nat_cfg;
++
++      ether_hdr = (struct ethhdr *)skb->data;
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      tcp_hdr = (struct tcphdr *)((u32)ip_hdr + (ip_hdr->ihl<<2));
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++      proto = ip_hdr->protocol;
++      sport = ntohs(tcp_hdr->source);
++      dport = ntohs(tcp_hdr->dest);
++
++#ifdef        NAT_DEBUG_MSG
++      {
++              nat_printf("To   GMAC-%d: 0x%-4X [%d] %d.%d.%d.%d [%d] --> %d.%d.%d.%d [%d]",
++                              port, ntohs(ip_hdr->id), proto,
++                              NIPQUAD(ip_hdr->saddr), sport,
++                              NIPQUAD(ip_hdr->daddr), dport);
++              if (proto == IPPROTO_TCP)
++              {
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_SYN) nat_printf(" SYN");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_FIN) nat_printf(" FIN");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_RST) nat_printf(" RST");
++                      if (tcp_flag_word(tcp_hdr) & TCP_FLAG_ACK) nat_printf(" ACK");
++              }
++              nat_printf("\n");
++      }
++#endif
++      nat_ip_conntrack = ip_conntrack_get(skb, &ctinfo);
++      if (!nat_ip_conntrack)
++      {
++              nat_printf("IP conntrack info is not found!\n");
++              return 0;
++      }
++      // nat_printf("nat_ip_conntrack = 0x%x, status=0x%lx, ctinfo=%d\n", (u32)nat_ip_conntrack, nat_ip_conntrack->status, ctinfo);
++      // if (nat_ip_conntrack->master || nat_ip_conntrack->helper)
++      if (nat_ip_conntrack->helper)
++      {
++              nat_printf("Sport=%d Dport=%d master=0x%x, helper=0x%x\n", sport, dport, (u32)nat_ip_conntrack->master, (u32)nat_ip_conntrack->helper);
++              return 0;
++      }
++
++      //if (proto == IPPROTO_TCP && !(nat_ip_conntrack->status & IPS_ASSURED))
++      //      return 0;
++
++#ifdef        NAT_DEBUG_MSG
++      nat_printf("nat_ip_conntrack=0x%x, nat_cb->state=%d\n", (u32)nat_ip_conntrack, nat_cb->state);
++      nat_printf("lan2wan_hash_index=%d,  wan2lan_hash_index=%d\n", nat_ip_conntrack->lan2wan_hash_index, nat_ip_conntrack->wan2lan_hash_index);
++      nat_printf("lan2wan_collision=%d, wan2lan_collision=%d\n", nat_ip_conntrack->lan2wan_collision, nat_ip_conntrack->wan2lan_collision);
++#endif
++      if (proto == IPPROTO_TCP)
++      {
++              if (nat_cb->state >= TCP_CONNTRACK_FIN_WAIT && nat_cb->state <= TCP_CONNTRACK_CLOSE)
++              {
++                      if      (nat_ip_conntrack->lan2wan_hash_index)
++                      {
++#ifdef        NAT_DEBUG_MSG
++                              nat_printf("Invalidate LAN->WAN hash entry %d\n", nat_ip_conntrack->lan2wan_hash_index - 1);
++#endif
++                              hash_nat_disable_owner(nat_ip_conntrack->lan2wan_hash_index - 1);
++                              hash_invalidate_entry(nat_ip_conntrack->lan2wan_hash_index - 1);
++                              nat_ip_conntrack->lan2wan_hash_index = 0;
++                      }
++                      if      (nat_ip_conntrack->wan2lan_hash_index)
++                      {
++#ifdef        NAT_DEBUG_MSG
++                              nat_printf("Invalidate WAN->LAN hash entry %d\n", nat_ip_conntrack->wan2lan_hash_index - 1);
++#endif
++                              hash_nat_disable_owner(nat_ip_conntrack->wan2lan_hash_index - 1);
++                              hash_invalidate_entry(nat_ip_conntrack->wan2lan_hash_index - 1);
++                              nat_ip_conntrack->wan2lan_hash_index = 0;
++                      }
++                      return 0;
++
++              }
++              else if (nat_cb->state != TCP_CONNTRACK_ESTABLISHED)
++              {
++                      return 0;
++              }
++      }
++      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST)))
++      // if (proto == IPPROTO_TCP &&  (tcp_flag_word(tcp_hdr) & (TCP_FLAG_SYN)))
++              return 0;
++
++      hash_entry = (NAT_HASH_ENTRY_T *)&hash_data;
++      if (port == cfg->wan_port)      // LAN-to-WAN
++      {
++              if (nat_ip_conntrack->lan2wan_hash_index || nat_ip_conntrack->lan2wan_collision)
++                      return 0;
++#ifndef _NOT_CHECK_SIP_DIP    // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(sip, port))
++              {
++                      printk("LAN->WAN Incorrect Sip %d.%d.%d.%d\n", HIPQUAD(sip));
++                      return 0;
++              }
++#endif
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->lan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = proto;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.sport           = nat_cb->sport;
++              hash_entry->key.dport           = nat_cb->dport;
++
++              hash_index = nat_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_LAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      nat_ip_conntrack->lan2wan_collision = 1;
++                      nat_collision++;
++#if 0
++                      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_FIN | TCP_FLAG_RST)))
++                      {
++                              if (memcmp((void *)&hash_entry->key, hash_get_entry(hash_index), sizeof(NAT_KEY_T)) == 0)
++                              {
++                                      hash_nat_disable_owner(hash_index);
++                                      hash_invalidate_entry(hash_index); // Must last one, else HW Tx fast SW
++                                      // nat_printf("Invalidate nat hash entry %d\n", hash_index);
++                              }
++                      }
++#endif
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = sport;
++              hash_entry->param.Dport = dport;
++              hash_entry->param.vlan = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              // check PPPoE
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      hash_entry->action.dword = NAT_PPPOE_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = htons(pppoe_hdr->sid);
++              }
++              else
++              {
++                      hash_entry->action.dword = NAT_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = 0;
++              }
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(proto, sip, dip, sport, dport);
++              hash_entry->action.bits.dest_qid +=     (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->tmo.counter = hash_entry->tmo.interval =
++                                              (proto == IPPROTO_TCP) ? cfg->tcp_tmo_interval : cfg->udp_tmo_interval;
++              nat_write_hash_entry(hash_index, hash_entry);
++              // nat_printf("%lu Validate a LAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              nat_ip_conntrack->lan2wan_hash_index = hash_index + 1;
++              nat_ip_conntrack->hw_nat |= 1;
++              return 0;
++      }
++      else // WAN-to-LAN
++      {
++              if (nat_ip_conntrack->wan2lan_hash_index || nat_ip_conntrack->wan2lan_collision)
++                      return 0;
++
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->wan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = proto;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.sport           = nat_cb->sport;
++              hash_entry->key.dport           = nat_cb->dport;
++
++              hash_index = nat_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_WAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      nat_ip_conntrack->wan2lan_collision = 1;
++                      nat_collision++;
++#if 0
++                      if (proto == IPPROTO_TCP && (tcp_flag_word(tcp_hdr) & (TCP_FLAG_FIN | TCP_FLAG_RST)))
++                      {
++                              if (memcmp((void *)&hash_entry->key, hash_get_entry(hash_index), sizeof(NAT_KEY_T)) == 0)
++                              {
++                                      hash_nat_disable_owner(hash_index);
++                                      hash_invalidate_entry(hash_index); // Must last one, else HW Tx fast SW
++                                      // nat_printf("Invalidate nat hash entry %d\n", hash_index);
++                              }
++                      }
++#endif
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = sport;
++              hash_entry->param.Dport = dport;
++              hash_entry->param.vlan = 0;
++              hash_entry->param.pppoe = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              hash_entry->action.dword = (nat_cb->pppoe_frame) ? NAT_PPPOE_WAN2LAN_ACTIONS : NAT_WAN2LAN_ACTIONS;
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(proto, sip, dip, sport, dport);
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;;
++              hash_entry->tmo.counter = hash_entry->tmo.interval =
++                                              (proto == IPPROTO_TCP) ? cfg->tcp_tmo_interval : cfg->udp_tmo_interval;
++              nat_write_hash_entry(hash_index, hash_entry);
++
++              // nat_printf("%lu Validate a WAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast SW
++              nat_ip_conntrack->wan2lan_hash_index = hash_index + 1;
++              nat_ip_conntrack->hw_nat |= 2;
++              return 0;
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* sl351x_nat_gre_output
++*     Handle NAT GRE output frames
++*----------------------------------------------------------------------*/
++int sl351x_nat_gre_output(struct sk_buff *skb, int port)
++{
++      u32                                     sip, dip;
++      struct ethhdr           *ether_hdr;
++      struct iphdr            *ip_hdr;
++      struct pppoe_hdr        *pppoe_hdr;
++      GRE_PKTHDR_T            *gre_hdr;
++      NAT_CB_T                        *nat_cb;
++      NAT_CFG_T                       *cfg;
++      u16                                     ppp_proto;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      GRE_HASH_ENTRY_T        *hash_entry;
++      int                                     hash_index;
++      struct ip_conntrack *nat_ip_conntrack;
++      enum ip_conntrack_info ctinfo;
++
++      nat_cb = NAT_SKB_CB(skb);
++      cfg = (NAT_CFG_T *)&nat_cfg;
++
++      ether_hdr = (struct ethhdr *)skb->data;
++      ip_hdr = (struct iphdr *)skb->h.ipiph;
++      gre_hdr = (GRE_PKTHDR_T *)((u32)ip_hdr + (ip_hdr->ihl<<2));
++      sip = ntohl(ip_hdr->saddr);
++      dip = ntohl(ip_hdr->daddr);
++
++#ifdef        NAT_DEBUG_MSG
++      {
++              nat_printf("To   GMAC-%d: 0x%-4X GRE %d.%d.%d.%d [%d] --> %d.%d.%d.%d",
++                              port, ntohs(ip_hdr->id),
++                              NIPQUAD(ip_hdr->saddr), ntohs(gre_hdr->call_id),
++                              NIPQUAD(ip_hdr->daddr));
++              nat_printf("\n");
++      }
++#endif
++      nat_ip_conntrack = ip_conntrack_get(skb, &ctinfo);
++      if (nat_ip_conntrack)
++      {
++              // if (nat_ip_conntrack->master || nat_ip_conntrack->helper)
++              if (nat_ip_conntrack->helper)
++              {
++                      nat_printf("GRE Call-ID=%d, master=0x%x, helper=0x%x\n", ntohs(gre_hdr->call_id), (u32)nat_ip_conntrack->master, (u32)nat_ip_conntrack->helper);
++                      return 0;
++              }
++              if (!(nat_ip_conntrack->status & IPS_ASSURED))
++                      return 0;
++      }
++
++      hash_entry = (GRE_HASH_ENTRY_T *)&hash_data;
++      if (port == cfg->wan_port)      // LAN-to-WAN
++      {
++#ifdef _NOT_CHECK_SIP_DIP     // enable it if know and get the wan ip address
++              if (!sl351x_nat_find_ipcfg(sip, port))
++              {
++                      printk("LAN->WAN Incorrect Sip %d.%d.%d.%d\n", HIPQUAD(sip));
++                      return 0;
++              }
++#endif
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->lan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = IPPROTO_GRE;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.reserved3       = 0;
++              hash_entry->key.reserved4       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.protocol        = nat_cb->sport;
++              hash_entry->key.call_id         = nat_cb->dport;
++
++              hash_index = gre_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_LAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->gre_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = 0;
++              hash_entry->param.Dport = ntohs(gre_hdr->call_id);
++              hash_entry->param.vlan = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              // check PPPoE
++              pppoe_hdr = (struct pppoe_hdr *)(ether_hdr + 1);
++              ppp_proto = *(u16 *)&pppoe_hdr->tag[0];
++              if (ether_hdr->h_proto == __constant_htons(ETH_P_PPP_SES)       // 0x8864
++                      && ppp_proto == __constant_htons(PPP_IP) )                              // 0x21
++              {
++                      hash_entry->action.dword = NAT_PPPOE_PPTP_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = htons(pppoe_hdr->sid);
++              }
++              else
++              {
++                      hash_entry->action.dword = NAT_PPTP_LAN2WAN_ACTIONS;
++                      hash_entry->param.pppoe = 0;
++              }
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(IPPROTO_GRE, sip, dip, 0, ntohs(gre_hdr->call_id));
++              hash_entry->action.bits.dest_qid +=     (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->tmo.counter = hash_entry->tmo.interval = cfg->gre_tmo_interval;
++              gre_write_hash_entry(hash_index, hash_entry);
++              // nat_printf("%lu Validate a LAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              return 0;
++      }
++      else // WAN-to-LAN
++      {
++              // Note: unused fields (including rule_id) MUST be zero
++              hash_entry->key.Ethertype       = 0;
++              hash_entry->key.port_id         = cfg->wan_port;
++              hash_entry->key.rule_id         = 0;
++              hash_entry->key.ip_protocol = IPPROTO_GRE;
++              hash_entry->key.reserved1       = 0;
++              hash_entry->key.reserved2       = 0;
++              hash_entry->key.reserved3       = 0;
++              hash_entry->key.reserved4       = 0;
++              hash_entry->key.sip             = ntohl(nat_cb->sip);
++              hash_entry->key.dip             = ntohl(nat_cb->dip);
++              hash_entry->key.protocol        = nat_cb->sport;
++              hash_entry->key.call_id         = nat_cb->dport;
++
++              hash_index = gre_build_keys(&hash_entry->key);
++
++#ifdef NAT_DEBUG_WAN_HASH_TIMEOUT
++              if (hash_get_nat_owner_flag(hash_index))
++                      return 0;
++#endif
++              if (hash_get_valid_flag(hash_index))
++              {
++                      return 0;
++              }
++
++              // write hash entry
++              hash_entry->key.rule_id = cfg->gre_rule_id;
++              memcpy(hash_entry->param.da, skb->data, 6);
++              memcpy(hash_entry->param.sa, skb->data+6, 6);
++              hash_entry->param.Sip = sip;
++              hash_entry->param.Dip = dip;
++              hash_entry->param.Sport = 0;
++              hash_entry->param.Dport = ntohs(gre_hdr->call_id);
++              hash_entry->param.vlan = 0;
++              hash_entry->param.pppoe = 0;
++              hash_entry->param.sw_id = 0;
++              hash_entry->param.mtu = 0;
++              hash_entry->action.dword = (nat_cb->pppoe_frame) ? NAT_PPPOE_PPTP_WAN2LAN_ACTIONS : NAT_PPTP_WAN2LAN_ACTIONS;
++              hash_entry->action.bits.dest_qid = sl351x_nat_assign_qid(IPPROTO_GRE, sip, dip, 0, ntohs(gre_hdr->call_id));
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;;
++              hash_entry->tmo.counter = hash_entry->tmo.interval = cfg->gre_tmo_interval;
++              gre_write_hash_entry(hash_index, hash_entry);
++
++              // nat_printf("%lu Validate a WAN hash entry %d\n", jiffies/HZ, hash_index);
++              // hash_dump_entry(hash_index);
++              hash_nat_enable_owner(hash_index);
++              hash_validate_entry(hash_index); // Must last one, else HW Tx fast SW
++              return 0;
++      }
++      return 0;
++}
++
++
++#ifdef _HAVE_DYNAMIC_PORT_LIST
++/*----------------------------------------------------------------------
++* sl_nat_add_port
++*----------------------------------------------------------------------*/
++void sl_nat_add_port(u8 protocol, u16 port)
++{
++      int     i;
++      u16             *port_ptr;
++
++      if (protocol == IPPROTO_TCP)
++              port_ptr = dynamic_tcp_port_list;
++      else if (protocol == IPPROTO_UDP)
++              port_ptr = dynamic_udp_port_list;
++      else
++              return;
++
++      for (i=0; *port_ptr; i++)
++      {
++              if (port == *port_ptr)
++                      return;
++              port_ptr++;
++      }
++      port_ptr++;
++      *port_ptr = port;
++}
++
++/*----------------------------------------------------------------------
++* sl_nat_remove_port
++*----------------------------------------------------------------------*/
++void sl_nat_remove_port(u8 protocol, u16 port)
++{
++      int     i, j;
++      u16             *port_ptr, *next;
++
++      if (protocol == IPPROTO_TCP)
++              port_ptr = dynamic_tcp_port_list;
++      else if (protocol == IPPROTO_UDP)
++              port_ptr = dynamic_udp_port_list;
++      else
++              return;
++
++      for (i=0; *port_ptr; i++, port_ptr++)
++      {
++              if (port == *port_ptr)
++              {
++                      port_next = port_ptr + 1;
++                      for (j=i+1; *port_next; i++, j++)
++                              *port_ptr++ = *port_next++;
++                      *port_ptr = 0;
++                      return;
++              }
++      }
++}
++#endif
++
++/*----------------------------------------------------------------------
++* sl351x_nat_ioctl
++*----------------------------------------------------------------------*/
++int sl351x_nat_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++      GMAC_INFO_T             *tp = (GMAC_INFO_T *)dev->priv;
++      int                             i, j, port_id;
++    NATCMD_HDR_T              nat_hdr;
++    NAT_REQ_E                 ctrl;
++      unsigned char           *req_datap;
++      NAT_IP_ENTRY_T          *ipcfg;
++      NAT_XPORT_ENTRY_T       *xport_entry;
++      NAT_WRULE_ENTRY_T       *wrule_entry;
++      unsigned int            qid;
++
++      if (copy_from_user((void *)&nat_hdr, rq->ifr_data, sizeof(nat_hdr)))
++              return -EFAULT;
++      req_datap = (unsigned char *)rq->ifr_data + sizeof(nat_hdr);
++      port_id = tp->port_id;
++      switch (nat_hdr.cmd) {
++      case NATSSTATUS:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_STATUS_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.status, req_datap, sizeof(ctrl.status)))
++                      return -EFAULT;
++              if (ctrl.status.enable != 0 && ctrl.status.enable != 1)
++                      return -EPERM;
++              // sl351x_nat_set_enabled_flag(ctrl.status.enable);
++              if (nat_cfg.enabled && (ctrl.status.enable == 0))
++              {
++                      for (i=0; i<HASH_TOTAL_ENTRIES; i++)
++                      {
++                              if (hash_get_nat_owner_flag(i))
++                              {
++                                      hash_nat_disable_owner(i);
++                                      hash_invalidate_entry(i);
++                              }
++                      }
++              }
++              nat_cfg.enabled = ctrl.status.enable;
++              break;
++      case NATGSTATUS:
++              if (nat_hdr.len != sizeof(NAT_STATUS_T))
++                      return -EPERM;
++              ctrl.status.enable = nat_cfg.enabled;
++              if (copy_to_user(req_datap, (void *)&ctrl.status, sizeof(ctrl.status)))
++                      return -EFAULT;
++              break;
++      case NATSETPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_PORTCFG_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.portcfg, req_datap, sizeof(ctrl.portcfg)))
++                      return -EFAULT;
++              if (ctrl.portcfg.portmap == 0)
++                      nat_cfg.lan_port = port_id;
++              else if (ctrl.portcfg.portmap == 1)
++                      nat_cfg.wan_port = port_id;
++              else
++                      return -EPERM;
++              break;
++      case NATGETPORT:
++              if (nat_hdr.len != sizeof(NAT_PORTCFG_T))
++                      return -EPERM;
++              if (nat_cfg.lan_port == port_id)
++                      ctrl.portcfg.portmap = 0;
++              else if (nat_cfg.wan_port == port_id)
++                      ctrl.portcfg.portmap = 1;
++              else
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&ctrl.portcfg, sizeof(ctrl.portcfg)))
++                      return -EFAULT;
++              break;
++      case NATADDIP:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_IPCFG_T))
++                      return -EPERM;
++              i = nat_cfg.ipcfg[port_id].total;
++              if (i >= CONFIG_NAT_MAX_IP_NUM)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.ipcfg[port_id].entry[i], req_datap, sizeof(NAT_IPCFG_T)))
++                      return -EFAULT;
++              nat_cfg.ipcfg[port_id].total++;
++              break;
++      case NATDELIP:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_IPCFG_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.ipcfg, req_datap, sizeof(ctrl.ipcfg)))
++                      return -EFAULT;
++              ipcfg = (NAT_IP_ENTRY_T *)&nat_cfg.ipcfg[port_id].entry[0];
++              for (i=0; i<nat_cfg.ipcfg[port_id].total; i++, ipcfg++)
++              {
++                      if (ipcfg->ipaddr == ctrl.ipcfg.entry.ipaddr)
++                      {
++                              NAT_IP_ENTRY_T *ipcfg_next;
++                              ipcfg_next = ipcfg + 1;
++                              for (j=i+1; j < nat_cfg.ipcfg[port_id].total; i++, j++)
++                              {
++                                      memcpy((void *)ipcfg, (void *)ipcfg_next, sizeof(NAT_IP_ENTRY_T));
++                                      ipcfg++;
++                                      ipcfg_next++;
++                              }
++                              ipcfg->ipaddr = 0;
++                              ipcfg->netmask = 0;
++                              nat_cfg.ipcfg[port_id].total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGETIP:
++              if (nat_hdr.len != sizeof(NAT_IPCFG_ALL_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.ipcfg[port_id], sizeof(NAT_IPCFG_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATAXPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_XPORT_T))
++                      return -EPERM;
++              i = nat_cfg.xport.total;
++              if (i >= CONFIG_NAT_MAX_XPORT)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.xport.entry[i], req_datap, sizeof(NAT_XPORT_T)))
++                      return -EFAULT;
++              nat_cfg.xport.total++;
++              break;
++      case NATDXPORT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_XPORT_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.xport, req_datap, sizeof(NAT_XPORT_T)))
++                      return -EFAULT;
++              xport_entry = (NAT_XPORT_ENTRY_T *)&nat_cfg.xport.entry[0];
++              for (i=0; i<nat_cfg.xport.total; i++, xport_entry++)
++              {
++                      if (memcmp((void *)xport_entry, (void *)&ctrl.xport, sizeof(NAT_XPORT_ENTRY_T)) == 0)
++                      {
++                              NAT_XPORT_ENTRY_T *xport_next;
++                              xport_next = xport_entry + 1;
++                              for (j=i+1; j < nat_cfg.xport.total; i++, j++)
++                              {
++                                      memcpy((void *)xport_entry, (void *)xport_next, sizeof(NAT_XPORT_ENTRY_T));
++                                      xport_entry++;
++                                      xport_next++;
++                              }
++                              memset((void *)xport_entry, 0, sizeof(NAT_XPORT_ENTRY_T));
++                              nat_cfg.xport.total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGXPORT:
++              if (nat_hdr.len != sizeof(NAT_XPORT_ALL_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.xport, sizeof(NAT_XPORT_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATSWEIGHT:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WEIGHT_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&nat_cfg.weight, req_datap, sizeof(NAT_WEIGHT_T)))
++                      return -EFAULT;
++              mac_set_hw_tx_weight(dev, (char *)&nat_cfg.weight);
++              break;
++      case NATGWEIGHT:
++              if (nat_hdr.len != sizeof(NAT_WEIGHT_T))
++                      return -EPERM;
++              mac_get_hw_tx_weight(dev, (char *)&nat_cfg.weight);
++              if (copy_to_user(req_datap, (void *)&nat_cfg.weight, sizeof(NAT_WEIGHT_T)))
++                      return -EFAULT;
++              break;
++      case NATAWRULE:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WRULE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&qid, req_datap, sizeof(qid)))
++                      return -EFAULT;
++              if (qid > CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              i = nat_cfg.wrule[qid].total;
++              if (i >= CONFIG_NAT_MAX_WRULE)
++                      return -E2BIG;
++              if (copy_from_user((void *)&nat_cfg.wrule[qid].entry[i], req_datap+sizeof(qid), sizeof(NAT_WRULE_T)))
++                      return -EFAULT;
++              nat_cfg.wrule[qid].total++;
++              break;
++      case NATDWRULE:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_WRULE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.wrule, req_datap, sizeof(NAT_WRULE_T)))
++                      return -EFAULT;
++              qid = ctrl.wrule.qid;
++              if (qid >= CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              wrule_entry = (NAT_WRULE_ENTRY_T *)&nat_cfg.wrule[qid].entry[0];
++              for (i=0; i<nat_cfg.wrule[qid].total; i++, wrule_entry++)
++              {
++                      if (memcmp((void *)wrule_entry, (void *)&ctrl.wrule.entry, sizeof(NAT_WRULE_ENTRY_T)) == 0)
++                      {
++                              NAT_WRULE_ENTRY_T *wrule_next;
++                              wrule_next = wrule_entry + 1;
++                              for (j=i+1; j < nat_cfg.wrule[qid].total; i++, j++)
++                              {
++                                      memcpy((void *)wrule_entry, (void *)wrule_next, sizeof(NAT_WRULE_ENTRY_T));
++                                      wrule_entry++;
++                                      wrule_next++;
++                              }
++                              memset((void *)wrule_entry, 0, sizeof(NAT_WRULE_ENTRY_T));
++                              nat_cfg.wrule[qid].total--;
++                              return 0;
++                      }
++              }
++              return -ENOENT;
++      case NATGWRULE:
++              if (nat_hdr.len != sizeof(NAT_WRULE_ALL_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&qid, req_datap, sizeof(qid)))
++                      return -EFAULT;
++              if (qid >= CONFIG_NAT_TXQ_NUM)
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.wrule[qid], sizeof(NAT_WRULE_ALL_T)))
++                      return -EFAULT;
++              break;
++      case NATSDEFQ:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_QUEUE_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&nat_cfg.default_hw_txq, req_datap, sizeof(u32)))
++                      return -EFAULT;
++              break;
++      case NATGDEFQ:
++              if (nat_hdr.len != sizeof(NAT_QUEUE_T))
++                      return -EPERM;
++              if (copy_to_user(req_datap, (void *)&nat_cfg.default_hw_txq, sizeof(u32)))
++                      return -EFAULT;
++      case NATRMIPCFG:
++              nat_cfg.ipcfg[port_id].total = 0;
++              break;
++      case NATTESTENTRY:
++              if (!capable(CAP_NET_ADMIN))
++                      return -EPERM;
++              if (nat_hdr.len != sizeof(NAT_TESTENTRY_T))
++                      return -EPERM;
++              if (copy_from_user((void *)&ctrl.init_entry, req_datap, sizeof(ctrl.init_entry)))
++                      return -EFAULT;
++              if (ctrl.init_entry.init_enable != 0 && ctrl.init_entry.init_enable != 1)
++                      return -EPERM;
++              nat_cfg.init_enabled = ctrl.init_entry.init_enable;
++              break;
++
++      default:
++              return -EPERM;
++      }
++
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++*     nat_init_test_entry
++*     Initialize NAT test hash entries
++*
++*     SmartBits P1  -----> Lepus GMAC 0 --------------+
++*                                                                                                     |
++*                                                                                                     |
++*             P3  <----- Lepus GMAC 1 -- HW TxQ0 <--+
++*                                                                       -- HW TxQ1 <--+
++*                                                                       -- HW TxQ2 <--+
++*                                                                       -- HW TxQ3 <--+
++*
++*     SmartBits P1  <----- Lepus GMAC 0 -- HW TxQ0 <--+
++*                                                                       -- HW TxQ1 <--+
++*                                     -- HW TxQ2 <--+
++*                                                                       -- HW TxQ3 <--+
++*                                                                                                     |
++*                                                                                                     |
++*             P3  -----> Lepus GMAC 1 --------------+
++*
++*   LAN GMAC0 <--------------------------------------------> GMAC1 WAN
++*     192.168.[x].[y]:50 --> 168.95.[x].[y]:80 ---TXQ[y-1]---> 192.168.2.254:200[y] --> 168.95.[x].[y]:80
++*     192.168.[x].[y]:50 <-- 168.95.[x].[y]:80 <--TXQ[y-1]---- 192.168.2.254:200[y] <-- 168.95.[x].[y]:80
++*   where:
++*             [x] : Packet Type
++*             [y] : Tx Queue, 1 for TxQ0, 2 for TxQ1, 3 for TxQ2, 4 for TxQ3,
++*
++*
++* Packet Type:
++* 1. TCP Frames <---> TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.1.1:50 --> 168.95.1.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.1.1:80
++*     192.168.1.1:50 <-- 168.95.1.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.1.1:80
++*
++*     192.168.1.2:50 --> 168.95.1.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.1.2:80
++*     192.168.1.2:50 <-- 168.95.1.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.1.2:80
++*
++*     192.168.1.3:50 --> 168.95.1.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.1.3:80
++*     192.168.1.3:50 <-- 168.95.1.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.1.3:80
++*
++*     192.168.1.4:50 --> 168.95.1.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.1.4:80
++*     192.168.1.4:50 <-- 168.95.1.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.1.4:80
++*
++* 2 TCP Frames <----> PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.2.1:50 --> 168.95.2.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.2.1:80
++*     192.168.2.1:50 <-- 168.95.2.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.2.1:80
++*
++*     192.168.2.2:50 --> 168.95.2.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.2.2:80
++*     192.168.2.2:50 <-- 168.95.2.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.2.2:80
++*
++*     192.168.2.3:50 --> 168.95.2.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.2.3:80
++*     192.168.2.3:50 <-- 168.95.2.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.2.3:80
++*
++*     192.168.2.4:50 --> 168.95.2.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.2.4:80
++*     192.168.2.4:50 <-- 168.95.2.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.2.4:80
++*
++* 3 TCP Frames <----> VLAN + PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.3.1:50 --> 168.95.3.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.3.1:80
++*     192.168.3.1:50 <-- 168.95.3.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.3.1:80
++*
++*     192.168.3.2:50 --> 168.95.3.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.3.2:80
++*     192.168.3.2:50 <-- 168.95.3.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.3.2:80
++*
++*     192.168.3.3:50 --> 168.95.3.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.3.3:80
++*     192.168.3.3:50 <-- 168.95.3.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.3.3:80
++*
++*     192.168.3.4:50 --> 168.95.3.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.3.4:80
++*     192.168.3.4:50 <-- 168.95.3.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.3.4:80
++*
++* 4 VLAN-A + TCP Frames <----> VLAN-B + PPPoE + TCP Frames
++*   LAN GMAC0 <--------------------------------> GMAC1 WAN
++*     192.168.4.1:50 --> 168.95.4.1:80 ---TXQ0---> 192.168.2.254:2001 --> 168.95.4.1:80
++*     192.168.4.1:50 <-- 168.95.4.1:80 <--TXQ0---- 192.168.2.254:2001 <-- 168.95.4.1:80
++*
++*     192.168.4.2:50 --> 168.95.4.2:80 ---TXQ1---> 192.168.2.254:2002 --> 168.95.4.2:80
++*     192.168.4.2:50 <-- 168.95.4.2:80 <--TXQ1---- 192.168.2.254:2002 <-- 168.95.4.2:80
++*
++*     192.168.4.3:50 --> 168.95.4.3:80 ---TXQ2---> 192.168.2.254:2003 --> 168.95.4.3:80
++*     192.168.4.3:50 <-- 168.95.4.3:80 <--TXQ2---- 192.168.2.254:2003 <-- 168.95.4.3:80
++*
++*     192.168.4.4:50 --> 168.95.4.4:80 ---TXQ3---> 192.168.2.254:2004 --> 168.95.4.4:80
++*     192.168.4.4:50 <-- 168.95.4.4:80 <--TXQ3---- 192.168.2.254:2004 <-- 168.95.4.4:80
++*
++*
++*
++*----------------------------------------------------------------------*/
++#ifdef SL351x_NAT_TEST_BY_SMARTBITS
++#define       NAT_IPIV(a,b,c,d)                       ((a<<24)+(b<<16)+(c<<8)+d)
++#define     NAT_TEST_CLIENT_IP                        NAT_IPIV(192,168,1,1)
++#define     NAT_TEST_SERVER_IP                        NAT_IPIV(168,95,1,1)
++#define               NAT_TEST_LAN_IP                         NAT_IPIV(192,168,1,254)
++#define               NAT_TEST_WAN_IP                         NAT_IPIV(192,168,2,254)
++#define     NAT_TEST_MAP_PORT_BASE            2001
++#define     NAT_TEST_SPORT                            50
++#define     NAT_TEST_DPORT                            80
++#define     NAT_TEST_PROTOCOL                 6
++u8                    nat_test_lan_target_da[6]={0x00,0x11,0x22,0x33,0x44,0x55};
++u8                    nat_test_wan_target_da[6]={0x00,0xaa,0xbb,0xcc,0xdd,0xee};
++u8                    nat_test_lan_my_da[6]={0x00,0x11,0x11,0x11,0x11,0x11};
++u8                    nat_test_wan_my_da[6]={0x00,0x22,0x22,0x22,0x22,0x22};
++static void nat_init_test_entry(void)
++{
++      int                             i, j ;
++      NAT_HASH_ENTRY_T        *hash_entry;
++      u32                                     sip, dip;
++      u32                                     hash_data[HASH_MAX_DWORDS];
++      NAT_CFG_T                       *cfg;
++      int                                     hash_index;
++
++      cfg = (NAT_CFG_T *)&nat_cfg;
++      hash_entry = (NAT_HASH_ENTRY_T *)&hash_data;
++      hash_entry->key.Ethertype       = 0;
++      hash_entry->key.rule_id         = 0;
++      hash_entry->key.ip_protocol = IPPROTO_TCP;
++      hash_entry->key.reserved1       = 0;
++      hash_entry->key.reserved2       = 0;
++      // hash_entry->key.sip          = NAT_TEST_CLIENT_IP;
++      // hash_entry->key.dip          = NAT_TEST_SERVER_IP;
++      hash_entry->key.sport           = htons(NAT_TEST_SPORT);
++      hash_entry->key.dport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.rule_id = cfg->tcp_udp_rule_id;
++      hash_entry->action.dword = NAT_LAN2WAN_ACTIONS;
++
++      sip = NAT_TEST_CLIENT_IP;
++      dip = NAT_TEST_SERVER_IP;
++
++      // Init TCP <------> TCP hash entries
++      // LAN --> WAN
++      // (1) TCP --> TCP
++      // (2) TCP --> PPPoE + TCP
++      // (3) TCP --> VLAN-B + PPPoE + TCP
++      // (4) TCP + VLAN-A --> VLAN-B + PPPoE + TCP
++      memcpy(hash_entry->param.da, nat_test_wan_target_da, 6);
++      memcpy(hash_entry->param.sa, nat_test_wan_my_da, 6);
++      hash_entry->key.port_id = cfg->lan_port;
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              if (i < 2)
++              {
++                      hash_entry->action.bits.dest_qid = i+2;
++              }
++              else
++              {
++                      hash_entry->action.bits.dest_qid = i;
++              }
++              hash_entry->action.bits.dest_qid += (cfg->wan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->param.Sport = NAT_TEST_MAP_PORT_BASE+i;
++              hash_entry->param.Dport = NAT_TEST_DPORT;
++              for (j=0; j<4; j++)
++              {
++                      hash_entry->key.sip = sip + i + j*0x100;
++                      hash_entry->key.dip = dip + i + j*0x100;
++                      hash_entry->param.Dip = hash_entry->key.dip;
++                      hash_entry->param.Sip = NAT_TEST_WAN_IP;
++                      switch (j)
++                      {
++                      case 0:
++                              hash_entry->action.bits.pppoe = 0;
++                              hash_entry->param.pppoe = 0;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 1:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 2:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+10;
++                              break;
++                      case 3:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+10;
++                              break;
++                      }
++                      hash_entry->tmo.counter = hash_entry->tmo.interval = 0x7fff;
++                      hash_index = nat_build_keys(&hash_entry->key);
++                      nat_write_hash_entry(hash_index, hash_entry);
++                      hash_nat_enable_owner(hash_index);
++                      hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              }
++      }
++
++
++      // WAN --> LAN
++      hash_entry->key.port_id         = cfg->wan_port;
++      hash_entry->key.sport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.dport           = htons(NAT_TEST_DPORT);
++      hash_entry->key.rule_id         = cfg->tcp_udp_rule_id;
++      hash_entry->action.dword        = NAT_WAN2LAN_ACTIONS;
++      hash_entry->key.sport           = htons(NAT_TEST_DPORT);
++      memcpy(hash_entry->param.da, nat_test_lan_target_da, 6);
++      memcpy(hash_entry->param.sa, nat_test_lan_my_da, 6);
++      for (i=0; i<TOE_HW_TXQ_NUM; i++)
++      {
++              hash_entry->key.dport = htons(NAT_TEST_MAP_PORT_BASE + i);
++              if (i < 2)
++              {
++                      hash_entry->action.bits.dest_qid = i+2;
++              }
++              else
++              {
++                      hash_entry->action.bits.dest_qid = i;
++              }
++              hash_entry->action.bits.dest_qid += (cfg->lan_port==0) ? TOE_GMAC0_HW_TXQ0_QID : TOE_GMAC1_HW_TXQ0_QID;
++              hash_entry->param.Dport = NAT_TEST_SPORT;
++              hash_entry->param.Sport = NAT_TEST_DPORT;
++              hash_entry->param.da[5] = i;
++              for (j=0; j<4; j++)
++              {
++                      hash_entry->key.sip = (dip + i + j*0x100);
++                      hash_entry->key.dip = (NAT_TEST_WAN_IP);
++                      hash_entry->param.Sip = hash_entry->key.sip;
++                      hash_entry->param.Dip = sip + i + j*0x100;
++                      switch (j)
++                      {
++                      case 0:
++                              hash_entry->action.bits.pppoe = 0;
++                              hash_entry->param.pppoe = 0;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 1:
++                              hash_entry->action.bits.pppoe = 2;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 0;
++                              hash_entry->param.vlan = 0;
++                              break;
++                      case 2:
++                              hash_entry->action.bits.pppoe = 2;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 2;
++                              hash_entry->param.vlan = i+5;
++                              break;
++                      case 3:
++                              hash_entry->action.bits.pppoe = 1;
++                              hash_entry->param.pppoe = i+1;
++                              hash_entry->action.bits.vlan = 1;
++                              hash_entry->param.vlan = i+5;
++                              break;
++                      }
++                      hash_entry->tmo.counter = hash_entry->tmo.interval = 0x7fff;
++                      hash_index = nat_build_keys(&hash_entry->key);
++                      nat_write_hash_entry(hash_index, hash_entry);
++                      hash_nat_enable_owner(hash_index);
++                      hash_validate_entry(hash_index); // Must last one, else HW Tx fast than SW
++              }
++      }
++}
++#endif        // SL351x_NAT_TEST_BY_SMARTBITS
++
++#endif // CONFIG_SL351x_NAT
++
+--- /dev/null
++++ b/drivers/net/sl351x_proc.c
+@@ -0,0 +1,578 @@
++/****************************************************************************
++* Copyright 2006 Storlink Corp.  All rights reserved.
++*----------------------------------------------------------------------------
++* Name                        : sl351x_proc.c
++* Description :
++*             Handle Proc Routines for Storlink SL351x Platform
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     04/13/2006      Gary Chen       Create and implement
++*
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/if_ether.h>
++#include <linux/if_pppox.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/ppp_defs.h>
++#ifdef CONFIG_NETFILTER
++// #include <linux/netfilter_ipv4/ip_conntrack.h>
++#endif
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++#include <linux/percpu.h>
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++#endif
++
++#define        MIDWAY
++#define        SL_LEPUS
++
++// #define PROC_DEBUG_MSG     1
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++#include <asm/arch/sl351x_toe.h>
++
++#ifdef CONFIG_PROC_FS
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       proc_printf                                     printk
++#define SL351x_GMAC_PROC_NAME         "sl351x_gmac"
++#define SL351x_NAT_PROC_NAME          "sl351x_nat"
++#define SL351x_TOE_PROC_NAME          "sl351x_toe"
++
++/*----------------------------------------------------------------------
++* Function Definition
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_open(struct inode *inode, struct file *file);
++static void *nat_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void nat_ct_seq_stop(struct seq_file *s, void *v);
++static void *nat_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int nat_ct_seq_show(struct seq_file *s, void *v);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_open(struct inode *inode, struct file *file);
++static void *toe_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void toe_ct_seq_stop(struct seq_file *s, void *v);
++static void *toe_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int toe_ct_seq_show(struct seq_file *s, void *v);
++extern int sl351x_get_toe_conn_flag(int index);
++extern struct toe_conn * sl351x_get_toe_conn_info(int index);
++#endif
++
++static int gmac_ct_open(struct inode *inode, struct file *file);
++static void *gmac_ct_seq_start(struct seq_file *s, loff_t *pos);
++static void gmac_ct_seq_stop(struct seq_file *s, void *v);
++static void *gmac_ct_seq_next(struct seq_file *s, void *v, loff_t *pos);
++static int gmac_ct_seq_show(struct seq_file *s, void *v);
++
++
++/*----------------------------------------------------------------------
++* Data
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SYSCTL
++// static struct ctl_table_header *nat_ct_sysctl_header;
++#endif
++
++#ifdef CONFIG_SL351x_NAT
++static struct seq_operations nat_ct_seq_ops = {
++      .start = nat_ct_seq_start,
++      .next  = nat_ct_seq_next,
++      .stop  = nat_ct_seq_stop,
++      .show  = nat_ct_seq_show
++};
++
++static struct file_operations nat_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = nat_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++#endif // CONFIG_SL351x_NAT
++
++#ifdef CONFIG_SL351x_RXTOE
++static struct seq_operations toe_ct_seq_ops = {
++      .start = toe_ct_seq_start,
++      .next  = toe_ct_seq_next,
++      .stop  = toe_ct_seq_stop,
++      .show  = toe_ct_seq_show
++};
++
++static struct file_operations toe_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = toe_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++#endif
++
++static struct seq_operations gmac_ct_seq_ops = {
++      .start = gmac_ct_seq_start,
++      .next  = gmac_ct_seq_next,
++      .stop  = gmac_ct_seq_stop,
++      .show  = gmac_ct_seq_show
++};
++
++static struct file_operations gmac_file_ops= {
++      .owner   = THIS_MODULE,
++      .open    = gmac_ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++
++#ifdef SL351x_GMAC_WORKAROUND
++extern u32 gmac_workaround_cnt[4];
++extern u32 gmac_short_frame_workaround_cnt[2];
++#ifdef CONFIG_SL351x_NAT
++      extern u32 sl351x_nat_workaround_cnt;
++#endif
++#endif
++/*----------------------------------------------------------------------
++* nat_ct_open
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &nat_ct_seq_ops);
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void *nat_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      for (i=*pos; i<HASH_TOTAL_ENTRIES; i++)
++      {
++              if (hash_get_nat_owner_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_stop
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void nat_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_next
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static void *nat_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      (*pos)++;
++      for (i=*pos; i<HASH_TOTAL_ENTRIES; i++)
++      {
++              if (hash_get_nat_owner_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif // CONFIG_SL351x_NAT
++/*----------------------------------------------------------------------
++* nat_ct_seq_show
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_NAT
++static int nat_ct_seq_show(struct seq_file *s, void *v)
++{
++      int                             idx;
++      NAT_HASH_ENTRY_T        *nat_entry;
++      GRE_HASH_ENTRY_T        *gre_entry;
++
++      idx = (int)v;
++      if (idx<=0 || idx >HASH_TOTAL_ENTRIES)
++              return -ENOSPC;
++
++      idx--;
++      nat_entry = (NAT_HASH_ENTRY_T *)&hash_tables[idx];
++      gre_entry = (GRE_HASH_ENTRY_T *)nat_entry;
++      if (nat_entry->key.ip_protocol == IPPROTO_GRE)
++      {
++              if (seq_printf(s, "%4d: KEY MAC-%d [%d] %u.%u.%u.%u [%u]-->%u.%u.%u.%u\n",
++                                      idx, gre_entry->key.port_id, gre_entry->key.ip_protocol,
++                                      HIPQUAD(gre_entry->key.sip), ntohs(gre_entry->key.call_id),
++                                      HIPQUAD(gre_entry->key.dip)))
++                      return -ENOSPC;
++              if (seq_printf(s, "      PARAMETER: %u.%u.%u.%u -->%u.%u.%u.%u [%u] Timeout:%ds\n",
++                                      HIPQUAD(gre_entry->param.Sip),
++                                      HIPQUAD(gre_entry->param.Dip), gre_entry->param.Dport,
++                                      gre_entry->tmo.counter))
++                      return -ENOSPC;
++      }
++      else
++      {
++              if (seq_printf(s, "%4d: KEY MAC-%d [%d] %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u]\n",
++                                      idx, nat_entry->key.port_id, nat_entry->key.ip_protocol,
++                                      HIPQUAD(nat_entry->key.sip), ntohs(nat_entry->key.sport),
++                                      HIPQUAD(nat_entry->key.dip), ntohs(nat_entry->key.dport)))
++                      return -ENOSPC;
++              if (seq_printf(s, "      PARAMETER: %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u] Timeout:%ds\n",
++                                      HIPQUAD(nat_entry->param.Sip), nat_entry->param.Sport,
++                                      HIPQUAD(nat_entry->param.Dip), nat_entry->param.Dport,
++                                      nat_entry->tmo.counter))
++                      return -ENOSPC;
++      }
++      return 0;
++}
++#endif // CONFIG_SL351x_NAT
++
++/*----------------------------------------------------------------------
++* toe_ct_open
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &toe_ct_seq_ops);
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void *toe_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      for (i=*pos; i<TOE_TOE_QUEUE_NUM; i++)
++      {
++              if (sl351x_get_toe_conn_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_stop
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void toe_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_next
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static void *toe_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++      (*pos)++;
++      for (i=*pos; i<TOE_TOE_QUEUE_NUM; i++)
++      {
++              if (sl351x_get_toe_conn_flag(i))
++              {
++                      *pos = i;
++                      return (void *)(i+1);
++              }
++      }
++      return NULL;
++}
++#endif
++/*----------------------------------------------------------------------
++* toe_ct_seq_show
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_SL351x_RXTOE
++static int toe_ct_seq_show(struct seq_file *s, void *v)
++{
++      int                             idx;
++      struct toe_conn         *toe_entry;
++
++      idx = (int)v;
++      if (idx<=0 || idx >TOE_TOE_QUEUE_NUM)
++              return -ENOSPC;
++
++      idx--;
++      toe_entry = (struct toe_conn *)sl351x_get_toe_conn_info(idx);
++      if (!toe_entry)
++              return -ENOSPC;
++
++      if (seq_printf(s, "%4d: Qid %d MAC-%d TCP %u.%u.%u.%u [%u]-->%u.%u.%u.%u [%u]\n",
++                              idx, toe_entry->qid, toe_entry->gmac->port_id,
++                              NIPQUAD(toe_entry->saddr[0]), ntohs(toe_entry->source),
++                              NIPQUAD(toe_entry->daddr[0]), ntohs(toe_entry->dest)))
++                      return -ENOSPC;
++      return 0;
++}
++#endif
++/*----------------------------------------------------------------------
++* gmac_ct_open
++*----------------------------------------------------------------------*/
++static int gmac_ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &gmac_ct_seq_ops);
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_start
++* find the first
++*----------------------------------------------------------------------*/
++static void *gmac_ct_seq_start(struct seq_file *s, loff_t *pos)
++{
++      int i;
++      i = (int)*pos + 1;;
++
++      if (i > 9)
++              return NULL;
++      else
++              return (void *)i;
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_stop
++*----------------------------------------------------------------------*/
++static void gmac_ct_seq_stop(struct seq_file *s, void *v)
++{
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_next
++*----------------------------------------------------------------------*/
++static void *gmac_ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      int i;
++
++      // proc_printf("%s: *pos=%d\n", __func__, (int)*pos);
++
++      (*pos)++;
++      i = (int)*pos + 1;;
++
++      if (i > 9)
++              return NULL;
++      else
++              return (void *)i;
++}
++
++/*----------------------------------------------------------------------
++* seq_dm_long
++*----------------------------------------------------------------------*/
++static void seq_dm_long(struct seq_file *s, u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              cond_resched();
++              seq_printf(s, "0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               seq_printf(s, "         ");
++                      else
++                      {
++                              data = *datap;
++                              seq_printf(s, "%08X ", data);
++                      }
++                      if (i==1)
++              seq_printf(s, "- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        seq_printf(s, "\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* gmac_ct_seq_show
++*----------------------------------------------------------------------*/
++static int gmac_ct_seq_show(struct seq_file *s, void *v)
++{
++      switch ((int)v)
++      {
++              case 1:
++                      seq_printf(s, "\nGMAC Global Registers\n");
++                      seq_dm_long(s, TOE_GLOBAL_BASE, 32);
++                      break;
++              case 2:
++                      seq_printf(s, "\nGMAC Non-TOE Queue Header\n");
++                      seq_dm_long(s, TOE_NONTOE_QUE_HDR_BASE, 12);
++                      break;
++              case 3:
++                      seq_printf(s, "\nGMAC TOE Queue Header\n");
++                      seq_dm_long(s, TOE_TOE_QUE_HDR_BASE, 12);
++                      break;
++              case 4:
++                      seq_printf(s, "\nGMAC-0 DMA Registers\n");
++                      seq_dm_long(s, TOE_GMAC0_DMA_BASE, 52);
++                      break;
++              case 5:
++                      seq_printf(s, "\nGMAC-0 Registers\n");
++                      seq_dm_long(s, TOE_GMAC0_BASE, 32);
++                      break;
++              case 6:
++                      seq_printf(s, "\nGMAC-1 DMA Registers\n");
++                      seq_dm_long(s, TOE_GMAC1_DMA_BASE, 52);
++                      break;
++              case 7:
++                      seq_printf(s, "\nGMAC-1 Registers\n");
++                      seq_dm_long(s, TOE_GMAC1_BASE, 32);
++                      break;
++              case 8:
++                      seq_printf(s, "\nGLOBAL Registers\n");
++                      seq_dm_long(s, GMAC_GLOBAL_BASE_ADDR, 16);
++                      break;
++              case 9:
++#ifdef SL351x_GMAC_WORKAROUND
++                      seq_printf(s, "\nGMAC-0 Rx/Tx/Short Workaround: %u, %u, %u\n", gmac_workaround_cnt[0], gmac_workaround_cnt[1], gmac_short_frame_workaround_cnt[0]);
++                      seq_printf(s, "GMAC-1 Rx/Tx/Short Workaround: %u, %u, %u\n", gmac_workaround_cnt[2], gmac_workaround_cnt[3], gmac_short_frame_workaround_cnt[1]);
++#ifdef CONFIG_SL351x_NAT
++                      seq_printf(s, "NAT Workaround: %u\n", sl351x_nat_workaround_cnt);
++#endif
++#endif
++                      break;
++              default:
++                      return -ENOSPC;
++      }
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* init
++*----------------------------------------------------------------------*/
++static int __init init(void)
++{
++      struct proc_dir_entry *proc_gmac=NULL;
++
++#ifdef CONFIG_SL351x_NAT
++      struct proc_dir_entry *proc_nat=NULL;
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      struct proc_dir_entry *proc_toe=NULL;
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // nat_ct_sysctl_header = NULL;
++#endif
++      proc_gmac = proc_net_fops_create(SL351x_GMAC_PROC_NAME, 0440, &gmac_file_ops);
++      if (!proc_gmac) goto init_bad;
++
++#ifdef CONFIG_SL351x_NAT
++      proc_nat = proc_net_fops_create(SL351x_NAT_PROC_NAME, 0440, &nat_file_ops);
++      if (!proc_nat) goto init_bad;
++#endif // CONFIG_SL351x_NAT
++
++#ifdef CONFIG_SL351x_RXTOE
++      proc_toe = proc_net_fops_create(SL351x_TOE_PROC_NAME, 0440, &toe_file_ops);
++      if (!proc_toe) goto init_bad;
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // nat_ct_sysctl_header = register_sysctl_table(nat_ct_net_table, 0);
++      // if (!nat_ct_sysctl_header) goto init_bad;
++#endif
++
++      return 0;
++
++init_bad:
++      if (proc_gmac) proc_net_remove(SL351x_GMAC_PROC_NAME);
++
++#ifdef CONFIG_SL351x_NAT
++      if (proc_nat) proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      if (proc_toe) proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // if (nat_ct_sysctl_header) unregister_sysctl_table(nat_ct_sysctl_header);
++#endif
++      proc_printf("SL351x NAT Proc: can't create proc or register sysctl.\n");
++      return -ENOMEM;
++}
++
++/*----------------------------------------------------------------------
++* fini
++*----------------------------------------------------------------------*/
++static void __exit fini(void)
++{
++      proc_net_remove(SL351x_GMAC_PROC_NAME);
++
++#ifdef CONFIG_SL351x_NAT
++      proc_net_remove(SL351x_NAT_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SL351x_RXTOE
++      proc_net_remove(SL351x_TOE_PROC_NAME);
++#endif
++
++#ifdef CONFIG_SYSCTL
++      // unregister_sysctl_table(nat_ct_sysctl_header);
++#endif
++}
++
++/*----------------------------------------------------------------------
++* module
++*----------------------------------------------------------------------*/
++module_init(init);
++module_exit(fini);
++
++#endif        // CONFIG_PROC_FS
+--- /dev/null
++++ b/drivers/net/sl351x_toe.c
+@@ -0,0 +1,1083 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_toe.c
++* Description :
++*             Provide TOE routines for SL351x
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*                             Xiaochong
++*
++****************************************************************************/
++
++#include <linux/pci.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/tcp.h>
++#include <linux/slab.h>
++#include <linux/etherdevice.h>
++#include <asm/io.h>
++#include <linux/sysctl_storlink.h>
++#include <net/tcp.h>
++#include <linux/if_ether.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <asm/arch/sl351x_toe.h>
++#include <asm/arch/sl351x_hash_cfg.h>
++#include <asm/arch/sl351x_nat_cfg.h>
++
++static int in_toe_isr;
++static int toe_initialized=0;
++
++static struct toe_conn        toe_connections[TOE_TOE_QUEUE_NUM];
++EXPORT_SYMBOL(toe_connections);
++static __u32 toe_connection_bits[TOE_TOE_QUEUE_NUM/32] __attribute__ ((aligned(16)));
++struct sk_buff* gen_pure_ack(struct toe_conn* connection, TOE_QHDR_T* toe_qhdr, INTR_QHDR_T *intr_curr_desc);
++
++extern struct storlink_sysctl storlink_ctl;
++extern TOE_INFO_T toe_private_data;
++extern spinlock_t gmac_fq_lock;
++extern void mac_write_dma_reg(int mac, unsigned int offset, u32 data);
++extern int mac_set_rule_reg(int mac, int rule, int enabled, u32 reg0, u32 reg1, u32 reg2);
++extern int hash_add_toe_entry(HASH_ENTRY_T *entry);
++extern void toe_gmac_fill_free_q(void);
++
++#define _DEBUG_SKB_           1
++#ifdef _DEBUG_SKB_
++/*---------------------------------------------------------------------------
++ * _debug_skb
++ *-------------------------------------------------------------------------*/
++static inline void _debug_skb(struct sk_buff *skb, GMAC_RXDESC_T *toe_curr_desc, u32 data)
++{
++      if ((u32)skb < 0x1000)
++      {
++              printk("%s skb=%x\n", __func__, (u32)skb);
++              while(1);
++      }
++      REG32(__va(toe_curr_desc->word2.buf_adr)-SKB_RESERVE_BYTES) = data;
++}
++#else
++#define _debug_skb(x, y, z)
++#endif
++
++/*---------------------------------------------------------------------------
++ * get_connection_seq_num
++ *-------------------------------------------------------------------------*/
++u32 get_connection_seq_num(unsigned short qid)
++{
++      TOE_QHDR_T      *toe_qhdr;
++
++      toe_qhdr = (TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++      toe_qhdr += qid;
++      return (u32)toe_qhdr->word3.seq_num;
++}
++EXPORT_SYMBOL(get_connection_seq_num);
++
++/*---------------------------------------------------------------------------
++ * get_connection_ack_num
++ *-------------------------------------------------------------------------*/
++u32 get_connection_ack_num(unsigned short qid)
++{
++      TOE_QHDR_T      *toe_qhdr;
++
++      toe_qhdr = (TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++      toe_qhdr += qid;
++      return (u32)toe_qhdr->word4.ack_num;
++}
++EXPORT_SYMBOL(get_connection_ack_num);
++
++/*---------------------------------------------------------------------------
++ * dump_toe_qhdr
++ *-------------------------------------------------------------------------*/
++void dump_toe_qhdr(TOE_QHDR_T *toe_qhdr)
++{
++      printk("TOE w1 %x, w2 %x, w3 %x\n", toe_qhdr->word1.bits32,
++              toe_qhdr->word2.bits32, toe_qhdr->word3.bits32);
++      printk("w4 %x, w5 %x, w6 %x\n", toe_qhdr->word4.bits32,
++              toe_qhdr->word5.bits32, toe_qhdr->word6.bits32);
++}
++
++/*---------------------------------------------------------------------------
++ * dump_intrq_desc
++ *-------------------------------------------------------------------------*/
++void dump_intrq_desc(INTR_QHDR_T *intr_curr_desc)
++{
++      printk("INTR w0 %x, w1 %x, seq %x\n", intr_curr_desc->word0.bits32,
++              intr_curr_desc->word1.bits32, intr_curr_desc->word2.bits32);
++      printk("ack %x, w4 %x\n", intr_curr_desc->word3.bits32,
++              intr_curr_desc->word4.bits32);
++}
++
++/*---------------------------------------------------------------------------
++ * This routine will initialize a TOE matching rule
++ * called by SL351x GMAC driver.
++ *-------------------------------------------------------------------------*/
++void sl351x_toe_init(void)
++{
++      GMAC_MRxCR0_T   mrxcr0;
++      GMAC_MRxCR1_T   mrxcr1;
++      GMAC_MRxCR2_T   mrxcr2;
++      int     rule, rc;
++
++      if (toe_initialized)
++              return;
++
++      toe_initialized = 1;
++
++#ifndef CONFIG_SL351x_NAT
++      mrxcr0.bits32 = 0;
++      mrxcr1.bits32 = 0;
++      mrxcr2.bits32 = 0;
++      mrxcr0.bits.l3 = 1;
++      mrxcr0.bits.l4 = 1;
++      mrxcr1.bits.sip = 1;
++      mrxcr1.bits.dip = 1;
++      mrxcr1.bits.l4_byte0_15 = 0x0f;
++      mrxcr0.bits.sprx = 1;
++      rule = 0;
++      rc = mac_set_rule_reg(0, rule, 1, mrxcr0.bits32, mrxcr1.bits32,
++                                              mrxcr2.bits32);
++      if (rc<0) {
++              printk("%s::Set MAC 0 rule fail!\n", __func__);
++      }
++      rc = mac_set_rule_reg(1, rule, 1, mrxcr0.bits32, mrxcr1.bits32,
++                                              mrxcr2.bits32);
++      if (rc<0) {
++              printk("%s::Set MAC 1 rule fail!\n", __func__);
++      }
++#endif // CONFIG_SL351x_NAT
++}
++
++/*---------------------------------------------------------------------------
++ * dump_intrq_desc
++ * assign an interrupt queue number to a give tcp queue
++ *-------------------------------------------------------------------------*/
++int get_interrupt_queue_id(int tcp_qid)
++{
++      return (int)(tcp_qid & 0x0003);
++}
++
++/*---------------------------------------------------------------------------
++ * reset_connection_index
++ * reset the connection bit by given index
++ *-------------------------------------------------------------------------*/
++void reset_connection_index(__u8 index)
++{
++      __u32 mask = ~(0xffffffff & (1<< (index&0x1f)));
++      toe_connection_bits[index>>5] = toe_connection_bits[index>>5] & mask;
++}
++
++/*---------------------------------------------------------------------------
++ * update_timer
++ *-------------------------------------------------------------------------*/
++void update_timer(struct toe_conn* connection)
++{
++//    if (time_before(jiffies, connection->last_rx_jiffies+3))
++//    if ((jiffies + 0xffffffff - connection->last_rx_jiffies) & 0x3)
++//    if (connection->last_rx_jiffies > jiffies)
++//            printk("%s::jif %g, last_rx_jif %g\n", __func__, jiffies, connection->last_rx_jiffies);
++/*    if ((long)(jiffies + 2)< 3) { // overflow...
++              printk("%s::jiffies %x\n", __func__, jiffies);
++      } */
++//    if ((long)(jiffies - connection->last_rx_jiffies)< 2)
++//            return;
++      connection->last_rx_jiffies = jiffies;
++      // gary chen mod_timer(&connection->rx_timer, jiffies+2);
++      connection->rx_timer.expires = jiffies + 2;
++      add_timer(&connection->rx_timer);
++//    printk("%s::nt %x, lj %x\n", __func__, (jiffies+2), connection->last_rx_jiffies);
++}
++
++/*---------------------------------------------------------------------------
++ * gen_pure_ack
++ *-------------------------------------------------------------------------*/
++struct sk_buff* gen_pure_ack(struct toe_conn* connection, TOE_QHDR_T* toe_qhdr,
++INTR_QHDR_T *intr_curr_desc)
++{
++      struct sk_buff  *skb;
++      struct iphdr    *ip_hdr;
++      struct tcphdr   *tcp_hdr;
++      struct ethhdr   *eth_hdr;
++
++      if ((skb= dev_alloc_skb(RX_BUF_SIZE))==NULL) {
++              printk("%s::alloc pure ack fail!\n", __func__);
++              return NULL;
++      }
++      skb_reserve(skb, RX_INSERT_BYTES);
++      memset(skb->data, 0, 60);
++
++      eth_hdr = (struct ethhdr*)&(skb->data[0]);
++      memcpy(eth_hdr, &connection->l2_hdr, sizeof(struct ethhdr));
++
++      ip_hdr = (struct iphdr*)&(skb->data[14]);
++      ip_hdr->version = connection->ip_ver;
++      ip_hdr->ihl = 20>>2;
++      ip_hdr->tot_len = ntohs(40);
++      ip_hdr->frag_off = htons(IP_DF);
++      ip_hdr->ttl = 128;
++      ip_hdr->protocol = 0x06;
++      ip_hdr->saddr = connection->saddr[0];
++      ip_hdr->daddr = connection->daddr[0];
++//    printk("%s ip sa %x, da %x\n",
++//            __func__, ntohl(ip_hdr->saddr), ntohl(ip_hdr->daddr));
++
++      tcp_hdr = (struct tcphdr*)&(skb->data[34]);
++      tcp_hdr->source = connection->source;
++      tcp_hdr->dest = connection->dest;
++      if (intr_curr_desc) {
++              tcp_hdr->seq = htonl(intr_curr_desc->word2.seq_num);
++              tcp_hdr->ack_seq = htonl(intr_curr_desc->word3.ack_num);
++              tcp_hdr->window = htons(intr_curr_desc->word0.bits.win_size);
++      } else {
++              tcp_hdr->seq = htonl(toe_qhdr->word3.seq_num);
++              tcp_hdr->ack_seq = htonl(toe_qhdr->word4.ack_num);
++              tcp_hdr->window = htons(toe_qhdr->word6.bits.WinSize);
++      }
++      tcp_hdr->ack = 1;
++      tcp_hdr->doff = 20 >> 2;
++#if 0
++      if (!intr_curr_desc) {
++              unsigned char byte;
++              for (i=0; i<20; i++) {
++                      byte = skb->data[34+i];
++                      printk("%x ", byte);
++              }
++              printk("\n");
++      }
++#endif
++      TCP_SKB_CB(skb)->connection = connection;
++      return skb;
++}
++
++/*---------------------------------------------------------------------------
++ * connection_rx_timer
++ *-------------------------------------------------------------------------*/
++void connection_rx_timer(unsigned long *data)
++{
++      struct toe_conn *connection = (struct toe_conn*)data;
++      unsigned int    tcp_qid, toeq_wptr;
++      unsigned int    pkt_size, desc_count;
++      struct sk_buff  *skb;
++      GMAC_RXDESC_T   *toe_curr_desc;
++      TOE_QHDR_T      *toe_qhdr;
++      struct net_device       *dev;
++      unsigned long   conn_flags;
++      DMA_RWPTR_T             toeq_rwptr;
++      unsigned short  timeout_descs;
++
++      if (in_toe_isr)
++              printk("%s::in_toe_isr=%d!\n", __func__, in_toe_isr);
++
++      if (connection) {
++              /* should we disable gmac interrupt first? */
++              if (!connection->gmac)
++                      printk("%s::conn gmac %x!\n", __func__, (u32)connection->gmac);
++              local_irq_save(conn_flags);
++              if (!spin_trylock(&connection->conn_lock)) {
++                      local_irq_restore(conn_flags);
++                      // timer should be updated by the toeq isr. So no need to update here.
++                      printk("%s::conn_lock is held by ISR!\n", __func__);
++                      return;
++              }
++              disable_irq(connection->gmac->irq);
++
++              /* disable hash entry and get toeq desc. */
++              hash_set_valid_flag(connection->hash_entry_index, 0);
++              do{} while(0);  /* wait until HW finish */
++
++              dev = connection->dev;
++              if (!dev)
++                      printk("%s::conn dev NULL!\n", __func__);
++              tcp_qid = connection->qid;
++              toe_qhdr = (TOE_QHDR_T *)(TOE_TOE_QUE_HDR_BASE +
++                            tcp_qid * sizeof(TOE_QHDR_T));
++              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++              toeq_wptr = toe_qhdr->word1.bits.wptr;
++              timeout_descs = toeq_wptr - toeq_rwptr.bits.rptr;
++
++              if (toeq_rwptr.bits.rptr == toeq_wptr) {
++                      if (toe_qhdr->word5.bits32) {
++                              // shall we check toe_qhdr->word2.bits?
++                              skb = gen_pure_ack(connection, toe_qhdr, (INTR_QHDR_T *)NULL);
++                              skb_put(skb, 54);
++                              skb->dev = connection->dev;
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++                              skb->protocol = eth_type_trans(skb, connection->dev);
++                              netif_rx(skb);
++                              connection->dev->last_rx = jiffies;
++                      }
++              } else {
++                      while (toeq_rwptr.bits.rptr != toeq_rwptr.bits.wptr) {
++                              /* we just simply send those packets to tcp? */
++                              toe_curr_desc = (GMAC_RXDESC_T*)(toe_private_data.toe_desc_base[tcp_qid]
++                                      + toeq_rwptr.bits.rptr * sizeof(GMAC_RXDESC_T));
++                              connection->curr_desc = toe_curr_desc;
++                              if (toe_curr_desc->word3.bits.ctrl_flag) {
++                                      printk("%s::ctrl flag! %x, conn rptr %d, to %d, jif %x, conn_jif %x\n",
++                                              __func__, toe_curr_desc->word3.bits32,
++                                              connection->toeq_rwptr.bits.rptr, timeout_descs,
++                                              (u32)jiffies, (u32)connection->last_rx_jiffies);
++                              }
++                              desc_count = toe_curr_desc->word0.bits.desc_count;
++                              pkt_size = toe_curr_desc->word1.bits.byte_count;
++                              consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                      PCI_DMA_FROMDEVICE);
++                              skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                      SKB_RESERVE_BYTES));
++                              _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x02);
++                              connection->curr_rx_skb = skb;
++                              skb_reserve(skb, RX_INSERT_BYTES);
++                              skb_put(skb, pkt_size);
++                              skb->dev = dev;
++                              skb->protocol = eth_type_trans(skb, dev);
++                              {
++                                      struct iphdr* ip_hdr = (struct iphdr*)&(skb->data[0]);
++                                      if (toe_curr_desc->word3.bits.ctrl_flag)
++                                              printk("%s::ip id %x\n", __func__, ntohs(ip_hdr->id));
++                              }
++                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++                              netif_rx(skb);
++                              dev->last_rx = jiffies;
++#if 0
++                              if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++                                      printk("%s::alloc buf fail!\n", __func__);
++                              }
++                              *(unsigned int*)(skb->data) = (unsigned int)skb;
++                              connection->curr_rx_skb = skb;
++                              skb_reserve(skb, SKB_RESERVE_BYTES);
++                              spin_lock_irqsave(&connection->gmac->rx_mutex, flags);
++                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                              if (toe_private_data.fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                      mac_stop_txdma((struct net_device*)connection->dev);
++                                      spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++                                      while(1);
++                              }
++                              fq_desc = (GMAC_RXDESC_T*)toe_private_data.swfq_desc_base + fq_rwptr.bits.wptr;
++                              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++                              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                              SET_WPTR(TOE_GLOBAL_BASE+GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                              toe_private_data.fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++                              spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++#endif
++//                            spin_lock_irqsave(&connection->gmac->rx_mutex, flags);
++                              toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                              SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                            spin_unlock_irqrestore(&connection->gmac->rx_mutex, flags);
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                      }
++                      toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++//                    toe_gmac_fill_free_q();
++              }
++              connection->last_rx_jiffies = jiffies;
++              if (connection->status != TCP_CONN_CLOSED)
++                      mod_timer(&connection->rx_timer, jiffies+2);
++              if (connection->status != TCP_CONN_ESTABLISHED)
++                      printk("%s::conn status %x\n", __func__, connection->status);
++              hash_set_valid_flag(connection->hash_entry_index, 1);
++              enable_irq(connection->gmac->irq);
++              // Gary Chen spin_unlock_irqrestore(&connection->conn_lock, conn_flags);
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * free_toeq_descs
++ *-------------------------------------------------------------------------*/
++void free_toeq_descs(int qid, TOE_INFO_T *toe)
++{
++      void    *desc_ptr;
++
++      desc_ptr = (void*)toe->toe_desc_base[qid];
++      pci_free_consistent(NULL, TOE_TOE_DESC_NUM*sizeof(GMAC_RXDESC_T), desc_ptr,
++         (dma_addr_t)toe->toe_desc_base_dma[qid]);
++      toe->toe_desc_base[qid] = 0;
++}
++
++/*---------------------------------------------------------------------------
++ * set_toeq_hdr
++ *-------------------------------------------------------------------------*/
++void set_toeq_hdr(struct toe_conn*    connection, TOE_INFO_T* toe, struct net_device *dev)
++{
++      volatile TOE_QHDR_T     *toe_qhdr;
++      volatile unsigned int   toeq_wptr; // toeq_rptr
++      volatile GMAC_RXDESC_T  *toe_curr_desc;
++      struct sk_buff  *skb;
++      unsigned int    pkt_size;
++      DMA_RWPTR_T     toeq_rwptr;
++
++      if (connection->status == TCP_CONN_CLOSING) {
++              connection->status = TCP_CONN_CLOSED;
++              hash_set_valid_flag(connection->hash_entry_index, 0);
++              // remove timer first.
++              // del_timer_sync(&(connection->rx_timer));
++              // check if any queued frames last time.
++              toe_qhdr = (volatile TOE_QHDR_T*)TOE_TOE_QUE_HDR_BASE;
++              toe_qhdr += connection->qid;
++              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++
++              //toeq_rptr = toe_qhdr->word1.bits.rptr;
++              toeq_wptr = toe_qhdr->word1.bits.wptr;
++              while (toeq_rwptr.bits.rptr != toeq_wptr) {
++                      printk("%s::pending frames in TOE Queue before closing!\n", __func__);
++                      toe_curr_desc = (GMAC_RXDESC_T*)(toe->toe_desc_base[connection->qid] +
++                              toe_qhdr->word1.bits.rptr*sizeof(GMAC_RXDESC_T));
++                      connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                      pkt_size = toe_curr_desc->word1.bits.byte_count;
++                      consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                              PCI_DMA_FROMDEVICE);
++                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr) -
++                              SKB_RESERVE_BYTES));
++                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x03);
++                      connection->curr_rx_skb = skb;
++                      skb_reserve(skb, RX_INSERT_BYTES);
++                      skb_put(skb, pkt_size);
++                      skb->dev = connection->dev;
++                      skb->protocol = eth_type_trans(skb, connection->dev);
++                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++                      netif_rx(skb);
++                      connection->dev->last_rx = jiffies;
++
++                      toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                      SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++              }
++              free_toeq_descs(connection->qid, toe);
++              // shall we re-fill free queue?
++
++              reset_connection_index(connection->qid);
++              //memset(connection, 0, sizeof(struct toe_conn));
++              printk(" del timer and close connection %x, qid %d\n", (u32)connection, connection->qid);
++              return;
++      }
++      /* enable or setup toe queue header */
++      if (connection->status == TCP_CONN_CONNECTING && storlink_ctl.rx_max_pktsize) {
++              volatile TOE_QHDR_T     *qhdr;
++              int iq_id;
++              connection->status = TCP_CONN_ESTABLISHED;
++              qhdr = (volatile TOE_QHDR_T*)((unsigned int)TOE_TOE_QUE_HDR_BASE +
++                             connection->qid * sizeof(TOE_QHDR_T));
++
++              iq_id = get_interrupt_queue_id(connection->qid);
++              connection->dev = dev;
++              connection->gmac = dev->priv;
++              connection->toeq_rwptr.bits32 = 0;
++
++//            qhdr->word6.bits.iq_num = iq_id;
++              qhdr->word6.bits.MaxPktSize = (connection->max_pktsize)>>2; // in word.
++              qhdr->word7.bits.AckThreshold = connection->ack_threshold;
++              qhdr->word7.bits.SeqThreshold = connection->seq_threshold;
++
++              // init timer.
++#if 1
++              init_timer(&connection->rx_timer);
++              connection->rx_timer.expires = jiffies + 5;
++              connection->rx_timer.data = (unsigned long)connection;
++              connection->rx_timer.function = (void *)&connection_rx_timer;
++              add_timer(&connection->rx_timer);
++              connection->last_rx_jiffies = jiffies;
++              printk("init_timer %x\n", (u32)jiffies);
++#endif
++              hash_set_valid_flag(connection->hash_entry_index, 1);
++              return;
++      } else {
++              printk("%s::conn status %x, rx_pktsize %d\n",
++                      __func__, connection->status, storlink_ctl.rx_max_pktsize);
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * get_connection_index
++ * get_connection_index will find an available index for the connection,
++ * when allocate a new connection is needed.
++ * we find available Qid from AV bits and write to hash_table, so that when RxTOE
++ * packet is received, sw_id from ToeQ descriptor is also the Qid of conneciton Q.
++ *-------------------------------------------------------------------------*/
++int get_connection_index(void)
++{
++      int i=0, j=0, index=-1;
++      __u32   connection_bits;
++
++      for (i = 0; i< TOE_TOE_QUEUE_NUM/32; i++) {
++              connection_bits = ~(toe_connection_bits[i]);
++              if (connection_bits == 0)
++                      // all 32 bits are used.
++                      continue;
++
++              for (j=0; j<32; j++) {
++                      if (connection_bits & 0x01) {
++                              index = i*32 + j;
++                              return index;
++                      }
++                      connection_bits = connection_bits >> 1;
++              }
++      }
++      return index;
++}
++
++/*---------------------------------------------------------------------------
++ * set_toe_connection
++ *-------------------------------------------------------------------------*/
++void set_toe_connection(int index, int val)
++{
++      if (val) {
++              toe_connection_bits[index/32] |= (1<<(index%32));
++      } else {
++              toe_connection_bits[index/32] &= (~(1<<(index%32)));
++      }
++}
++
++/*---------------------------------------------------------------------------
++ * sl351x_get_toe_conn_flag
++ *-------------------------------------------------------------------------*/
++int sl351x_get_toe_conn_flag(int index)
++{
++      if (index < TOE_TOE_QUEUE_NUM)
++              return (toe_connection_bits[index/32] & (1 << (index %32)));
++      else
++              return 0;
++}
++
++/*---------------------------------------------------------------------------
++ * sl351x_get_toe_conn_info
++ *-------------------------------------------------------------------------*/
++struct toe_conn * sl351x_get_toe_conn_info(int index)
++{
++      if (index < TOE_TOE_QUEUE_NUM)
++              return (struct toe_conn *)&toe_connections[index];
++      else
++              return NULL;
++}
++
++/*---------------------------------------------------------------------------
++ * create_sw_toe_connection
++ *-------------------------------------------------------------------------*/
++struct toe_conn* create_sw_toe_connection(int qid, int ip_ver, void* ip_hdr,
++      struct tcphdr* tcp_hdr)
++{
++      struct toe_conn*        connection =  &(toe_connections[qid]);
++
++      connection->ip_ver = (__u8)ip_ver;
++      connection->qid = (__u8)qid;
++      connection->source = (__u16)tcp_hdr->source;
++      connection->dest = (__u16)tcp_hdr->dest;
++      if (ip_ver == 4) {
++              struct iphdr* iph = (struct iphdr*) ip_hdr;
++              connection->saddr[0] = (__u32)iph->saddr;
++              connection->daddr[0] = (__u32)iph->daddr;
++//            printk("%s::saddr %x, daddr %x\n", __func__,
++//                    ntohl(connection->saddr[0]), ntohl(connection->daddr[0]));
++      } else if (ip_ver == 6) {
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              int i=0;
++              for (i=0; i<4; i++) {
++                      connection->saddr[i] = (__u32)iph->saddr.in6_u.u6_addr32[i];
++                      connection->daddr[i] = (__u32)iph->daddr.in6_u.u6_addr32[i];
++              }
++      }
++      connection->status = TCP_CONN_CREATION;
++      return connection;
++}
++
++/*---------------------------------------------------------------------------
++ * fill_toeq_buf
++ *-------------------------------------------------------------------------*/
++int fill_toeq_buf(int index, TOE_INFO_T* toe)
++{
++      volatile TOE_QHDR_T     *qhdr;
++      //struct toe_conn* connection;
++      GMAC_RXDESC_T   *desc_ptr;
++
++      if (!toe->toe_desc_base[index]) {
++              // first time. init.
++              desc_ptr = (GMAC_RXDESC_T*)(pci_alloc_consistent(NULL, TOE_TOE_DESC_NUM
++                          *sizeof(GMAC_RXDESC_T), (dma_addr_t*)&toe->toe_desc_base_dma[index]));
++
++              toe->toe_desc_num = TOE_TOE_DESC_NUM;
++              toe->toe_desc_base[index] = (unsigned int)desc_ptr;
++      }
++      qhdr = (volatile TOE_QHDR_T*)((unsigned int)TOE_TOE_QUE_HDR_BASE +
++                                                                      index*sizeof(TOE_QHDR_T));
++      //connection = (struct toe_conn*)&(toe_connections[index]);
++
++      qhdr->word0.base_size = ((unsigned int)toe->toe_desc_base_dma[index]&TOE_QHDR0_BASE_MASK)
++                                      | TOE_TOE_DESC_POWER;
++      qhdr->word1.bits32 = 0;
++      qhdr->word2.bits32 = 0;
++      qhdr->word3.bits32 = 0;
++      qhdr->word4.bits32 = 0;
++      qhdr->word5.bits32 = 0;
++      return 1;
++}
++
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry_smb
++ * add SMB header in hash entry.
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry_smb(int ip_ver, void* ip_hdr, struct tcphdr* tcp_hdr,
++      int sw_id)
++{
++      HASH_ENTRY_T    hash_entry, *entry;
++      int     hash_entry_index;
++      int i;
++
++      entry = (HASH_ENTRY_T*)&hash_entry;
++      memset((void*)entry, 0, sizeof(HASH_ENTRY_T));
++      entry->rule = 0;
++
++      /* enable fields of hash key */
++      entry->key_present.ip_protocol = 1;
++      entry->key_present.sip = 1;
++      entry->key_present.dip = 1;
++      entry->key_present.l4_bytes_0_3 = 1;    // src port and dest port
++      entry->key_present.l7_bytes_0_3 = 0;    // do we need to enable NETBIOS? how?
++      entry->key_present.l7_bytes_4_7 = 1;    // "SMB" header
++
++      /* hash key */
++      entry->key.ip_protocol = IPPROTO_TCP;
++      if (ip_ver == 4) {
++              struct iphdr *iph = (struct iphdr*)ip_hdr;
++              memcpy(entry->key.sip, &iph->saddr, 4);
++              memcpy(entry->key.dip, &iph->daddr, 4);
++      } else if (ip_ver == 6) {
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              for (i=0; i<4; i++) {
++                      memcpy(&(entry->key.sip[i*4]), &(iph->saddr.in6_u.u6_addr32[i]), 4);
++                      memcpy(&(entry->key.dip[i*4]), &(iph->daddr.in6_u.u6_addr32[i]), 4);
++              }
++      }
++      *(__u16*)&entry->key.l4_bytes[0] = tcp_hdr->source;
++      *(__u16*)&entry->key.l4_bytes[2] = tcp_hdr->dest;
++
++      entry->key.l7_bytes[4] = 0xff;
++      entry->key.l7_bytes[5] = 0x53;
++      entry->key.l7_bytes[6] = 0x4d;
++      entry->key.l7_bytes[7] = 0x42;
++
++      /* action of hash entry match */
++      entry->action.sw_id = 1;
++      entry->action.dest_qid = (__u8)TOE_TOE_QID(sw_id);
++      entry->action.srce_qid = 0;
++      hash_entry_index = hash_add_toe_entry(entry);
++
++      return hash_entry_index;
++}
++
++// best performance of tcp streaming.
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry_smb
++ * add SMB header in hash entry.
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry_ftp(int ip_ver, void* ip_hdr, struct tcphdr* tcphdr)
++{
++      return 0;
++}
++
++// is hash entry for nfs needed?
++
++/*
++ * Create a TOE hash entry by given ip addresses and tcp port numbers.
++ * hash entry index will be saved in sw connection.
++ */
++/*---------------------------------------------------------------------------
++ * create_toe_hash_entry
++ *-------------------------------------------------------------------------*/
++int create_toe_hash_entry(int ip_ver, void* ip_hdr, struct tcphdr* tcp_hdr, int sw_id)
++{
++      HASH_ENTRY_T    hash_entry, *entry;
++//    unsigned long   hash_key[HASH_MAX_DWORDS];
++      int     hash_entry_index;
++
++      entry = (HASH_ENTRY_T*) &hash_entry;
++      memset((void*)entry, 0, sizeof(HASH_ENTRY_T));
++      entry->rule = 0;
++      /* enable fields of hash key */
++      entry->key_present.ip_protocol = 1;
++      entry->key_present.sip = 1;
++      entry->key_present.dip = 1;
++      entry->key_present.l4_bytes_0_3 = 1;    // src port and dest port
++
++      /* hash key */
++      entry->key.ip_protocol = IPPROTO_TCP;
++      if (ip_ver == 4) {
++              // key of ipv4
++              struct iphdr* iph = (struct iphdr*)ip_hdr;
++              memcpy(entry->key.sip, &iph->saddr, 4);
++              memcpy(entry->key.dip, &iph->daddr, 4);
++      } else if (ip_ver == 6) {
++              // key of ipv6
++              int i=0;
++              struct ipv6hdr *iph = (struct ipv6hdr*)ip_hdr;
++              for (i=0; i<4; i++) {
++                      memcpy(&(entry->key.sip[i*4]), &(iph->saddr.in6_u.u6_addr32[i]), 4);
++                      memcpy(&(entry->key.dip[i*4]), &(iph->daddr.in6_u.u6_addr32[i]), 4);
++              }
++      }
++      *(__u16*)&entry->key.l4_bytes[0] = tcp_hdr->source;
++      *(__u16*)&entry->key.l4_bytes[2] = tcp_hdr->dest;
++      // is it necessary to write ip version to hash key?
++
++      /* action of hash entry match */
++      entry->action.sw_id = 1;
++      entry->action.dest_qid = (__u8)TOE_TOE_QID(sw_id);
++      entry->action.srce_qid = 0;     // 0 for SW FreeQ. 1 for HW FreeQ.
++      hash_entry_index = hash_add_toe_entry(entry);
++//    printk("\n%s. sw_id %d, hash_entry index %x\n",
++//            __func__, TOE_TOE_QID(sw_id), hash_entry_index);
++      return hash_entry_index;
++}
++
++/*---------------------------------------------------------------------------
++ * init_toeq
++ * 1. Reserve a TOE Queue id first, to get the sw toe_connection.
++ * 2. Setup the hash entry with given iphdr and tcphdr, save hash entry index
++ *    in sw toe_connection.
++ * 3. Prepare sw toe_connection and allocate buffers.
++ * 4. Validate hash entry.
++ *-------------------------------------------------------------------------*/
++struct toe_conn* init_toeq(int ipver, void* iph, struct tcphdr* tcp_hdr,
++      TOE_INFO_T* toe, unsigned char* l2hdr)
++{
++//    printk("\t*** %s, ipver %d\n", __func__, ipver);
++      int qid=-1;
++      struct toe_conn* connection;
++      int hash_entry_index;
++      // int i=0;
++      unsigned short  dest_port = ntohs(tcp_hdr->dest);
++
++      if (dest_port == 445) {
++              printk("%s::SMB/CIFS connection\n", __func__);
++      } else if (dest_port == 20) {
++              printk("%s::ftp-data connection\n", __func__);
++      } else if (dest_port == 2049) {
++              printk("%s::nfs daemon connection\n", __func__);
++      }
++      qid = get_connection_index();
++      if (qid<0)
++              return 0;       // setup toeq failure
++      set_toe_connection(qid, 1); // reserve this sw toeq.
++
++      //connection = (struct toe_conn*)&(toe_connections[qid]);
++      hash_entry_index = create_toe_hash_entry(ipver, iph, tcp_hdr, qid);
++      if (hash_entry_index <0) {
++              printk("%s::release toe hash entry!\n", __func__);
++              set_toe_connection(qid, 0); // release this sw toeq.
++              return 0;
++      }
++      connection = create_sw_toe_connection(qid, ipver, iph, tcp_hdr);
++      connection->hash_entry_index = (__u16) hash_entry_index;
++
++      fill_toeq_buf(qid, toe);
++      memcpy(&connection->l2_hdr, l2hdr, sizeof(struct ethhdr));
++      spin_lock_init(&connection->conn_lock);
++
++      return connection;
++}
++
++#if 0
++/*----------------------------------------------------------------------
++*   toe_init_toe_queue
++*   (1) Initialize the TOE Queue Header
++*       Register: TOE_TOE_QUE_HDR_BASE (0x60003000)
++*   (2) Initialize Descriptors of TOE Queues
++*----------------------------------------------------------------------*/
++void toe_init_toe_queue(TOE_INFO_T* toe)
++{
++}
++EXPORT_SYMBOL(toe_init_toe_queue);
++#endif
++
++/*---------------------------------------------------------------------------
++ * dump_jumbo_skb
++ *-------------------------------------------------------------------------*/
++void dump_jumbo_skb(struct jumbo_frame *jumbo_skb)
++{
++      if (jumbo_skb->skb0) {
++//            printk("%s. jumbo skb %x, len %d\n",
++//                    __func__, jumbo_skb->skb0->data, jumbo_skb->skb0->len);
++              netif_rx(jumbo_skb->skb0);
++      }
++      jumbo_skb->skb0 = 0;
++      jumbo_skb->tail = 0;
++      jumbo_skb->iphdr0 = 0;
++      jumbo_skb->tcphdr0 = 0;
++}
++
++/* ---------------------------------------------------------------------
++ * Append skb to skb0. skb0 is the jumbo frame that will be passed to
++ * kernel tcp.
++ * --------------------------------------------------------------------*/
++void rx_append_skb(struct jumbo_frame *jumbo_skb, struct sk_buff* skb, int payload_len)
++{
++      struct iphdr* iphdr0 = (struct iphdr*)&(skb->data[0]);
++      int ip_hdrlen = iphdr0->ihl << 2;
++      struct tcphdr* tcphdr0 = (struct tcphdr*)&(skb->data[ip_hdrlen]);
++
++      if (!jumbo_skb->skb0) {
++              // head of the jumbo frame.
++              jumbo_skb->skb0 = skb;
++              jumbo_skb->tail = 0;
++              jumbo_skb->iphdr0 = iphdr0;
++              jumbo_skb->tcphdr0 = tcphdr0;
++      } else {
++              if (!jumbo_skb->tail)
++                      skb_shinfo(jumbo_skb->skb0)->frag_list = skb;
++              else
++                      (jumbo_skb->tail)->next = skb;
++              jumbo_skb->tail = skb;
++
++              // do we need to change truesize as well?
++              jumbo_skb->skb0->len += payload_len;
++              jumbo_skb->skb0->data_len += payload_len;
++
++              jumbo_skb->iphdr0->tot_len = htons(ntohs(jumbo_skb->iphdr0->tot_len)+payload_len);
++              jumbo_skb->tcphdr0->ack_seq = tcphdr0->ack_seq;
++              jumbo_skb->tcphdr0->window = tcphdr0->window;
++
++              skb->len += payload_len;
++              skb->data_len = 0;
++              skb->data += ntohs(iphdr0->tot_len) - payload_len;
++      }
++}
++
++/*----------------------------------------------------------------------
++* toe_gmac_handle_toeq
++* (1) read interrupt Queue to get TOE Q.
++* (2) get packet fro TOE Q and send to upper layer handler.
++* (3) allocate new buffers and put to TOE Q. Intr Q buffer is recycled.
++*----------------------------------------------------------------------*/
++void toe_gmac_handle_toeq(struct net_device *dev, GMAC_INFO_T* tp, __u32 status)
++{
++      //volatile INTRQ_INFO_T *intrq_info;
++      //TOEQ_INFO_T           *toeq_info;
++      volatile NONTOE_QHDR_T  *intr_qhdr;
++      volatile TOE_QHDR_T             *toe_qhdr;
++      volatile INTR_QHDR_T    *intr_curr_desc;
++      TOE_INFO_T      *toe = &toe_private_data;
++
++      volatile GMAC_RXDESC_T  *toe_curr_desc; // , *fq_desc;// *tmp_desc;
++      volatile DMA_RWPTR_T    intr_rwptr, toeq_rwptr;  // fq_rwptr;
++
++      unsigned int    pkt_size, desc_count, tcp_qid;
++      volatile unsigned int   toeq_wptr;
++      struct toe_conn*                connection;
++      int             i, frag_id = 0;
++      // unsigned long        toeq_flags;
++      struct jumbo_frame      jumbo_skb;
++      struct sk_buff  *skb;
++      __u32   interrupt_status;
++
++      in_toe_isr++;
++
++      interrupt_status = status >> 24;
++      // get interrupt queue header
++      intr_qhdr = (volatile NONTOE_QHDR_T*)TOE_INTR_Q_HDR_BASE;
++      memset(&jumbo_skb, 0, sizeof(struct jumbo_frame));
++
++      for (i=0; i<TOE_INTR_QUEUE_NUM; i++, intr_qhdr++) {
++              if (!(interrupt_status & 0x0001)) {
++                      // no interrupt of this IntQ
++                      interrupt_status = interrupt_status >> 1;
++                      continue;
++              }
++              interrupt_status = interrupt_status >> 1;
++              intr_rwptr.bits32 = readl(&intr_qhdr->word1);
++
++              while ( intr_rwptr.bits.rptr != intr_rwptr.bits.wptr) {
++                      int max_pktsize = 1;
++                      // get interrupt queue descriptor.
++                      intr_curr_desc = (INTR_QHDR_T*)toe->intr_desc_base +
++                              i* TOE_INTR_DESC_NUM + intr_rwptr.bits.rptr;
++//                    printk("%s::int %x\n", __func__, intr_curr_desc->word1.bits32);
++                      // get toeq id
++                      tcp_qid = (u8)intr_curr_desc->word1.bits.tcp_qid - (u8)TOE_TOE_QID(0);
++                      // get toeq queue header
++                      toe_qhdr = (volatile TOE_QHDR_T*) TOE_TOE_QUE_HDR_BASE;
++                      toe_qhdr += tcp_qid;
++                      connection = &toe_connections[tcp_qid];
++                      del_timer(&connection->rx_timer);
++                      // Gary Chen spin_lock_irqsave(&connection->conn_lock, toeq_flags);
++                      // handling interrupts of this TOE Q.
++                      if (intr_curr_desc->word1.bits.ctl || intr_curr_desc->word1.bits.osq ||
++                              intr_curr_desc->word1.bits.abn)
++                              max_pktsize = 0;
++                      if (!max_pktsize || intr_curr_desc->word1.bits.TotalPktSize) {
++                              desc_count=0;
++                              // wptr in intl queue is where this TOE interrupt should stop.
++                              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++                              toeq_wptr = intr_curr_desc->word0.bits.wptr;
++                              if (connection->toeq_rwptr.bits.rptr != toeq_rwptr.bits.rptr)
++                                      printk("conn rptr %d, hw rptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_rwptr.bits.rptr);
++
++                              if (intr_curr_desc->word1.bits.ctl &&
++                                      (toeq_rwptr.bits.rptr == toeq_wptr)) {
++                                      printk("\nctrl frame, but not in TOE queue! conn rptr %d, hw wptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_wptr);
++//                                    dump_toe_qhdr(toe_qhdr);
++//                                    dump_intrq_desc(intr_curr_desc);
++                              }
++                              // while (toeq_rwptr.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                              while (toe_qhdr->word1.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                                      frag_id++;
++                                      toe_curr_desc = (volatile GMAC_RXDESC_T *)(toe->toe_desc_base[tcp_qid]
++                                              + toe_qhdr->word1.bits.rptr *sizeof(GMAC_RXDESC_T));
++                                      connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                                      desc_count = toe_curr_desc->word0.bits.desc_count;
++                                      pkt_size = toe_curr_desc->word1.bits.byte_count;
++                                      consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                              PCI_DMA_FROMDEVICE);
++                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                              SKB_RESERVE_BYTES));
++                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x01);
++                                      connection->curr_rx_skb = skb;
++                                      skb_reserve(skb, RX_INSERT_BYTES);
++                                      if ((skb->len + pkt_size) > (1514+16))
++                                      {
++                                              printk("skb->len=%d, pkt_size=%d\n",skb->len, pkt_size);
++                                              while(1);
++                                      }
++
++                                      skb_put(skb, pkt_size);
++                                      skb->dev = dev;
++                                      skb->protocol = eth_type_trans(skb, dev);
++                                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++                                      if (toe_curr_desc->word3.bits32 & 0x1b000000)
++                                              dump_jumbo_skb(&jumbo_skb);
++
++                                      rx_append_skb(&jumbo_skb, skb, pkt_size-toe_curr_desc->word3.bits.l7_offset);
++//                                    spin_lock_irqsave(&gmac_fq_lock, flags);
++                                      toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                                      SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                                    spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                      if (storlink_ctl.fqint_threshold)
++                                              continue;
++#if 0
++//#if (HANDLE_FREEQ_METHOD == HANDLE_FREEQ_INDIVIDUAL)
++                                      if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++                                              printk("%s::toe queue alloc buffer ", __func__);
++                                      }
++                                      *(unsigned int*)(skb->data) = (unsigned int)skb;
++                                      connection->curr_rx_skb = skb;
++                                      skb_reserve(skb, SKB_RESERVE_BYTES);
++
++                                      spin_lock_irqsave(&gmac_fq_lock, flags);
++                                      fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++                                      if (toe->fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                              printk("%s::fq_rx_rwptr %x\n", __func__, toe->fq_rx_rwptr.bits32);
++                                              mac_stop_txdma((struct net_device*) tp->dev);
++                                              spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                              while(1);
++                                      }
++                                      fq_desc = (GMAC_RXDESC_T*)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++                                      fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++
++                                      fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                                      SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                                      toe->fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++#endif
++                              } // end of this multi-desc.
++                              dump_jumbo_skb(&jumbo_skb);
++                              dev->last_rx = jiffies;
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                      } else if (intr_curr_desc->word1.bits.sat) {
++                              toeq_rwptr.bits32 = readl(&toe_qhdr->word1);
++                              toeq_wptr = intr_curr_desc->word0.bits.wptr;
++                              if (connection->toeq_rwptr.bits.rptr != toeq_rwptr.bits.rptr)
++                                      printk("SAT. conn rptr %d, hw rptr %d\n",
++                                              connection->toeq_rwptr.bits.rptr, toeq_rwptr.bits.rptr);
++/*
++                                      printk("%s::SAT int!, ackcnt %x, seqcnt %x, rptr %d, wptr %d, ack %x, qhack %x\n",
++                                              __func__, intr_curr_desc->word4.bits.AckCnt, intr_curr_desc->word4.bits.SeqCnt,
++                                              toeq_rptr, toeq_wptr, intr_curr_desc->word3.ack_num, toe_qhdr->word4.ack_num);*/
++                              /* pure ack */
++                              if (toeq_rwptr.bits.rptr == toeq_wptr) {
++                                      if (intr_curr_desc->word4.bits32) {
++                                              skb = gen_pure_ack(connection, (TOE_QHDR_T *)toe_qhdr, (INTR_QHDR_T *)intr_curr_desc);
++                                              skb_put(skb, 60);
++                                              skb->dev = connection->dev;
++                                              skb->ip_summed = CHECKSUM_UNNECESSARY;
++                                              skb->protocol = eth_type_trans(skb, connection->dev);
++                                              netif_rx(skb);
++                                      } else
++                                              printk("%s::SAT Interrupt!. But cnt is 0!\n", __func__);
++                              } else {
++                                      // while (toeq_rwptr.bits.rptr != toeq_wptr) {
++                                      while (toe_qhdr->word1.bits.rptr != intr_curr_desc->word0.bits.wptr) {
++                                              toe_curr_desc = (volatile GMAC_RXDESC_T*)(toe->toe_desc_base[tcp_qid]
++                                                      + toe_qhdr->word1.bits.rptr * sizeof(GMAC_RXDESC_T));
++                                              connection->curr_desc = (GMAC_RXDESC_T *)toe_curr_desc;
++                                              desc_count = toe_curr_desc->word0.bits.desc_count;
++                                              pkt_size = toe_curr_desc->word1.bits.byte_count;
++                                              consistent_sync((void*)__va(toe_curr_desc->word2.buf_adr), pkt_size,
++                                                      PCI_DMA_FROMDEVICE);
++                                              // if ( ((toeq_rwptr.bits.rptr +1)&(TOE_TOE_DESC_NUM-1)) == toeq_wptr) {
++                                              if ( RWPTR_ADVANCE_ONE(toe_qhdr->word1.bits.rptr, TOE_TOE_DESC_NUM) == toeq_wptr) {
++                                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr) -
++                                                              SKB_RESERVE_BYTES));
++                                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x04);
++                                                      connection->curr_rx_skb = skb;
++                                                      skb_reserve(skb, RX_INSERT_BYTES);
++                                                      skb_put(skb, pkt_size);
++                                                      skb->dev = dev;
++                                                      skb->protocol = eth_type_trans(skb, dev);
++                                                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++                                                      // printk("toeq_rptr %d, wptr %d\n", toeq_rptr, toeq_wptr);
++                                                      netif_rx(skb);
++                                                      dev->last_rx = jiffies;
++/*
++                                                      if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
++
++                                                      }
++                                                      *(unsigned int*)(skb->data) = (unsigned int) skb;
++                                                      skb_reserve(skb, SKB_RESERVE_BYTES); */
++                                              } else {
++                                                      // reuse this skb, append to free queue..
++                                                      skb = (struct sk_buff*)(REG32(__va(toe_curr_desc->word2.buf_adr)-
++                                                              SKB_RESERVE_BYTES));
++                                                      _debug_skb(skb, (GMAC_RXDESC_T *)toe_curr_desc, 0x05);
++                                                      connection->curr_rx_skb = skb;
++                                                      dev_kfree_skb_irq(skb);
++                                              }
++#if 0
++                                              spin_lock_irqsave(&gmac_fq_lock, flags);
++                                              fq_rwptr.bits32 = readl(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG);
++/*                                            if (toe->fq_rx_rwptr.bits.wptr != fq_rwptr.bits.wptr) {
++                                                      printk("%s::fq_rx_rwptr %x\n", __func__, toe->fq_rx_rwptr.bits32);
++                                                      mac_stop_txdma((struct net_device*) tp->dev);
++                                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                                      while(1);
++                                              } */
++                                              fq_desc = (GMAC_RXDESC_T*)toe->swfq_desc_base + fq_rwptr.bits.wptr;
++                                              fq_desc->word2.buf_adr = (unsigned int)__pa(skb->data);
++
++                                              fq_rwptr.bits.wptr = RWPTR_ADVANCE_ONE(fq_rwptr.bits.wptr, TOE_SW_FREEQ_DESC_NUM);
++                                              SET_WPTR(TOE_GLOBAL_BASE + GLOBAL_SWFQ_RWPTR_REG, fq_rwptr.bits.wptr);
++                                              toe->fq_rx_rwptr.bits32 = fq_rwptr.bits32;
++      //                                      spin_unlock_irqrestore(&gmac_fq_lock, flags);
++#endif
++//                                            spin_lock_irqsave(&gmac_fq_lock, flags);
++                                              toeq_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(toeq_rwptr.bits.rptr, TOE_TOE_DESC_NUM);
++                                              SET_RPTR(&toe_qhdr->word1, toeq_rwptr.bits.rptr);
++//                                            spin_unlock_irqrestore(&gmac_fq_lock, flags);
++                                      }
++                              } // end of ACK with options.
++                              connection->toeq_rwptr.bits32 = toeq_rwptr.bits32;
++                              // Gary Chen spin_unlock_irqrestore(&connection->conn_lock, toeq_flags);
++//                            }
++                      };
++                      update_timer(connection);
++                      // any protection against interrupt queue header?
++                      intr_rwptr.bits.rptr = RWPTR_ADVANCE_ONE(intr_rwptr.bits.rptr, TOE_INTR_DESC_NUM);
++                      SET_RPTR(&intr_qhdr->word1, intr_rwptr.bits.rptr);
++                      intr_rwptr.bits32 = readl(&intr_qhdr->word1);
++                      toe_gmac_fill_free_q();
++              } // end of this interrupt Queue processing.
++      } // end of all interrupt Queues.
++
++      in_toe_isr = 0;
++}
++
++
+--- /dev/null
++++ b/drivers/net/sl_lepus_hash.c
+@@ -0,0 +1,553 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl_lepus_hash.c
++* Description :
++*             Handle Storlink Lepus Hash Functions
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*     03/13/2006      Gary Chen       Create and implement
++*
++****************************************************************************/
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/compiler.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/delay.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/completion.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/semaphore.h>
++#include <asm/arch/irqs.h>
++#include <asm/arch/it8712.h>
++#include <linux/mtd/kvctl.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
++#define        MIDWAY
++#define        SL_LEPUS
++
++#include <asm/arch/sl2312.h>
++#include <asm/arch/sl_lepus_gmac.h>
++#include <asm/arch/sl_hash_cfg.h>
++
++#ifndef RXTOE_DEBUG
++#define RXTOE_DEBUG
++#endif
++#undef RXTOE_DEBUG
++
++/*----------------------------------------------------------------------
++* Definition
++*----------------------------------------------------------------------*/
++#define       hash_printf                             printk
++
++#define HASH_TIMER_PERIOD             (60*HZ) // seconds
++#define HASH_ILLEGAL_INDEX            0xffff
++
++/*----------------------------------------------------------------------
++* Variables
++*----------------------------------------------------------------------*/
++u32                                   hash_activate_bits[HASH_TOTAL_ENTRIES/32];
++u32                                   hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++char                          hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++static struct timer_list hash_timer_obj;
++LIST_HEAD(hash_timeout_list);
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length);
++static void hash_timer_func(u32 data);
++
++/*----------------------------------------------------------------------
++* hash_init
++*----------------------------------------------------------------------*/
++void hash_init(void)
++{
++      int i;
++      volatile u32 *dp1, *dp2, dword;
++
++      dp1 = (volatile u32 *) TOE_V_BIT_BASE;
++      dp2 = (volatile u32 *) TOE_A_BIT_BASE;
++
++      for (i=0; i<HASH_TOTAL_ENTRIES/32; i++)
++      {
++              *dp1++ = 0;
++              dword = *dp2++; // read-clear
++      }
++      memset((void *)&hash_nat_owner_bits, 0, sizeof(hash_nat_owner_bits));
++      memset((void *)&hash_tables, 0, sizeof(hash_tables));
++
++      init_timer(&hash_timer_obj);
++      hash_timer_obj.expires = jiffies + HASH_TIMER_PERIOD;
++      hash_timer_obj.data = (unsigned long)&hash_timer_obj;
++      hash_timer_obj.function = (void *)&hash_timer_func;
++      add_timer(&hash_timer_obj);
++
++#if (HASH_MAX_BYTES == 128)
++      writel((unsigned long)__pa(&hash_tables) | 3,   // 32 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#elif (HASH_MAX_BYTES == 64)
++      writel((unsigned long)__pa(&hash_tables) | 2,   // 16 words
++                      TOE_GLOBAL_BASE + GLOBAL_HASH_TABLE_BASE_REG);
++#else
++      #error Incorrect setting for HASH_MAX_BYTES
++#endif
++
++}
++/*----------------------------------------------------------------------
++* hash_add_entry
++*----------------------------------------------------------------------*/
++int hash_add_entry(HASH_ENTRY_T *entry)
++{
++      int     rc;
++      u32     key[HASH_MAX_DWORDS];
++      rc = hash_build_keys((u32 *)&key, entry);
++      if (rc < 0)
++              return -1;
++      hash_write_entry(entry, (unsigned char*) &key[0]);
++//    hash_set_valid_flag(entry->index, 1);
++//    printk("Dump hash key!\n");
++//    dump_hash_key(entry);
++      return entry->index;
++}
++
++/*----------------------------------------------------------------------
++* hash_set_valid_flag
++*----------------------------------------------------------------------*/
++void hash_set_valid_flag(int index, int valid)
++{
++      register u32 reg32;
++
++      reg32 = TOE_V_BIT_BASE + (index/32) * 4;
++
++      if (valid)
++      {
++              writel(readl(reg32) | (1 << (index%32)), reg32);
++      }
++      else
++      {
++              writel(readl(reg32) & ~(1 << (index%32)), reg32);
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_set_nat_owner_flag
++*----------------------------------------------------------------------*/
++void hash_set_nat_owner_flag(int index, int valid)
++{
++      if (valid)
++      {
++              hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++      }
++      else
++      {
++              hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++      }
++}
++
++
++/*----------------------------------------------------------------------
++* hash_build_keys
++*----------------------------------------------------------------------*/
++int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      u32     data;
++      unsigned char   *cp;
++      int                             i, j;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++      cp = (unsigned char *)destp;
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++      {
++              HASH_PUSH_WORD(cp, entry->key.Ethertype);               // word 0
++              HASH_PUSH_BYTE(cp, entry->key.port);                    // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++      else
++      {
++              HASH_PUSH_DWORD(cp, 0);
++      }
++
++      if (entry->key_present.da || entry->key_present.sa)
++      {
++              unsigned char mac[4];
++              if (entry->key_present.da)
++              {
++                      for (i=0; i<4; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.da[i]);
++              }
++              mac[0] = (entry->key_present.da) ? entry->key.da[4] : 0;
++              mac[1] = (entry->key_present.da) ? entry->key.da[5] : 0;
++              mac[2] = (entry->key_present.sa) ? entry->key.sa[0] : 0;
++              mac[3] = (entry->key_present.sa) ? entry->key.sa[1] : 0;
++              data = mac[0] + (mac[1]<<8) + (mac[2]<<16) + (mac[3]<<24);
++              HASH_PUSH_DWORD(cp, data);
++              if (entry->key_present.sa)
++              {
++                      for (i=2; i<6; i++)
++                              HASH_PUSH_BYTE(cp, entry->key.sa[i]);
++              }
++      }
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++      if (entry->key_present.ipv4_hdrlen || entry->key_present.ip_tos || entry->key_present.ip_protocol)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.ip_protocol);             // Byte 0
++              HASH_PUSH_BYTE(cp, entry->key.ip_tos);                  // Byte 1
++              HASH_PUSH_BYTE(cp, entry->key.ipv4_hdrlen);             // Byte 2
++              HASH_PUSH_BYTE(cp, 0);                                                  // Byte 3
++      }
++
++      if (entry->key_present.ipv6_flow_label)
++      {
++              HASH_PUSH_DWORD(cp, entry->key.ipv6_flow_label);        // low word
++      }
++      if (entry->key_present.sip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.sip[j]);
++                      }
++              }
++      }
++      if (entry->key_present.dip)
++      {
++              // input (entry->key.sip[i]) is network-oriented
++              // output (hash key) is host-oriented
++              for (i=3; i>=0; i--)
++                      HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++              if (entry->key.ipv6)
++              {
++                      for (i=4; i<16; i+=4)
++                      {
++                              for (j=i+3; j>=i; j--)
++                                      HASH_PUSH_BYTE(cp, entry->key.dip[j]);
++                      }
++              }
++      }
++
++      if (entry->key_present.l4_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++      }
++      if (entry->key_present.l4_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[7]);
++      }
++      if (entry->key_present.l4_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[11]);
++      }
++      if (entry->key_present.l4_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[15]);
++      }
++      if (entry->key_present.l4_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[19]);
++      }
++      if (entry->key_present.l4_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l4_bytes[23]);
++      }
++      if (entry->key_present.l7_bytes_0_3)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[0]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[1]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[2]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[3]);
++      }
++      if (entry->key_present.l7_bytes_4_7)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[4]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[5]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[6]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[7]);
++      }
++      if (entry->key_present.l7_bytes_8_11)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[8]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[9]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[10]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[11]);
++      }
++      if (entry->key_present.l7_bytes_12_15)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[12]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[13]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[14]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[15]);
++      }
++      if (entry->key_present.l7_bytes_16_19)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[16]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[17]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[18]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[19]);
++      }
++      if (entry->key_present.l7_bytes_20_23)
++      {
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[20]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[21]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[22]);
++              HASH_PUSH_BYTE(cp, entry->key.l7_bytes[23]);
++      }
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      if (total > HASH_MAX_KEY_DWORD)
++      {
++              //hash_printf("Total key words (%d) is too large (> %d)!\n",
++              //                              total, HASH_MAX_KEY_DWORD);
++              return -1;
++      }
++
++      if (entry->key_present.port || entry->key_present.Ethertype)
++              index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      else
++      {
++              if (total == 1)
++              {
++                      hash_printf("No key is assigned!\n");
++                      return -1;
++              }
++
++              index = hash_gen_crc16((unsigned char *)(destp+1), (total-1) * 4);
++      }
++
++      entry->index = index & HASH_BITS_MASK;
++
++      //hash_printf("Total key words = %d, Hash Index= %d\n",
++      //                              total, entry->index);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++
++      return total;
++}
++
++/*----------------------------------------------------------------------
++* hash_build_nat_keys
++*----------------------------------------------------------------------*/
++void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry)
++{
++      unsigned char   *cp;
++      int                             i;
++      unsigned short  index;
++      int                     total;
++
++      memset((void *)destp, 0, HASH_MAX_BYTES);
++
++      cp = (unsigned char *)destp + 2;
++      HASH_PUSH_BYTE(cp, entry->key.port);
++      cp++;
++
++      if (entry->key_present.pppoe_sid || entry->key_present.vlan_id)
++      {
++              HASH_PUSH_WORD(cp, entry->key.vlan_id);         // low word
++              HASH_PUSH_WORD(cp, entry->key.pppoe_sid);       // high word
++      }
++
++      HASH_PUSH_BYTE(cp, entry->key.ip_protocol);
++      cp+=3;
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.sip[i]);
++
++      // input (entry->key.sip[i]) is network-oriented
++      // output (hash key) is host-oriented
++      for (i=3; i>=0; i--)
++              HASH_PUSH_BYTE(cp, entry->key.dip[i]);
++
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[0]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[1]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[2]);
++      HASH_PUSH_BYTE(cp, entry->key.l4_bytes[3]);
++
++      // get hash index
++      total = (u32)((u32)cp - (u32)destp) / (sizeof(u32));
++
++      index = hash_gen_crc16((unsigned char *)destp, total * 4);
++      entry->index = index & ((1 << HASH_BITS) - 1);
++
++      cp = (unsigned char *)destp;
++      cp+=3;
++      HASH_PUSH_BYTE(cp, entry->rule);        // rule
++
++      entry->total_dwords = total;
++}
++
++
++/*----------------------------------------------------------------------
++* hash_write_entry
++*----------------------------------------------------------------------*/
++int hash_write_entry(HASH_ENTRY_T *entry, unsigned char *key)
++{
++      int             i;
++      u32             *srcep, *destp, *destp2;
++
++      srcep = (u32 *)key;
++      destp2 = destp = (u32 *)&hash_tables[entry->index][0];
++
++      for (i=0; i<(entry->total_dwords); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      srcep = (u32 *)&entry->action;
++      *destp++ = *srcep;
++
++      srcep = (u32 *)&entry->param;
++      for (i=0; i<(sizeof(ENTRY_PARAM_T)/sizeof(*destp)); i++, srcep++, destp++)
++              *destp = *srcep;
++
++      memset(destp, 0, (HASH_MAX_DWORDS-entry->total_dwords-HASH_ACTION_DWORDS) * sizeof(u32));
++
++      consistent_sync(destp2, (entry->total_dwords+HASH_ACTION_DWORDS) * 4, PCI_DMA_TODEVICE);
++      return 0;
++}
++
++/*----------------------------------------------------------------------
++* hash_timer_func
++*----------------------------------------------------------------------*/
++static void hash_timer_func(u32 data)
++{
++      int                             i, j;
++      volatile u32    *active_p, *own_p, *valid_p;
++      u32                             a_bits, own_bits;
++
++      valid_p = (volatile u32 *)TOE_V_BIT_BASE;
++      active_p = (volatile u32 *)hash_activate_bits;
++      own_p = (volatile u32 *)hash_nat_owner_bits;
++      for (i=0; i<(HASH_TOTAL_ENTRIES/32); i++, own_p++, active_p++, valid_p++)
++      {
++              *active_p |= readl(TOE_A_BIT_BASE + (i*4));
++              a_bits = *active_p;
++              own_bits = *own_p;
++              if (own_bits)
++              {
++#ifndef DEBUG_NAT_MIXED_HW_SW_TX
++                      a_bits = own_bits & ~a_bits;
++#else
++                      a_bits = own_bits & a_bits;
++#endif
++                      for (j=0; a_bits && j<32; j++)
++                      {
++                              if (a_bits & 1)
++                              {
++                                      *valid_p &= ~(1 << j);          // invalidate it
++#if !(defined(NAT_DEBUG_LAN_HASH_TIMEOUT) || defined(NAT_DEBUG_WAN_HASH_TIMEOUT))
++                                      *own_p &= ~(1 << j);            // release ownership for NAT
++#endif
++// #ifdef DEBUG_NAT_MIXED_HW_SW_TX
++#if 0
++                                      hash_printf("%lu %s: Clear hash index: %d\n", jiffies/HZ, __func__, i*32+j);
++#endif
++                              }
++                              a_bits >>= 1;
++                      }
++                      *active_p &= ~own_bits;         // deactivate it for next polling
++              }
++      }
++
++      hash_timer_obj.expires = jiffies + HASH_TIMER_PERIOD;
++      add_timer((struct timer_list *)data);
++}
++
++/*----------------------------------------------------------------------
++* dm_long
++*----------------------------------------------------------------------*/
++void dm_long(u32 location, int length)
++{
++      u32             *start_p, *curr_p, *end_p;
++      u32             *datap, data;
++      int             i;
++
++      //if (length > 1024)
++      //      length = 1024;
++
++      start_p = (u32 *)location;
++      end_p = (u32 *)location + length;
++      curr_p = (u32 *)((u32)location & 0xfffffff0);
++      datap = (u32 *)location;
++      while (curr_p < end_p)
++      {
++              hash_printf("0x%08x: ",(u32)curr_p & 0xfffffff0);
++              for (i=0; i<4; i++)
++              {
++                      if (curr_p < start_p || curr_p >= end_p)
++               hash_printf("         ");
++                      else
++                      {
++                              data = *datap;
++                              hash_printf("%08X ", data);
++                      }
++                      if (i==1)
++              hash_printf("- ");
++
++                      curr_p++;
++                      datap++;
++              }
++        hash_printf("\n");
++      }
++}
++
++/*----------------------------------------------------------------------
++* hash_dump_entry
++*----------------------------------------------------------------------*/
++void hash_dump_entry(int index)
++{
++      hash_printf("Hash Index %d:\n", index);
++      dm_long((u32)&hash_tables[index][0], HASH_MAX_DWORDS);
++}
++
++
+--- /dev/null
++++ b/drivers/net/sl_switch.c
+@@ -0,0 +1,650 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++#define GPIO_BASE_ADDR1  (IO_ADDRESS(SL2312_GPIO_BASE1))
++enum GPIO_REG
++{
++    GPIO_DATA_OUT   = 0x00,
++    GPIO_DATA_IN    = 0x04,
++    GPIO_PIN_DIR    = 0x08,
++    GPIO_BY_PASS    = 0x0c,
++    GPIO_DATA_SET   = 0x10,
++    GPIO_DATA_CLEAR = 0x14,
++};
++
++#define GMAC_SPEED_10                 0
++#define GMAC_SPEED_100                        1
++#define GMAC_SPEED_1000                       2
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++#ifndef BIT
++#define BIT(x)                                                (1 << (x))
++#endif
++
++//int Get_Set_port_status();
++unsigned int SPI_read_bit(void);
++void SPI_write_bit(char bit_EEDO);
++void SPI_write(unsigned char block,unsigned char subblock,unsigned char addr,unsigned int value);
++unsigned int SPI_read(unsigned char block,unsigned char subblock,unsigned char addr);
++int SPI_default(void);
++void SPI_CS_enable(unsigned char enable);
++unsigned int SPI_get_identifier(void);
++void phy_write(unsigned char port_no,unsigned char reg,unsigned int val);
++unsigned int phy_read(unsigned char port_no,unsigned char reg);
++void phy_write_masked(unsigned char port_no,unsigned char reg,unsigned int val,unsigned int mask);
++void init_seq_7385(unsigned char port_no) ;
++void phy_receiver_init (unsigned char port_no);
++
++#define PORT_NO               4
++int switch_pre_speed[PORT_NO]={0,0,0,0};
++int switch_pre_link[PORT_NO]={0,0,0,0};
++
++
++
++
++
++/*                            NOTES
++ *   The Protocol of the SPI are as follows:
++ *
++ *                       Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
++ *    byte0     |   Block id  | r/w | sub-block        |
++ *    byte1     |             Address                  |
++ *    byte2     |             Data                     |
++ *    byte3     |             Data                     |
++ *    byte4     |             Data                     |
++ *    byte5     |             Data                     |
++ */
++
++
++
++
++/***************************************/
++/* define GPIO module base address     */
++/***************************************/
++#define GPIO_EECS          0x80000000         /*   EECS: GPIO[22]   */
++#define GPIO_MOSI          0x20000000         /*   EEDO: GPIO[29]   send to 6996*/
++#define GPIO_MISO          0x40000000         /*   EEDI: GPIO[30]   receive from 6996*/
++#define GPIO_EECK          0x10000000         /*   EECK: GPIO[31]   */
++
++/*************************************************************
++* SPI protocol for ADM6996 control
++**************************************************************/
++#define SPI_OP_LEN         0x08               // the length of start bit and opcode
++#define SPI_OPWRITE        0X05               // write
++#define SPI_OPREAD         0X06               // read
++#define SPI_OPERASE        0X07               // erase
++#define SPI_OPWTEN         0X04               // write enable
++#define SPI_OPWTDIS        0X04               // write disable
++#define SPI_OPERSALL       0X04               // erase all
++#define SPI_OPWTALL        0X04               // write all
++
++#define SPI_ADD_LEN        8                  // bits of Address
++#define SPI_DAT_LEN        32                 // bits of Data
++
++
++/****************************************/
++/*    Function Declare                */
++/****************************************/
++
++//unsigned int SPI_read_bit(void);
++//void SPI_write_bit(char bit_EEDO);
++//unsigned int SPI_read_bit(void);
++/******************************************
++* SPI_write
++* addr -> Write Address
++* value -> value to be write
++***************************************** */
++void phy_receiver_init (unsigned char port_no)
++{
++    phy_write(port_no,31,0x2a30);
++    phy_write_masked(port_no, 12, 0x0200, 0x0300);
++    phy_write(port_no,31,0);
++}
++
++void phy_write(unsigned char port_no,unsigned char reg,unsigned int val)
++{
++      unsigned int cmd;
++
++      cmd = (port_no<<21)|(reg<<16)|val;
++      SPI_write(3,0,1,cmd);
++}
++
++unsigned int phy_read(unsigned char port_no,unsigned char reg)
++{
++      unsigned int cmd,reg_val;
++
++      cmd = BIT(26)|(port_no<<21)|(reg<<16);
++      SPI_write(3,0,1,cmd);
++      msleep(2);
++      reg_val = SPI_read(3,0,2);
++      return reg_val;
++}
++
++void phy_write_masked(unsigned char port_no,unsigned char reg,unsigned int val,unsigned int mask)
++{
++      unsigned int cmd,reg_val;
++
++      cmd = BIT(26)|(port_no<<21)|(reg<<16);  // Read reg_val
++      SPI_write(3,0,1,cmd);
++      mdelay(2);
++      reg_val = SPI_read(3,0,2);
++      reg_val &= ~mask;                       // Clear masked bit
++      reg_val |= (val&mask) ;                 // set masked bit ,if true
++      cmd = (port_no<<21)|(reg<<16)|reg_val;
++      SPI_write(3,0,1,cmd);
++}
++
++void init_seq_7385(unsigned char port_no)
++{
++      unsigned char rev;
++
++      phy_write(port_no, 31, 0x2a30);
++      phy_write_masked(port_no, 8, 0x0200, 0x0200);
++      phy_write(port_no, 31, 0x52b5);
++      phy_write(port_no, 16, 0xb68a);
++      phy_write_masked(port_no, 18, 0x0003, 0xff07);
++      phy_write_masked(port_no, 17, 0x00a2, 0x00ff);
++      phy_write(port_no, 16, 0x968a);
++      phy_write(port_no, 31, 0x2a30);
++      phy_write_masked(port_no, 8, 0x0000, 0x0200);
++      phy_write(port_no, 31, 0x0000); /* Read revision */
++      rev = phy_read(port_no, 3) & 0x000f;
++      if (rev == 0)
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 8, 0x0200, 0x0200);
++              phy_write(port_no, 31, 0x52b5);
++              phy_write(port_no, 18, 0x0000);
++              phy_write(port_no, 17, 0x0689);
++              phy_write(port_no, 16, 0x8f92);
++              phy_write(port_no, 31, 0x52B5);
++              phy_write(port_no, 18, 0x0000);
++              phy_write(port_no, 17, 0x0E35);
++              phy_write(port_no, 16, 0x9786);
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 8, 0x0000, 0x0200);
++              phy_write(port_no, 23, 0xFF80);
++              phy_write(port_no, 23, 0x0000);
++      }
++      phy_write(port_no, 31, 0x0000);
++      phy_write(port_no, 18, 0x0048);
++      if (rev == 0)
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write(port_no, 20, 0x6600);
++              phy_write(port_no, 31, 0x0000);
++              phy_write(port_no, 24, 0xa24e);
++      }
++      else
++      {
++              phy_write(port_no, 31, 0x2a30);
++              phy_write_masked(port_no, 22, 0x0240, 0x0fc0);
++              phy_write_masked(port_no, 20, 0x4000, 0x6000);
++              phy_write(port_no, 31, 1);
++              phy_write_masked(port_no, 20, 0x6000, 0xe000);
++              phy_write(port_no, 31, 0x0000);
++      }
++}
++
++int Get_Set_port_status()
++{
++      unsigned int    reg_val,ability,rcv_mask,mac_config;
++      int is_link=0;
++      int i;
++
++      rcv_mask = SPI_read(2,0,0x10);                  // Receive mask
++
++      for(i=0;i<4;i++){
++              reg_val = phy_read(i,1);
++              if ((reg_val & 0x0024) == 0x0024) /* link is established and auto_negotiate process completed */
++              {
++                      is_link=1;
++                      if(switch_pre_link[i]==LINK_DOWN){              // Link Down ==> Link up
++
++                              rcv_mask |= BIT(i);                     // Enable receive
++
++                              reg_val = phy_read(i,10);
++                              if(reg_val & 0x0c00){
++                                      printk("Port%d:Giga mode\n",i);
++//                                    SPI_write(1,i,0x00,0x300701B1);
++                                      mac_config = 0x00060004|(6<<6);
++
++                                      SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                      mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                      SPI_write(1,i,0x00,mac_config);
++                                      SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                      reg_val = SPI_read(5,0,0x12);
++                                      reg_val &= ~BIT(i);
++                                      SPI_write(5,0,0x12,reg_val);
++
++                                      reg_val = SPI_read(1,i,0x00);
++                                      reg_val |= 0x10010000;
++                                      SPI_write(1,i,0x00,reg_val);
++//                                    SPI_write(1,i,0x00,0x10070181);
++                                      switch_pre_link[i]=LINK_UP;
++                                      switch_pre_speed[i]=GMAC_SPEED_1000;
++                              }
++                              else{
++                                      reg_val = phy_read(i,5);
++                                      ability = (reg_val&0x5e0) >>5;
++                                      if ((ability & 0x0C)) /* 100M */
++                                      {
++//                                            SPI_write(1,i,0x00,0x30050472);
++                                              if((ability&0x08)==0)           // Half
++                                                      mac_config = 0x00040004 |(17<<6);
++                                              else                            // Full
++                                                      mac_config = 0x00040004 |(17<<6);
++
++                                              SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                              mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                              SPI_write(1,i,0x00,mac_config);
++                                              SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                              reg_val = SPI_read(5,0,0x12);
++                                              reg_val &= ~BIT(i);
++                                              SPI_write(5,0,0x12,reg_val);
++
++                                              reg_val = SPI_read(1,i,0x00);
++                                              reg_val &= ~0x08000000;
++                                              reg_val |= 0x10010000;
++                                              SPI_write(1,i,0x00,reg_val);
++//                                            SPI_write(1,i,0x00,0x10050442);
++                                              printk("Port%d:100M\n",i);
++                                              switch_pre_link[i]=LINK_UP;
++                                              switch_pre_speed[i]=GMAC_SPEED_100;
++                                      }
++                                      else if((ability & 0x03)) /* 10M */
++                                      {
++//                                            SPI_write(1,i,0x00,0x30050473);
++                                              if((ability&0x2)==0)            // Half
++                                                      mac_config = 0x00040004 |(17<<6);
++                                              else                            // Full
++                                                      mac_config = 0x00040004 |(17<<6);
++
++                                              SPI_write(1,i,0x00,((mac_config & 0xfffffff8) | 1) | 0x20000030);       // reset port
++                                              mac_config |= (( BIT(i) << 19) | 0x08000000);
++                                              SPI_write(1,i,0x00,mac_config);
++                                              SPI_write(1,i,0x04,0x000300ff);         // flow control
++
++                                              reg_val = SPI_read(5,0,0x12);
++                                              reg_val &= ~BIT(i);
++                                              SPI_write(5,0,0x12,reg_val);
++
++                                              reg_val = SPI_read(1,i,0x00);
++                                              reg_val &= ~0x08000000;
++                                              reg_val |= 0x10010000;
++                                              SPI_write(1,i,0x00,reg_val);
++//                                            SPI_write(1,i,0x00,0x10050443);
++                                              printk("Port%d:10M\n",i);
++                                              switch_pre_link[i]=LINK_UP;
++                                              switch_pre_speed[i]=GMAC_SPEED_10;
++                                      }
++                                      else{
++                                              SPI_write(1,i,0x00,0x20000030);
++                                              printk("Port%d:Unknown mode\n",i);
++                                              switch_pre_link[i]=LINK_DOWN;
++                                              switch_pre_speed[i]=GMAC_SPEED_10;
++                                      }
++                              }
++                      }
++                      else{                                           // Link up ==> Link UP
++
++                      }
++              }
++              else{                                                   // Link Down
++                      if(switch_pre_link[i]==LINK_UP){
++                              printk("Port%d:Link Down\n",i);
++                              //phy_receiver_init(i);
++                              reg_val = SPI_read(1,i,0);
++                              reg_val &= ~BIT(16);
++                              SPI_write(1,i,0x00,reg_val);                    // disable RX
++                              SPI_write(5,0,0x0E,BIT(i));                     // dicard packet
++                              while((SPI_read(5,0,0x0C)&BIT(i))==0)           // wait to be empty
++                                      msleep(1);
++                              SPI_write(1,i,0x00,0x20000030);                 // PORT_RST
++                              SPI_write(5,0,0x0E,SPI_read(5,0,0x0E) & ~BIT(i));// accept packet
++
++                              reg_val = SPI_read(5,0,0x12);
++                              reg_val |= BIT(i);
++                              SPI_write(5,0,0x12,reg_val);
++                      }
++                      switch_pre_link[i]=LINK_DOWN;
++                      rcv_mask &= ~BIT(i);                    // disable receive
++              }
++      }
++
++      SPI_write(2,0,0x10,rcv_mask);                   // Receive mask
++      return is_link;
++
++}
++EXPORT_SYMBOL(Get_Set_port_status);
++
++void SPI_write(unsigned char block,unsigned char subblock,unsigned char addr,unsigned int value)
++{
++      int     i;
++      char    bit;
++      unsigned int data;
++
++      SPI_CS_enable(1);
++
++      data = (block<<5) | 0x10 | subblock;
++
++      //send write command
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (data>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++      // send 32 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = (value>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      SPI_CS_enable(0);       // CS low
++
++}
++
++
++/************************************
++* SPI_write_bit
++* bit_EEDO -> 1 or 0 to be written
++************************************/
++void SPI_write_bit(char bit_EEDO)
++{
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECK |GPIO_MOSI ;   /* set EECK/MISO Pin to output */
++      writel(value,addr);
++      if(bit_EEDO)
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++              writel(GPIO_MOSI,addr); /* set MISO to 1 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_MOSI,addr); /* set MISO to 0 */
++      }
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); /* set EECK to 1 */
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); /* set EECK to 0 */
++
++      //return ;
++}
++
++/**********************************************************************
++* read a bit from ADM6996 register
++***********************************************************************/
++unsigned int SPI_read_bit(void) // read data from
++{
++      unsigned int addr;
++      unsigned int value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) & (~GPIO_MISO);   // set EECK to output and MISO to input
++      writel(value,addr);
++
++      addr =(GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++      writel(GPIO_EECK,addr); // set EECK to 1
++
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_IN);
++      value = readl(addr) ;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(GPIO_EECK,addr); // set EECK to 0
++
++
++      value = value >> 30;
++      return value ;
++}
++
++/******************************************
++* SPI_default
++* EEPROM content default value
++*******************************************/
++int SPI_default(void)
++{
++      int i;
++      unsigned reg_val,cmd;
++
++#if 0
++      SPI_write(7,0,0x1C,0x01);                               // map code space to 0
++
++      reg_val = SPI_read(7,0,0x10);
++      reg_val |= 0x0146;
++      reg_val &= ~0x0001;
++      SPI_write(7,0,0x10,reg_val);                            // reset iCPU and enable ext_access
++      SPI_write(7,0,0x11,0x0000);                             // start address
++      for(i=0;i<sizeof(vts_img);i++){
++              SPI_write(7,0,0x12,vts_img[i]);                 // fill in ROM data
++      }
++      reg_val |= BIT(0)|BIT(3);
++      SPI_write(7,0,0x10,reg_val);                            // release iCPU
++      SPI_write(7,0,0x10,SPI_read(7,0,0x10)&~BIT(7));                         // release iCPU
++      return ;
++#endif
++
++
++      for(i=0;i<15;i++){
++              if(i!=6 && i!=7)
++                      SPI_write(3,2,0,0x1010400+i);           // Initial memory
++              mdelay(1);
++      }
++
++      mdelay(30);
++
++      SPI_write(2,0,0xB0,0x05);                       // Clear MAC table
++      SPI_write(2,0,0xD0,0x03);                       // Clear VLAN
++
++      //for(i=0;i<5;i++)
++      SPI_write(1,6,0x19,0x2C);                       // Double Data rate
++
++      for(i=0;i<4;i++){
++              SPI_write(1,i,0x00,0x30050472);         // MAC configure
++              SPI_write(1,i,0x00,0x10050442);         // MAC configure
++              SPI_write(1,i,0x10,0x5F4);              // Max length
++              SPI_write(1,i,0x04,0x00030000);         // Flow control
++              SPI_write(1,i,0xDF,0x00000001);         // Flow control
++              SPI_write(1,i,0x08,0x000050c2);         // Flow control mac high
++              SPI_write(1,i,0x0C,0x002b00f1);         // Flow control mac low
++              SPI_write(1,i,0x6E,BIT(3));             // forward pause frame
++      }
++      SPI_write(1,i,0x00,0x20000030);                 // set port 4 as reset
++
++      SPI_write(1,6,0x00,0x300701B1);                 // MAC configure
++      SPI_write(1,6,0x00,0x10070181);                 // MAC configure
++      SPI_write(1,6,0x10,0x5F4);                      // Max length
++      SPI_write(1,6,0x04,0x00030000);         // Flow control
++      SPI_write(1,6,0xDF,0x00000002);         // Flow control
++      SPI_write(1,6,0x08,0x000050c2);         // Flow control mac high
++      SPI_write(1,6,0x0C,0x002b00f1);         // Flow control mac low
++      SPI_write(1,6,0x6E,BIT(3));             // forward pause frame
++
++
++      //SPI_write(7,0,0x05,0x31);                     // MII delay for loader
++      //SPI_write(7,0,0x05,0x01);                     // MII delay for kernel
++      SPI_write(7,0,0x05,0x33);
++
++      SPI_write(2,0,0x10,0x4F);                       // Receive mask
++
++      mdelay(50);
++
++      SPI_write(7,0,0x14,0x02);                       // Release Reset
++
++      mdelay(3);
++
++      for(i=0;i<4;i++){
++              init_seq_7385(i);
++              phy_receiver_init(i);
++              cmd = BIT(26)|(i<<21)|(0x1B<<16);       // Config LED
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val &= 0xFF00;
++              reg_val |= 0x61;
++              cmd = (i<<21)|(0x1B<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++
++              cmd = BIT(26)|(i<<21)|(0x04<<16);       // Pause enable
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val |= BIT(10)|BIT(11);
++              cmd = (i<<21)|(0x04<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++
++              cmd = BIT(26)|(i<<21)|(0x0<<16);        // collision test and re-negotiation
++              SPI_write(3,0,1,cmd);
++              mdelay(10);
++              reg_val = SPI_read(3,0,2);
++              reg_val |= BIT(7)|BIT(8)|BIT(9);
++              cmd = (i<<21)|(0x0<<16)|reg_val;
++              SPI_write(3,0,1,cmd);
++      }
++      init_seq_7385(i);
++      writel(0x5787a7f0,GMAC_GLOBAL_BASE_ADDR+0x1c);//For switch timing
++      return 4;               // return port_no
++}
++EXPORT_SYMBOL(SPI_default);
++
++/***********************************************************
++* SPI_CS_enable
++* before access ,you have to enable Chip Select. (pull high)
++* When fisish, you should pull low !!
++*************************************************************/
++void SPI_CS_enable(unsigned char enable)
++{
++
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) |GPIO_EECS |GPIO_EECK;   /* set EECS/EECK Pin to output */
++      writel(value,addr);
++
++      if(enable)
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_EECK,addr); /* set EECK to 0 */     // pull low clk first
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++              writel(GPIO_EECS,addr); /* set EECS to 0 */
++
++      }
++      else
++      {
++              addr = (GPIO_BASE_ADDR1 + GPIO_DATA_SET);
++              writel(GPIO_EECK,addr); /* set EECK to 1 */     // pull high clk before disable
++              writel(GPIO_EECS,addr); /* set EECS to 1 */
++      }
++}
++
++
++/************************************************
++* SPI_read
++* table -> which table to be read: 1/count  0/EEPROM
++* addr  -> Address to be read
++* return : Value of the register
++*************************************************/
++unsigned int SPI_read(unsigned char block,unsigned char subblock,unsigned char addr)
++{
++      int     i;
++      char    bit;
++      unsigned int data,value=0;
++
++      SPI_CS_enable(1);
++
++      data = (block<<5) | subblock;
++
++      //send write command
++      for(i=SPI_OP_LEN-1;i>=0;i--)
++      {
++              bit = (data>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // send 8 bits address (MSB first, LSB last)
++      for(i=SPI_ADD_LEN-1;i>=0;i--)
++      {
++              bit = (addr>>i)& 0x01;
++              SPI_write_bit(bit);
++      }
++
++      // dummy read for chip ready
++      for(i=0;i<8;i++)
++              SPI_read_bit();
++
++
++      // read 32 bits data (MSB first, LSB last)
++      for(i=SPI_DAT_LEN-1;i>=0;i--)
++      {
++              bit = SPI_read_bit();
++              value |= bit<<i;
++      }
++
++      SPI_CS_enable(0);       // CS low
++      return(value);
++
++}
++
++void pull_low_gpio(unsigned int val)
++{
++
++      unsigned int addr,value;
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_DATA_CLEAR);
++      writel(val,addr); /* set pin low to save power*/
++
++      addr = (GPIO_BASE_ADDR1 + GPIO_PIN_DIR);
++      value = readl(addr) & ~ val;   /* set Pin to input */
++      writel(value,addr);
++
++//    value = readl(GMAC_GLOBAL_BASE_ADDR+0x0C);      // reset GPIO1 module(self clear)
++//    value |= BIT(21);
++//    writel(value,GMAC_GLOBAL_BASE_ADDR+0x0C);
++}
++
++unsigned int SPI_get_identifier(void)
++{
++      unsigned int flag=0;
++
++      SPI_write(7,0,0x01,0x01);
++      flag = SPI_read(7,0,0x18);  // chip id
++      if((flag & 0x0ffff000)==0x07385000){
++              printk("Get VSC-switch ID 0x%08x\n",flag);
++              //Giga_switch = 1;;
++              return 1;
++      }
++      else{
++              printk("VSC-switch not found\n");
++              //Giga_switch = 0;
++              pull_low_gpio(GPIO_EECK|GPIO_MOSI|GPIO_MISO|GPIO_EECS); // reduce power consume
++              return 0;
++      }
++}
++EXPORT_SYMBOL(SPI_get_identifier);
++
+--- /dev/null
++++ b/include/asm-arm/arch-sl2312/sl351x_gmac.h
+@@ -0,0 +1,2223 @@
++/****************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_gmac.h
++* Description :
++*             Define for device driver of Storlink SL351x network Engine
++*
++* Historych
++*
++*     Date            Writer          Description
++*     -----------     -----------     -------------------------------------------------
++*     08/22/2005      Gary Chen       Create and implement
++*
++****************************************************************************/
++#ifndef _GMAC_SL351x_H
++#define _GMAC_SL351x_H
++#include <linux/skbuff.h>
++
++#define SL351x_GMAC_WORKAROUND                1
++
++#undef BIG_ENDIAN
++#define BIG_ENDIAN                            0
++#define GMAC_DEBUG                            1
++#define GMAC_NUM                                      2
++//#define     L2_jumbo_frame                          1
++
++#define _PACKED_                                      __attribute__ ((aligned(1), packed))
++
++#ifndef BIT
++#define BIT(x)                                                (1 << (x))
++#endif
++
++#define REG32(addr)                           (*(volatile unsigned long  * const)(addr))
++
++#define DMA_MALLOC(size,handle)               pci_alloc_consistent(NULL,size,handle)
++#define DMA_MFREE(mem,size,handle)    pci_free_consistent(NULL,size,mem,handle)
++
++// Define frame size
++#define ETHER_ADDR_LEN                                6
++#define GMAC_MAX_ETH_FRAME_SIZE               1514
++#define GMAC_TX_BUF_SIZE                      ((GMAC_MAX_ETH_FRAME_SIZE + 31) & (~31))
++#define MAX_ISR_WORK                  20
++
++#ifdef        L2_jumbo_frame
++#define SW_RX_BUF_SIZE                                9234    // 2048 ,9234
++#else
++#define SW_RX_BUF_SIZE                                1536    // 2048
++#endif
++
++#define HW_RX_BUF_SIZE                                1536    // 2048
++
++#define GMAC_DEV_TX_TIMEOUT           (10*HZ)                 //add by CH
++#define       SKB_RESERVE_BYTES                       16
++
++/**********************************************************************
++ * Base Register
++ **********************************************************************/
++#define TOE_BASE                                      (IO_ADDRESS(SL2312_TOE_BASE))
++#define GMAC_GLOBAL_BASE_ADDR       (IO_ADDRESS(SL2312_GLOBAL_BASE))
++
++#define TOE_GLOBAL_BASE                               (TOE_BASE + 0x0000)
++#define TOE_NONTOE_QUE_HDR_BASE               (TOE_BASE + 0x2000)
++#define TOE_TOE_QUE_HDR_BASE          (TOE_BASE + 0x3000)
++#define TOE_V_BIT_BASE                                (TOE_BASE + 0x4000)
++#define TOE_A_BIT_BASE                                (TOE_BASE + 0x6000)
++#define TOE_GMAC0_DMA_BASE                    (TOE_BASE + 0x8000)
++#define TOE_GMAC0_BASE                                (TOE_BASE + 0xA000)
++#define TOE_GMAC1_DMA_BASE                    (TOE_BASE + 0xC000)
++#define TOE_GMAC1_BASE                                (TOE_BASE + 0xE000)
++
++/**********************************************************************
++ * Queue ID
++ **********************************************************************/
++#define TOE_SW_FREE_QID                               0x00
++#define TOE_HW_FREE_QID                               0x01
++#define TOE_GMAC0_SW_TXQ0_QID         0x02
++#define TOE_GMAC0_SW_TXQ1_QID         0x03
++#define TOE_GMAC0_SW_TXQ2_QID         0x04
++#define TOE_GMAC0_SW_TXQ3_QID         0x05
++#define TOE_GMAC0_SW_TXQ4_QID         0x06
++#define TOE_GMAC0_SW_TXQ5_QID         0x07
++#define TOE_GMAC0_HW_TXQ0_QID         0x08
++#define TOE_GMAC0_HW_TXQ1_QID         0x09
++#define TOE_GMAC0_HW_TXQ2_QID         0x0A
++#define TOE_GMAC0_HW_TXQ3_QID         0x0B
++#define TOE_GMAC1_SW_TXQ0_QID         0x12
++#define TOE_GMAC1_SW_TXQ1_QID         0x13
++#define TOE_GMAC1_SW_TXQ2_QID         0x14
++#define TOE_GMAC1_SW_TXQ3_QID         0x15
++#define TOE_GMAC1_SW_TXQ4_QID         0x16
++#define TOE_GMAC1_SW_TXQ5_QID         0x17
++#define TOE_GMAC1_HW_TXQ0_QID         0x18
++#define TOE_GMAC1_HW_TXQ1_QID         0x19
++#define TOE_GMAC1_HW_TXQ2_QID         0x1A
++#define TOE_GMAC1_HW_TXQ3_QID         0x1B
++#define TOE_GMAC0_DEFAULT_QID         0x20
++#define TOE_GMAC1_DEFAULT_QID         0x21
++#define TOE_CLASSIFICATION_QID(x)     (0x22 + x)      // 0x22 ~ 0x2F
++#define TOE_TOE_QID(x)                                (0x40 + x)      // 0x40 ~ 0x7F
++
++/**********************************************************************
++ * TOE DMA Queue Number should be 2^n, n = 6...12
++ * TOE DMA Queues are the following queue types:
++ *            SW Free Queue, HW Free Queue,
++ *            GMAC 0/1 SW TX Q0-5, and GMAC 0/1 HW TX Q0-5
++ * They have same descriptor numbers.
++ * The base address and descriptor number are configured at
++ * DMA Queues Descriptor Ring Base Address/Size Register (offset 0x0004)
++ **********************************************************************/
++#define TOE_SW_FREEQ_DESC_POWER               10
++#define TOE_SW_FREEQ_DESC_NUM         (1<<TOE_SW_FREEQ_DESC_POWER)
++#define TOE_HW_FREEQ_DESC_POWER               8
++#define TOE_HW_FREEQ_DESC_NUM         (1<<TOE_HW_FREEQ_DESC_POWER)
++#define TOE_GMAC0_SWTXQ_DESC_POWER    8
++#define TOE_GMAC0_SWTXQ_DESC_NUM      (1<<TOE_GMAC0_SWTXQ_DESC_POWER)
++#define TOE_GMAC0_HWTXQ_DESC_POWER    8
++#define TOE_GMAC0_HWTXQ_DESC_NUM      (1<<TOE_GMAC0_HWTXQ_DESC_POWER)
++#define TOE_GMAC1_SWTXQ_DESC_POWER    8
++#define TOE_GMAC1_SWTXQ_DESC_NUM      (1<<TOE_GMAC1_SWTXQ_DESC_POWER)
++#define TOE_GMAC1_HWTXQ_DESC_POWER    8
++#define TOE_GMAC1_HWTXQ_DESC_NUM      (1<<TOE_GMAC1_HWTXQ_DESC_POWER)
++#define TOE_DEFAULT_Q0_DESC_POWER     8
++#define TOE_DEFAULT_Q0_DESC_NUM               (1<<TOE_DEFAULT_Q0_DESC_POWER)
++#define TOE_DEFAULT_Q1_DESC_POWER     8
++#define TOE_DEFAULT_Q1_DESC_NUM               (1<<TOE_DEFAULT_Q1_DESC_POWER)
++#define TOE_TOE_DESC_POWER                    8
++#define TOE_TOE_DESC_NUM                      (1<<TOE_TOE_DESC_POWER)
++#define TOE_CLASS_DESC_POWER          8
++#define TOE_CLASS_DESC_NUM                    (1<<TOE_CLASS_DESC_POWER)
++#define TOE_INTR_DESC_POWER                   8
++#define TOE_INTR_DESC_NUM                     (1<<TOE_INTR_DESC_POWER)
++
++#define TOE_TOE_QUEUE_MAX                     64
++#define TOE_TOE_QUEUE_NUM                     64
++#define TOE_CLASS_QUEUE_MAX                   14
++#define TOE_CLASS_QUEUE_NUM                   14
++#define TOE_INTR_QUEUE_MAX                    4
++#define TOE_INTR_QUEUE_NUM                    4
++#define TOE_SW_TXQ_MAX                                6
++#define TOE_SW_TXQ_NUM                                1
++#define TOE_HW_TXQ_MAX                                4
++#define TOE_HW_TXQ_NUM                                4
++#define _max(x,y)                                     ((x>y) ? x :y)
++#define TX_DESC_NUM                                   _max(TOE_GMAC0_SWTXQ_DESC_NUM, TOE_GMAC1_SWTXQ_DESC_NUM)
++
++#define RWPTR_ADVANCE_ONE(x, max)     ((x == (max -1)) ? 0 : x+1)
++#define RWPTR_RECEDE_ONE(x, max)      ((x == 0) ? (max -1) : x-1)
++#define SET_WPTR(addr, data)          (*(volatile u16 * const)((u32)(addr)+2) = (u16)data)
++#define SET_RPTR(addr, data)          (*(volatile u16 * const)((u32)(addr)) = (u16)data)
++
++/**********************************************************************
++ * Global registers
++ * #define TOE_GLOBAL_BASE                    (TOE_BASE + 0x0000)
++ * Base 0x60000000
++ **********************************************************************/
++#define GLOBAL_TOE_VERSION_REG                        0x0000
++#define GLOBAL_SW_FREEQ_BASE_SIZE_REG 0x0004
++#define GLOBAL_HW_FREEQ_BASE_SIZE_REG 0x0008
++#define GLOBAL_DMA_SKB_SIZE_REG                       0x0010
++#define GLOBAL_SWFQ_RWPTR_REG                 0x0014
++#define GLOBAL_HWFQ_RWPTR_REG                 0x0018
++#define GLOBAL_INTERRUPT_STATUS_0_REG 0x0020
++#define GLOBAL_INTERRUPT_ENABLE_0_REG 0x0024
++#define GLOBAL_INTERRUPT_SELECT_0_REG 0x0028
++#define GLOBAL_INTERRUPT_STATUS_1_REG 0x0030
++#define GLOBAL_INTERRUPT_ENABLE_1_REG 0x0034
++#define GLOBAL_INTERRUPT_SELECT_1_REG 0x0038
++#define GLOBAL_INTERRUPT_STATUS_2_REG 0x0040
++#define GLOBAL_INTERRUPT_ENABLE_2_REG 0x0044
++#define GLOBAL_INTERRUPT_SELECT_2_REG 0x0048
++#define GLOBAL_INTERRUPT_STATUS_3_REG 0x0050
++#define GLOBAL_INTERRUPT_ENABLE_3_REG 0x0054
++#define GLOBAL_INTERRUPT_SELECT_3_REG 0x0058
++#define GLOBAL_INTERRUPT_STATUS_4_REG 0x0060
++#define GLOBAL_INTERRUPT_ENABLE_4_REG 0x0064
++#define GLOBAL_INTERRUPT_SELECT_4_REG 0x0068
++#define GLOBAL_HASH_TABLE_BASE_REG            0x006C
++#define GLOBAL_QUEUE_THRESHOLD_REG            0x0070
++
++/**********************************************************************
++ * GMAC 0/1 DMA/TOE register
++ * #define TOE_GMAC0_DMA_BASE         (TOE_BASE + 0x8000)
++ * #define TOE_GMAC1_DMA_BASE         (TOE_BASE + 0xC000)
++ * Base 0x60008000 or 0x6000C000
++ **********************************************************************/
++#define GMAC_DMA_CTRL_REG                             0x0000
++#define GMAC_TX_WEIGHTING_CTRL_0_REG  0x0004
++#define GMAC_TX_WEIGHTING_CTRL_1_REG  0x0008
++#define GMAC_SW_TX_QUEUE0_PTR_REG             0x000C
++#define GMAC_SW_TX_QUEUE1_PTR_REG             0x0010
++#define GMAC_SW_TX_QUEUE2_PTR_REG             0x0014
++#define GMAC_SW_TX_QUEUE3_PTR_REG             0x0018
++#define GMAC_SW_TX_QUEUE4_PTR_REG             0x001C
++#define GMAC_SW_TX_QUEUE5_PTR_REG             0x0020
++#define GMAC_HW_TX_QUEUE0_PTR_REG             0x0024
++#define GMAC_HW_TX_QUEUE1_PTR_REG             0x0028
++#define GMAC_HW_TX_QUEUE2_PTR_REG             0x002C
++#define GMAC_HW_TX_QUEUE3_PTR_REG             0x0030
++#define GMAC_DMA_TX_FIRST_DESC_REG            0x0038
++#define GMAC_DMA_TX_CURR_DESC_REG             0x003C
++#define GMAC_DMA_TX_DESC_WORD0_REG            0x0040
++#define GMAC_DMA_TX_DESC_WORD1_REG            0x0044
++#define GMAC_DMA_TX_DESC_WORD2_REG            0x0048
++#define GMAC_DMA_TX_DESC_WORD3_REG            0x004C
++#define GMAC_SW_TX_QUEUE_BASE_REG             0x0050
++#define GMAC_HW_TX_QUEUE_BASE_REG             0x0054
++#define GMAC_DMA_RX_FIRST_DESC_REG            0x0058
++#define GMAC_DMA_RX_CURR_DESC_REG             0x005C
++#define GMAC_DMA_RX_DESC_WORD0_REG            0x0060
++#define GMAC_DMA_RX_DESC_WORD1_REG            0x0064
++#define GMAC_DMA_RX_DESC_WORD2_REG            0x0068
++#define GMAC_DMA_RX_DESC_WORD3_REG            0x006C
++#define GMAC_HASH_ENGINE_REG0                 0x0070
++#define GMAC_HASH_ENGINE_REG1                 0x0074
++#define GMAC_MR0CR0                                           0x0078  // matching rule 0 Control register 0
++#define GMAC_MR0CR1                                           0x007C  // matching rule 0 Control register 1
++#define GMAC_MR0CR2                                           0x0080  // matching rule 0 Control register 2
++#define GMAC_MR1CR0                                           0x0084  // matching rule 1 Control register 0
++#define GMAC_MR1CR1                                           0x0088  // matching rule 1 Control register 1
++#define GMAC_MR1CR2                                           0x008C  // matching rule 1 Control register 2
++#define GMAC_MR2CR0                                           0x0090  // matching rule 2 Control register 0
++#define GMAC_MR2CR1                                           0x0094  // matching rule 2 Control register 1
++#define GMAC_MR2CR2                                           0x0098  // matching rule 2 Control register 2
++#define GMAC_MR3CR0                                           0x009C  // matching rule 3 Control register 0
++#define GMAC_MR3CR1                                           0x00A0  // matching rule 3 Control register 1
++#define GMAC_MR3CR2                                           0x00A4  // matching rule 3 Control register 2
++#define GMAC_SPR0                                             0x00A8  // Support Protocol Regsister 0
++#define GMAC_SPR1                                             0x00AC  // Support Protocol Regsister 1
++#define GMAC_SPR2                                             0x00B0  // Support Protocol Regsister 2
++#define GMAC_SPR3                                             0x00B4  // Support Protocol Regsister 3
++#define GMAC_SPR4                                             0x00B8  // Support Protocol Regsister 4
++#define GMAC_SPR5                                             0x00BC  // Support Protocol Regsister 5
++#define GMAC_SPR6                                             0x00C0  // Support Protocol Regsister 6
++#define GMAC_SPR7                                             0x00C4  // Support Protocol Regsister 7
++#define GMAC_AHB_WEIGHT_REG                           0x00C8  // GMAC Hash/Rx/Tx AHB Weighting register
++
++/**********************************************************************
++ * TOE GMAC 0/1 register
++ * #define TOE_GMAC0_BASE                             (TOE_BASE + 0xA000)
++ * #define TOE_GMAC1_BASE                             (TOE_BASE + 0xE000)
++ * Base 0x6000A000 or 0x6000E000
++ **********************************************************************/
++enum GMAC_REGISTER {
++      GMAC_STA_ADD0   = 0x0000,
++      GMAC_STA_ADD1   = 0x0004,
++      GMAC_STA_ADD2   = 0x0008,
++      GMAC_RX_FLTR    = 0x000c,
++      GMAC_MCAST_FIL0 = 0x0010,
++      GMAC_MCAST_FIL1 = 0x0014,
++      GMAC_CONFIG0    = 0x0018,
++      GMAC_CONFIG1    = 0x001c,
++      GMAC_CONFIG2    = 0x0020,
++      GMAC_CONFIG3    = 0x0024,
++      GMAC_RESERVED   = 0x0028,
++      GMAC_STATUS             = 0x002c,
++      GMAC_IN_DISCARDS= 0x0030,
++      GMAC_IN_ERRORS  = 0x0034,
++      GMAC_IN_MCAST   = 0x0038,
++      GMAC_IN_BCAST   = 0x003c,
++      GMAC_IN_MAC1    = 0x0040,       // for STA 1 MAC Address
++      GMAC_IN_MAC2    = 0x0044        // for STA 2 MAC Address
++};
++/**********************************************************************
++ * TOE version Register (offset 0x0000)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int reserved           : 15;   // bit 31:17
++              unsigned int v_bit_mode         : 1;    // bit 16               1: 128-entry
++              unsigned int device_id          : 12;   // bit 15:4     Device ID
++              unsigned int revision_id        : 4;    // bit  3:0     Revision ID
++#else
++              unsigned int revision_id        : 4;    // bit  3:0     Revision ID
++              unsigned int device_id          : 12;   // bit 15:4     Device ID
++              unsigned int v_bit_mode         : 1;    // bit 16               1: 128-entry
++              unsigned int reserved           : 15;   // bit 31:17
++#endif
++      } bits;
++} TOE_VERSION_T;
++
++
++/**********************************************************************
++ * DMA Queues description Ring Base Address/Size Register (offset 0x0004)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} DMA_Q_BASE_SIZE_T;
++#define DMA_Q_BASE_MASK       (~0x0f)
++
++/**********************************************************************
++ * DMA SKB Buffer register (offset 0x0008)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0008
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int hw_skb_size        : 16;   // bit 31:16    HW Free poll SKB Size
++              unsigned int sw_skb_size        : 16;   // bit 15:0     SW Free poll SKB Size
++#else
++              unsigned int sw_skb_size        : 16;   // bit 15:0     SW Free poll SKB Size
++              unsigned int hw_skb_size        : 16;   // bit 31:16    HW Free poll SKB Size
++#endif
++      } bits;
++} DMA_SKB_SIZE_T;
++
++/**********************************************************************
++ * DMA SW Free Queue Read/Write Pointer Register (offset 0x000C)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_000c
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16    Write Ptr, RW
++              unsigned int rptr                       : 16;   // bit 15:0             Read Ptr, RO
++#else
++              unsigned int rptr                       : 16;   // bit 15:0             Read Ptr, RO
++              unsigned int wptr                       : 16;   // bit 31:16    Write Ptr, RW
++#endif
++      } bits;
++} DMA_RWPTR_T;
++
++/**********************************************************************
++ * DMA HW Free Queue Read/Write Pointer Register (offset 0x0010)
++ **********************************************************************/
++// see DMA_RWPTR_T structure
++
++/**********************************************************************
++ * Interrupt Status Register 0        (offset 0x0020)
++ * Interrupt Mask Register 0  (offset 0x0024)
++ * Interrupt Select Register 0        (offset 0x0028)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int txDerr1            : 1;    // bit 31       GMAC1 AHB Bus Error while Tx
++              unsigned int txPerr1            : 1;    // bit 30       GMAC1 Tx Descriptor Protocol Error
++              unsigned int txDerr0            : 1;    // bit 29       GMAC0 AHB Bus Error while Tx
++              unsigned int txPerr0            : 1;    // bit 28       GMAC0 Tx Descriptor Protocol Error
++              unsigned int rxDerr1            : 1;    // bit 27       GMAC1 AHB Bus Error while Rx
++              unsigned int rxPerr1            : 1;    // bit 26       GMAC1 Rx Descriptor Protocol Error
++              unsigned int rxDerr0            : 1;    // bit 25       GMAC0 AHB Bus Error while Rx
++              unsigned int rxPerr0            : 1;    // bit 24       GMAC0 Rx Descriptor Protocol Error
++              unsigned int swtq15_fin         : 1;    // bit 23       GMAC1 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq14_fin         : 1;    // bit 22       GMAC1 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq13_fin         : 1;    // bit 21       GMAC1 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq12_fin         : 1;    // bit 20       GMAC1 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq11_fin         : 1;    // bit 19       GMAC1 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq10_fin         : 1;    // bit 18       GMAC1 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq05_fin         : 1;    // bit 17       GMAC0 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq04_fin         : 1;    // bit 16       GMAC0 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq03_fin         : 1;    // bit 15       GMAC0 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq02_fin         : 1;    // bit 14       GMAC0 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq01_fin         : 1;    // bit 13       GMAC0 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq00_fin         : 1;    // bit 12       GMAC0 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq15_eof         : 1;    // bit 11       GMAC1 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq14_eof         : 1;    // bit 10       GMAC1 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq13_eof         : 1;    // bit 9        GMAC1 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq12_eof         : 1;    // bit 8        GMAC1 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq11_eof         : 1;    // bit 7        GMAC1 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq10_eof         : 1;    // bit 6        GMAC1 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq05_eof         : 1;    // bit 5        GMAC0 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq04_eof         : 1;    // bit 4        GMAC0 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq03_eof         : 1;    // bit 3        GMAC0 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq02_eof         : 1;    // bit 2        GMAC0 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq01_eof         : 1;    // bit 1        GMAC0 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq00_eof         : 1;    // bit 0        GMAC0 SW Tx Queue 0 EOF Interrupt
++#else
++              unsigned int swtq00_eof         : 1;    // bit 0        GMAC0 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq01_eof         : 1;    // bit 1        GMAC0 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq02_eof         : 1;    // bit 2        GMAC0 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq03_eof         : 1;    // bit 3        GMAC0 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq04_eof         : 1;    // bit 4        GMAC0 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq05_eof         : 1;    // bit 5        GMAC0 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq10_eof         : 1;    // bit 6        GMAC1 SW Tx Queue 0 EOF Interrupt
++              unsigned int swtq11_eof         : 1;    // bit 7        GMAC1 SW Tx Queue 1 EOF Interrupt
++              unsigned int swtq12_eof         : 1;    // bit 8        GMAC1 SW Tx Queue 2 EOF Interrupt
++              unsigned int swtq13_eof         : 1;    // bit 9        GMAC1 SW Tx Queue 3 EOF Interrupt
++              unsigned int swtq14_eof         : 1;    // bit 10       GMAC1 SW Tx Queue 4 EOF Interrupt
++              unsigned int swtq15_eof         : 1;    // bit 11       GMAC1 SW Tx Queue 5 EOF Interrupt
++              unsigned int swtq00_fin         : 1;    // bit 12       GMAC0 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq01_fin         : 1;    // bit 13       GMAC0 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq02_fin         : 1;    // bit 14       GMAC0 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq03_fin         : 1;    // bit 15       GMAC0 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq04_fin         : 1;    // bit 16       GMAC0 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq05_fin         : 1;    // bit 17       GMAC0 SW Tx Queue 5 Finish Interrupt
++              unsigned int swtq10_fin         : 1;    // bit 18       GMAC1 SW Tx Queue 0 Finish Interrupt
++              unsigned int swtq11_fin         : 1;    // bit 19       GMAC1 SW Tx Queue 1 Finish Interrupt
++              unsigned int swtq12_fin         : 1;    // bit 20       GMAC1 SW Tx Queue 2 Finish Interrupt
++              unsigned int swtq13_fin         : 1;    // bit 21       GMAC1 SW Tx Queue 3 Finish Interrupt
++              unsigned int swtq14_fin         : 1;    // bit 22       GMAC1 SW Tx Queue 4 Finish Interrupt
++              unsigned int swtq15_fin         : 1;    // bit 23       GMAC1 SW Tx Queue 5 Finish Interrupt
++              unsigned int rxPerr0            : 1;    // bit 24       GMAC0 Rx Descriptor Protocol Error
++              unsigned int rxDerr0            : 1;    // bit 25       GMAC0 AHB Bus Error while Rx
++              unsigned int rxPerr1            : 1;    // bit 26       GMAC1 Rx Descriptor Protocol Error
++              unsigned int rxDerr1            : 1;    // bit 27       GMAC1 AHB Bus Error while Rx
++              unsigned int txPerr0            : 1;    // bit 28       GMAC0 Tx Descriptor Protocol Error
++              unsigned int txDerr0            : 1;    // bit 29       GMAC0 AHB Bus Error while Tx
++              unsigned int txPerr1            : 1;    // bit 30       GMAC1 Tx Descriptor Protocol Error
++              unsigned int txDerr1            : 1;    // bit 31       GMAC1 AHB Bus Error while Tx
++#endif
++      } bits;
++} INTR_REG0_T;
++
++#define GMAC1_TXDERR_INT_BIT          BIT(31)
++#define GMAC1_TXPERR_INT_BIT          BIT(30)
++#define GMAC0_TXDERR_INT_BIT          BIT(29)
++#define GMAC0_TXPERR_INT_BIT          BIT(28)
++#define GMAC1_RXDERR_INT_BIT          BIT(27)
++#define GMAC1_RXPERR_INT_BIT          BIT(26)
++#define GMAC0_RXDERR_INT_BIT          BIT(25)
++#define GMAC0_RXPERR_INT_BIT          BIT(24)
++#define GMAC1_SWTQ15_FIN_INT_BIT      BIT(23)
++#define GMAC1_SWTQ14_FIN_INT_BIT      BIT(22)
++#define GMAC1_SWTQ13_FIN_INT_BIT      BIT(21)
++#define GMAC1_SWTQ12_FIN_INT_BIT      BIT(20)
++#define GMAC1_SWTQ11_FIN_INT_BIT      BIT(19)
++#define GMAC1_SWTQ10_FIN_INT_BIT      BIT(18)
++#define GMAC0_SWTQ05_FIN_INT_BIT      BIT(17)
++#define GMAC0_SWTQ04_FIN_INT_BIT      BIT(16)
++#define GMAC0_SWTQ03_FIN_INT_BIT      BIT(15)
++#define GMAC0_SWTQ02_FIN_INT_BIT      BIT(14)
++#define GMAC0_SWTQ01_FIN_INT_BIT      BIT(13)
++#define GMAC0_SWTQ00_FIN_INT_BIT      BIT(12)
++#define GMAC1_SWTQ15_EOF_INT_BIT      BIT(11)
++#define GMAC1_SWTQ14_EOF_INT_BIT      BIT(10)
++#define GMAC1_SWTQ13_EOF_INT_BIT      BIT(9)
++#define GMAC1_SWTQ12_EOF_INT_BIT      BIT(8)
++#define GMAC1_SWTQ11_EOF_INT_BIT      BIT(7)
++#define GMAC1_SWTQ10_EOF_INT_BIT      BIT(6)
++#define GMAC0_SWTQ05_EOF_INT_BIT      BIT(5)
++#define GMAC0_SWTQ04_EOF_INT_BIT      BIT(4)
++#define GMAC0_SWTQ03_EOF_INT_BIT      BIT(3)
++#define GMAC0_SWTQ02_EOF_INT_BIT      BIT(2)
++#define GMAC0_SWTQ01_EOF_INT_BIT      BIT(1)
++#define GMAC0_SWTQ00_EOF_INT_BIT      BIT(0)
++
++
++/**********************************************************************
++ * Interrupt Status Register 1        (offset 0x0030)
++ * Interrupt Mask Register 1  (offset 0x0034)
++ * Interrupt Select Register 1        (offset 0x0038)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0030
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_iq3_full       : 1;    // bit 31       TOE Interrupt Queue 3 Full Interrupt
++              unsigned int toe_iq2_full       : 1;    // bit 30       TOE Interrupt Queue 2 Full Interrupt
++              unsigned int toe_iq1_full       : 1;    // bit 29       TOE Interrupt Queue 1 Full Interrupt
++              unsigned int toe_iq0_full       : 1;    // bit 28       TOE Interrupt Queue 0 Full Interrupt
++              unsigned int toe_iq3_intr       : 1;    // bit 27       TOE Interrupt Queue 3 with Interrupts
++              unsigned int toe_iq2_intr       : 1;    // bit 26       TOE Interrupt Queue 2 with Interrupts
++              unsigned int toe_iq1_intr       : 1;    // bit 25       TOE Interrupt Queue 1 with Interrupts
++              unsigned int toe_iq0_intr       : 1;    // bit 24       TOE Interrupt Queue 0 with Interrupts
++              unsigned int hwtq13_eof         : 1;    // bit 23       GMAC1 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq12_eof         : 1;    // bit 22       GMAC1 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq11_eof         : 1;    // bit 21       GMAC1 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq10_eof         : 1;    // bit 20       GMAC1 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq03_eof         : 1;    // bit 19       GMAC0 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq02_eof         : 1;    // bit 18       GMAC0 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq01_eof         : 1;    // bit 17       GMAC0 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq00_eof         : 1;    // bit 16       GMAC0 HW Tx Queue0 EOF Interrupt
++              unsigned int class_rx           : 14;   // bit 15:2     Classification Queue Rx Interrupt
++              unsigned int default_q1_eof     : 1;    // bit 1        Default Queue 1 EOF Interrupt
++              unsigned int default_q0_eof     : 1;    // bit 0        Default Queue 0 EOF Interrupt
++#else
++              unsigned int default_q0_eof     : 1;    // bit 0        Default Queue 0 EOF Interrupt
++              unsigned int default_q1_eof     : 1;    // bit 1        Default Queue 1 EOF Interrupt
++              unsigned int class_rx           : 14;   // bit 15:2     Classification Queue Rx Interrupt
++              unsigned int hwtq00_eof         : 1;    // bit 16       GMAC0 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq01_eof         : 1;    // bit 17       GMAC0 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq02_eof         : 1;    // bit 18       GMAC0 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq03_eof         : 1;    // bit 19       GMAC0 HW Tx Queue3 EOF Interrupt
++              unsigned int hwtq10_eof         : 1;    // bit 20       GMAC1 HW Tx Queue0 EOF Interrupt
++              unsigned int hwtq11_eof         : 1;    // bit 21       GMAC1 HW Tx Queue1 EOF Interrupt
++              unsigned int hwtq12_eof         : 1;    // bit 22       GMAC1 HW Tx Queue2 EOF Interrupt
++              unsigned int hwtq13_eof         : 1;    // bit 23       GMAC1 HW Tx Queue3 EOF Interrupt
++              unsigned int toe_iq0_intr       : 1;    // bit 24       TOE Interrupt Queue 0 with Interrupts
++              unsigned int toe_iq1_intr       : 1;    // bit 25       TOE Interrupt Queue 1 with Interrupts
++              unsigned int toe_iq2_intr       : 1;    // bit 26       TOE Interrupt Queue 2 with Interrupts
++              unsigned int toe_iq3_intr       : 1;    // bit 27       TOE Interrupt Queue 3 with Interrupts
++              unsigned int toe_iq0_full       : 1;    // bit 28       TOE Interrupt Queue 0 Full Interrupt
++              unsigned int toe_iq1_full       : 1;    // bit 29       TOE Interrupt Queue 1 Full Interrupt
++              unsigned int toe_iq2_full       : 1;    // bit 30       TOE Interrupt Queue 2 Full Interrupt
++              unsigned int toe_iq3_full       : 1;    // bit 31       TOE Interrupt Queue 3 Full Interrupt
++#endif
++      } bits;
++} INTR_REG1_T;
++
++#define TOE_IQ3_FULL_INT_BIT          BIT(31)
++#define TOE_IQ2_FULL_INT_BIT          BIT(30)
++#define TOE_IQ1_FULL_INT_BIT          BIT(29)
++#define TOE_IQ0_FULL_INT_BIT          BIT(28)
++#define TOE_IQ3_INT_BIT                               BIT(27)
++#define TOE_IQ2_INT_BIT                               BIT(26)
++#define TOE_IQ1_INT_BIT                               BIT(25)
++#define TOE_IQ0_INT_BIT                               BIT(24)
++#define GMAC1_HWTQ13_EOF_INT_BIT      BIT(23)
++#define GMAC1_HWTQ12_EOF_INT_BIT      BIT(22)
++#define GMAC1_HWTQ11_EOF_INT_BIT      BIT(21)
++#define GMAC1_HWTQ10_EOF_INT_BIT      BIT(20)
++#define GMAC0_HWTQ03_EOF_INT_BIT      BIT(19)
++#define GMAC0_HWTQ02_EOF_INT_BIT      BIT(18)
++#define GMAC0_HWTQ01_EOF_INT_BIT      BIT(17)
++#define GMAC0_HWTQ00_EOF_INT_BIT      BIT(16)
++#define CLASS_RX_INT_BIT(x)                   BIT((x+2))
++#define DEFAULT_Q1_INT_BIT                    BIT(1)
++#define DEFAULT_Q0_INT_BIT                    BIT(0)
++
++#define TOE_IQ_INT_BITS                               (TOE_IQ0_INT_BIT | TOE_IQ1_INT_BIT | \
++                                                      TOE_IQ2_INT_BIT | TOE_IQ3_INT_BIT)
++#define       TOE_IQ_FULL_BITS                        (TOE_IQ0_FULL_INT_BIT | TOE_IQ1_FULL_INT_BIT | \
++                                                      TOE_IQ2_FULL_INT_BIT | TOE_IQ3_FULL_INT_BIT)
++#define       TOE_IQ_ALL_BITS                         (TOE_IQ_INT_BITS | TOE_IQ_FULL_BITS)
++#define TOE_CLASS_RX_INT_BITS         0xfffc
++
++/**********************************************************************
++ * Interrupt Status Register 2        (offset 0x0040)
++ * Interrupt Mask Register 2  (offset 0x0044)
++ * Interrupt Select Register 2        (offset 0x0048)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0040
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_q31_full       : 1;    // bit 31       TOE Queue 31 Full Interrupt
++              unsigned int toe_q30_full       : 1;    // bit 30       TOE Queue 30 Full Interrupt
++              unsigned int toe_q29_full       : 1;    // bit 29       TOE Queue 29 Full Interrupt
++              unsigned int toe_q28_full       : 1;    // bit 28       TOE Queue 28 Full Interrupt
++              unsigned int toe_q27_full       : 1;    // bit 27       TOE Queue 27 Full Interrupt
++              unsigned int toe_q26_full       : 1;    // bit 26       TOE Queue 26 Full Interrupt
++              unsigned int toe_q25_full       : 1;    // bit 25       TOE Queue 25 Full Interrupt
++              unsigned int toe_q24_full       : 1;    // bit 24       TOE Queue 24 Full Interrupt
++              unsigned int toe_q23_full       : 1;    // bit 23       TOE Queue 23 Full Interrupt
++              unsigned int toe_q22_full       : 1;    // bit 22       TOE Queue 22 Full Interrupt
++              unsigned int toe_q21_full       : 1;    // bit 21       TOE Queue 21 Full Interrupt
++              unsigned int toe_q20_full       : 1;    // bit 20       TOE Queue 20 Full Interrupt
++              unsigned int toe_q19_full       : 1;    // bit 19       TOE Queue 19 Full Interrupt
++              unsigned int toe_q18_full       : 1;    // bit 18       TOE Queue 18 Full Interrupt
++              unsigned int toe_q17_full       : 1;    // bit 17       TOE Queue 17 Full Interrupt
++              unsigned int toe_q16_full       : 1;    // bit 16       TOE Queue 16 Full Interrupt
++              unsigned int toe_q15_full       : 1;    // bit 15       TOE Queue 15 Full Interrupt
++              unsigned int toe_q14_full       : 1;    // bit 14       TOE Queue 14 Full Interrupt
++              unsigned int toe_q13_full       : 1;    // bit 13       TOE Queue 13 Full Interrupt
++              unsigned int toe_q12_full       : 1;    // bit 12       TOE Queue 12 Full Interrupt
++              unsigned int toe_q11_full       : 1;    // bit 11       TOE Queue 11 Full Interrupt
++              unsigned int toe_q10_full       : 1;    // bit 10       TOE Queue 10 Full Interrupt
++              unsigned int toe_q9_full        : 1;    // bit 9        TOE Queue 9 Full Interrupt
++              unsigned int toe_q8_full        : 1;    // bit 8        TOE Queue 8 Full Interrupt
++              unsigned int toe_q7_full        : 1;    // bit 7        TOE Queue 7 Full Interrupt
++              unsigned int toe_q6_full        : 1;    // bit 6        TOE Queue 6 Full Interrupt
++              unsigned int toe_q5_full        : 1;    // bit 5        TOE Queue 5 Full Interrupt
++              unsigned int toe_q4_full        : 1;    // bit 4        TOE Queue 4 Full Interrupt
++              unsigned int toe_q3_full        : 1;    // bit 3        TOE Queue 3 Full Interrupt
++              unsigned int toe_q2_full        : 1;    // bit 2        TOE Queue 2 Full Interrupt
++              unsigned int toe_q1_full        : 1;    // bit 1        TOE Queue 1 Full Interrupt
++              unsigned int toe_q0_full        : 1;    // bit 0        TOE Queue 0 Full Interrupt
++#else
++              unsigned int toe_q0_full        : 1;    // bit 0        TOE Queue 0 Full Interrupt
++              unsigned int toe_q1_full        : 1;    // bit 1        TOE Queue 1 Full Interrupt
++              unsigned int toe_q2_full        : 1;    // bit 2        TOE Queue 2 Full Interrupt
++              unsigned int toe_q3_full        : 1;    // bit 3        TOE Queue 3 Full Interrupt
++              unsigned int toe_q4_full        : 1;    // bit 4        TOE Queue 4 Full Interrupt
++              unsigned int toe_q5_full        : 1;    // bit 5        TOE Queue 5 Full Interrupt
++              unsigned int toe_q6_full        : 1;    // bit 6        TOE Queue 6 Full Interrupt
++              unsigned int toe_q7_full        : 1;    // bit 7        TOE Queue 7 Full Interrupt
++              unsigned int toe_q8_full        : 1;    // bit 8        TOE Queue 8 Full Interrupt
++              unsigned int toe_q9_full        : 1;    // bit 9        TOE Queue 9 Full Interrupt
++              unsigned int toe_q10_full       : 1;    // bit 10       TOE Queue 10 Full Interrupt
++              unsigned int toe_q11_full       : 1;    // bit 11       TOE Queue 11 Full Interrupt
++              unsigned int toe_q12_full       : 1;    // bit 12       TOE Queue 12 Full Interrupt
++              unsigned int toe_q13_full       : 1;    // bit 13       TOE Queue 13 Full Interrupt
++              unsigned int toe_q14_full       : 1;    // bit 14       TOE Queue 14 Full Interrupt
++              unsigned int toe_q15_full       : 1;    // bit 15       TOE Queue 15 Full Interrupt
++              unsigned int toe_q16_full       : 1;    // bit 16       TOE Queue 16 Full Interrupt
++              unsigned int toe_q17_full       : 1;    // bit 17       TOE Queue 17 Full Interrupt
++              unsigned int toe_q18_full       : 1;    // bit 18       TOE Queue 18 Full Interrupt
++              unsigned int toe_q19_full       : 1;    // bit 19       TOE Queue 19 Full Interrupt
++              unsigned int toe_q20_full       : 1;    // bit 20       TOE Queue 20 Full Interrupt
++              unsigned int toe_q21_full       : 1;    // bit 21       TOE Queue 21 Full Interrupt
++              unsigned int toe_q22_full       : 1;    // bit 22       TOE Queue 22 Full Interrupt
++              unsigned int toe_q23_full       : 1;    // bit 23       TOE Queue 23 Full Interrupt
++              unsigned int toe_q24_full       : 1;    // bit 24       TOE Queue 24 Full Interrupt
++              unsigned int toe_q25_full       : 1;    // bit 25       TOE Queue 25 Full Interrupt
++              unsigned int toe_q26_full       : 1;    // bit 26       TOE Queue 26 Full Interrupt
++              unsigned int toe_q27_full       : 1;    // bit 27       TOE Queue 27 Full Interrupt
++              unsigned int toe_q28_full       : 1;    // bit 28       TOE Queue 28 Full Interrupt
++              unsigned int toe_q29_full       : 1;    // bit 29       TOE Queue 29 Full Interrupt
++              unsigned int toe_q30_full       : 1;    // bit 30       TOE Queue 30 Full Interrupt
++              unsigned int toe_q31_full       : 1;    // bit 31       TOE Queue 31 Full Interrupt
++#endif
++      } bits;
++} INTR_REG2_T;
++
++#define TOE_QL_FULL_INT_BIT(x)                BIT(x)
++
++/**********************************************************************
++ * Interrupt Status Register 3        (offset 0x0050)
++ * Interrupt Mask Register 3  (offset 0x0054)
++ * Interrupt Select Register 3        (offset 0x0058)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0050
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int toe_q63_full       : 1;    // bit 63       TOE Queue 63 Full Interrupt
++              unsigned int toe_q62_full       : 1;    // bit 62       TOE Queue 62 Full Interrupt
++              unsigned int toe_q61_full       : 1;    // bit 61       TOE Queue 61 Full Interrupt
++              unsigned int toe_q60_full       : 1;    // bit 60       TOE Queue 60 Full Interrupt
++              unsigned int toe_q59_full       : 1;    // bit 59       TOE Queue 59 Full Interrupt
++              unsigned int toe_q58_full       : 1;    // bit 58       TOE Queue 58 Full Interrupt
++              unsigned int toe_q57_full       : 1;    // bit 57       TOE Queue 57 Full Interrupt
++              unsigned int toe_q56_full       : 1;    // bit 56       TOE Queue 56 Full Interrupt
++              unsigned int toe_q55_full       : 1;    // bit 55       TOE Queue 55 Full Interrupt
++              unsigned int toe_q54_full       : 1;    // bit 54       TOE Queue 54 Full Interrupt
++              unsigned int toe_q53_full       : 1;    // bit 53       TOE Queue 53 Full Interrupt
++              unsigned int toe_q52_full       : 1;    // bit 52       TOE Queue 52 Full Interrupt
++              unsigned int toe_q51_full       : 1;    // bit 51       TOE Queue 51 Full Interrupt
++              unsigned int toe_q50_full       : 1;    // bit 50       TOE Queue 50 Full Interrupt
++              unsigned int toe_q49_full       : 1;    // bit 49       TOE Queue 49 Full Interrupt
++              unsigned int toe_q48_full       : 1;    // bit 48       TOE Queue 48 Full Interrupt
++              unsigned int toe_q47_full       : 1;    // bit 47       TOE Queue 47 Full Interrupt
++              unsigned int toe_q46_full       : 1;    // bit 46       TOE Queue 46 Full Interrupt
++              unsigned int toe_q45_full       : 1;    // bit 45       TOE Queue 45 Full Interrupt
++              unsigned int toe_q44_full       : 1;    // bit 44       TOE Queue 44 Full Interrupt
++              unsigned int toe_q43_full       : 1;    // bit 43       TOE Queue 43 Full Interrupt
++              unsigned int toe_q42_full       : 1;    // bit 42       TOE Queue 42 Full Interrupt
++              unsigned int toe_q41_full       : 1;    // bit 41       TOE Queue 41 Full Interrupt
++              unsigned int toe_q40_full       : 1;    // bit 40       TOE Queue 40 Full Interrupt
++              unsigned int toe_q39_full       : 1;    // bit 39       TOE Queue 39 Full Interrupt
++              unsigned int toe_q38_full       : 1;    // bit 38       TOE Queue 38 Full Interrupt
++              unsigned int toe_q37_full       : 1;    // bit 37       TOE Queue 37 Full Interrupt
++              unsigned int toe_q36_full       : 1;    // bit 36       TOE Queue 36 Full Interrupt
++              unsigned int toe_q35_full       : 1;    // bit 35       TOE Queue 35 Full Interrupt
++              unsigned int toe_q34_full       : 1;    // bit 34       TOE Queue 34 Full Interrupt
++              unsigned int toe_q33_full       : 1;    // bit 33       TOE Queue 33 Full Interrupt
++              unsigned int toe_q32_full       : 1;    // bit 32       TOE Queue 32 Full Interrupt
++#else
++              unsigned int toe_q32_full       : 1;    // bit 32       TOE Queue 32 Full Interrupt
++              unsigned int toe_q33_full       : 1;    // bit 33       TOE Queue 33 Full Interrupt
++              unsigned int toe_q34_full       : 1;    // bit 34       TOE Queue 34 Full Interrupt
++              unsigned int toe_q35_full       : 1;    // bit 35       TOE Queue 35 Full Interrupt
++              unsigned int toe_q36_full       : 1;    // bit 36       TOE Queue 36 Full Interrupt
++              unsigned int toe_q37_full       : 1;    // bit 37       TOE Queue 37 Full Interrupt
++              unsigned int toe_q38_full       : 1;    // bit 38       TOE Queue 38 Full Interrupt
++              unsigned int toe_q39_full       : 1;    // bit 39       TOE Queue 39 Full Interrupt
++              unsigned int toe_q40_full       : 1;    // bit 40       TOE Queue 40 Full Interrupt
++              unsigned int toe_q41_full       : 1;    // bit 41       TOE Queue 41 Full Interrupt
++              unsigned int toe_q42_full       : 1;    // bit 42       TOE Queue 42 Full Interrupt
++              unsigned int toe_q43_full       : 1;    // bit 43       TOE Queue 43 Full Interrupt
++              unsigned int toe_q44_full       : 1;    // bit 44       TOE Queue 44 Full Interrupt
++              unsigned int toe_q45_full       : 1;    // bit 45       TOE Queue 45 Full Interrupt
++              unsigned int toe_q46_full       : 1;    // bit 46       TOE Queue 46 Full Interrupt
++              unsigned int toe_q47_full       : 1;    // bit 47       TOE Queue 47 Full Interrupt
++              unsigned int toe_q48_full       : 1;    // bit 48       TOE Queue 48 Full Interrupt
++              unsigned int toe_q49_full       : 1;    // bit 49       TOE Queue 49 Full Interrupt
++              unsigned int toe_q50_full       : 1;    // bit 50       TOE Queue 50 Full Interrupt
++              unsigned int toe_q51_full       : 1;    // bit 51       TOE Queue 51 Full Interrupt
++              unsigned int toe_q52_full       : 1;    // bit 52       TOE Queue 52 Full Interrupt
++              unsigned int toe_q53_full       : 1;    // bit 53       TOE Queue 53 Full Interrupt
++              unsigned int toe_q54_full       : 1;    // bit 54       TOE Queue 54 Full Interrupt
++              unsigned int toe_q55_full       : 1;    // bit 55       TOE Queue 55 Full Interrupt
++              unsigned int toe_q56_full       : 1;    // bit 56       TOE Queue 56 Full Interrupt
++              unsigned int toe_q57_full       : 1;    // bit 57       TOE Queue 57 Full Interrupt
++              unsigned int toe_q58_full       : 1;    // bit 58       TOE Queue 58 Full Interrupt
++              unsigned int toe_q59_full       : 1;    // bit 59       TOE Queue 59 Full Interrupt
++              unsigned int toe_q60_full       : 1;    // bit 60       TOE Queue 60 Full Interrupt
++              unsigned int toe_q61_full       : 1;    // bit 61       TOE Queue 61 Full Interrupt
++              unsigned int toe_q62_full       : 1;    // bit 62       TOE Queue 62 Full Interrupt
++              unsigned int toe_q63_full       : 1;    // bit 63       TOE Queue 63 Full Interrupt
++#endif
++      } bits;
++} INTR_REG3_T;
++
++#define TOE_QH_FULL_INT_BIT(x)                BIT(x-32)
++
++/**********************************************************************
++ * Interrupt Status Register 4        (offset 0x0060)
++ * Interrupt Mask Register 4  (offset 0x0064)
++ * Interrupt Select Register 4        (offset 0x0068)
++ **********************************************************************/
++typedef union
++{
++      unsigned char byte;
++      struct bit_0060
++      {
++#if (BIG_ENDIAN==1)
++              unsigned char reserved          : 1;    //
++              unsigned char cnt_full          : 1;    // MIB counters half full interrupt
++              unsigned char rx_pause_on       : 1;    // received pause on frame interrupt
++              unsigned char tx_pause_on       : 1;    // transmit pause on frame interrupt
++              unsigned char rx_pause_off  : 1;        // received pause off frame interrupt
++              unsigned char tx_pause_off      : 1;    // received pause off frame interrupt
++              unsigned char rx_overrun        : 1;    // GMAC Rx FIFO overrun interrupt
++              unsigned char status_changed: 1;        // Status Changed Intr for RGMII Mode
++#else
++              unsigned char status_changed: 1;        // Status Changed Intr for RGMII Mode
++              unsigned char rx_overrun        : 1;   // GMAC Rx FIFO overrun interrupt
++              unsigned char tx_pause_off      : 1;    // received pause off frame interrupt
++              unsigned char rx_pause_off  : 1;        // received pause off frame interrupt
++              unsigned char tx_pause_on       : 1;    // transmit pause on frame interrupt
++              unsigned char rx_pause_on       : 1;    // received pause on frame interrupt
++              unsigned char cnt_full          : 1;    // MIB counters half full interrupt
++              unsigned char reserved          : 1;    //
++#endif
++      } _PACKED_ bits;
++} _PACKED_ GMAC_INTR_T;
++
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0060_2
++      {
++#if (BIG_ENDIAN==1)
++              GMAC_INTR_T             gmac1;
++              GMAC_INTR_T             gmac0;
++              unsigned int    class_qf_int: 14;       // bit 15:2 Classification Rx Queue13-0 Full Intr.
++              unsigned int    hwfq_empty      : 1;    // bit 1        Hardware Free Queue Empty Intr.
++              unsigned int    swfq_empty      : 1;    // bit 0        Software Free Queue Empty Intr.
++#else
++#endif
++              unsigned int    swfq_empty      : 1;    // bit 0        Software Free Queue Empty Intr.
++              unsigned int    hwfq_empty      : 1;    // bit 1        Hardware Free Queue Empty Intr.
++              unsigned int    class_qf_int: 14;       // bit 15:2 Classification Rx Queue13-0 Full Intr.
++              GMAC_INTR_T             gmac0;
++              GMAC_INTR_T             gmac1;
++      } bits;
++} INTR_REG4_T;
++
++#define GMAC1_RESERVED_INT_BIT                BIT(31)
++#define GMAC1_MIB_INT_BIT                     BIT(30)
++#define GMAC1_RX_PAUSE_ON_INT_BIT     BIT(29)
++#define GMAC1_TX_PAUSE_ON_INT_BIT     BIT(28)
++#define GMAC1_RX_PAUSE_OFF_INT_BIT    BIT(27)
++#define GMAC1_TX_PAUSE_OFF_INT_BIT    BIT(26)
++#define GMAC1_RX_OVERRUN_INT_BIT      BIT(25)
++#define GMAC1_STATUS_CHANGE_INT_BIT   BIT(24)
++#define GMAC0_RESERVED_INT_BIT                BIT(23)
++#define GMAC0_MIB_INT_BIT                     BIT(22)
++#define GMAC0_RX_PAUSE_ON_INT_BIT     BIT(21)
++#define GMAC0_TX_PAUSE_ON_INT_BIT     BIT(20)
++#define GMAC0_RX_PAUSE_OFF_INT_BIT    BIT(19)
++#define GMAC0_TX_PAUSE_OFF_INT_BIT    BIT(18)
++#define GMAC0_RX_OVERRUN_INT_BIT      BIT(17)
++#define GMAC0_STATUS_CHANGE_INT_BIT   BIT(16)
++#define CLASS_RX_FULL_INT_BIT(x)      BIT((x+2))
++#define HWFQ_EMPTY_INT_BIT                    BIT(1)
++#define SWFQ_EMPTY_INT_BIT                    BIT(0)
++
++#if 1
++#define GMAC0_INT_BITS                                (GMAC0_MIB_INT_BIT)
++#define GMAC1_INT_BITS                                (GMAC1_MIB_INT_BIT)
++#else
++#define GMAC0_INT_BITS                                (GMAC0_RESERVED_INT_BIT | GMAC0_MIB_INT_BIT | \
++                                                                       GMAC0_RX_PAUSE_ON_INT_BIT | GMAC0_TX_PAUSE_ON_INT_BIT |        \
++                                                                       GMAC0_RX_PAUSE_OFF_INT_BIT | GMAC0_TX_PAUSE_OFF_INT_BIT |      \
++                                                                       GMAC0_RX_OVERRUN_INT_BIT | GMAC0_STATUS_CHANGE_INT_BIT)
++#define GMAC1_INT_BITS                                (GMAC1_RESERVED_INT_BIT | GMAC1_MIB_INT_BIT | \
++                                                                       GMAC1_RX_PAUSE_ON_INT_BIT | GMAC1_TX_PAUSE_ON_INT_BIT |        \
++                                                                       GMAC1_RX_PAUSE_OFF_INT_BIT | GMAC1_TX_PAUSE_OFF_INT_BIT |      \
++                                                                       GMAC1_RX_OVERRUN_INT_BIT | GMAC1_STATUS_CHANGE_INT_BIT)
++#endif
++
++#define CLASS_RX_FULL_INT_BITS                0xfffc
++
++/**********************************************************************
++ * GLOBAL_QUEUE_THRESHOLD_REG         (offset 0x0070)
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_0070_2
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    toe_class       : 8;    // 31:24
++              unsigned int    intrq           : 8;    // 23:16
++              unsigned int    hwfq_empty      : 8;    // 15:8         Hardware Free Queue Empty Threshold
++              unsigned int    swfq_empty      : 8;    //  7:0         Software Free Queue Empty Threshold
++#else
++#endif
++              unsigned int    swfq_empty      : 8;    //  7:0         Software Free Queue Empty Threshold
++              unsigned int    hwfq_empty      : 8;    // 15:8         Hardware Free Queue Empty Threshold
++              unsigned int    intrq           : 8;    // 23:16
++              unsigned int    toe_class       : 8;    // 31:24
++      } bits;
++} QUEUE_THRESHOLD_T;
++
++
++/**********************************************************************
++ * GMAC DMA Control Register
++ * GMAC0 offset 0x8000
++ * GMAC1 offset 0xC000
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8000
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    rd_enable               : 1;    // bit 31       Rx DMA Enable
++              unsigned int    td_enable               : 1;    // bit 30       Tx DMA Enable
++              unsigned int    loopback                : 1;    // bit 29       Loopback TxDMA to RxDMA
++              unsigned int    drop_small_ack  : 1;    // bit 28       1: Drop, 0: Accept
++              unsigned int    reserved                : 10;   // bit 27:18
++              unsigned int    rd_insert_bytes : 2;    // bit 17:16
++              unsigned int    rd_prot                 : 4;    // bit 15:12 DMA Protection Control
++              unsigned int    rd_burst_size   : 2;    // bit 11:10 DMA max burst size for every AHB request
++              unsigned int    rd_bus              : 2;        // bit 9:8      Peripheral Bus Width
++              unsigned int    td_prot                 : 4;    // bit 7:4  TxDMA protection control
++              unsigned int    td_burst_size   : 2;    // bit 3:2      TxDMA max burst size for every AHB request
++              unsigned int    td_bus              : 2;        // bit 1:0  Peripheral Bus Width
++#else
++              unsigned int    td_bus              : 2;        // bit 1:0  Peripheral Bus Width
++              unsigned int    td_burst_size   : 2;    // bit 3:2      TxDMA max burst size for every AHB request
++              unsigned int    td_prot                 : 4;    // bit 7:4  TxDMA protection control
++              unsigned int    rd_bus              : 2;        // bit 9:8      Peripheral Bus Width
++              unsigned int    rd_burst_size   : 2;    // bit 11:10 DMA max burst size for every AHB request
++              unsigned int    rd_prot                 : 4;    // bit 15:12 DMA Protection Control
++              unsigned int    rd_insert_bytes : 2;    // bit 17:16
++              unsigned int    reserved                : 10;   // bit 27:18
++              unsigned int    drop_small_ack  : 1;    // bit 28       1: Drop, 0: Accept
++              unsigned int    loopback                : 1;    // bit 29       Loopback TxDMA to RxDMA
++              unsigned int    td_enable               : 1;    // bit 30       Tx DMA Enable
++              unsigned int    rd_enable               : 1;    // bit 31       Rx DMA Enable
++#endif
++      } bits;
++} GMAC_DMA_CTRL_T;
++
++/**********************************************************************
++ * GMAC Tx Weighting Control Register 0
++ * GMAC0 offset 0x8004
++ * GMAC1 offset 0xC004
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8004
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 8;    // bit 31:24
++              unsigned int    hw_tq3                  : 6;    // bit 23:18    HW TX Queue 0
++              unsigned int    hw_tq2                  : 6;    // bit 17:12    HW TX Queue 1
++              unsigned int    hw_tq1                  : 6;    // bit 11:6             HW TX Queue 2
++              unsigned int    hw_tq0                  : 6;    // bit 5:0              HW TX Queue 3
++#else
++              unsigned int    hw_tq0                  : 6;    // bit 5:0              HW TX Queue 3
++              unsigned int    hw_tq1                  : 6;    // bit 11:6             HW TX Queue 2
++              unsigned int    hw_tq2                  : 6;    // bit 17:12    HW TX Queue 1
++              unsigned int    hw_tq3                  : 6;    // bit 23:18    HW TX Queue 0
++              unsigned int    reserved                : 8;    // bit 31:24
++#endif
++      } bits;
++} GMAC_TX_WCR0_T;     // Weighting Control Register 0
++
++/**********************************************************************
++ * GMAC Tx Weighting Control Register 1
++ * GMAC0 offset 0x8008
++ * GMAC1 offset 0xC008
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8008
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 2;    // bit 31:30
++              unsigned int    sw_tq5                  : 5;    // bit 29:25    SW TX Queue 5
++              unsigned int    sw_tq4                  : 5;    // bit 24:20    SW TX Queue 4
++              unsigned int    sw_tq3                  : 5;    // bit 19:15    SW TX Queue 3
++              unsigned int    sw_tq2                  : 5;    // bit 14:10    SW TX Queue 2
++              unsigned int    sw_tq1                  : 5;    // bit 9:5              SW TX Queue 1
++              unsigned int    sw_tq0                  : 5;    // bit 4:0              SW TX Queue 0
++#else
++              unsigned int    sw_tq0                  : 5;    // bit 4:0              SW TX Queue 0
++              unsigned int    sw_tq1                  : 5;    // bit 9:5              SW TX Queue 1
++              unsigned int    sw_tq2                  : 5;    // bit 14:10    SW TX Queue 2
++              unsigned int    sw_tq3                  : 5;    // bit 19:15    SW TX Queue 3
++              unsigned int    sw_tq4                  : 5;    // bit 24:20    SW TX Queue 4
++              unsigned int    sw_tq5                  : 5;    // bit 29:25    SW TX Queue 5
++              unsigned int    reserved                : 2;    // bit 31:30
++#endif
++      } bits;
++} GMAC_TX_WCR1_T;     // Weighting Control Register 1
++
++/**********************************************************************
++ * Queue Read/Write Pointer
++ * GMAC SW TX Queue 0~5 Read/Write Pointer register
++ * GMAC0 offset 0x800C ~ 0x8020
++ * GMAC1 offset 0xC00C ~ 0xC020
++ * GMAC HW TX Queue 0~3 Read/Write Pointer register
++ * GMAC0 offset 0x8024 ~ 0x8030
++ * GMAC1 offset 0xC024 ~ 0xC030
++ **********************************************************************/
++// see DMA_RWPTR_T structure
++
++/**********************************************************************
++ * GMAC DMA Tx First Description Address Register
++ * GMAC0 offset 0x8038
++ * GMAC1 offset 0xC038
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8038
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_first_des_ptr   : 28;   // bit 31:4     first descriptor address
++              unsigned int td_busy                    :  1;   // bit 3        1: TxDMA busy; 0: TxDMA idle
++              unsigned int reserved                   :  3;
++#else
++              unsigned int reserved                   :  3;
++              unsigned int td_busy                    :  1;   // bit 3        1: TxDMA busy; 0: TxDMA idle
++              unsigned int td_first_des_ptr   : 28;   // bit 31:4     first descriptor address
++#endif
++      } bits;
++} GMAC_TXDMA_FIRST_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Current Description Address Register
++ * GMAC0 offset 0x803C
++ * GMAC1 offset 0xC03C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_803C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int td_curr_desc_ptr   : 28;   // bit 31:4     current descriptor address
++              unsigned int reserved                   :  4;
++#else
++              unsigned int reserved                   :  4;
++              unsigned int td_curr_desc_ptr   : 28;   // bit 31:4     current descriptor address
++#endif
++      } bits;
++} GMAC_TXDMA_CURR_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 0 Register
++ * GMAC0 offset 0x8040
++ * GMAC1 offset 0xC040
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8040
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           : 1;    // bit 31
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int status_rvd         : 6;    // bit 28:23 Tx Status, Reserved bits
++              unsigned int status_tx_ok       : 1;    // bit 22    Tx Status, 1: Successful 0: Failed
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int buffer_size        : 16;   // bit 15:0  Transfer size
++#else
++              unsigned int buffer_size        : 16;   // bit 15:0  Transfer size
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int status_tx_ok       : 1;    // bit 22    Tx Status, 1: Successful 0: Failed
++              unsigned int status_rvd         : 6;    // bit 28:23 Tx Status, Reserved bits
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int reserved           : 1;    // bit 31
++#endif
++      } bits;
++} GMAC_TXDESC_0_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 1 Register
++ * GMAC0 offset 0x8044
++ * GMAC1 offset 0xC044
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct txdesc_word1
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved        : 9;    // bit 31:23    Tx Flag, Reserved
++              unsigned int    ip_fixed_len: 1;        // bit 22
++              unsigned int    bypass_tss      : 1;    // bit 21
++              unsigned int    udp_chksum      : 1;    // bit 20               UDP Checksum Enable
++              unsigned int    tcp_chksum      : 1;    // bit 19               TCP Checksum Enable
++              unsigned int    ipv6_enable     : 1;    // bit 18               IPV6 Tx Enable
++              unsigned int    ip_chksum       : 1;    // bit 17               IPV4 Header Checksum Enable
++              unsigned int    mtu_enable      : 1;    // bit 16               TSS segmentation use MTU setting
++              unsigned int    byte_count      : 16;   // bit 15: 0    Tx Frame Byte Count
++#else
++              unsigned int    byte_count      : 16;   // bit 15: 0    Tx Frame Byte Count
++              unsigned int    mtu_enable      : 1;    // bit 16               TSS segmentation use MTU setting
++              unsigned int    ip_chksum       : 1;    // bit 17               IPV4 Header Checksum Enable
++              unsigned int    ipv6_enable     : 1;    // bit 18               IPV6 Tx Enable
++              unsigned int    tcp_chksum      : 1;    // bit 19               TCP Checksum Enable
++              unsigned int    udp_chksum      : 1;    // bit 20               UDP Checksum Enable
++              unsigned int    bypass_tss      : 1;    // bit 21
++              unsigned int    ip_fixed_len: 1;        // bit 22
++              unsigned int    reserved        : 9;    // bit 31:23    Tx Flag, Reserved
++#endif
++      } bits;
++} GMAC_TXDESC_1_T;
++
++#define TSS_IP_FIXED_LEN_BIT  BIT(22)
++#define TSS_UDP_CHKSUM_BIT            BIT(20)
++#define TSS_TCP_CHKSUM_BIT            BIT(19)
++#define TSS_IPV6_ENABLE_BIT           BIT(18)
++#define TSS_IP_CHKSUM_BIT             BIT(17)
++#define TSS_MTU_ENABLE_BIT            BIT(16)
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 2 Register
++ * GMAC0 offset 0x8048
++ * GMAC1 offset 0xC048
++ **********************************************************************/
++typedef union
++{
++      unsigned int    bits32;
++      unsigned int    buf_adr;
++} GMAC_TXDESC_2_T;
++
++/**********************************************************************
++ * GMAC DMA Tx Description Word 3 Register
++ * GMAC0 offset 0x804C
++ * GMAC1 offset 0xC04C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct txdesc_word3
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    reserved        : 18;   // bit 28:11
++              unsigned int    mtu_size        : 11;   // bit 10: 0    Tx Frame Byte Count
++#else
++              unsigned int    mtu_size        : 11;   // bit 10: 0    Tx Frame Byte Count
++              unsigned int    reserved        : 18;   // bit 28:11
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++#endif
++      } bits;
++} GMAC_TXDESC_3_T;
++#define SOF_EOF_BIT_MASK      0x3fffffff
++#define SOF_BIT                               0x80000000
++#define EOF_BIT                               0x40000000
++#define EOFIE_BIT                     BIT(29)
++#define MTU_SIZE_BIT_MASK     0x7ff
++
++/**********************************************************************
++ * GMAC Tx Descriptor
++ **********************************************************************/
++typedef struct
++{
++      GMAC_TXDESC_0_T word0;
++      GMAC_TXDESC_1_T word1;
++      GMAC_TXDESC_2_T word2;
++      GMAC_TXDESC_3_T word3;
++} GMAC_TXDESC_T;
++
++
++/**********************************************************************
++ * GMAC DMA Rx First Description Address Register
++ * GMAC0 offset 0x8058
++ * GMAC1 offset 0xC058
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8058
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_first_des_ptr   : 28;   // bit 31:4 first descriptor address
++              unsigned int rd_busy                    :  1;   // bit 3        1-RxDMA busy; 0-RxDMA idle
++              unsigned int reserved                   :  3;   // bit 2:0
++#else
++              unsigned int reserved                   :  3;   // bit 2:0
++              unsigned int rd_busy                    :  1;   // bit 3        1-RxDMA busy; 0-RxDMA idle
++              unsigned int rd_first_des_ptr   : 28;   // bit 31:4 first descriptor address
++#endif
++      } bits;
++} GMAC_RXDMA_FIRST_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Current Description Address Register
++ * GMAC0 offset 0x805C
++ * GMAC1 offset 0xC05C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_805C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rd_curr_des_ptr    : 28;   // bit 31:4 current descriptor address
++              unsigned int reserved                   :  4;   // bit 3:0
++#else
++              unsigned int reserved                   :  4;   // bit 3:0
++              unsigned int rd_curr_des_ptr    : 28;   // bit 31:4 current descriptor address
++#endif
++      } bits;
++} GMAC_RXDMA_CURR_DESC_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 0 Register
++ * GMAC0 offset 0x8060
++ * GMAC1 offset 0xC060
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8060
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int drop                       : 1;    // bit 31        TOE/CIS Queue Full dropped packet to default queue
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int chksum_status      : 3;    // bit 28:26 Check Sum Status
++              unsigned int status                     : 4;    // bit 24:22 Status of rx frame
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int buffer_size        : 16;   // bit 15:0  number of descriptors used for the current frame
++#else
++              unsigned int buffer_size        : 16;   // bit 15:0  number of descriptors used for the current frame
++              unsigned int desc_count         : 6;    // bit 21:16 number of descriptors used for the current frame
++              unsigned int status                     : 4;    // bit 24:22 Status of rx frame
++              unsigned int chksum_status      : 3;    // bit 28:26 Check Sum Status
++              unsigned int perr                       : 1;    // bit 29        protocol error during processing this descriptor
++              unsigned int derr                       : 1;    // bit 30        data error during processing this descriptor
++              unsigned int drop                       : 1;    // bit 31        TOE/CIS Queue Full dropped packet to default queue
++#endif
++      } bits;
++} GMAC_RXDESC_0_T;
++
++#define               GMAC_RXDESC_0_T_derr                            BIT(30)
++#define               GMAC_RXDESC_0_T_perr                            BIT(29)
++#define               GMAC_RXDESC_0_T_chksum_status(x)        BIT((x+26))
++#define               GMAC_RXDESC_0_T_status(x)                       BIT((x+22))
++#define               GMAC_RXDESC_0_T_desc_count(x)           BIT((x+16))
++
++#define       RX_CHKSUM_IP_UDP_TCP_OK                 0
++#define       RX_CHKSUM_IP_OK_ONLY                    1
++#define       RX_CHKSUM_NONE                                  2
++#define       RX_CHKSUM_IP_ERR_UNKNOWN                4
++#define       RX_CHKSUM_IP_ERR                                5
++#define       RX_CHKSUM_TCP_UDP_ERR                   6
++#define RX_CHKSUM_NUM                                 8
++
++#define RX_STATUS_GOOD_FRAME                  0
++#define RX_STATUS_TOO_LONG_GOOD_CRC           1
++#define RX_STATUS_RUNT_FRAME                  2
++#define RX_STATUS_SFD_NOT_FOUND                       3
++#define RX_STATUS_CRC_ERROR                           4
++#define RX_STATUS_TOO_LONG_BAD_CRC            5
++#define RX_STATUS_ALIGNMENT_ERROR             6
++#define RX_STATUS_TOO_LONG_BAD_ALIGN  7
++#define RX_STATUS_RX_ERR                              8
++#define RX_STATUS_DA_FILTERED                 9
++#define RX_STATUS_BUFFER_FULL                 10
++#define RX_STATUS_NUM                                 16
++
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 1 Register
++ * GMAC0 offset 0x8064
++ * GMAC1 offset 0xC064
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct rxdesc_word1
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sw_id           : 16;   // bit 31:16    Software ID
++              unsigned int    byte_count      : 16;   // bit 15: 0    Rx Frame Byte Count
++#else
++              unsigned int    byte_count      : 16;   // bit 15: 0    Rx Frame Byte Count
++              unsigned int    sw_id           : 16;   // bit 31:16    Software ID
++#endif
++      } bits;
++} GMAC_RXDESC_1_T;
++
++/**********************************************************************
++ * GMAC DMA Rx Description Word 2 Register
++ * GMAC0 offset 0x8068
++ * GMAC1 offset 0xC068
++ **********************************************************************/
++typedef union
++{
++      unsigned int    bits32;
++      unsigned int    buf_adr;
++} GMAC_RXDESC_2_T;
++
++#define RX_INSERT_NONE                0
++#define RX_INSERT_1_BYTE      1
++#define RX_INSERT_2_BYTE      2
++#define RX_INSERT_3_BYTE      3
++
++#define RX_INSERT_BYTES               RX_INSERT_2_BYTE
++/**********************************************************************
++ * GMAC DMA Rx Description Word 3 Register
++ * GMAC0 offset 0x806C
++ * GMAC1 offset 0xC06C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct rxdesc_word3
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    ctrl_flag       : 1;    // bit 28               Control Flag is present
++              unsigned int    out_of_seq      : 1;    // bit 27               Out of Sequence packet
++              unsigned int    option          : 1;    // bit 26               IPV4 option or IPV6 extension header
++              unsigned int    abnormal        : 1;    // bit 25               abnormal case found
++              unsigned int    dup_ack         : 1;    // bit 24               Duplicated ACK detected
++              unsigned int    l7_offset       : 8;    // bit 23: 16   L7 data offset
++              unsigned int    l4_offset       : 8;    // bit 15: 8    L4 data offset
++              unsigned int    l3_offset       : 8;    // bit 7: 0             L3 data offset
++#else
++              unsigned int    l3_offset       : 8;    // bit 7: 0             L3 data offset
++              unsigned int    l4_offset       : 8;    // bit 15: 8    L4 data offset
++              unsigned int    l7_offset       : 8;    // bit 23: 16   L7 data offset
++              unsigned int    dup_ack         : 1;    // bit 24               Duplicated ACK detected
++              unsigned int    abnormal        : 1;    // bit 25               abnormal case found
++              unsigned int    option          : 1;    // bit 26               IPV4 option or IPV6 extension header
++              unsigned int    out_of_seq      : 1;    // bit 27               Out of Sequence packet
++              unsigned int    ctrl_flag       : 1;    // bit 28               Control Flag is present
++              unsigned int    eofie           : 1;    // bit 29               End of frame interrupt enable
++              unsigned int    sof_eof         : 2;    // bit 31:30    11: only one, 10: first, 01: last, 00: linking
++#endif
++      } bits;
++} GMAC_RXDESC_3_T;
++
++/**********************************************************************
++ * GMAC Rx Descriptor
++ **********************************************************************/
++typedef struct
++{
++      GMAC_RXDESC_0_T word0;
++      GMAC_RXDESC_1_T word1;
++      GMAC_RXDESC_2_T word2;
++      GMAC_RXDESC_3_T word3;
++} GMAC_RXDESC_T;
++
++/**********************************************************************
++ * GMAC Hash Engine Enable/Action Register 0 Offset Register
++ * GMAC0 offset 0x8070
++ * GMAC1 offset 0xC070
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8070
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    mr1en           : 1;    // bit 31               Enable Matching Rule 1
++              unsigned int    reserved1       : 1;    // bit 30
++              unsigned int    timing          : 3;    // bit 29:27
++              unsigned int    mr1_action      : 5;    // bit 26:22    Matching Rule 1 action offset
++              unsigned int    mr1hel          : 6;    // bit 21:16    match rule 1 hash entry size
++              unsigned int    mr0en           : 1;    // bit 15               Enable Matching Rule 0
++              unsigned int    reserved0       : 4;    // bit 14:11
++              unsigned int    mr0_action      : 5;    // bit 10:6             Matching Rule 0 action offset
++              unsigned int    mr0hel          : 6;    // bit 5:0              match rule 0 hash entry size
++#else
++              unsigned int    mr0hel          : 6;    // bit 5:0              match rule 0 hash entry size
++              unsigned int    mr0_action      : 5;    // bit 10:6             Matching Rule 0 action offset
++              unsigned int    reserved0       : 4;    // bit 14:11
++              unsigned int    mr0en           : 1;    // bit 15               Enable Matching Rule 0
++              unsigned int    mr1hel          : 6;    // bit 21:16    match rule 1 hash entry size
++              unsigned int    mr1_action      : 5;    // bit 26:22    Matching Rule 1 action offset
++              unsigned int    timing          : 3;    // bit 29:27
++              unsigned int    reserved1       : 1;    // bit 30
++              unsigned int    mr1en           : 1;    // bit 31               Enable Matching Rule 1
++#endif
++      } bits;
++} GMAC_HASH_ENABLE_REG0_T;
++
++/**********************************************************************
++ * GMAC Hash Engine Enable/Action Register 1 Offset Register
++ * GMAC0 offset 0x8074
++ * GMAC1 offset 0xC074
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8074
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    mr3en           : 1;    // bit 31               Enable Matching Rule 3
++              unsigned int    reserved3       : 4;    // bit 30:27
++              unsigned int    mr3_action      : 5;    // bit 26:22    Matching Rule 3 action offset
++              unsigned int    mr3hel          : 6;    // bit 21:16    match rule 3 hash entry size
++              unsigned int    mr2en           : 1;    // bit 15               Enable Matching Rule 2
++              unsigned int    reserved2       : 4;    // bit 14:11
++              unsigned int    mr2_action      : 5;    // bit 10:6             Matching Rule 2 action offset
++              unsigned int    mr2hel          : 6;    // bit 5:0              match rule 2 hash entry size
++#else
++              unsigned int    mr2hel          : 6;    // bit 5:0              match rule 2 hash entry size
++              unsigned int    mr2_action      : 5;    // bit 10:6             Matching Rule 2 action offset
++              unsigned int    reserved2       : 4;    // bit 14:11
++              unsigned int    mr2en           : 1;    // bit 15               Enable Matching Rule 2
++              unsigned int    mr3hel          : 6;    // bit 21:16    match rule 3 hash entry size
++              unsigned int    mr3_action      : 5;    // bit 26:22    Matching Rule 3 action offset
++              unsigned int    reserved1       : 4;    // bit 30:27
++              unsigned int    mr3en           : 1;    // bit 31               Enable Matching Rule 3
++#endif
++      } bits;
++} GMAC_HASH_ENABLE_REG1_T;
++
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 0
++ * GMAC0 offset 0x8078
++ * GMAC1 offset 0xC078
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_8078
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    l2                      : 1;    // bit 31               L2 matching enable
++              unsigned int    l3                      : 1;    // bit 30               L3 matching enable
++              unsigned int    l4                      : 1;    // bit 29               L4 matching enable
++              unsigned int    l7                      : 1;    // bit 28               L7 matching enable
++              unsigned int    port            : 1;    // bit 27               PORT ID matching enable
++              unsigned int    priority        : 3;    // bit 26:24    priority if multi-rules matched
++              unsigned int    da                      : 1;    // bit 23               MAC DA enable
++              unsigned int    sa                      : 1;    // bit 22               MAC SA enable
++              unsigned int    ether_type      : 1;    // bit 21               Ethernet type enable
++              unsigned int    vlan            : 1;    // bit 20               VLAN ID enable
++              unsigned int    pppoe           : 1;    // bit 19               PPPoE Session ID enable
++              unsigned int    reserved1       : 3;    // bit 18:16
++              unsigned int    ip_version      : 1;    // bit 15               0: IPV4, 1: IPV6
++              unsigned int    ip_hdr_len      : 1;    // bit 14               IPV4 Header length
++              unsigned int    flow_lable      : 1;    // bit 13               IPV6 Flow label
++              unsigned int    tos_traffic     : 1;    // bit 12               IPV4 TOS or IPV6 Traffice Class
++              unsigned int    reserved2       : 4;    // bit 11:8
++              unsigned int    sprx            : 8;    // bit 7:0              Support Protocol Register 7:0
++#else
++              unsigned int    sprx            : 8;    // bit 7:0              Support Protocol Register 7:0
++              unsigned int    reserved2       : 4;    // bit 11:8
++              unsigned int    tos_traffic     : 1;    // bit 12               IPV4 TOS or IPV6 Traffice Class
++              unsigned int    flow_lable      : 1;    // bit 13               IPV6 Flow label
++              unsigned int    ip_hdr_len      : 1;    // bit 14               IPV4 Header length
++              unsigned int    ip_version      : 1;    // bit 15               0: IPV4, 1: IPV6
++              unsigned int    reserved1       : 3;    // bit 18:16
++              unsigned int    pppoe           : 1;    // bit 19               PPPoE Session ID enable
++              unsigned int    vlan            : 1;    // bit 20               VLAN ID enable
++              unsigned int    ether_type      : 1;    // bit 21               Ethernet type enable
++              unsigned int    sa                      : 1;    // bit 22               MAC SA enable
++              unsigned int    da                      : 1;    // bit 23               MAC DA enable
++              unsigned int    priority        : 3;    // bit 26:24    priority if multi-rules matched
++              unsigned int    port            : 1;    // bit 27               PORT ID matching enable
++              unsigned int    l7                      : 1;    // bit 28               L7 matching enable
++              unsigned int    l4                      : 1;    // bit 29               L4 matching enable
++              unsigned int    l3                      : 1;    // bit 30               L3 matching enable
++              unsigned int    l2                      : 1;    // bit 31               L2 matching enable
++#endif
++      } bits;
++} GMAC_MRxCR0_T;
++
++#define MR_L2_BIT                     BIT(31)
++#define MR_L3_BIT                     BIT(30)
++#define MR_L4_BIT                     BIT(29)
++#define MR_L7_BIT                     BIT(28)
++#define MR_PORT_BIT                   BIT(27)
++#define MR_PRIORITY_BIT               BIT(26)
++#define MR_DA_BIT                     BIT(23)
++#define MR_SA_BIT                     BIT(22)
++#define MR_ETHER_TYPE_BIT     BIT(21)
++#define MR_VLAN_BIT                   BIT(20)
++#define MR_PPPOE_BIT          BIT(19)
++#define MR_IP_VER_BIT         BIT(15)
++#define MR_IP_HDR_LEN_BIT     BIT(14)
++#define MR_FLOW_LABLE_BIT     BIT(13)
++#define MR_TOS_TRAFFIC_BIT    BIT(12)
++#define MR_SPR_BIT(x)         BIT(x)
++#define MR_SPR_BITS           0xff
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 1
++ * GMAC0 offset 0x807C
++ * GMAC1 offset 0xC07C
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_807C
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    sip                     : 1;    // bit 31               Srce IP
++              unsigned int    sip_netmask     : 7;    // bit 30:24    Srce IP net mask, number of mask bits
++              unsigned int    dip                     : 1;    // bit 23               Dest IP
++              unsigned int    dip_netmask     : 7;    // bit 22:16    Dest IP net mask, number of mask bits
++              unsigned int    l4_byte0_15     : 16;   // bit 15: 0
++#else
++              unsigned int    l4_byte0_15     : 16;   // bit 15: 0
++              unsigned int    dip_netmask     : 7;    // bit 22:16    Dest IP net mask, number of mask bits
++              unsigned int    dip                     : 1;    // bit 23               Dest IP
++              unsigned int    sip_netmask     : 7;    // bit 30:24    Srce IP net mask, number of mask bits
++              unsigned int    sip                     : 1;    // bit 31               Srce IP
++#endif
++      } bits;
++} GMAC_MRxCR1_T;
++
++/**********************************************************************
++ * GMAC Matching Rule Control Register 2
++ * GMAC0 offset 0x8080
++ * GMAC1 offset 0xC080
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_8080
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    l4_byte16_24: 8;        // bit 31: 24
++              unsigned int    l7_byte0_23     : 24;   // bit 23:0
++#else
++              unsigned int    l7_byte0_23     : 24;   // bit 23:0
++              unsigned int    l4_byte16_24: 8;        // bit 31: 24
++#endif
++      } bits;
++} GMAC_MRxCR2_T;
++
++
++/**********************************************************************
++ * GMAC Support registers
++ * GMAC0 offset 0x80A8
++ * GMAC1 offset 0xC0A8
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_80A8
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved: 21;   // bit 31:11
++              unsigned int    swap    : 3;    // bit 10:8             Swap
++              unsigned int    protocol: 8;    // bit 7:0              Supported protocol
++#else
++              unsigned int    protocol: 8;    // bit 7:0              Supported protocol
++              unsigned int    swap    : 3;    // bit 10:8             Swap
++              unsigned int    reserved: 21;   // bit 31:11
++#endif
++      } bits;
++} GMAC_SPR_T;
++
++/**********************************************************************
++ * GMAC_AHB_WEIGHT registers
++ * GMAC0 offset 0x80C8
++ * GMAC1 offset 0xC0C8
++ **********************************************************************/
++ typedef union
++{
++      unsigned int bits32;
++      struct bit_80C8
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int    reserved                : 7;    // 31:25
++              unsigned int    tqDV_threshold  : 5;    // 24:20 DMA TqCtrl to Start tqDV FIFO Threshold
++              unsigned int    pre_req                 : 5;    // 19:15 Rx Data Pre Request FIFO Threshold
++              unsigned int    tx_weight               : 5;    // 14:10
++              unsigned int    rx_weight               : 5;    // 9:5
++              unsigned int    hash_weight             : 5;    // 4:0
++#else
++              unsigned int    hash_weight             : 5;    // 4:0
++              unsigned int    rx_weight               : 5;    // 9:5
++              unsigned int    tx_weight               : 5;    // 14:10
++              unsigned int    pre_req                 : 5;    // 19:15 Rx Data Pre Request FIFO Threshold
++              unsigned int    tqDV_threshold  : 5;    // 24:20 DMA TqCtrl to Start tqDV FIFO Threshold
++              unsigned int    reserved                : 7;    // 31:25
++#endif
++      } bits;
++} GMAC_AHB_WEIGHT_T;
++/**********************************************************************
++ * the register structure of GMAC
++ **********************************************************************/
++
++/**********************************************************************
++ * GMAC RX FLTR
++ * GMAC0 Offset 0xA00C
++ * GMAC1 Offset 0xE00C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_000c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 27;
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++#else
++              unsigned int unicast            :  1;   /* enable receive of unicast frames that are sent to STA address */
++              unsigned int multicast          :  1;   /* enable receive of multicast frames that pass multicast filter */
++              unsigned int broadcast          :  1;   /* enable receive of broadcast frames */
++              unsigned int promiscuous        :  1;   /* enable receive of all frames */
++              unsigned int error                      :  1;   /* enable receive of all error frames */
++              unsigned int                            : 27;
++#endif
++      } bits;
++} GMAC_RX_FLTR_T;
++
++/**********************************************************************
++ * GMAC Configuration 0
++ * GMAC0 Offset 0xA018
++ * GMAC1 Offset 0xE018
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0018
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           :  2;   // 31
++              unsigned int port1_chk_classq :  1;     // 29
++              unsigned int port0_chk_classq :  1;     // 28
++              unsigned int port1_chk_toeq     :  1;   // 27
++              unsigned int port0_chk_toeq     :  1;   // 26
++              unsigned int port1_chk_hwq      :  1;   // 25
++              unsigned int port0_chk_hwq      :  1;   // 24
++              unsigned int rx_err_detect  :  1;       // 23
++              unsigned int ipv6_exthdr_order: 1;      // 22
++              unsigned int rxc_inv            :  1;   // 21
++              unsigned int rgmm_edge          :  1;   // 20
++        unsigned int rx_tag_remove  :  1;   /* 19: Remove Rx VLAN tag */
++        unsigned int ipv6_rx_chksum :  1;   /* 18: IPv6 RX Checksum enable */
++        unsigned int ipv4_rx_chksum :  1;   /* 17: IPv4 RX Checksum enable */
++        unsigned int rgmii_en       :  1;   /* 16: RGMII in-band status enable */
++              unsigned int tx_fc_en           :  1;   /* 15: TX flow control enable */
++              unsigned int rx_fc_en           :  1;   /* 14: RX flow control enable */
++              unsigned int sim_test           :  1;   /* 13: speed up timers in simulation */
++              unsigned int dis_col            :  1;   /* 12: disable 16 collisions abort function */
++              unsigned int dis_bkoff          :  1;   /* 11: disable back-off function */
++              unsigned int max_len            :  3;   /* 8-10 maximum receive frame length allowed */
++              unsigned int adj_ifg            :  4;   /* 4-7: adjust IFG from 96+/-56 */
++        unsigned int flow_ctrl      :  1;   /* 3: flow control also trigged by Rx queues */
++              unsigned int loop_back          :  1;   /* 2: transmit data loopback enable */
++              unsigned int dis_rx                     :  1;   /* 1: disable receive */
++              unsigned int dis_tx                     :  1;   /* 0: disable transmit */
++#else
++              unsigned int dis_tx                     :  1;   /* 0: disable transmit */
++              unsigned int dis_rx                     :  1;   /* 1: disable receive */
++              unsigned int loop_back          :  1;   /* 2: transmit data loopback enable */
++        unsigned int flow_ctrl      :  1;   /* 3: flow control also trigged by Rx queues */
++              unsigned int adj_ifg            :  4;   /* 4-7: adjust IFG from 96+/-56 */
++              unsigned int max_len            :  3;   /* 8-10 maximum receive frame length allowed */
++              unsigned int dis_bkoff          :  1;   /* 11: disable back-off function */
++              unsigned int dis_col            :  1;   /* 12: disable 16 collisions abort function */
++              unsigned int sim_test           :  1;   /* 13: speed up timers in simulation */
++              unsigned int rx_fc_en           :  1;   /* 14: RX flow control enable */
++              unsigned int tx_fc_en           :  1;   /* 15: TX flow control enable */
++        unsigned int rgmii_en       :  1;   /* 16: RGMII in-band status enable */
++        unsigned int ipv4_rx_chksum :  1;   /* 17: IPv4 RX Checksum enable */
++        unsigned int ipv6_rx_chksum :  1;   /* 18: IPv6 RX Checksum enable */
++        unsigned int rx_tag_remove  :  1;   /* 19: Remove Rx VLAN tag */
++              unsigned int rgmm_edge          :  1;   // 20
++              unsigned int rxc_inv            :  1;   // 21
++              unsigned int ipv6_exthdr_order: 1;      // 22
++              unsigned int rx_err_detect  :  1;       // 23
++              unsigned int port0_chk_hwq      :  1;   // 24
++              unsigned int port1_chk_hwq      :  1;   // 25
++              unsigned int port0_chk_toeq     :  1;   // 26
++              unsigned int port1_chk_toeq     :  1;   // 27
++              unsigned int port0_chk_classq :  1;     // 28
++              unsigned int port1_chk_classq :  1;     // 29
++              unsigned int reserved           :  2;   // 31
++#endif
++      } bits;
++} GMAC_CONFIG0_T;
++
++/**********************************************************************
++ * GMAC Configuration 1
++ * GMAC0 Offset 0xA01C
++ * GMAC1 Offset 0xE01C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_001c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int reserved           : 16;
++              unsigned int rel_threshold      : 8;    /* flow control release threshold */
++              unsigned int set_threshold      : 8;    /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 8;    /* flow control set threshold */
++              unsigned int rel_threshold      : 8;    /* flow control release threshold */
++              unsigned int reserved           : 16;
++#endif
++      } bits;
++} GMAC_CONFIG1_T;
++
++#define GMAC_FLOWCTRL_SET_MAX         32
++#define GMAC_FLOWCTRL_SET_MIN         0
++#define GMAC_FLOWCTRL_RELEASE_MAX     32
++#define GMAC_FLOWCTRL_RELEASE_MIN     0
++
++/**********************************************************************
++ * GMAC Configuration 2
++ * GMAC0 Offset 0xA020
++ * GMAC1 Offset 0xE020
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0020
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG2_T;
++
++/**********************************************************************
++ * GMAC Configuration 3
++ * GMAC0 Offset 0xA024
++ * GMAC1 Offset 0xE024
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_0024
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++#else
++              unsigned int set_threshold      : 16;   /* flow control set threshold */
++              unsigned int rel_threshold      : 16;   /* flow control release threshold */
++#endif
++      } bits;
++} GMAC_CONFIG3_T;
++
++
++/**********************************************************************
++ * GMAC STATUS
++ * GMAC0 Offset 0xA02C
++ * GMAC1 Offset 0xE02C
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit1_002c
++      {
++#if (BIG_ENDIAN==1)
++              unsigned int                            : 25;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int reserved           :  1;
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int link                       :  1;   /* link status */
++#else
++              unsigned int link                       :  1;   /* link status */
++              unsigned int speed                      :  2;   /* link speed(00->2.5M 01->25M 10->125M) */
++              unsigned int duplex                     :  1;   /* duplex mode */
++              unsigned int reserved           :  1;
++              unsigned int mii_rmii           :  2;   /* PHY interface type */
++              unsigned int                            : 25;
++#endif
++      } bits;
++} GMAC_STATUS_T;
++
++#define GMAC_SPEED_10                 0
++#define GMAC_SPEED_100                        1
++#define GMAC_SPEED_1000                       2
++
++#define GMAC_PHY_MII                  0
++#define GMAC_PHY_GMII                 1
++#define GMAC_PHY_RGMII_100            2
++#define GMAC_PHY_RGMII_1000           3
++
++/**********************************************************************
++ * Queue Header
++ *    (1) TOE Queue Header
++ *    (2) Non-TOE Queue Header
++ *    (3) Interrupt Queue Header
++ *
++ * memory Layout
++ *    TOE Queue Header
++ *     0x60003000 +---------------------------+ 0x0000
++ *                            |     TOE Queue 0 Header        |
++ *                            |         8 * 4 Bytes       |
++ *                            +---------------------------+ 0x0020
++ *                            |     TOE Queue 1 Header        |
++ *                            |         8 * 4 Bytes           |
++ *                            +---------------------------+ 0x0040
++ *                            |       ......                          |
++ *                            |                                               |
++ *                            +---------------------------+
++ *
++ *    Non TOE Queue Header
++ *     0x60002000 +---------------------------+ 0x0000
++ *                            |   Default Queue 0 Header  |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x0008
++ *                            |   Default Queue 1 Header      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x0010
++ *                            |   Classification Queue 0      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |   Classification Queue 1      |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ (n * 8 + 0x10)
++ *                            |               ...                             |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ (13 * 8 + 0x10)
++ *                            |   Classification Queue 13     |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+ 0x80
++ *                            |      Interrupt Queue 0        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 1        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 2        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *                            |      Interrupt Queue 3        |
++ *                            |         2 * 4 Bytes           |
++ *                            +---------------------------+
++ *
++ **********************************************************************/
++#define TOE_QUEUE_HDR_ADDR(n)         (TOE_TOE_QUE_HDR_BASE + n * 32)
++#define TOE_Q_HDR_AREA_END                    (TOE_QUEUE_HDR_ADDR(TOE_TOE_QUEUE_MAX+1))
++#define TOE_DEFAULT_Q0_HDR_BASE               (TOE_NONTOE_QUE_HDR_BASE + 0x00)
++#define TOE_DEFAULT_Q1_HDR_BASE               (TOE_NONTOE_QUE_HDR_BASE + 0x08)
++#define TOE_CLASS_Q_HDR_BASE          (TOE_NONTOE_QUE_HDR_BASE + 0x10)
++#define TOE_INTR_Q_HDR_BASE                   (TOE_NONTOE_QUE_HDR_BASE + 0x80)
++#define INTERRUPT_QUEUE_HDR_ADDR(n)   (TOE_INTR_Q_HDR_BASE + n * 8)
++#define NONTOE_Q_HDR_AREA_END         (INTERRUPT_QUEUE_HDR_ADDR(TOE_INTR_QUEUE_MAX+1))
++/**********************************************************************
++ * TOE Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} TOE_QHDR0_T;
++
++#define TOE_QHDR0_BASE_MASK   (~0x0f)
++
++/**********************************************************************
++ * TOE Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16
++              unsigned int rptr                       : 16;   // bit 15:0
++#else
++              unsigned int rptr                       : 16;   // bit 15:0
++              unsigned int wptr                       : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR1_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 2
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr2
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int usd                        : 1;    // bit 31               0: if no data assembled yet
++              unsigned int ctl                        : 1;    // bit 30               1: have control flag bits (except ack)
++              unsigned int osq                        : 1;    // bit 29               1: out of sequence
++              unsigned int sat                        : 1;    // bit 28               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int ip_opt                     : 1;    // bit 27               1: have IPV4 option or IPV6 Extension header
++              unsigned int tcp_opt            : 1;    // bit 26               1: Have TCP option
++              unsigned int abn                        : 1;    // bit 25               1: Abnormal case Found
++              unsigned int dack                       : 1;    // bit 24               1: Duplicated ACK
++              unsigned int reserved           : 7;    // bit 23:17
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++#else
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++              unsigned int reserved           : 7;    // bit 23:17
++              unsigned int dack                       : 1;    // bit 24               1: Duplicated ACK
++              unsigned int abn                        : 1;    // bit 25               1: Abnormal case Found
++              unsigned int tcp_opt            : 1;    // bit 26               1: Have TCP option
++              unsigned int ip_opt                     : 1;    // bit 27               1: have IPV4 option or IPV6 Extension header
++              unsigned int sat                        : 1;    // bit 28               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int osq                        : 1;    // bit 29               1: out of sequence
++              unsigned int ctl                        : 1;    // bit 30               1: have control flag bits (except ack)
++              unsigned int usd                        : 1;    // bit 31               0: if no data assembled yet
++#endif
++      } bits;
++} TOE_QHDR2_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 3
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int seq_num;
++} TOE_QHDR3_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 4
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int ack_num;
++} TOE_QHDR4_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 5
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr5
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqCnt             : 16;   // bit 31:16
++              unsigned int AckCnt             : 16;   // bit 15:0
++#else
++              unsigned int AckCnt             : 16;   // bit 15:0
++              unsigned int SeqCnt             : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR5_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 6
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr6
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int MaxPktSize : 14;   // bit 31:18
++              unsigned int iq_num             : 2;    // bit 17:16
++              unsigned int WinSize    : 16;   // bit 15:0
++#else
++              unsigned int WinSize    : 16;   // bit 15:0
++              unsigned int iq_num             : 2;    // bit 17:16
++              unsigned int MaxPktSize : 14;   // bit 31:18
++#endif
++      } bits;
++} TOE_QHDR6_T;
++
++/**********************************************************************
++ * TOE Queue Header Word 7
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_qhdr7
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqThreshold       : 16;   // bit 31:16
++              unsigned int AckThreshold       : 16;   // bit 15:0
++#else
++              unsigned int AckThreshold       : 16;   // bit 15:0
++              unsigned int SeqThreshold       : 16;   // bit 31:16
++#endif
++      } bits;
++} TOE_QHDR7_T;
++
++/**********************************************************************
++ * TOE Queue Header
++ **********************************************************************/
++typedef struct
++{
++      TOE_QHDR0_T             word0;
++      TOE_QHDR1_T             word1;
++      TOE_QHDR2_T             word2;
++      TOE_QHDR3_T             word3;
++      TOE_QHDR4_T             word4;
++      TOE_QHDR5_T             word5;
++      TOE_QHDR6_T             word6;
++      TOE_QHDR7_T             word7;
++} TOE_QHDR_T;
++
++/**********************************************************************
++ * NONTOE Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int base_size;
++} NONTOE_QHDR0_T;
++
++#define NONTOE_QHDR0_BASE_MASK        (~0x0f)
++
++/**********************************************************************
++ * NONTOE Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_nonqhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr                       : 16;   // bit 31:16
++              unsigned int rptr                       : 16;   // bit 15:0
++#else
++              unsigned int rptr                       : 16;   // bit 15:0
++              unsigned int wptr                       : 16;   // bit 31:16
++#endif
++      } bits;
++} NONTOE_QHDR1_T;
++
++/**********************************************************************
++ * Non-TOE Queue Header
++ **********************************************************************/
++typedef struct
++{
++      NONTOE_QHDR0_T          word0;
++      NONTOE_QHDR1_T          word1;
++} NONTOE_QHDR_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 0
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr0
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int wptr               : 16;   // bit 31:16    Write Pointer where hw stopped
++              unsigned int win_size   : 16;   // bit 15:0     Descriptor Ring Size
++#else
++              unsigned int win_size   : 16;   // bit 15:0     Descriptor Ring Size
++              unsigned int wptr               : 16;   // bit 31:16    Write Pointer where hw stopped
++#endif
++      } bits;
++} INTR_QHDR0_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 1
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr1
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int ctl                        : 1;    // bit 31               1: have control flag bits (except ack)
++              unsigned int osq                        : 1;    // bit 30               1: out of sequence
++              unsigned int sat                        : 1;    // bit 29               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int ip_opt                     : 1;    // bit 28               1: have IPV4 option or IPV6 Extension header
++              unsigned int tcp_opt            : 1;    // bit 27               1: Have TCP option
++              unsigned int abn                        : 1;    // bit 26               1: Abnormal case Found
++              unsigned int dack                       : 1;    // bit 25               1: Duplicated ACK
++              unsigned int tcp_qid            : 8;    // bit 24:17    TCP Queue ID
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++#else
++              unsigned int TotalPktSize       : 17;   // bit 16: 0    Total packet size
++              unsigned int tcp_qid            : 8;    // bit 24:17    TCP Queue ID
++              unsigned int dack                       : 1;    // bit 25               1: Duplicated ACK
++              unsigned int abn                        : 1;    // bit 26               1: Abnormal case Found
++              unsigned int tcp_opt            : 1;    // bit 27               1: Have TCP option
++              unsigned int ip_opt                     : 1;    // bit 28               1: have IPV4 option or IPV6 Extension header
++              unsigned int sat                        : 1;    // bit 29               1: SeqCnt > SeqThreshold, or AckCnt > AckThreshold
++              unsigned int osq                        : 1;    // bit 30               1: out of sequence
++              unsigned int ctl                        : 1;    // bit 31               1: have control flag bits (except ack)
++#endif
++      } bits;
++} INTR_QHDR1_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 2
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int seq_num;
++} INTR_QHDR2_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 3
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      unsigned int ack_num;
++} INTR_QHDR3_T;
++
++/**********************************************************************
++ * Interrupt Queue Header Word 4
++ **********************************************************************/
++typedef union
++{
++      unsigned int bits32;
++      struct bit_intrqhdr4
++      {
++#if (BIG_ENDIAN==1)
++
++              unsigned int SeqCnt             : 16;   // bit 31:16    Seq# change since last seq# intr.
++              unsigned int AckCnt             : 16;   // bit 15:0     Ack# change since last ack# intr.
++#else
++              unsigned int AckCnt             : 16;   // bit 15:0             Ack# change since last ack# intr.
++              unsigned int SeqCnt             : 16;   // bit 31:16    Seq# change since last seq# intr.
++#endif
++      } bits;
++} INTR_QHDR4_T;
++
++/**********************************************************************
++ * Interrupt Queue Header
++ **********************************************************************/
++typedef struct
++{
++      INTR_QHDR0_T            word0;
++      INTR_QHDR1_T            word1;
++      INTR_QHDR2_T            word2;
++      INTR_QHDR3_T            word3;
++      INTR_QHDR4_T            word4;
++      unsigned int            word5;
++      unsigned int            word6;
++      unsigned int            word7;
++} INTR_QHDR_T;
++
++/**********************************************************************
++ * GMAC Conf
++ **********************************************************************/
++typedef struct gmac_conf {
++      struct net_device *dev;
++      int portmap;
++      int vid;
++      int flag;     /* 1: active  0: non-active */
++} sys_gmac_conf;
++
++/**********************************************************************
++ * GMAC private data
++ **********************************************************************/
++typedef struct {
++      unsigned int            rwptr_reg;
++      unsigned int            desc_base;
++      unsigned int            total_desc_num;
++      unsigned short          finished_idx;
++      GMAC_TXDESC_T           *curr_tx_desc;
++      GMAC_TXDESC_T           *curr_finished_desc;
++      struct sk_buff          *tx_skb[TX_DESC_NUM];
++      unsigned long           total_sent;
++      unsigned long           total_finished;
++      unsigned long           intr_cnt;
++} GMAC_SWTXQ_T;
++
++typedef struct {
++      unsigned int            desc_base;
++      unsigned long           eof_cnt;
++} GMAC_HWTXQ_T;
++
++typedef struct gmac_private{
++      struct net_device       *dev;
++      unsigned int            existed;
++      unsigned int            port_id;        // 0 or 1
++      unsigned int            base_addr;
++      unsigned int            dma_base_addr;
++      unsigned char           *mac_addr1;
++      unsigned char           *mac_addr2;
++      unsigned int            swtxq_desc_base;
++      unsigned int            hwtxq_desc_base;
++      GMAC_SWTXQ_T            swtxq[TOE_SW_TXQ_NUM];
++      GMAC_HWTXQ_T            hwtxq[TOE_HW_TXQ_NUM];
++      NONTOE_QHDR_T           *default_qhdr;
++      unsigned int            default_desc_base;
++      unsigned int            default_desc_num;
++      unsigned int            rx_curr_desc;
++      DMA_RWPTR_T                     rx_rwptr;
++      struct sk_buff          *curr_rx_skb;
++      dma_addr_t                      default_desc_base_dma;
++      dma_addr_t                      swtxq_desc_base_dma;
++      dma_addr_t                      hwtxq_desc_base_dma;
++      unsigned int            irq;
++      unsigned int            flow_control_enable     ;
++      unsigned int            pre_phy_status;
++      unsigned int            full_duplex_cfg;
++      unsigned int            speed_cfg;
++      unsigned int            auto_nego_cfg;
++      unsigned int            full_duplex_status;
++      unsigned int            speed_status;
++      unsigned int            phy_mode;       /* 0->MII 1->GMII 2->RGMII(10/100) 3->RGMII(1000) */
++      unsigned int            phy_addr;
++      unsigned int            intr0_enabled;  // 1: enabled
++      unsigned int            intr1_enabled;  // 1: enabled
++      unsigned int            intr2_enabled;  // 1: enabled
++      unsigned int            intr3_enabled;  // 1: enabled
++      unsigned int            intr4_enabled;  // 1: enabled
++//    unsigned int            intr4_enabled_1;        // 1: enabled
++      unsigned int            intr0_selected; // 1: selected
++      unsigned int            intr1_selected; // 1: selected
++      unsigned int            intr2_selected; // 1: selected
++      unsigned int            intr3_selected; // 1: selected
++      unsigned int            intr4_selected; // 1: selected
++      // void                                 (*gmac_rcv_handler)(struct sk_buff *, int);
++      struct net_device_stats ifStatics;
++      unsigned long           txDerr_cnt[GMAC_NUM];
++      unsigned long           txPerr_cnt[GMAC_NUM];
++      unsigned long           RxDerr_cnt[GMAC_NUM];
++      unsigned long           RxPerr_cnt[GMAC_NUM];
++      unsigned int            isr_rx_cnt;
++      unsigned int            isr_tx_cnt;
++      unsigned long           rx_discard;
++      unsigned long           rx_error;
++      unsigned long           rx_mcast;
++      unsigned long           rx_bcast;
++      unsigned long           rx_status_cnt[8];
++      unsigned long           rx_chksum_cnt[8];
++      unsigned long           rx_sta1_ucast;  // for STA 1 MAC Address
++      unsigned long           rx_sta2_ucast;  // for STA 2 MAC Address
++      unsigned long           mib_full_cnt;
++      unsigned long           rx_pause_on_cnt;
++      unsigned long           tx_pause_on_cnt;
++      unsigned long           rx_pause_off_cnt;
++      unsigned long           tx_pause_off_cnt;
++      unsigned long           rx_overrun_cnt;
++      unsigned long           status_changed_cnt;
++      unsigned long           default_q_cnt;
++      unsigned long           hw_fq_empty_cnt;
++      unsigned long           sw_fq_empty_cnt;
++      unsigned long           default_q_intr_cnt;
++      pid_t               thr_pid;
++      wait_queue_head_t   thr_wait;
++      struct completion   thr_exited;
++    spinlock_t          lock;
++    int                 time_to_die;
++    int                                       operation;
++#ifdef SL351x_GMAC_WORKAROUND
++    unsigned long             short_frames_cnt;
++#endif
++}GMAC_INFO_T ;
++
++typedef struct toe_private {
++      unsigned int    swfq_desc_base;
++      unsigned int    hwfq_desc_base;
++      unsigned int    hwfq_buf_base;
++//    unsigned int    toe_desc_base[TOE_TOE_QUEUE_NUM];
++//    unsigned int    toe_desc_num;
++//    unsigned int    class_desc_base;
++//    unsigned int    class_desc_num;
++//    unsigned int    intr_desc_base;
++//    unsigned int    intr_desc_num;
++//    unsigned int    intr_buf_base;
++      DMA_RWPTR_T             fq_rx_rwptr;
++      GMAC_INFO_T             gmac[GMAC_NUM];
++      dma_addr_t              sw_freeq_desc_base_dma;
++      dma_addr_t              hw_freeq_desc_base_dma;
++      dma_addr_t              hwfq_buf_base_dma;
++      dma_addr_t              hwfq_buf_end_dma;
++//    dma_addr_t              toe_desc_base_dma[TOE_TOE_QUEUE_NUM];
++//    dma_addr_t              class_desc_base_dma;
++//    dma_addr_t              intr_desc_base_dma;
++//    dma_addr_t              intr_buf_base_dma;
++//    unsigned long   toe_iq_intr_full_cnt[TOE_INTR_QUEUE_NUM];
++//    unsigned long   toe_iq_intr_cnt[TOE_INTR_QUEUE_NUM];
++//    unsigned long   toe_q_intr_full_cnt[TOE_TOE_QUEUE_NUM];
++//    unsigned long   class_q_intr_full_cnt[TOE_CLASS_QUEUE_NUM];
++//    unsigned long   class_q_intr_cnt[TOE_CLASS_QUEUE_NUM];
++} TOE_INFO_T;
++
++extern TOE_INFO_T toe_private_data;
++
++#define GMAC_PORT0    0
++#define GMAC_PORT1    1
++/**********************************************************************
++ * PHY Definition
++ **********************************************************************/
++#define HPHY_ADDR                     0x01
++#define GPHY_ADDR                     0x02
++
++enum phy_state
++{
++    LINK_DOWN   = 0,
++    LINK_UP     = 1
++};
++
++/* transmit timeout value */
++
++#endif //_GMAC_SL351x_H
+--- /dev/null
++++ b/include/asm-arm/arch-sl2312/sl351x_hash_cfg.h
+@@ -0,0 +1,365 @@
++/*-----------------------------------------------------------------------------------
++*     sl351x_hash_cfg.h
++*
++*     Description:
++*     
++*     History:
++*
++*     9/14/2005       Gary Chen       Create
++*
++*-------------------------------------------------------------------------------------*/
++#ifndef _SL351x_HASH_CFG_H_
++#define _SL351x_HASH_CFG_H_   1
++
++// #define NAT_DEBUG_MSG      1
++// #define DEBUG_NAT_MIXED_HW_SW_TX   1
++#ifdef DEBUG_NAT_MIXED_HW_SW_TX
++      // #define NAT_DEBUG_LAN_HASH_TIMEOUT   1
++      // #define NAT_DEBUG_WAN_HASH_TIMEOUT   1
++#endif
++
++#define IPIV(a,b,c,d)         ((a<<24)+(b<<16)+(c<<8)+d)
++#define       IPIV1(a)                        ((a>>24)&0xff)
++#define       IPIV2(a)                        ((a>>16)&0xff)
++#define IPIV3(a)                      ((a>>8)&0xff)
++#define IPIV4(a)                      ((a)&0xff)
++
++#define HASH_MAX_BYTES                        64      // 128
++#define HASH_ACTION_DWORDS            9
++#define HASH_MAX_DWORDS                       (HASH_MAX_BYTES / sizeof(u32))
++#define HASH_MAX_KEY_DWORD            (HASH_MAX_DWORDS - HASH_ACTION_DWORDS)
++#define HASH_INIT_KEY                 0x534C4F52
++#define HASH_BITS                             12      // 12 : Normal, 7: Simulation
++#define HASH_TOTAL_ENTRIES            (1 << HASH_BITS)
++#define HASH_MAX_ENTRIES              (1 << 12)
++#define HASH_TOE_ENTRIES              (HASH_TOTAL_ENTRIES >> 5)
++#define HASH_BITS_MASK                        ((1 << HASH_BITS) - 1)
++
++#define hash_lock(lock)                       // spin_lock_bh(lock)
++#define hash_unlock(lock)             // spin_unlock_bh(lock)
++
++/*----------------------------------------------------------------------
++ *  special macro
++ ----------------------------------------------------------------------*/
++#define HASH_PUSH_WORD(cp, data)      {*cp++ = (((u16)(data))     ) & 0xff;   \
++                                                                      *cp++ = (((u16)(data)) >> 8) & 0xff;} 
++#define HASH_PUSH_DWORD(cp, data)     {*cp++ = (u8)(((u32)(data))      ) & 0xff;      \
++                                                                      *cp++ = (u8)(((u32)(data)) >>  8) & 0xff;       \
++                                                                      *cp++ = (u8)(((u32)(data)) >> 16) & 0xff;       \
++                                                                      *cp++ = (u8)(((u32)(data)) >> 24) & 0xff;}
++#define HASH_PUSH_BYTE(cp, data)      {*cp++ = ((u8)(data)) & 0xff;}
++
++/*----------------------------------------------------------------------
++ *  key
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u8              port;
++      u16             Ethertype;
++      u8              da[6];
++      u8              sa[6];
++      u16             pppoe_sid;      
++      u16             vlan_id;        
++      u8              ipv4_hdrlen;    
++      u8              ip_tos; 
++      u8              ip_protocol;    
++      u32             ipv6_flow_label;
++      u8              sip[16];
++      u8              dip[16];
++      //__u32                 sip[4];
++      //__u32                 dip[4];
++      u8              l4_bytes[24];
++      u8              l7_bytes[24];
++      u8              ipv6;   // 1: IPv6, 0: IPV4
++} ENTRY_KEY_T;
++
++/*----------------------------------------------------------------------
++ *  key for NAT
++ *    Note: packed
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u16             Ethertype;              // not used
++      u8              port_id;
++      u8              rule_id;
++      u8              ip_protocol;
++      u8              reserved1;              // ip_tos, not used
++      u16             reserved2;              // not used
++      u32             sip;
++      u32             dip;
++      u16             sport;
++      u16             dport;
++} NAT_KEY_T;
++
++#define NAT_KEY_DWORD_SIZE    (sizeof(NAT_KEY_T)/sizeof(u32))
++#define NAT_KEY_SIZE          (sizeof(NAT_KEY_T))
++
++/*----------------------------------------------------------------------
++ *  key for NAT
++ *    Note: packed
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u16             Ethertype;              // not used
++      u8              port_id;
++      u8              rule_id;
++      u8              ip_protocol;
++      u8              reserved1;              // ip_tos, not used
++      u16             reserved2;              // not used
++      u32             sip;
++      u32             dip;
++      u16             reserved3;
++      u16             protocol;
++      u16             reserved4;
++      u16             call_id;
++} GRE_KEY_T;
++
++#define GRE_KEY_DWORD_SIZE    (sizeof(GRE_KEY_T)/sizeof(u32))
++#define GRE_KEY_SIZE          (sizeof(GRE_KEY_T))
++/*----------------------------------------------------------------------
++ *  key present or not
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u32             port                    : 1;
++      u32             Ethertype               : 1;
++      u32             da                              : 1;
++      u32             sa                              : 1;
++      u32             pppoe_sid               : 1;    
++      u32             vlan_id                 : 1;    
++      u32             ipv4_hdrlen             : 1;    
++      u32             ip_tos                  : 1;
++      u32             ip_protocol             : 1;    
++      u32             ipv6_flow_label : 1;
++      u32             sip                             : 1;
++      u32             dip                             : 1;
++      u32             l4_bytes_0_3    : 1;
++      u32             l4_bytes_4_7    : 1;
++      u32             l4_bytes_8_11   : 1;
++      u32             l4_bytes_12_15  : 1;
++      u32             l4_bytes_16_19  : 1;
++      u32             l4_bytes_20_23  : 1;
++      u32             l7_bytes_0_3    : 1;
++      u32             l7_bytes_4_7    : 1;
++      u32             l7_bytes_8_11   : 1;
++      u32             l7_bytes_12_15  : 1;
++      u32             l7_bytes_16_19  : 1;
++      u32             l7_bytes_20_23  : 1;
++      u32             reserved                : 8;
++} KEY_FIELD_T;
++
++/*----------------------------------------------------------------------
++ *  action
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u32             reserved0       : 5;    // bit 0:4
++      u32             pppoe           : 2;    // bit 5:6
++      u32             vlan            : 2;    // bit 7:8
++      u32             sa                      : 1;    // bit 9
++      u32             da                      : 1;    // bit 10
++      u32             Dport           : 1;    // bit 11
++      u32             Sport           : 1;    // bit 12
++      u32             Dip                     : 1;    // bit 13
++      u32             Sip                     : 1;    // bit 14
++      u32             sw_id           : 1;    // bit 15
++      u32             frag            : 1;    // bit 16
++      u32             option          : 1;    // bit 17
++      u32             ttl_0           : 1;    // bit 18
++      u32             ttl_1           : 1;    // bit 19
++      u32             mtu                     : 1;    // bit 20
++      u32             exception       : 1;    // bit 21
++      u32             srce_qid        : 1;    // bit 22
++      u32             discard         : 1;    // bit 23
++      u32             dest_qid        : 8;    // bit 24:31
++} ENTRY_ACTION_T;
++
++#define ACTION_DISCARD_BIT            BIT(23)
++#define ACTION_SRCE_QID_BIT           BIT(22)
++#define ACTION_EXCEPTION_BIT  BIT(21)
++#define ACTION_MTU_BIT                        BIT(20)
++#define ACTION_TTL_1_BIT              BIT(19)
++#define ACTION_TTL_0_BIT              BIT(18)
++#define ACTION_IP_OPTION              BIT(17)
++#define ACTION_FRAG_BIT                       BIT(16)
++#define ACTION_SWID_BIT                       BIT(15)
++#define ACTION_SIP_BIT                        BIT(14)
++#define ACTION_DIP_BIT                        BIT(13)
++#define ACTION_SPORT_BIT              BIT(12)
++#define ACTION_DPORT_BIT              BIT(11)
++#define ACTION_DA_BIT                 BIT(10)
++#define ACTION_SA_BIT                 BIT(9)
++#define ACTION_VLAN_DEL_BIT           BIT(8)
++#define ACTION_VLAN_INS_BIT           BIT(7)
++#define ACTION_PPPOE_DEL_BIT  BIT(6)
++#define ACTION_PPPOE_INS_BIT  BIT(5)
++#define ACTION_L4_THIRD_BIT           BIT(4)
++#define ACTION_L4_FOURTH_BIT  BIT(3)
++
++#define NAT_ACTION_BITS                       (ACTION_SRCE_QID_BIT  | ACTION_EXCEPTION_BIT |  \
++                                                              ACTION_TTL_1_BIT | ACTION_TTL_0_BIT |                   \
++                                                              ACTION_IP_OPTION | ACTION_FRAG_BIT |                    \
++                                                              ACTION_DA_BIT | ACTION_SA_BIT)
++#define NAT_LAN2WAN_ACTIONS           (NAT_ACTION_BITS | ACTION_SIP_BIT | ACTION_SPORT_BIT)
++#define NAT_WAN2LAN_ACTIONS           (NAT_ACTION_BITS | ACTION_DIP_BIT | ACTION_DPORT_BIT)
++#define NAT_PPPOE_LAN2WAN_ACTIONS     (NAT_LAN2WAN_ACTIONS | ACTION_PPPOE_INS_BIT)
++#define NAT_PPPOE_WAN2LAN_ACTIONS     (NAT_WAN2LAN_ACTIONS | ACTION_PPPOE_DEL_BIT)
++#define NAT_PPTP_LAN2WAN_ACTIONS      (NAT_ACTION_BITS | ACTION_SIP_BIT | ACTION_L4_FOURTH_BIT)
++#define NAT_PPTP_WAN2LAN_ACTIONS      (NAT_ACTION_BITS | ACTION_DIP_BIT | ACTION_L4_FOURTH_BIT)
++#define NAT_PPPOE_PPTP_LAN2WAN_ACTIONS        (NAT_PPTP_LAN2WAN_ACTIONS | ACTION_PPPOE_INS_BIT)
++#define NAT_PPPOE_PPTP_WAN2LAN_ACTIONS        (NAT_PPTP_WAN2LAN_ACTIONS | ACTION_PPPOE_DEL_BIT)
++                                                              
++/*----------------------------------------------------------------------
++ *  parameter
++ ----------------------------------------------------------------------*/
++typedef struct {
++      u8              da[6];
++      u8              sa[6];
++      u16             vlan;   
++      u16     pppoe;  
++      u32             Sip;
++      u32             Dip;
++      u16     Sport;  
++      u16     Dport;  
++      u16     sw_id;  
++      u16     mtu;    
++} ENTRY_PARAM_T;
++
++/*----------------------------------------------------------------------
++ *  Hash Entry
++ ----------------------------------------------------------------------*/
++typedef struct {
++      char                    rule;
++      ENTRY_KEY_T             key;
++      KEY_FIELD_T             key_present;
++      ENTRY_ACTION_T  action;
++      ENTRY_PARAM_T   param;
++      int                             index;
++      int                             total_dwords;
++} HASH_ENTRY_T;
++
++/*----------------------------------------------------------------------
++ *  NAT Hash Entry
++ ----------------------------------------------------------------------*/
++typedef struct {
++      short   counter;
++      short   interval;
++} HASH_TIMEOUT_T;
++
++/*----------------------------------------------------------------------
++ *  NAT Hash Entry for TCP/UDP protocol
++ ----------------------------------------------------------------------*/
++typedef struct {
++      NAT_KEY_T                       key;
++      union {
++              u32                             dword;
++              ENTRY_ACTION_T  bits;
++      } action;
++      ENTRY_PARAM_T           param;
++      HASH_TIMEOUT_T          tmo;    // used by software only, to use memory space efficiently
++} NAT_HASH_ENTRY_T;
++
++#define NAT_HASH_ENTRY_SIZE           (sizeof(NAT_HASH_ENTRY_T))
++
++/*----------------------------------------------------------------------
++ *  GRE Hash Entry for PPTP/GRE protocol
++ ----------------------------------------------------------------------*/
++typedef struct {
++      GRE_KEY_T                       key;
++      union {
++              u32                             dword;
++              ENTRY_ACTION_T  bits;
++      } action;
++      ENTRY_PARAM_T           param;
++      HASH_TIMEOUT_T          tmo;    // used by software only, to use memory space efficiently
++} GRE_HASH_ENTRY_T;
++
++#define GRE_HASH_ENTRY_SIZE           (sizeof(GRE_HASH_ENTRY_T))
++
++/*----------------------------------------------------------------------
++ *  External Variables
++ ----------------------------------------------------------------------*/
++extern char                           hash_tables[HASH_TOTAL_ENTRIES][HASH_MAX_BYTES] __attribute__ ((aligned(16)));
++extern u32                            hash_nat_owner_bits[HASH_TOTAL_ENTRIES/32];
++/*----------------------------------------------------------------------
++* hash_get_valid_flag
++*----------------------------------------------------------------------*/
++static inline int hash_get_valid_flag(int index)
++{
++      volatile u32 *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++
++#ifdef SL351x_GMAC_WORKAROUND
++      if (index >= (0x80 * 8) && index < (0x8c * 8))
++              return 1;
++#endif        
++      return (hash_valid_bits_ptr[index/32] & (1 << (index %32)));
++}
++
++/*----------------------------------------------------------------------
++* hash_get_nat_owner_flag
++*----------------------------------------------------------------------*/
++static inline int hash_get_nat_owner_flag(int index)
++{
++      return (hash_nat_owner_bits[index/32] & (1 << (index %32)));
++}
++
++/*----------------------------------------------------------------------
++* hash_validate_entry
++*----------------------------------------------------------------------*/
++static inline void hash_validate_entry(int index)
++{
++      volatile u32    *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++      register int    ptr = index/32, bits = 1 << (index %32);
++      
++      hash_valid_bits_ptr[ptr] |= bits;
++}
++
++/*----------------------------------------------------------------------
++* hash_invalidate_entry
++*----------------------------------------------------------------------*/
++static inline void hash_invalidate_entry(int index)
++{
++      volatile u32 *hash_valid_bits_ptr = (volatile u32 *)TOE_V_BIT_BASE;
++      register int    ptr = index/32, bits = 1 << (index %32);
++      
++      hash_valid_bits_ptr[ptr] &= ~(bits);
++}
++
++/*----------------------------------------------------------------------
++* hash_nat_enable_owner
++*----------------------------------------------------------------------*/
++static inline void hash_nat_enable_owner(int index)
++{
++      hash_nat_owner_bits[index/32] |= (1 << (index % 32));
++}
++
++/*----------------------------------------------------------------------
++* hash_nat_disable_owner
++*----------------------------------------------------------------------*/
++static inline void hash_nat_disable_owner(int index)
++{
++      hash_nat_owner_bits[index/32] &= ~(1 << (index % 32));
++}
++
++/*----------------------------------------------------------------------
++* hash_get_entry
++*----------------------------------------------------------------------*/
++static inline void *hash_get_entry(int index)
++{
++      return (void*) &hash_tables[index][0];
++}
++
++/*----------------------------------------------------------------------
++* Functions
++*----------------------------------------------------------------------*/
++extern int hash_add_entry(HASH_ENTRY_T *entry);
++extern void sl351x_hash_init(void);
++extern void hash_set_valid_flag(int index, int valid);
++extern void hash_set_nat_owner_flag(int index, int valid);
++extern void *hash_get_entry(int index);
++extern int hash_build_keys(u32 *destp, HASH_ENTRY_T *entry);
++extern void hash_build_nat_keys(u32 *destp, HASH_ENTRY_T *entry);
++extern int hash_write_entry(HASH_ENTRY_T *entry, u8 *key);
++extern int hash_add_entry(HASH_ENTRY_T *entry);
++extern        u16 hash_crc16(u16 crc, u8 *datap, u32 len);
++extern        u16 hash_gen_crc16(u8 *datap, u32 len);
++
++#endif // _SL351x_HASH_CFG_H_
++
++
++
+--- /dev/null
++++ b/include/asm-arm/arch-sl2312/sl351x_nat_cfg.h
+@@ -0,0 +1,211 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.                
++*--------------------------------------------------------------------------
++*     sl_nat_cfg.h
++*
++*     Description:
++*             - Define the Device Control Commands for NAT Configuration
++*     
++*     History:
++*
++*     4/28/2006       Gary Chen       Create
++*
++*-----------------------------------------------------------------------------*/
++#ifndef _SL351x_NAT_CFG_H_
++#define _SL351x_NAT_CFG_H_    1
++
++/*----------------------------------------------------------------------
++* Confiuration
++*----------------------------------------------------------------------*/
++#ifdef CONFIG_NETFILTER
++#define CONFIG_SL351x_NAT                     1
++#undef CONFIG_SL351x_NAT
++#undef CONFIG_SL351x_SYSCTL
++#endif
++#define CONFIG_NAT_MAX_IP_NUM         4       // per device (eth0 or eth1)
++#define CONFIG_NAT_MAX_XPORT          64
++#define CONFIG_NAT_MAX_WRULE          16      // per Queue
++#define CONFIG_NAT_TXQ_NUM                    4
++/*----------------------------------------------------------------------
++* Command set
++*----------------------------------------------------------------------*/
++#define SIOCDEVSL351x SIOCDEVPRIVATE  // 0x89F0
++#define NATSSTATUS            0
++#define NATGSTATUS            1
++#define NATSETPORT            2
++#define NATGETPORT            3
++#define NATADDIP              4
++#define NATDELIP              5
++#define NATGETIP              6
++#define NATAXPORT             7
++#define NATDXPORT             8
++#define NATGXPORT             9
++#define NATSWEIGHT            10
++#define NATGWEIGHT            11
++#define NATAWRULE             12
++#define NATDWRULE             13
++#define NATGWRULE             14
++#define NATSDEFQ              15
++#define NATGDEFQ              16
++#define NATRMIPCFG            17              // remove IP config
++#define NATTESTENTRY  18
++#define NATSETMEM             19
++#define NATSHOWMEM            20
++/*----------------------------------------------------------------------
++* Command Structure
++*----------------------------------------------------------------------*/
++// Common Header
++typedef struct {
++      unsigned short          cmd;    // command ID
++      unsigned short          len;    // data length, excluding this header
++} NATCMD_HDR_T;
++
++// NATSSTATUS & NATGSTATUS commands
++typedef struct {
++      unsigned char           enable;
++} NAT_STATUS_T;       
++
++// NATSETPORT & NATGETPORT commands
++typedef struct {
++      unsigned char           portmap;
++} NAT_PORTCFG_T;
++
++typedef struct {
++      unsigned int            ipaddr;
++      unsigned int            netmask;
++} NAT_IP_ENTRY_T;
++
++// NATADDIP & NATDELIP commands
++typedef struct {
++      NAT_IP_ENTRY_T  entry;
++} NAT_IPCFG_T;
++
++// NATGETIP command
++typedef struct {
++      unsigned int    total;
++      NAT_IP_ENTRY_T  entry[CONFIG_NAT_MAX_IP_NUM];
++} NAT_IPCFG_ALL_T;
++
++typedef struct {
++      unsigned int            protocol;
++      unsigned short          sport_start;
++      unsigned short          sport_end;
++      unsigned short          dport_start;
++      unsigned short          dport_end;
++} NAT_XPORT_ENTRY_T;
++
++// NATAXPORT & NATDXPORT Commands
++typedef struct {
++      NAT_XPORT_ENTRY_T       entry;
++} NAT_XPORT_T;
++
++// NATGXPORT Command
++typedef struct {
++      unsigned int            total;
++      NAT_XPORT_ENTRY_T       entry[CONFIG_NAT_MAX_XPORT];
++} NAT_XPORT_ALL_T;
++
++// NATSWEIGHT & NATGWEIGHT Commands
++typedef struct {
++      unsigned char           weight[CONFIG_NAT_TXQ_NUM];
++} NAT_WEIGHT_T;
++
++typedef struct {
++      unsigned int            protocol;
++      unsigned int            sip_start;
++      unsigned int            sip_end;
++      unsigned int            dip_start;
++      unsigned int            dip_end;
++      unsigned short          sport_start;
++      unsigned short          sport_end;
++      unsigned short          dport_start;
++      unsigned short          dport_end;
++} NAT_WRULE_ENTRY_T;  
++
++// NATAWRULE & NATDWRULE Commands
++typedef struct {
++      unsigned int            qid;
++      NAT_WRULE_ENTRY_T       entry;
++} NAT_WRULE_T;
++
++// NATGWRULE Command
++typedef struct {
++      unsigned int            total;
++      NAT_WRULE_ENTRY_T       entry[CONFIG_NAT_MAX_WRULE];
++} NAT_WRULE_ALL_T;
++
++// NATSDEFQ & NATGDEFQ commands
++typedef struct {
++      unsigned int            qid;
++} NAT_QUEUE_T;        
++
++// NATTESTENTRY 
++typedef struct {
++      u_int16_t               cmd;    // command ID
++      u_int16_t               len;    // data length, excluding this header
++      u_int8_t                init_enable;
++} NAT_TESTENTRY_T;    
++      
++typedef union
++{
++      NAT_STATUS_T            status;
++      NAT_PORTCFG_T           portcfg;
++      NAT_IPCFG_T                     ipcfg;
++      NAT_XPORT_T                     xport;
++      NAT_WEIGHT_T            weight;
++      NAT_WRULE_T                     wrule;
++      NAT_QUEUE_T                     queue;
++      NAT_TESTENTRY_T init_entry;
++} NAT_REQ_E;
++      
++/*----------------------------------------------------------------------
++* NAT Configuration
++*     - Used by driver only
++*----------------------------------------------------------------------*/
++typedef struct {
++      unsigned int            enabled;
++      unsigned int            init_enabled;
++      unsigned int            tcp_udp_rule_id;
++      unsigned int            gre_rule_id;
++      unsigned int            lan_port;
++      unsigned int            wan_port;
++      unsigned int            default_hw_txq;
++      short                           tcp_tmo_interval;
++      short                           udp_tmo_interval;
++      short                           gre_tmo_interval;
++      NAT_IPCFG_ALL_T         ipcfg[2];       // LAN/WAN port
++      NAT_XPORT_ALL_T         xport;
++      NAT_WEIGHT_T            weight;
++      NAT_WRULE_ALL_T         wrule[CONFIG_NAT_TXQ_NUM];
++} NAT_CFG_T;
++
++/*----------------------------------------------------------------------
++* NAT Control Block
++*     - Used by driver only
++*     - Stores LAN-IN or WAN-IN information
++*     - WAN-OUT and LAN-OUT driver use them to build up a hash entry
++*     - NOTES: To update this data structure, MUST take care of alignment issue
++*   -          MUST make sure that the size of skbuff structure must 
++*            be larger than (40 + sizof(NAT_CB_T))
++*----------------------------------------------------------------------*/
++typedef struct {
++      unsigned short          tag;
++      unsigned char           sa[6];
++      unsigned int            sip;
++      unsigned int            dip;
++      unsigned short          sport;
++      unsigned short          dport;
++      unsigned char           pppoe_frame;
++      unsigned char           state;                  // same to enum tcp_conntrack
++      unsigned char           reserved[2];
++} NAT_CB_T;
++
++#define NAT_CB_TAG            0x4C53  // "SL"
++#define NAT_CB_SIZE           sizeof(NAT_CB_T)
++// #define NAT_SKB_CB(skb)    (NAT_CB_T *)(((unsigned int)&((skb)->cb[40]) + 3) & ~3)  // for align 4
++#define NAT_SKB_CB(skb)       (NAT_CB_T *)&((skb)->cb[40])  // for align 4
++
++#endif // _SL351x_NAT_CFG_H_
++
++
++
+--- /dev/null
++++ b/include/asm-arm/arch-sl2312/sl351x_toe.h
+@@ -0,0 +1,88 @@
++/**************************************************************************
++* Copyright 2006 StorLink Semiconductors, Inc.  All rights reserved.
++*--------------------------------------------------------------------------
++* Name                        : sl351x_toe.h
++* Description :
++*             Define for TOE driver of Storlink SL351x
++*
++* History
++*
++*     Date            Writer          Description
++*----------------------------------------------------------------------------
++*                             Xiaochong       Create
++*
++****************************************************************************/
++#ifndef __SL351x_TOE_H
++#define __SL351x_TOE_H        1
++#include <net/sock.h>
++#include <asm/arch/sl351x_gmac.h>
++#include <linux/timer.h>
++#include <linux/netdevice.h>
++#include <linux/ip.h>
++#include <linux/if_ether.h>
++/*
++ * TOE_CONN_T is data structure of tcp connection info, used at both
++ * device layer and kernel tcp layer
++ * skb is the jumbo frame
++ */
++
++struct toe_conn{
++      __u8    qid;            // connection qid 0~63.
++      __u8    ip_ver;         // 0: not used; 4: ipv4; 6: ipv6.
++      /* hash key of the connection */
++      __u16   source;
++      __u16   dest;
++      __u32   saddr[4];
++      __u32   daddr[4];
++
++      __u32   seq;
++      __u32   ack_seq;
++
++      /* these fields are used to set TOE QHDR */
++      __u32   ack_threshold;
++      __u32   seq_threshold;
++      __u16   max_pktsize;
++
++      /* used by sw toe, accumulated ack_seq of ack frames */
++      __u16   ack_cnt;
++      /* used by sw toe, accumulated data frames held at driver */
++      __u16   cur_pktsize;
++
++      __u8    status;
++#define       TCP_CONN_UNDEFINE               0X00
++#define       TCP_CONN_CREATION               0X01
++#define       TCP_CONN_CONNECTING             0X02
++#define       TCP_CONN_ESTABLISHED    0X04
++#define       TCP_CONN_RESET                  0X08    // this is used for out-of-order
++                                                      // or congestion window is small
++#define       TCP_CONN_CLOSING                0X10
++#define       TCP_CONN_CLOSED                 0x11
++
++      __u16   hash_entry_index;       /* associated hash entry */
++
++      // one timer per connection. Otherwise all connections should be scanned
++      // in a timeout interrupt, and timeout interrupt is triggered no matter
++      // a connection is actually timeout or not.
++      struct timer_list       rx_timer;
++      unsigned long           last_rx_jiffies;
++      GMAC_INFO_T                     *gmac;
++      struct net_device       *dev;
++
++      //      for generating pure ack frame.
++      struct ethhdr           l2_hdr;
++      struct iphdr            l3_hdr;
++
++      spinlock_t                      conn_lock;
++      DMA_RWPTR_T                     toeq_rwptr;
++      GMAC_RXDESC_T           *curr_desc;
++      struct sk_buff          *curr_rx_skb;
++};
++
++struct jumbo_frame {
++      struct sk_buff  *skb0;          // the head of jumbo frame
++      struct sk_buff  *tail;          // the tail of jumbo frame
++      struct iphdr    *iphdr0;        // the ip hdr of skb0.
++      struct tcphdr   *tcphdr0;       // the tcp hdr of skb0.
++};
++
++#endif // __SL351x_TOE_H
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2131,6 +2131,42 @@
+         The safe and default value for this is N.
++config NET_GMAC
++      tristate "Storlink Gigabit Ethernet support"
++      depends on ARCH_SL2312
++      help
++        This driver supports Storlink dual Gigabit Ethernet.
++
++config NET_SL2312
++      tristate "Storlink Gigabit Ethernet support"
++      depends on NET_GMAC
++      help
++        This driver supports Storlink dual Gigabit Ethernet.
++
++config NET_SL351X
++      tristate "Storlink Lepus Gigabit Ethernet support"
++      depends on NET_GMAC
++      help
++        This driver supports Storlink TOE and NAT dual Gigabit Ethernet.
++
++config SL2312_TSO
++      bool "Tx Segmentation Enable"
++      depends on NET_GMAC
++      help
++        TBD
++
++config SL2312_MPAGE
++      bool "Tx Multipage Enable"
++      depends on NET_GMAC
++      help
++        TBD
++
++config SL2312_RECVFILE
++      bool "Rx Multipage Enable"
++      depends on NET_GMAC
++      help
++        TBD
++
+ config DL2K
+       tristate "D-Link DL2000-based Gigabit Ethernet support"
+       depends on PCI
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -236,4 +236,8 @@
+ obj-$(CONFIG_FS_ENET) += fs_enet/
+-obj-$(CONFIG_NETXEN_NIC) += netxen/
++
++obj-$(CONFIG_NET_SL351X)+= sl351x_gmac.o sl351x_nat.o sl351x_hash.o sl351x_crc16.o sl351x_proc.o sl_switch.o
++obj-$(CONFIG_NET_SL2312)+= sl2312_emac.o
++
++