8139cp.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,903 行 · 第 1/4 页

C
1,903
字号
/* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. *//*	Copyright 2001-2004 Jeff Garzik <jgarzik@pobox.com>	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]	Copyright 2001 Manfred Spraul				    [natsemi.c]	Copyright 1999-2001 by Donald Becker.			    [natsemi.c]       	Written 1997-2001 by Donald Becker.			    [8139too.c]	Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. [acenic.c]	This software may be used and distributed according to the terms of	the GNU General Public License (GPL), incorporated herein by reference.	Drivers based on or derived from this code fall under the GPL and must	retain the authorship, copyright and license notice.  This file is not	a complete program and may only be used when the entire operating	system is licensed under the GPL.	See the file COPYING in this distribution for more information.	Contributors:			Wake-on-LAN support - Felipe Damasio <felipewd@terra.com.br>		PCI suspend/resume  - Felipe Damasio <felipewd@terra.com.br>		LinkChg interrupt   - Felipe Damasio <felipewd@terra.com.br>				TODO:	* Test Tx checksumming thoroughly	* Implement dev->tx_timeout	Low priority TODO:	* Complete reset on PciErr	* Consider Rx interrupt mitigation using TimerIntr	* Investigate using skb->priority with h/w VLAN priority	* Investigate using High Priority Tx Queue with skb->priority	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error	* Implement Tx software interrupt mitigation via	  Tx descriptor bit	* The real minimum of CP_MIN_MTU is 4 bytes.  However,	  for this to be supported, one must(?) turn on packet padding.	* Support external MII transceivers (patch available)	NOTES:	* TX checksumming is considered experimental.  It is off by	  default, use ethtool to turn it on. */#define DRV_NAME		"8139cp"#define DRV_VERSION		"1.2"#define DRV_RELDATE		"Mar 22, 2004"#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/pci.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/if_vlan.h>#include <linux/crc32.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/cache.h>#include <asm/io.h>#include <asm/uaccess.h>/* VLAN tagging feature enable/disable */#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[] =KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");MODULE_LICENSE("GPL");static int debug = -1;MODULE_PARM (debug, "i");MODULE_PARM_DESC (debug, "8139cp: bitmapped message enable number");/* 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, "8139cp: maximum number of filtered multicast addresses");#define PFX			DRV_NAME ": "#ifndef TRUE#define FALSE 0#define TRUE (!FALSE)#endif#define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \				 NETIF_MSG_PROBE 	| \				 NETIF_MSG_LINK)#define CP_NUM_STATS		14	/* struct cp_dma_stats, plus one */#define CP_STATS_SIZE		64	/* size in bytes of DMA stats block */#define CP_REGS_SIZE		(0xff + 1)#define CP_REGS_VER		1		/* version 1 */#define CP_RX_RING_SIZE		64#define CP_TX_RING_SIZE		64#define CP_RING_BYTES		\		((sizeof(struct cp_desc) * CP_RX_RING_SIZE) +	\		 (sizeof(struct cp_desc) * CP_TX_RING_SIZE) +	\		 CP_STATS_SIZE)#define NEXT_TX(N)		(((N) + 1) & (CP_TX_RING_SIZE - 1))#define NEXT_RX(N)		(((N) + 1) & (CP_RX_RING_SIZE - 1))#define TX_BUFFS_AVAIL(CP)					\	(((CP)->tx_tail <= (CP)->tx_head) ?			\	  (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head :	\	  (CP)->tx_tail - (CP)->tx_head - 1)#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/#define RX_OFFSET		2#define CP_INTERNAL_PHY		32/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */#define RX_FIFO_THRESH		5	/* Rx buffer level before first PCI xfer.  */#define RX_DMA_BURST		4	/* Maximum PCI burst, '4' is 256 */#define TX_DMA_BURST		6	/* Maximum PCI burst, '6' is 1024 */#define TX_EARLY_THRESH		256	/* Early Tx threshold, in bytes *//* 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		4096enum {	/* NIC register offsets */	MAC0		= 0x00,	/* Ethernet hardware address. */	MAR0		= 0x08,	/* Multicast filter. */	StatsAddr	= 0x10,	/* 64-bit start addr of 64-byte DMA stats blk */	TxRingAddr	= 0x20, /* 64-bit start addr of Tx ring */	HiTxRingAddr	= 0x28, /* 64-bit start addr of high priority Tx ring */	Cmd		= 0x37, /* Command register */	IntrMask	= 0x3C, /* Interrupt mask */	IntrStatus	= 0x3E, /* Interrupt status */	TxConfig	= 0x40, /* Tx configuration */	ChipVersion	= 0x43, /* 8-bit chip version, inside TxConfig */	RxConfig	= 0x44, /* Rx configuration */	RxMissed	= 0x4C,	/* 24 bits valid, write clears */	Cfg9346		= 0x50, /* EEPROM select/control; Cfg reg [un]lock */	Config1		= 0x52, /* Config1 */	Config3		= 0x59, /* Config3 */	Config4		= 0x5A, /* Config4 */	MultiIntr	= 0x5C, /* Multiple interrupt select */	BasicModeCtrl	= 0x62,	/* MII BMCR */	BasicModeStatus	= 0x64, /* MII BMSR */	NWayAdvert	= 0x66, /* MII ADVERTISE */	NWayLPAR	= 0x68, /* MII LPA */	NWayExpansion	= 0x6A, /* MII Expansion */	Config5		= 0xD8,	/* Config5 */	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */	RxMaxSize	= 0xDA, /* Max size of an Rx packet (8169 only) */	CpCmd		= 0xE0, /* C+ Command register (C+ mode only) */	IntrMitigate	= 0xE2,	/* rx/tx interrupt mitigation control */	RxRingAddr	= 0xE4, /* 64-bit start addr of Rx ring */	TxThresh	= 0xEC, /* Early Tx threshold */	OldRxBufAddr	= 0x30, /* DMA address of Rx ring buffer (C mode) */	OldTSD0		= 0x10, /* DMA address of first Tx desc (C mode) */	/* 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 */	TxError		= (1 << 23), /* Tx error summary */	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 << 17), /* 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,	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */	TxOWC		= (1 << 22), /* Tx Out-of-window collision */	TxLinkFail	= (1 << 21), /* Link failed during Tx of packet */	TxMaxCol	= (1 << 20), /* Tx aborted due to excessive collisions */	TxColCntShift	= 16,	     /* Shift, to get 4-bit Tx collision cnt */	TxColCntMask	= 0x01 | 0x02 | 0x04 | 0x08, /* 4-bit collision count */	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 */	RxErrLong	= (1 << 21), /* Rx error, packet > 4096 bytes */	RxErrFIFO	= (1 << 22), /* Rx error, FIFO overflowed, pkt bad */	/* StatsAddr register */	DumpStats	= (1 << 3),  /* Begin stats dump */	/* RxConfig register */	RxCfgFIFOShift	= 13,	     /* Shift, to get Rx FIFO thresh value */	RxCfgDMAShift	= 8,	     /* Shift, to get Rx Max DMA value */	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 */	/* IntrMask / IntrStatus registers */	PciErr		= (1 << 15), /* System error on the PCI bus */	TimerIntr	= (1 << 14), /* Asserted when TCTR reaches TimerInt value */	LenChg		= (1 << 13), /* Cable length change */	SWInt		= (1 << 8),  /* Software-requested interrupt */	TxEmpty		= (1 << 7),  /* No Tx descriptors available */	RxFIFOOvr	= (1 << 6),  /* Rx FIFO Overflow */	LinkChg		= (1 << 5),  /* Packet underrun, or link change */	RxEmpty		= (1 << 4),  /* No Rx descriptors available */	TxErr		= (1 << 3),  /* Tx error */	TxOK		= (1 << 2),  /* Tx packet sent */	RxErr		= (1 << 1),  /* Rx error */	RxOK		= (1 << 0),  /* Rx packet received */	IntrResvd	= (1 << 10), /* reserved, according to RealTek engineers,					but hardware likes to raise it */	IntrAll		= PciErr | TimerIntr | LenChg | SWInt | TxEmpty |			  RxFIFOOvr | LinkChg | RxEmpty | TxErr | TxOK |			  RxErr | RxOK | IntrResvd,	/* C mode command register */	CmdReset	= (1 << 4),  /* Enable to reset; self-clearing */	RxOn		= (1 << 3),  /* Rx mode enable */	TxOn		= (1 << 2),  /* Tx mode enable */	/* C+ mode command register */	RxVlanOn	= (1 << 6),  /* Rx VLAN de-tagging enable */	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */	PCIDAC		= (1 << 4),  /* PCI Dual Address Cycle (64-bit PCI) */	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */	CpRxOn		= (1 << 1),  /* Rx mode enable */	CpTxOn		= (1 << 0),  /* Tx mode enable */	/* Cfg9436 EEPROM control register */	Cfg9346_Lock	= 0x00,	     /* Lock ConfigX/MII register access */	Cfg9346_Unlock	= 0xC0,	     /* Unlock ConfigX/MII register access */	/* TxConfig register */	IFG		= (1 << 25) | (1 << 24), /* standard IEEE interframe gap */	TxDMAShift	= 8,	     /* DMA burst value (0-7) is shift this many bits */	/* Early Tx Threshold register */	TxThreshMask	= 0x3f,	     /* Mask bits 5-0 */	TxThreshMax	= 2048,	     /* Max early Tx threshold */	/* Config1 register */	DriverLoaded	= (1 << 5),  /* Software marker, driver is loaded */	LWACT           = (1 << 4),  /* LWAKE active mode */	PMEnable	= (1 << 0),  /* Enable various PM features of chip */	/* Config3 register */	PARMEnable	= (1 << 6),  /* Enable auto-loading of PHY parms */	MagicPacket     = (1 << 5),  /* Wake up when receives a Magic Packet */	LinkUp          = (1 << 4),  /* Wake up when the cable connection is re-established */	/* Config4 register */	LWPTN           = (1 << 1),  /* LWAKE Pattern */	LWPME           = (1 << 4),  /* LANWAKE vs PMEB */	/* Config5 register */	BWF             = (1 << 6),  /* Accept Broadcast wakeup frame */	MWF             = (1 << 5),  /* Accept Multicast wakeup frame */	UWF             = (1 << 4),  /* Accept Unicast wakeup frame */	LANWake         = (1 << 1),  /* Enable LANWake signal */	PMEStatus	= (1 << 0),  /* PME status can be reset by PCI RST# */	cp_norx_intr_mask = PciErr | LinkChg | TxOK | TxErr | TxEmpty,	cp_rx_intr_mask = RxOK | RxErr | RxEmpty | RxFIFOOvr,	cp_intr_mask = cp_rx_intr_mask | cp_norx_intr_mask,};static const unsigned int cp_rx_config =	  (RX_FIFO_THRESH << RxCfgFIFOShift) |	  (RX_DMA_BURST << RxCfgDMAShift);struct cp_desc {	u32		opts1;	u32		opts2;	u64		addr;};struct ring_info {	struct sk_buff		*skb;	dma_addr_t		mapping;	unsigned		frag;};struct cp_dma_stats {	u64			tx_ok;	u64			rx_ok;	u64			tx_err;	u32			rx_err;	u16			rx_fifo;	u16			frame_align;	u32			tx_ok_1col;	u32			tx_ok_mcol;	u64			rx_ok_phys;	u64			rx_ok_bcast;	u32			rx_ok_mcast;	u16			tx_abort;	u16			tx_underrun;} __attribute__((packed));struct cp_extra_stats {	unsigned long		rx_frags;};struct cp_private {	void			*regs;	struct net_device	*dev;	spinlock_t		lock;	u32			msg_enable;	struct pci_dev		*pdev;	u32			rx_config;	u16			cpcmd;	struct net_device_stats net_stats;	struct cp_extra_stats	cp_stats;	struct cp_dma_stats	*nic_stats;	dma_addr_t		nic_stats_dma;	unsigned		rx_tail		____cacheline_aligned;	struct cp_desc		*rx_ring;	struct ring_info	rx_skb[CP_RX_RING_SIZE];	unsigned		rx_buf_sz;	unsigned		tx_head		____cacheline_aligned;	unsigned		tx_tail;	struct cp_desc		*tx_ring;	struct ring_info	tx_skb[CP_TX_RING_SIZE];	dma_addr_t		ring_dma;#if CP_VLAN_TAG_USED	struct vlan_group	*vlgrp;#endif	unsigned int		wol_enabled : 1; /* Is Wake-on-LAN enabled? */	u32			power_state[16];	struct mii_if_info	mii_if;};#define cpr8(reg)	readb(cp->regs + (reg))#define cpr16(reg)	readw(cp->regs + (reg))#define cpr32(reg)	readl(cp->regs + (reg))#define cpw8(reg,val)	writeb((val), cp->regs + (reg))#define cpw16(reg,val)	writew((val), cp->regs + (reg))#define cpw32(reg,val)	writel((val), cp->regs + (reg))#define cpw8_f(reg,val) do {			\	writeb((val), cp->regs + (reg));	\	readb(cp->regs + (reg));		\	} while (0)#define cpw16_f(reg,val) do {			\	writew((val), cp->regs + (reg));	\	readw(cp->regs + (reg));		\	} while (0)#define cpw32_f(reg,val) do {			\	writel((val), cp->regs + (reg));	\	readl(cp->regs + (reg));		\	} while (0)static void __cp_set_rx_mode (struct net_device *dev);static void cp_tx (struct cp_private *cp);static void cp_clean_rings (struct cp_private *cp);static struct pci_device_id cp_pci_tbl[] = {	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, },	{ },};MODULE_DEVICE_TABLE(pci, cp_pci_tbl);static struct {	const char str[ETH_GSTRING_LEN];} ethtool_stats_keys[] = {	{ "tx_ok" },	{ "rx_ok" },	{ "tx_err" },	{ "rx_err" },	{ "rx_fifo" },	{ "frame_align" },	{ "tx_ok_1col" },	{ "tx_ok_mcol" },	{ "rx_ok_phys" },	{ "rx_ok_bcast" },	{ "rx_ok_mcast" },	{ "tx_abort" },	{ "tx_underrun" },	{ "rx_frags" },};#if CP_VLAN_TAG_USEDstatic void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp){	struct cp_private *cp = netdev_priv(dev);	unsigned long flags;	spin_lock_irqsave(&cp->lock, flags);	cp->vlgrp = grp;	cp->cpcmd |= RxVlanOn;	cpw16(CpCmd, cp->cpcmd);	spin_unlock_irqrestore(&cp->lock, flags);}static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid){	struct cp_private *cp = netdev_priv(dev);	unsigned long flags;	spin_lock_irqsave(&cp->lock, flags);	cp->cpcmd &= ~RxVlanOn;	cpw16(CpCmd, cp->cpcmd);	if (cp->vlgrp)		cp->vlgrp->vlan_devices[vid] = NULL;	spin_unlock_irqrestore(&cp->lock, flags);}#endif /* CP_VLAN_TAG_USED */static inline void cp_set_rxbufsize (struct cp_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 cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,			      struct cp_desc *desc){	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;#if CP_VLAN_TAG_USED	if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {		vlan_hwaccel_receive_skb(skb, cp->vlgrp,					 be16_to_cpu(desc->opts2 & 0xffff));	} else

⌨️ 快捷键说明

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