⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth8186.c

📁 瑞昱公司无线局域网芯片8186的无线多媒体扩展补丁
💻 C
📖 第 1 页 / 共 3 页
字号:
	// fragmented packet/* 8186nic.c: A Linux Ethernet driver for the RealTek 8186 chips. */#define DRV_NAME		"8186NIC"#define DRV_VERSION		"0.0.7"#define DRV_RELDATE		"Nov 8, 2006"#define BIT(x)	(1<<(x))#define RTL8186_CHECKSUM_OFFLOAD#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/compiler.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/if_vlan.h>#include <net/pkt_sched.h>//#include <linux/crc32.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/slab.h>#include <linux/proc_fs.h>#define BR_SHORTCUT#define VLAN_QOS//#ifdef CONFIG_RTL8186_KB//	#define VLAN_QOS//#endif#ifdef DRIVER_SPEEDUP#ifndef DELAY_RX#define DELAY_RX#endif#endif#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)#define CP_VLAN_TAG_USED 1#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \	do { (tx_desc)->opts2 = (vlan_tag_value); } while (0)#else#define CP_VLAN_TAG_USED 0#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \	do { (tx_desc)->opts2 = 0; } while (0)#endif/* These identify the driver base version and may not be removed. */static char version[] __devinitdata =KERN_INFO DRV_NAME " Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";MODULE_AUTHOR("Arthur Yang <ysy@realtek.com.tw>");MODULE_DESCRIPTION("RealTek RTL8186 series 10/100 Ethernet driver");MODULE_LICENSE("GPL");#if 0static int debug = -1;MODULE_PARM (debug, "i");MODULE_PARM_DESC (debug, "RTL8186NIC bitmapped message enable number");#endif/* 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;MODULE_PARM (multicast_filter_limit, "i");MODULE_PARM_DESC (multicast_filter_limit, "RTL8186NIC maximum number of filtered multicast addresses");#define PFX						DRV_NAME ": "#define CP_DEF_MSG_ENABLE		(NETIF_MSG_DRV		| \								 NETIF_MSG_PROBE 	| \								 NETIF_MSG_LINK)#define CP_REGS_SIZE			(0xff + 1)#define RTL8186_RX_RING_SIZE	32#define RTL8186_TX_RING_SIZE	64#define DESC_ALIGN				0x100#define UNCACHE_MASK			0xa0000000#define RTL8186_RXRING_BYTES	((sizeof(struct dma_desc) * (RTL8186_RX_RING_SIZE+1)) + DESC_ALIGN)#define RTL8186_TXRING_BYTES	((sizeof(struct dma_desc) * (RTL8186_TX_RING_SIZE+1)) + DESC_ALIGN)#define NEXT_TX(N)		(((N) + 1) & (RTL8186_TX_RING_SIZE - 1))#define NEXT_RX(N)		(((N) + 1) & (RTL8186_RX_RING_SIZE - 1))#define TX_HQBUFFS_AVAIL(CP)					\	(((CP)->tx_hqtail <= (CP)->tx_hqhead) ?			\	  (CP)->tx_hqtail + (RTL8186_TX_RING_SIZE - 1) - (CP)->tx_hqhead : \	  (CP)->tx_hqtail - (CP)->tx_hqhead - 1)#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/#define RX_OFFSET		2/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT		(6*HZ)/* hardware minimum and maximum for a single frame's data payload */#define CP_MIN_MTU		60	/* TODO: allow lower, but pad */#define CP_MAX_MTU		4096#define RTL_W32(reg, value)	(*(volatile u32*)(cp->regs+reg)) = (u32)value#define RTL_W16(reg, value)	(*(volatile u16*)(cp->regs+reg)) = (u16)value#define RTL_W8(reg, value)	(*(volatile u8*)(cp->regs+reg)) = (u8)value#define RTL_R32(reg)		(*(volatile u32*)(cp->regs+reg))#define RTL_R16(reg)		(*(volatile u16*)(cp->regs+reg))#define RTL_R8(reg)		(*(volatile u8*)(cp->regs+reg))enum PHY_REGS {	TXFCE	= BIT(7),	RXFCE	= BIT(6),	SP100	= BIT(3),	LINK	= BIT(2),	TXPF	= BIT(1),	RXPF	= BIT(0),	FORCE_TX = BIT(5),};enum {	NIC0,	NIC1,	NICEND,};enum {	NIC0IRQ=4,	NIC1IRQ=5,};enum {	NIC0BASE=0xbd200000,	NIC1BASE=0xbd300000,};enum {	/* NIC register offsets */	IDR0 			=0,	/* Ethernet ID */	IDR1 			=0x1,	/* Ethernet ID */	IDR2 			=0x2,	/* Ethernet ID */	IDR3 			=0x3,	/* Ethernet ID */	IDR4 			=0x4,	/* Ethernet ID */	IDR5 			=0x5,	/* Ethernet ID */	MAR0 			=0x8,	/* Multicast register */	MAR1 			=0x9,	MAR2 			=0xa,	MAR3 			=0xb,	MAR4 			=0xc,	MAR5 			=0xd,	MAR6 			=0xe,	MAR7 			=0xf,	TXOKCNT			=0x10,	RXOKCNT			=0x12,	TXERR 			=0x14,	RXERRR 			=0x16,	MISSPKT 		=0x18,	FAE				=0x1A,	TX1COL 			=0x1c,	TXMCOL			=0x1e,	RXOKPHY			=0x20,	RXOKBRD			=0x22,	RXOKMUL			=0x24,	TXABT			=0x26,	TXUNDRN			=0x28,	TRSR			=0x34,	CMD				=0x3B,	IMR				=0x3C,	ISR				=0x3E,	TCR				=0x40,	RCR				=0x44,	MSR				=0x58,	MIIAR			=0x5C,	TxFDP1			=0x1300,	TxCDO1			=0x1304,	TXCPO1			=0x1308,	TXPSA1			=0x130A,	TXCPA1			=0x130C,	LastTxCDO1		=0x1310,	TXPAGECNT1		=0x1312,	Tx1ScratchDes	=0x1350,	TxFDP2			=0x1380,	TxCDO2			=0x1384,	TXCPO2			=0x1388,	TXPSA2			=0x138A,	TXCPA2			=0x138C,	LASTTXCDO2		=0x1390,	TXPAGECNT2		=0x1392,	Tx2ScratchDes	=0x13A0,	RxFDP			=0x13F0,	RxCDO			=0x13F4,	RxRingSize		=0x13F6,	RxCPO			=0x13F8,	RxPSA			=0x13FA,	RXPLEN			=0x1403,	//LASTRXCDO		=0x1402,	RXPFDP			=0x1404,	RXPAGECNT		=0x1408,	RXSCRATCHDES		=0x1410,	EthrntRxCPU_Des_Num	=0x1430,	EthrntRxCPU_Des_Wrap 	=0x1431,	Rx_Pse_Des_Thres 	=0x1432,	IO_CMD 			=0x1434,	MII_RE 			=BIT(3),	MII_TE 			=BIT(2),	TX_FNL 			=BIT(1),	TX_FNH 			=BIT(0),};enum RTL8186_STATUS_REGS {	/* Tx and Rx status descriptors */	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */	RingEnd		= (1 << 30), /* End of descriptor ring */	FirstFrag	= (1 << 29), /* First segment of a packet */	LastFrag	= (1 << 28), /* Final segment of a packet */	RxError		= (1 << 20), /* Rx error summary */	IPCS		= (1 << 18), /* Calculate IP checksum */	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */	TxVlanTag	= (1 << 16), /* Add VLAN tag */	RxVlanTagged	= (1 << 16), /* Rx VLAN tag available */	IPFail		= (1 << 15), /* IP checksum failed */	UDPFail		= (1 << 14), /* UDP/IP checksum failed */	TCPFail		= (1 << 13), /* TCP/IP checksum failed */	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */	RxProtoTCP	= 1,	RxProtoUDP	= 2,	RxProtoIP	= 3,	RxErrFrame	= (1 << 27), /* Rx frame alignment error */	RxMcast		= (1 << 26), /* Rx multicast packet rcv'd */	RxErrCRC	= (1 << 18), /* Rx CRC error */	RxErrRunt	= (1 << 19), /* Rx error, packet < 64 bytes */	RWT			= (1 << 21), /* Rx  */	E8023		= (1 << 22), /* Receive Ethernet 802.3 packet  */	TxCRC		= (1 << 23),	PPPOE		= (1 << 23),	RxVlanOn	= (1 << 2),  /* Rx VLAN de-tagging enable */	RxChkSum	= (1 << 1),  /* Rx checksum offload enable */};enum RTL8186_THRESHOLD_REGS {	THVAL			= 2,	RINGSIZE		= 2,	LOOPBACK		= (0x3 << 8), 	AcceptErr		= 0x20,	     /* Accept packets with CRC errors */	AcceptRunt		= 0x10,	     /* Accept runt (<64 bytes) packets */	AcceptBroadcast	= 0x08,	     /* Accept broadcast packets */	AcceptMulticast	= 0x04,	     /* Accept multicast packets */	AcceptMyPhys	= 0x02,	     /* Accept pkts with our MAC as dest */	AcceptAllPhys	= 0x01,	     /* Accept all pkts w/ physical dest */	AcceptAll		= AcceptBroadcast | AcceptMulticast | AcceptMyPhys |					  AcceptAllPhys | AcceptErr | AcceptRunt,	AcceptNoBroad	= AcceptMulticast |AcceptMyPhys |  AcceptAllPhys | AcceptErr | AcceptRunt,	AcceptNoMulti	= AcceptMyPhys |  AcceptAllPhys | AcceptErr | AcceptRunt,	NoErrAccept		= AcceptBroadcast | AcceptMulticast | AcceptMyPhys |  AcceptAllPhys,};enum RTL8186_ISR_REGS {	SW_INT 		= BIT(10),	TX_EMPTY	= BIT(9),	LINK_CHG	= BIT(8),	TX_ERR		= BIT(7),	TX_OK		= BIT(6),	RX_EMPTY	= BIT(5),	RX_FIFOOVR	= BIT(4),	RX_ERR		= BIT(2),	RX_OK		= BIT(0),};enum RTL8186_IOCMD_REG {#ifdef DRIVER_SPEEDUP	RX_MIT 		= 1,#else	RX_MIT		= 3,#endif	RX_TIMER 	= 1,	RX_FIFO 	= 2,	TX_FIFO		= 1,#ifdef DRIVER_SPEEDUP	TX_MIT		= 1,#else	TX_MIT		= 3,#endif	TX_POLL		= 1 << 0,	CMD_CONFIG	= 0x3c | RX_MIT << 8 | RX_FIFO << 11 |  RX_TIMER << 13 |				  TX_MIT << 16 | TX_FIFO<<19,};static const u32 rtl8186_intr_mask =	SW_INT | LINK_CHG |	RX_OK | RX_ERR | RX_EMPTY | RX_FIFOOVR |	TX_OK | TX_ERR | TX_EMPTY;typedef struct dma_desc {	u32		opts1;		// status	u32		addr;		// buffer address	u32		opts2;		// vlan stuff	u32		opts3;		// partial checksum} DMA_DESC;struct ring_info {	struct sk_buff	*skb;	dma_addr_t		mapping;	unsigned		frag;};struct cp_extra_stats {	unsigned long	rx_frags;	unsigned long 	tx_timeouts;};#ifdef VLAN_QOSstruct qos_node {	unsigned char	valid;	unsigned char	addr[6];	unsigned char	vlan_tagged;	unsigned char	priority;	unsigned char	vlan_id_h;	unsigned char	vlan_id_l;};#endifstruct re_private {	unsigned		tx_hqhead;	unsigned		tx_hqtail;	unsigned		tx_lqhead;	unsigned		tx_lqtail;	unsigned		rx_tail;	void			*regs;	struct net_device	*dev;#ifdef DELAY_RX	struct tasklet_struct 	rx_tasklet;#endif	spinlock_t		lock;	DMA_DESC		*rx_ring;	DMA_DESC		*tx_hqring;	DMA_DESC		*tx_lqring;	struct ring_info	tx_skb[RTL8186_TX_RING_SIZE];	struct ring_info	rx_skb[RTL8186_RX_RING_SIZE];	unsigned		rx_buf_sz;	dma_addr_t		ring_dma;#if CP_VLAN_TAG_USED	struct vlan_group	*vlgrp;#endif	u32			msg_enable;	struct net_device_stats net_stats;	struct cp_extra_stats	cp_stats;	struct pci_dev		*pdev;	u32			rx_config;	struct sk_buff		*frag_skb;	unsigned		dropping_frag : 1;	char*			rxdesc_buf;	char*			txdesc_buf;	struct mii_if_info	mii_if;#ifdef VLAN_QOS	struct qos_node	qosnode_table[8][8];	unsigned char	qosnode_index[8];#endif};struct re_private *reDev[2];extern int r3k_flush_dcache_range(int, int);static void __rtl8186_set_rx_mode(struct net_device *dev);static inline void rtl8186_tx(struct re_private *cp);static void rtl8186_clean_rings(struct re_private *cp);static void rtl8186_tx_timeout(struct net_device *dev);static int rtl8139_set_hwaddr(struct net_device *dev, void *addr);static int eth_flag=0;	// bit0 - disable DELAY_RX, bit1 - disable BR_SHORTCUT#ifdef VLAN_QOSstatic __inline__ int mac_hash(unsigned char *mac){	unsigned long x;	x = mac[0];	x = (x << 2) ^ mac[1];	x = (x << 2) ^ mac[2];	x = (x << 2) ^ mac[3];	x = (x << 2) ^ mac[4];	x = (x << 2) ^ mac[5];	x ^= x >> 8;	return x & (8 - 1);}void qosnode_insert(struct re_private *cp, unsigned char *sa, unsigned char vlan_tagged,				unsigned char priority, unsigned char vlan_id_h, unsigned char vlan_id_l){	unsigned int index, i;	struct qos_node *pbuf;	index = mac_hash(sa);	for (i=0; i<8; i++)	{		if ((cp->qosnode_table[index][i].valid) && !(memcmp(cp->qosnode_table[index][i].addr, sa, 6))) {			//printk("qosnode: entry %02x%02x%02x%02x%02x%02x found\n",			//	sa[0],sa[1],sa[2],sa[3],sa[4],sa[5]);			cp->qosnode_table[index][i].vlan_tagged = vlan_tagged;			if (vlan_tagged) {				cp->qosnode_table[index][i].priority = priority;				cp->qosnode_table[index][i].vlan_id_h = vlan_id_h;				cp->qosnode_table[index][i].vlan_id_l = vlan_id_l;			}			return;		}	}	// not found	pbuf = &cp->qosnode_table[index][cp->qosnode_index[index]];	cp->qosnode_index[index] = (cp->qosnode_index[index] + 1) & (8 - 1);	pbuf->valid = 1;	memcpy(pbuf->addr, sa, 6);	pbuf->vlan_tagged = vlan_tagged;	if (vlan_tagged) {		pbuf->priority = priority;		pbuf->vlan_id_h = vlan_id_h;		pbuf->vlan_id_l = vlan_id_l;	}	//printk("qosnode: entry %02x%02x%02x%02x%02x%02x insert\n",	//	sa[0],sa[1],sa[2],sa[3],sa[4],sa[5]);}struct qos_node *qosnode_lookup(struct re_private *cp, unsigned char *da){	unsigned int index, i;	index = mac_hash(da);	for (i=0; i<8; i++)	{		if ((cp->qosnode_table[index][i].valid) && !(memcmp(cp->qosnode_table[index][i].addr, da, 6))) {			//printk("qosnode: entry %02x%02x%02x%02x%02x%02x lookup\n",			//	da[0],da[1],da[2],da[3],da[4],da[5]);			return &cp->qosnode_table[index][i];		}	}	return 0;}#endif // VLAN_QOSstatic int write_proc(struct file *file, const char *buffer,		      unsigned long count, void *data){	unsigned char tmp;	if (count < 2)		return -EFAULT;	if (buffer && !copy_from_user(&tmp, buffer, 1)) {	    eth_flag = tmp - '0';	    return count;    }    return -EFAULT;}static inline void rtl8186_set_rxbufsize(struct re_private *cp){	unsigned int mtu = cp->dev->mtu;	if (mtu > ETH_DATA_LEN)		/* MTU + ethernet header + FCS + optional VLAN tag */		cp->rx_buf_sz = mtu + ETH_HLEN + 8;	else		cp->rx_buf_sz = PKT_BUF_SZ;}static inline void rtl8186_rx_skb(struct re_private *cp, struct sk_buff *skb,			      DMA_DESC *desc){#ifdef BR_SHORTCUT	extern struct net_device *get_shortcut_dev(unsigned char *da);	struct net_device *dev;#endif	skb->protocol = eth_type_trans (skb, cp->dev);	cp->net_stats.rx_packets++;	cp->net_stats.rx_bytes += skb->len;	cp->dev->last_rx = jiffies;#ifdef VLAN_QOS	if (desc->opts2 & RxVlanTagged) {		unsigned char priority  = (desc->opts2 & 0x000000e0) >> 5;		unsigned char vlan_id_h = (desc->opts2 & 0x0000000f);		unsigned char vlan_id_l = (desc->opts2 & 0x0000ff00) >> 8;		qosnode_insert(cp, skb->mac.ethernet->h_source, 1, priority, vlan_id_h, vlan_id_l);		skb->cb[0] = priority;	}#endif#if CP_VLAN_TAG_USED	if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {		vlan_hwaccel_rx(skb, cp->vlgrp, desc->opts2 & 0xffff);	}	else#endif	{#if defined(BR_SHORTCUT) && defined(CONFIG_RTL8185)		if (!(skb->mac.ethernet->h_dest[0] & 0x01) &&			!(eth_flag & 2) &&			(cp->dev->br_port) &&			((dev = get_shortcut_dev(skb->mac.ethernet->h_dest)) != NULL)) {			skb_push(skb, ETH_HLEN);			memcpy(skb->data, skb->mac.ethernet, ETH_HLEN);			dev->hard_start_xmit(skb, dev);		}		else#endif		{#ifdef CONFIG_RTL8186_KB			skb->__unused = 0;#endif			netif_rx(skb);		}	}}static void rtl8186_rx_err_acct(struct re_private *cp, unsigned rx_tail,			    u32 status, u32 len){#if 0	if (netif_msg_rx_err (cp))		printk (KERN_DEBUG			"%s: rx err, slot %d status 0x%x len %d\n",			cp->dev->name, rx_tail, status, len);#endif	cp->net_stats.rx_errors++;	if (status & RxErrFrame)		cp->net_stats.rx_frame_errors++;	if (status & RxErrCRC)		cp->net_stats.rx_crc_errors++;	if (status & RxErrRunt)		cp->net_stats.rx_length_errors++;}static void rtl8186_rx_frag(struct re_private *cp, unsigned rx_tail,			struct sk_buff *skb, u32 status, u32 len){	struct sk_buff *copy_skb, *frag_skb = cp->frag_skb;	unsigned orig_len = frag_skb ? frag_skb->len : 0;	unsigned target_len = orig_len + len;	unsigned first_frag = status & FirstFrag;	unsigned last_frag = status & LastFrag;	if (netif_msg_rx_status (cp))		printk (KERN_DEBUG "%s: rx %s%sfrag, slot %d status 0x%x len %d\n",			cp->dev->name,			cp->dropping_frag ? "dropping " : "",			first_frag ? "first " :			last_frag ? "last " : "",			rx_tail, status, len);	cp->cp_stats.rx_frags++;	if (!frag_skb && !first_frag)		cp->dropping_frag = 1;	if (cp->dropping_frag)		goto drop_frag;	copy_skb = dev_alloc_skb (target_len + RX_OFFSET);	if (!copy_skb) {		printk(KERN_WARNING "%s: rx slot %d alloc failed\n",		       cp->dev->name, rx_tail);		cp->dropping_frag = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -