/*
 *  linux/drivers/net/8139emb.c 
 *  A Linux driver for the embedded RTL8139 inside the RTL8181 SoC
 *
 *  Based on linux/drivers/net/8139too.c
 *  Copyright 2000-2002 Jeff Garzik <jgarzik@mandrakesoft.com>
 *
 *  Modified by Realtek and distributed as part of the RTL8181 SDK
 *  Cleaned up by Streetdata (streetdata at users.sourceforge.net)
 *
 *  Portions Copyright (C) Realtek Semiconductors
 *  Portions Copyright (C) 2004, Streetdata Pty Ltd
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/circ_buf.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/ip.h>
#include <asm/io.h>
#include <asm/rtl8181.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#define TRUE 1
#define FALSE 0

#define RTL8139AP_CHECKSUM_OFFLOAD TRUE
//#define REALHACK_RECV TRUE	/* Realtek RECV congestion hack */
//#define REALHACK_IMTR TRUE	/* Realtek IMTR undocumented hack */
//#define RTL8139_EARLY_FREE

#define RTL8139_VERSION "0.9.10"
#define RTL8139_MODULE_NAME "8139too"
#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
#define PFX RTL8139_MODULE_NAME ": "

#undef RTL8139_DEBUG

/* define to 1 to disable lightweight runtime debugging checks */
#define RTL8139_NDEBUG

#ifdef RTL8139_DEBUG
/* note: prints function name for you */
#  define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#  define DPRINTK(fmt, args...)
#endif

#ifdef RTL8139_NDEBUG
#  define assert(expr) do {} while (0)
#else
#  define assert(expr) \
        if(!(expr)) {					\
        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
        #expr,__FILE__,__FUNCTION__,__LINE__);		\
        }
#endif

#define arraysize(x)            (sizeof(x)/sizeof(*(x)))


/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 20;
#define  MAX_RX_INTERRUPT_WORK  58 

/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
static int multicast_filter_limit = 32;

/*-----------------------------------------------------------------------------
						Some flags about Rx/Tx
------------------------------------------------------------------------------*/	

typedef struct 
{
	int header;
	int tag;
	int addr;
	int dummy;
}desc_t;


#define NUM_DESC 64	


/*-----------------Rx	Flags------------------------*/
#define NUM_RX_DESC	(NUM_DESC)
// please refer to net/core/skbuff.c to find the reasons... sizeof(struct skb_shared_info)==0x3c)
//#define RX_BUF_LEN (2048*2 - 16 - (sizeof(struct skb_shared_info)))		// Allocate skb size
#define RX_BUF_LEN (2048 - 16 - (sizeof(struct skb_shared_info)))		// Allocate skb size
#define RX_DESC_SIZE	(NUM_RX_DESC * sizeof(desc_t))


/*-----------------Rx	Flags------------------------*/
#define NUM_TX_DESC	(NUM_DESC)
#define TX_DESC_SIZE	(NUM_TX_DESC * sizeof(desc_t))

#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */


/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT  (6*HZ)

/* Some handy defines */
#define RTL8181_MAC0_ADDR 0x1f0000
#define RTL8181_MAC1_ADDR 0x2f0000
#define RTL8181_MAC0_IRQ 4
#define RTL8181_MAC1_IRQ 5

#ifdef CONFIG_RTL8181_SWAPMACS /* Formerly CONFIG_RTL8181_8305PATCH */
#define RTL8181_ETH0_ADDR RTL8181_MAC1_ADDR 
#define RTL8181_ETH1_ADDR RTL8181_MAC0_ADDR 
#define RTL8181_ETH0_IRQ  RTL8181_MAC1_IRQ
#define RTL8181_ETH1_IRQ  RTL8181_MAC0_IRQ
#else
#define RTL8181_ETH0_ADDR RTL8181_MAC0_ADDR 
#define RTL8181_ETH1_ADDR RTL8181_MAC1_ADDR 
#define RTL8181_ETH0_IRQ  RTL8181_MAC0_IRQ
#define RTL8181_ETH1_IRQ  RTL8181_MAC1_IRQ
#endif

/* 
 * Values borrowed from Realtek's original driver
 */
#define MII_PHY8305_ETH0	0x1e010
#define MII_PHY8305_ETH1	0x46000
#define MII_PHY8201			0x16000

enum	RxBurstConfig	{
	RxBurst_64  = 0x0,
	RxBurst_128 = 0x1,
	RxBurst_256 = 0x2,
	RxBurst_512 = 0x3,	
};


enum	TxBurstConfig	{
	TxBurst_32  = 0x0,
	TxBurst_64  = 0x2,
	TxBurst_128 = 0x3,
	TxBurst_256 = 0x4,
	TxBurst_512 = 0x5,
	TxBurst_all = 0x6,
};


enum NIC_CNTRL_REGISTERS {
	RxBLenShift = 30, 
	RxBLenMask  = ( BIT(31) | BIT(30) ),
	TxBLenShift = 26,
	TxBLenMask  = ( BIT(28)  | BIT(27) | BIT(26) ),
	TxDescFN    = BIT(24),
	Reset	    = BIT(20),
	RxEnable    = BIT(19),
	TxEnable    = BIT(18),
	TxFCenable  = BIT(17),
	RxChkSum    = BIT(13),

  	AER	= BIT(8),		/* AcceptErr */
	AB  = BIT(7),		/* AcceptBroadcast */
	AM  = BIT(6),		/* AcceptMulticast */
	AMP = BIT(5),		/* AcceptMyPhys */
	AAP = BIT(4),		/* AcceptAllPhys */
	ATM = BIT(3),
	AR  = BIT(2),
	ALEN= BIT(1),
};

/* Interrupt register bits, using my own meaningful names. */
enum NIC_INTERRUPT_MASK {
	LinkChMask	= BIT(9),
	LinkChStats	= BIT(9),
	RxErrMask	= BIT(8),
	RxErrStats	= BIT(8),
	TxErrMask	= BIT(7),
	TxErrStats	= BIT(7),
	RxOkMask	= BIT(6),
	RxOkStats	= BIT(6),
	TxOkMask	= BIT(5),
	TxOkStats	= BIT(5),
	RxFFOvMask	= BIT(4),
	RxFFOvStats	= BIT(4),
	RxDescUnMask	= BIT(3),
	RxDescUnStats	= BIT(3),
	TxDescUnMask	= BIT(1),
	TxDescUnStats	= BIT(1),
};

enum RTL8139_DESC_ATTRIBUTE { 
	OWNBYNIC	=0x80000000,
	ENDOFRING	=0x40000000,
	FIRSTSEG	=0x20000000,
	LASTSEG		=0x10000000,
	TXLENMASK	=0x0000ffff,
	TXERR		=0x00800000,
	TXERR_OUTOFWIN	=0x00400000,
	TXERR_LINKF	=0x00200000,
	TXERR_COLLISION	=0x00100000,
	RXLENMASK	=0x00001FFF,
	RXERR		=0x00100000,
	RXRUNT		=0x00080000,
	RXCRC		=0x00040000,
	RX_PID0		=(1 << 16),
	RX_PID1		=(1 << 17),
	PROTO_TCP	=1,
	PROTO_UDP	=2,
	PROTO_IP	=3,
	TCPFail		= (1 << 13),
	UDPFail		= (1 << 14),
	IPFail		= (1 << 15),
	TcpTxCsumEn	= (1 << 16),
	UdpTxCsumEn	= (1 << 17),
	IpTxCsumEn	= (1 << 18),
};


struct rtl8139_private {
	void *mmio_addr;
	struct net_device_stats stats;
#ifdef REALHACK_RECV
	struct timer_list timer;
	struct timer_list rxtimer;
#endif
#ifdef REALHACK_IMTR
	struct timer_list imtrtimer;	// timer for tuning imtr	
#endif
	unsigned int rxinterrupt_count;
	unsigned int intr_mask;	

	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
	desc_t	*rx_desc;
	struct sk_buff * rx_skb[NUM_RX_DESC];

	unsigned int tx_flag;
	atomic_t cur_tx;
	atomic_t dirty_tx;
	desc_t 	 *tx_desc;	/* Tx bounce buffers */
	struct sk_buff * tx_skb[NUM_TX_DESC];

	char phys[4];		/* MII device addresses. */
	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
	unsigned int duplex_lock:1;
	unsigned int default_port:4;	/* Last dev->if_port value. */
	unsigned int media2:4;	/* Secondary monitored media port. */
	unsigned int medialock:1;	/* Don't sense media type. */
	unsigned int mediasense:1;	/* Media sensing in progress. */
	unsigned char MacAddr[6];
	unsigned int  netrxdrop;	
	spinlock_t lock;  // we only need this lock in case of SMP
};

static void rtl8139_chip_reset (void *ioaddr);
static int  rtl8139_sw_init(struct rtl8139_private *tp);
static int  rtl8139_open (struct net_device *dev);
#if 0
static int  mdio_read (struct net_device *dev, int phy_id, int location);
static void mdio_write (struct net_device *dev, int phy_id, int location, int val);
#endif
#ifdef REALHACK_RECV
static void rtl8139_timer (unsigned long data);
static void rtl8139_rxtimer (unsigned long data);
#endif
#ifdef REALHACK_IMTR
static void rtl8139_imtrtimer (unsigned long data);
#endif
static void rtl8139_tx_timeout (struct net_device *dev);
static int  rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev);
static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static int  rtl8139_close (struct net_device *dev);
static int  mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
static inline u32 ether_crc (int length, unsigned char *data);
static void rtl8139_set_rx_mode (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
static int rtl8139_sw_free(struct rtl8139_private *tp);
static void rtl8139_txrx_stop (struct rtl8139_private *tp);

#define RTL_W32_F(reg, val32)	outl ((val32), (int)(ioaddr + (reg)))
#define RTL_W32		RTL_W32_F
#define RTL_R32(reg)		inl ((int)(ioaddr + (reg)))

static const int rtl8139_intr_mask =
        LinkChMask |  RxOkMask | RxFFOvMask | RxDescUnMask |
        TxOkMask |  TxDescUnMask;

#ifdef RTL8139AP_CHECKSUM_OFFLOAD 
static const unsigned int rtl8139_trx_config =
			(((TxBurst_256  << TxBLenShift) & TxBLenMask) 
			     |  ((RxBurst_64  << RxBLenShift) & RxBLenMask)) | RxChkSum ; 
#else
static const unsigned int rtl8139_trx_config =
            (((TxBurst_256  << TxBLenShift) & TxBLenMask)
                 |  ((RxBurst_64  << RxBLenShift) & RxBLenMask)) ;

#endif

#ifdef RTL8139AP_CHECKSUM_OFFLOAD
static inline unsigned int rx_csum_ok(unsigned int status)
{
	unsigned int protocol = (status >> 16) & 0x3;
	if ((protocol == PROTO_IP) && (!(status & IPFail)))
		return 1;
	else if ((protocol == PROTO_TCP) && (!(status & TCPFail)))
		return 1;
	else if ((protocol == PROTO_UDP) && (!(status & UDPFail)))
		return 1;
	else
		return 0;
}
#endif

static void rtl8139_chip_reset (void *ioaddr)
{
	int i;

	/* Soft reset the chip. */
	RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1)) | Reset);

	/* Check that the chip has finished the reset. */
	for (i = 1000; i > 0; i--) {
	//	barrier();
		if ((RTL_R32 (NIC_CNR1) & Reset) == 0)
			break;
		udelay (10);
	}
	RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1)) &( ~Reset));
}

// Obviously, the job of init_one only to setup ioaddr, hardware reset.
// All the software initialization will be done in rtl8139_open
static int rtl8139_set_hwaddr(struct net_device *dev, void *addr)
{
	unsigned long flags, reg;
	int i;
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	unsigned char *p ;
	p = ((struct sockaddr *)addr)->sa_data;
	save_flags(flags); cli();

	for (i = 0; i < 6; ++i){
		dev->dev_addr[i] = p[i];
        //printk("setup %s hw_address %d : %X\n", dev->name, i, p[i]);
	}

	reg = *(unsigned long *)(dev->dev_addr);
	//printk("programming NIC_ID0=%08X", cpu_to_le32(reg));
	RTL_W32(NIC_ID, (cpu_to_le32(reg)));	

	reg = *(unsigned long *)((unsigned long)dev->dev_addr + 4);
	reg = reg & 0xffff0000;
	//printk("programming NIC_ID0 + 4=%08X", cpu_to_le32(reg));
	RTL_W32(NIC_ID + 4, (cpu_to_le32(reg)));
	restore_flags(flags);
	return 0;
}	


static int __init rtl8139_init_one (int nic_nr)
{
	struct net_device *dev = NULL;
	struct rtl8139_private *tp;
	void *ioaddr = NULL;

	DPRINTK ("ENTER\n");

	/* dev zeroed in init_etherdev */
	dev = init_etherdev (NULL, sizeof (*tp));
	if (dev == NULL) {
		printk (KERN_ERR PFX "unable to alloc new ethernet\n");
		DPRINTK ("EXIT, returning -ENOMEM\n");
		return -ENOMEM;
	}
	tp = dev->priv;
	// for MAC address
	tp->MacAddr[0] = 0x00 ;
	tp->MacAddr[1] = 0x11 ;
	tp->MacAddr[2] = 0x22 + 4*nic_nr;
	tp->MacAddr[3] = 0x33 ;
	tp->MacAddr[4] = 0x44 ;
	tp->MacAddr[5] = 0x00 ; 

	memcpy(dev->dev_addr, tp->MacAddr, 6);

	if (nic_nr == 0) {
		ioaddr = (void *)RTL8181_ETH0_ADDR;
		dev->irq = RTL8181_ETH0_IRQ;
	} else {
		ioaddr = (void *)RTL8181_ETH1_ADDR;
		dev->irq = RTL8181_ETH1_IRQ;
	}

	//tp->nic_nr = nic_nr;
	//assigned MAC address by driver, instead of reading eeprom
	//* The Rtl8139-specific entries in the device structure. */
	dev->base_addr = (unsigned long) ioaddr;
	dev->open = rtl8139_open;
	dev->hard_start_xmit = rtl8139_start_xmit;
	dev->stop = rtl8139_close;
	dev->get_stats = rtl8139_get_stats;
	dev->set_multicast_list = rtl8139_set_rx_mode;
	dev->do_ioctl = mii_ioctl;
	dev->tx_timeout = rtl8139_tx_timeout;
	dev->watchdog_timeo = TX_TIMEOUT;
	dev->set_mac_address = rtl8139_set_hwaddr; 
#ifdef RTL8139AP_CHECKSUM_OFFLOAD
	dev->features |= ( NETIF_F_IP_CSUM );
	//dev->features |= ( NETIF_F_HW_CSUM | NETIF_F_SG);
#endif
	tp->mmio_addr = ioaddr;
	tp->lock = SPIN_LOCK_UNLOCKED;
	tp->phys[0] = 32;

	rtl8139_chip_reset(ioaddr);

	DPRINTK ("EXIT - returning 0\n");
	return 0;
}

static void __init rtl8139_init_all (void)
{
	rtl8139_init_one(0);
#ifndef CONFIG_RTL8181_AP	
	rtl8139_init_one(1);
#endif	
}


#if 0
static void rtl8139_quick_reset(struct net_device *dev,struct rtl8139_private *tp, void *ioaddr)
{
	unsigned long flags;
	netif_stop_queue (dev);
	save_flags(flags);cli();
	rtl8139_txrx_stop (tp);
    rtl8139_sw_free(tp);
    rtl8139_sw_init(tp);
    rtl8139_hw_start (dev);
	restore_flags(flags);
}
#endif

/* MII serial management: mostly bogus for now. */
/* Read and write the MII management registers using software-generated
   serial MDIO protocol.
   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
   "overclocking" issues. */
#define MDIO_DIR		0x80
#define MDIO_DATA_OUT	0x04
#define MDIO_DATA_IN	0x02
#define MDIO_CLK		0x01
#define MDIO_WRITE0 (MDIO_DIR)
#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)

#define mdio_delay()	readb(mdio_addr)


static void SetOwnByNic(unsigned int* header, int len, int own,int index)
{
	int tmp = (own | FIRSTSEG | LASTSEG | len) ;
	
	if ( index == NUM_DESC - 1)	
		tmp |= ENDOFRING;
	
	*(volatile unsigned long *)header = tmp;
}


// The job of this sub-routine is to allocate sw buffer for all purpose
static int rtl8139_sw_init(struct rtl8139_private *tp)
{
	int i;
	unsigned char* page_ptr;
	struct sk_buff *skb_ptr;	
	
	page_ptr = kmalloc(PAGE_SIZE, GFP_KERNEL);

	// right now we have a 4096 bytes of free memory, allocate 2048 for rx/tx descriptors respectively

    //prom_printf("page_ptr=%08x\n", (unsigned int )page_ptr);	
	tp->rx_desc = (desc_t *) page_ptr;
	tp->tx_desc = (desc_t *)(page_ptr + (PAGE_SIZE >> 1));

	// initialize rx channel
	tp->cur_rx = 0;
	for (i=0; i< NUM_RX_DESC; i++)
	{
		tp->rx_desc[i].header = tp->rx_skb[i] = NULL;
		skb_ptr = dev_alloc_skb(RX_BUF_LEN);
		if (skb_ptr == NULL)
			return 1;
		skb_reserve(skb_ptr, 2);	// to make tcp/ip happy
		tp->rx_skb[i] = skb_ptr;
		tp->rx_desc[i].addr = Virtual2Physical((int)(skb_ptr->data)); 
		tp->rx_desc[i].tag = 0;
		tp->rx_desc[i].dummy = 0;
		SetOwnByNic(&(tp->rx_desc[i].header),RX_BUF_LEN ,OWNBYNIC ,i);
		//prom_printf("rx_skb[i].skb_ptr=%08x\n",(unsigned int)skb_ptr);
#if 0
		printk("rx_skb[i].skb_ptr=%08x, sizeof(struct skb_shared_info)=%08x\n",
			(unsigned int)(skb_ptr->data), sizeof(struct skb_shared_info));
#endif		
	}
	atomic_set (&tp->dirty_tx, 0);
	atomic_set (&tp->cur_tx, 0);
	for(i=0; i< NUM_TX_DESC; i++)
	{
		SetOwnByNic(&(tp->tx_desc[i].header),RX_BUF_LEN ,0 ,i);
		tp->tx_desc[i].tag=0;
		tp->tx_desc[i].dummy=0;
		tp->tx_desc[i].addr = 0;
	}

	return 0;
}


static int rtl8139_sw_free(struct rtl8139_private *tp)
{
	int i;
	// free rx channel
	for(i=0; i< NUM_RX_DESC; i++)
	{
		if (tp->rx_skb[i])	
			dev_kfree_skb (tp->rx_skb[i]);
		// Clear Own By Nic
		SetOwnByNic(&(tp->rx_desc[i].header),RX_BUF_LEN ,0 ,i);
	}	
	// free tx channel
	for(i=0; i< NUM_TX_DESC; i++)
	{
		if (tp->tx_skb[i])
			dev_kfree_skb(tp->tx_skb[i]);
		// Clear Own By Nic
		SetOwnByNic(&(tp->tx_desc[i].header),RX_BUF_LEN ,0 ,i);
	}
	kfree(tp->rx_desc);
	return 0;
}

static int rtl8139_open (struct net_device *dev)
{
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	int retval;

	DPRINTK ("ENTER\n");

	MOD_INC_USE_COUNT;

	retval = request_irq (dev->irq, rtl8139_interrupt, SA_INTERRUPT, dev->name, dev);
	if (retval) {
		DPRINTK ("EXIT, returning %d\n", retval);
		MOD_DEC_USE_COUNT;
		return retval;
	}

	//sw init
	if (rtl8139_sw_init(tp))
	{		
		printk("sw init %s error! no memory!\n",dev->name);
		return -ENOMEM;
	}

	tp->full_duplex = tp->duplex_lock;
	rtl8139_hw_start (dev);

#ifdef REALHACK_RECV
	/* Set the timer to switch to check for link beat and perhaps switch
	   to an alternate media type. */
	init_timer (&tp->timer);
	tp->timer.expires = jiffies + 5;
	tp->timer.data = (unsigned long) dev;
	tp->timer.function = &rtl8139_timer;

	init_timer (&tp->rxtimer);
	tp->rxtimer.expires = jiffies + 10;
	tp->rxtimer.data = (unsigned long) dev;
	tp->rxtimer.function = &rtl8139_rxtimer;
#endif

#ifdef REALHACK_IMTR
	init_timer (&tp->imtrtimer);
	tp->imtrtimer.expires = jiffies + 400 ;
	tp->imtrtimer.data = (unsigned long) dev;
	tp->imtrtimer.function = &rtl8139_imtrtimer;
	mod_timer(&tp->imtrtimer, jiffies + 400);
#endif

	DPRINTK ("EXIT, returning 0\n");
	return 0;
}

static void rtl8139_txrx_stop (struct rtl8139_private *tp)
{
	void *ioaddr = tp->mmio_addr;
 
	RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1)) & ((~RxEnable) | (~TxEnable)) );
	udelay (100);
} 

/* Start the hardware at open or resume. */
static void rtl8139_hw_start (struct net_device *dev)
{
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;

	DPRINTK ("ENTER\n");

	/* Stop txrx first */
	rtl8139_txrx_stop (tp);
	rtl8139_chip_reset(ioaddr);

/* Force MII register to  reflect the current status of phy */
#ifdef	CONFIG_PHYTYPE_BYFLASH
	if (((*(volatile unsigned short *)(0xbfc06006)) >> 8) & 0x01) {
		printk("PHY type (by flash) is 8305SB\n");
		if (ioaddr == (void *) RTL8181_ETH0_ADDR)
			RTL_W32(NIC_MII, MII_PHY8305_ETH0);
		else
			RTL_W32(NIC_MII, MII_PHY8305_ETH1);
	} else {
		printk("PHY type (by flash) is 8201BL\n");
		RTL_W32(NIC_MII, MII_PHY8201);
	}
#else

#ifdef CONFIG_RTL8181_8305SB //Wireless Router Mode
	printk("PHY type (hardcoded) is 8305SB\n");
	if (ioaddr == (void *) RTL8181_ETH0_ADDR)
		RTL_W32(NIC_MII, MII_PHY8305_ETH0);
	else
		RTL_W32(NIC_MII, MII_PHY8305_ETH1);
#else
	printk("PHY type (hardcoded) is 8201BL\n");
	RTL_W32(NIC_MII, MII_PHY8201);
#endif

#endif /* CONFIG_PHYTYPE_BYFLASH */

	if (ioaddr == (void *) RTL8181_ETH0_ADDR)
		RTL_W32_F (NIC_ID + 0, 0x33221100);
	else
		RTL_W32_F (NIC_ID + 0, 0x33261100);

	RTL_W32_F (NIC_ID + 4, 0x00000044);
	
	/* Must enable Tx/Rx before setting transfer thresholds! */
	RTL_W32_F (NIC_CNR1, RxEnable | TxEnable );
	RTL_W32_F (NIC_CNR1, RTL_R32(NIC_CNR1) | rtl8139_trx_config); 

	rtl8139_set_rx_mode (dev);

	/* fill the base address of tx/rx descriptors! */
	RTL_W32_F(NIC_TSAD,Virtual2Physical(tp->tx_desc));
	RTL_W32_F(NIC_RSAD,Virtual2Physical(tp->rx_desc));

	tp->intr_mask = rtl8139_intr_mask;

	/* Enable all known interrupts by setting the interrupt mask. */
	RTL_W32_F(NIC_IMR, tp->intr_mask);
	RTL_W32(NIC_RXERR, 0x0);
	netif_start_queue (dev);

	DPRINTK ("EXIT\n");
}

#ifdef REALHACK_RECV
static void rtl8139_timer (unsigned long data)
{
	unsigned long flags;
	struct net_device *dev = (struct net_device *)data;
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	int this_cpu = smp_processor_id();
 	// we should query to check if now the rx queue is okay for accepting
	//new skb
	get_sample_stats(this_cpu);
	//if (softnet_data[this_cpu].cng_level != NET_RX_SUCCESS)
	if (softnet_data[this_cpu].cng_level == NET_RX_DROP)
	{
		//printk("timer check shows still congested network traffic for %s\n"
			//, dev->name);
		mod_timer(&tp->timer, jiffies + 5);
	} else {
		//printk("timer check success!\n");
		save_flags(flags);cli();
		tp->netrxdrop = FALSE;
		//RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1)) | (RxEnable) );
		RTL_W32(NIC_IMR, tp->intr_mask);
		restore_flags(flags);
	}	  
}

// This is for the case where RxFFOv happens
// We have disabled RxInterrupt for a while
// Therefore, we should re-open it again 
static void rtl8139_rxtimer (unsigned long data)
{
    unsigned long flags;
    struct net_device *dev = (struct net_device *)data;
    struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
    volatile void *ioaddr = tp->mmio_addr;

	save_flags(flags); cli();
	tp->intr_mask |= (RxDescUnMask | RxFFOvMask);
	RTL_W32_F(NIC_IMR, tp->intr_mask);
	RTL_W32_F(NIC_ISR,  (RxDescUnMask | RxFFOvMask));
	restore_flags(flags);
}
#endif /* REALHACK_RECV */

#ifdef REALHACK_IMTR
static void rtl8139_imtrtimer (unsigned long data)
{
	unsigned long flags;
	struct net_device *dev = (struct net_device *)data;
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	volatile void *ioaddr = tp->mmio_addr;
	unsigned int regval;
	save_flags(flags);cli();
	regval = RTL_R32(NIC_IMTR);
	if (tp->rxinterrupt_count >= 3600)
	{	
		if (regval != 0xAAAA)
		{	
			RTL_W32(NIC_IMTR, 0xAA88);
			//printk("tuning IMTR to 0xAAAA with ioaddr=%X\n", ioaddr); 
		}	
	}
	else
	{
		if (regval != 0xAA00)
		{	
			RTL_W32(NIC_IMTR, 0xAA00);
			//printk("tuning IMTR to 0xAA00 with ioaddr=%X\n", ioaddr);
		}	
	}
	tp->rxinterrupt_count=0;
	restore_flags(flags);
	mod_timer(&tp->imtrtimer, jiffies + 1000);
}	
#endif /* REALHACK_IMTR */

static void rtl8139_tx_timeout (struct net_device *dev)
{

	printk("tx_timeout ! on dev %s\n", dev->name);
#if 0
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	int i;
	unsigned long flags;

	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
		 "media %2.2x.\n", dev->name,
		 RTL_R8 (NIC_CNR1),
		 RTL_R16 (IntrStatus),
		 RTL_R8 (MediaStatus));

	/* Disable interrupts by clearing the interrupt mask. */
	RTL_W16 (NIC_IMR, 0x0000);

	/* Emit info to figure out what went wrong. */
	printk (KERN_DEBUG "%s: Tx queue start entry %d  dirty entry %d.\n",
		dev->name, atomic_read (&tp->cur_tx),
		atomic_read (&tp->dirty_tx));
	for (i = 0; i < NUM_TX_DESC; i++)
		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",
			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
			i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ?
				" (queue head)" : "");

	spin_lock_irqsave (&tp->lock, flags);

	/* Stop a shared interrupt from scavenging while we are. */
	atomic_set (&tp->cur_tx, 0);
	atomic_set (&tp->dirty_tx, 0);

	/* Dump the unsent Tx packets. */
	for (i = 0; i < NUM_TX_DESC; i++) {
		struct ring_info *rp = &tp->tx_info[i];
		if (rp->mapping != 0) {
			pci_unmap_single (tp->pci_dev, rp->mapping,
					  rp->skb->len, PCI_DMA_TODEVICE);
			rp->mapping = 0;
		}
		if (rp->skb) {
			dev_kfree_skb (rp->skb);
			rp->skb = NULL;
			tp->stats.tx_dropped++;
		}
	}

	spin_unlock_irqrestore (&tp->lock, flags);

	/* ...and finally, reset everything */
	rtl8139_hw_start (dev);
#endif
}



static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	int	txmit_count;
	int cur_tx, dirty_tx;
	unsigned int own;
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;

	//save_flags(flags);cli();
	cur_tx = atomic_read(&tp->cur_tx) & (NUM_TX_DESC - 1);
	dirty_tx = atomic_read(&tp->dirty_tx) & (NUM_TX_DESC - 1);
	if (((cur_tx + 1) & (NUM_TX_DESC - 1)) == dirty_tx)
		txmit_count = 0;
	else
		txmit_count = 1;
	//if ((txmit_count=(CIRC_SPACE(cur_tx, dirty_tx, NUM_TX_DESC))))
	if (txmit_count)
	{
		// Great! we have free tx descriptors!
		own = OWNBYNIC;
		tp->tx_skb[cur_tx]=skb;
		*(volatile unsigned int *)(&(tp->tx_desc[cur_tx].addr)) = Virtual2Physical(skb->data);
#if 0 
		if ((tp->tx_desc[cur_tx].header) & 0x80000000)
			printk("bug in start_xmit! cur_tx=%08x, dirty_tx=%08x\n",
			cur_tx, dirty_tx);
#endif 

#ifdef RTL8139AP_CHECKSUM_OFFLOAD
		if (skb->ip_summed == CHECKSUM_HW)	
		{
		const struct iphdr *ip = skb->nh.iph;
				
				printk("tx offload,ip->protocol=%08x\n",ip->protocol);
				if ((ip->protocol == IPPROTO_TCP) ||
					(ip->protocol == IPPROTO_UDP)) {
				if (ip->protocol == IPPROTO_TCP)
					own |= 	(IpTxCsumEn) | (TcpTxCsumEn);
				else
					own |=  (IpTxCsumEn) | (UdpTxCsumEn);
				}				
		}
#endif
		SetOwnByNic(&(tp->tx_desc[cur_tx].header),skb->len ,own,cur_tx);
	
		// Remember to Poll Tx Registers!!!
		RTL_W32( NIC_CNR1, RTL_R32(NIC_CNR1) |  TxDescFN); 
		//RTL_R32( NIC_CNR1); 
#ifdef	RTL8139_EARLY_FREE
		dev_kfree_skb(skb);
#endif

		dev->trans_start = jiffies;
		cur_tx++;
		cur_tx &= (NUM_TX_DESC - 1);
		atomic_set (&tp->cur_tx, cur_tx);
	}
	else
	{
		// No more tx descriptors allowed!
		netif_stop_queue (dev);
		//printk("stop_tx_queue!\n");
		if (skb)
			dev_kfree_skb(skb);	
		else
			printk("tx a null queue?\n");
	}
	/* Note: the chip doesn't have auto-pad! */

	//restore_flags(flags);
	return 0;
}

// The purpose of this tx_interrupt:
// 1. Free the skb that has been sent.
// atomic increase dirty_tx;
static __inline__ void rtl8139_tx_interrupt (struct net_device *dev)
{
	unsigned int tx_header;
	unsigned int tx_header_addr;
	int tx_count,cur_tx,dirty_tx;
	struct rtl8139_private *tp = dev->priv;

	// if we can make sure this handler occurred in ISR,
	// then we do'nt need to use atomic operation
	dirty_tx = atomic_read (&tp->dirty_tx);
	cur_tx = atomic_read (&tp->cur_tx);
	tx_count = CIRC_CNT(cur_tx, dirty_tx, NUM_TX_DESC);
	while ( tx_count-- )
	//while (1)
	{
		tx_header_addr=(unsigned int)(&(tp->tx_desc[dirty_tx].header)) | 0x20000000;
		tx_header = *(volatile unsigned int *)(tx_header_addr);
		
		if (tx_header & OWNBYNIC)
			break; 
		tp->stats.tx_bytes += ((tx_header) & (0xfff))  ;
		if (tx_header & TXERR)
		{
			tp->stats.tx_errors++;
			if (tx_header & TXERR_OUTOFWIN)
				tp->stats.tx_window_errors++;
			if (tx_header & TXERR_LINKF)
				tp->stats.tx_carrier_errors++;
			if (tx_header & TXERR_COLLISION)
				tp->stats.collisions += (tx_header >> 16) & (0xf);		
		}
		else
		{
			tp->stats.tx_packets++;
		}	
#if 0
	// The code below is for checking if Linux will use scatter-list for tx_skb
		if ((tp->tx_skb[dirty_tx])->next)
				printk("Non null?\n");
#endif
			
			//Free skb
#ifndef RTL8139_EARLY_FREE
			dev_kfree_skb_irq(tp->tx_skb[dirty_tx]);
#endif			
			tp->tx_skb[dirty_tx]=NULL;
			dirty_tx++;dirty_tx &= (NUM_TX_DESC - 1);
	}
	
	if (netif_queue_stopped(dev) && CIRC_SPACE(cur_tx, dirty_tx, NUM_TX_DESC))
		netif_wake_queue(dev);
	atomic_set (&tp->dirty_tx, dirty_tx);
}



/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
   field alignments and semantics. */
static __inline__ void rtl8139_rx_interrupt (struct net_device *dev)
{
	int k, netreturn;
	volatile int cur_rx;
	unsigned int rxheader;
	struct sk_buff* skb_ptr; // skb_ptr is used to re-new the desc.
	volatile struct sk_buff* rx_ptr;  // rx_ptr is used to post to os(network layer)
	unsigned int header_addr;
	unsigned int flush_cache;
	struct rtl8139_private *tp = dev->priv;
	// void *ioaddr = tp->mmio_addr;

	cur_rx = tp->cur_rx;
	flush_cache=0;	
	tp->rxinterrupt_count++;

	for(k=0; k< MAX_RX_INTERRUPT_WORK; k++)
	{
		rx_ptr=(struct sk_buff *)0;
		// Check each descriptor's header, by using physical address
		header_addr = (unsigned int)(&(tp->rx_desc[cur_rx].header));
		rxheader = *(volatile unsigned int *)(header_addr | 0xa0000000);	
		if (rxheader & OWNBYNIC)
				break;
		
		if (rxheader & RXERR) 
		{
			//printk("Rx ErrPkt on %s, rxheader=%08x,header_addr=%08x cur_rx=%08x \n", dev->name, rxheader,header_addr,cur_rx);
			// just ignore this pkt
			// re-use the descriptor
			skb_ptr = tp->rx_skb[cur_rx];
		}
		else if (tp->netrxdrop)
		//else if (softnet_data[0].input_pkt_queue.qlen >= 100)
		{
			skb_ptr = tp->rx_skb[cur_rx];
			//printk("qlen >=100, stop queuing\n");
		}
		else if (((rxheader & RXLENMASK) - 4) > 1520)
		{
			//printk("weird rxheader=%08x\n", rxheader);
			skb_ptr = tp->rx_skb[cur_rx];
		}
		else
		{
			rx_ptr = tp->rx_skb[cur_rx];
			rx_ptr->dev=dev;
			skb_ptr = dev_alloc_skb(RX_BUF_LEN);
			if (skb_ptr == NULL)
			{	
			
				printk("System out of skbuff for %s, k=%d\n",dev->name,k);
				skb_ptr = rx_ptr;
				rx_ptr = (struct sk_buff *)NULL;
			}
			else
			{
				skb_reserve(skb_ptr, 2);	// to make tcp/ip happy
				tp->rx_skb[cur_rx] = skb_ptr;
				skb_ptr->dev=dev;
			}
		}

		*(volatile unsigned long *)(&(tp->rx_desc[cur_rx].addr)) = Virtual2Physical((int)(skb_ptr->data)); 
		// Renew this descriptor
		SetOwnByNic(&(tp->rx_desc[cur_rx].header),RX_BUF_LEN ,OWNBYNIC ,cur_rx);
		cur_rx ++;
		cur_rx &= (NUM_RX_DESC - 1);
			
		if (rx_ptr)
		{
			flush_cache++;
#ifdef RTL8139AP_CHECKSUM_OFFLOAD
			if (rx_csum_ok(rxheader))
				rx_ptr->ip_summed = CHECKSUM_UNNECESSARY;
			else
				rx_ptr->ip_summed = CHECKSUM_NONE;
#endif
			skb_put (rx_ptr, (rxheader & RXLENMASK) - 4);
			rx_ptr->protocol = eth_type_trans (rx_ptr, dev);
			if ((netreturn = netif_rx(rx_ptr)) == NET_RX_DROP)
			{
#ifdef REALHACK_RECV
				//printk("NetIf =%08x , halting post skb to os \n",netreturn);
				tp->netrxdrop=TRUE;
				//RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1)) & ((~RxEnable)));
				mod_timer(&tp->timer, jiffies + 10);
#else
				printk("NET_RX_DROP on %s\n", dev->name);
#endif	
			}
			else
				tp->netrxdrop=FALSE;

			tp->stats.rx_bytes += (rxheader & RXLENMASK) - 4 ;
        	tp->stats.rx_packets++;			
		}
	}
	tp->cur_rx = cur_rx;
}



/* The interrupt handler does all of the Rx thread work and cleans up
   after the Tx thread. */
static void rtl8139_interrupt (int irq, void *dev_instance,
			       struct pt_regs *regs)
{
	struct net_device *dev = (struct net_device *) dev_instance;
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	int status = 0;  /* avoid bogus "uninit" warning */

	spin_lock (&tp->lock);

	status = RTL_R32 (NIC_ISR);
	// RTL_W32_F (NIC_ISR,  status); /* Moved to end of function */
	// status &= tp->intr_mask;

	/* Check uncommon events with one test. */
	if (status & (RxErrStats))
		printk("RxErr on %s\n", dev->name);
	if (status & (TxErrStats))
		printk("TxErr on %s\n", dev->name);
	if (status & (RxDescUnStats))
		printk("RxDescUn on %s\n", dev->name);
	if (status & (RxFFOvMask))
	{
		// Does this imply Lexra Bus is hardly occupied by NIC ?
		// Should we adjust burst length case by case?
		// This is partially because of non-consistency of hardware and
		// software rx_cur mechanism. Try to reset hardware and software.
		//rtl8139_quick_reset(dev,tp,ioaddr);

		printk("RxFFOv on %s\n", dev->name);

#ifdef REALHACK_RECV
		tp->intr_mask &= ~(RxFFOvMask | RxDescUnMask); 
		RTL_W32_F(NIC_IMR, tp->intr_mask);
		mod_timer(&tp->rxtimer, jiffies + 9);
#endif
	}

	if (status & (TxOkStats | TxDescUnStats))
		rtl8139_tx_interrupt(dev);

	if (status & (RxOkStats | RxDescUnStats | RxFFOvStats )) /* Rx interrupt */
		rtl8139_rx_interrupt(dev);

	RTL_W32_F (NIC_ISR, status);
	spin_unlock (&tp->lock);
}


static int rtl8139_close (struct net_device *dev)
{
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	unsigned long flags;
	printk("before close, nr_free_pages=%08x\n", nr_free_pages());
	DPRINTK ("ENTER\n");

	netif_stop_queue (dev);

#ifdef REALHACK_RECV
	del_timer_sync (&tp->timer);
	del_timer_sync (&tp->rxtimer);
#endif
#ifdef REALHACK_IMTR
	del_timer_sync (&tp->imtrtimer);
#endif

	spin_lock_irqsave (&tp->lock, flags);

	/* Disable interrupts by clearing the interrupt mask. */
	RTL_W32 (NIC_IMR, 0x0000);

	/* Stop the chip's Tx and Rx DMA processes. */
	RTL_W32 (NIC_CNR1, (RTL_R32 (NIC_CNR1) & ((~RxEnable) | (~TxEnable))));

	/* Update the error counts. */
	tp->stats.rx_missed_errors += (RTL_R32 (NIC_RXERR) & 0xffff);
	RTL_W32 (NIC_RXERR, 0);

	spin_unlock_irqrestore (&tp->lock, flags);

	/* snooze for a small bit */
	if (current->need_resched)
		schedule ();

	free_irq (dev->irq, dev);

	rtl8139_sw_free(tp);
	/* Green! Put the chip in low-power mode. */
	MOD_DEC_USE_COUNT;

	printk("after close, nr_free_pages=%08x\n", nr_free_pages());
	DPRINTK ("EXIT\n");
	return 0;
}


static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
#if 0
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	u16 *data = (u16 *) & rq->ifr_data;
	unsigned long flags;
	int rc = 0;

	DPRINTK ("ENTER\n");

	switch (cmd) {
	case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
		data[0] = tp->phys[0] & 0x3f;
		/* Fall Through */

	case SIOCDEVPRIVATE + 1:	/* Read the specified MII register. */
		spin_lock_irqsave (&tp->lock, flags);
		data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
		spin_unlock_irqrestore (&tp->lock, flags);
		break;

	case SIOCDEVPRIVATE + 2:	/* Write the specified MII register */
		if (!capable (CAP_NET_ADMIN)) {
			rc = -EPERM;
			break;
		}

		spin_lock_irqsave (&tp->lock, flags);
		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
		spin_unlock_irqrestore (&tp->lock, flags);
		break;

	default:
		rc = -EOPNOTSUPP;
		break;
	}

	DPRINTK ("EXIT, returning %d\n", rc);
	return rc;
#endif
	return  -EOPNOTSUPP;
}


static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
{
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;

	DPRINTK ("ENTER\n");

	assert (tp != NULL);

	if (netif_running(dev)) {
		unsigned long flags;

		spin_lock_irqsave (&tp->lock, flags);

		tp->stats.rx_missed_errors += RTL_R32 (NIC_RXERR) & 0xffff;
		RTL_W32 (NIC_RXERR, 0);

		spin_unlock_irqrestore (&tp->lock, flags);
	}

	DPRINTK ("EXIT\n");
	return &tp->stats;
}

/* Set or clear the multicast filter for this adaptor.
   This routine is not state sensitive and need not be SMP locked. */

static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc (int length, unsigned char *data)
{
	int crc = -1;

	DPRINTK ("ENTER\n");

	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);
	}

	DPRINTK ("EXIT\n");
	return crc;
}


static void rtl8139_set_rx_mode (struct net_device *dev)
{
	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
	void *ioaddr = tp->mmio_addr;
	u32 mc_filter[2];	/* Multicast hash filter */
	int i, rx_mode;
	u32 tmp;

	DPRINTK ("ENTER\n");
#if 0
	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
			dev->name, dev->flags, RTL_R32 (RxConfig));
#endif
	/* Note: do not reorder, GCC is clever about common statements. */
	if (dev->flags & IFF_PROMISC) {
		/* Unconditionally log net taps. */
		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
			dev->name);
		rx_mode = AB | AM | AMP | AAP;
		mc_filter[1] = mc_filter[0] = 0xffffffff;
	} else if ((dev->mc_count > multicast_filter_limit)
		   || (dev->flags & IFF_ALLMULTI)) {
		/* Too many to filter perfectly -- accept all multicasts. */
		rx_mode = AB | AM| AMP;
		mc_filter[1] = mc_filter[0] = 0xffffffff;
	} else {
		struct dev_mc_list *mclist;
		rx_mode = AB | AM | AMP;
		mc_filter[1] = mc_filter[0] = 0;
		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
		     i++, mclist = mclist->next)
			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
				 mc_filter);
	}

	/* if called from irq handler, lock already acquired */
	if (!in_irq ())
		spin_lock_irq (&tp->lock);

	/* We can safely update without stopping the chip. */
	tmp = rtl8139_trx_config | rx_mode | TxEnable | RxEnable ; 
	RTL_W32_F (NIC_CNR1, tmp);
	RTL_W32_F (NIC_MAR + 0, mc_filter[0]);
	RTL_W32_F (NIC_MAR + 4, mc_filter[1]);

	if (!in_irq ())
		spin_unlock_irq (&tp->lock);

	DPRINTK ("EXIT\n");
}

module_init(rtl8139_init_all);
