tg3.c

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

C
2,490
字号
/* * tg3.c: Broadcom Tigon3 ethernet driver. * * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. * * Firmware is: * 	Copyright (C) 2000-2003 Broadcom Corporation. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/compiler.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/if_vlan.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/workqueue.h>#include <net/checksum.h>#include <asm/system.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#ifdef CONFIG_SPARC64#include <asm/idprom.h>#include <asm/oplib.h>#include <asm/pbm.h>#endif#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)#define TG3_VLAN_TAG_USED 1#else#define TG3_VLAN_TAG_USED 0#endif#ifdef NETIF_F_TSO#define TG3_TSO_SUPPORT	1#else#define TG3_TSO_SUPPORT	0#endif#include "tg3.h"#define DRV_MODULE_NAME		"tg3"#define PFX DRV_MODULE_NAME	": "#define DRV_MODULE_VERSION	"3.10"#define DRV_MODULE_RELDATE	"September 14, 2004"#define TG3_DEF_MAC_MODE	0#define TG3_DEF_RX_MODE		0#define TG3_DEF_TX_MODE		0#define TG3_DEF_MSG_ENABLE	  \	(NETIF_MSG_DRV		| \	 NETIF_MSG_PROBE	| \	 NETIF_MSG_LINK		| \	 NETIF_MSG_TIMER	| \	 NETIF_MSG_IFDOWN	| \	 NETIF_MSG_IFUP		| \	 NETIF_MSG_RX_ERR	| \	 NETIF_MSG_TX_ERR)/* length of time before we decide the hardware is borked, * and dev->tx_timeout() should be called to fix the problem */#define TG3_TX_TIMEOUT			(5 * HZ)/* hardware minimum and maximum for a single frame's data payload */#define TG3_MIN_MTU			60#define TG3_MAX_MTU(tp)	\	((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && \	  GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750) ? 9000 : 1500)/* These numbers seem to be hard coded in the NIC firmware somehow. * You can't change the ring sizes, but you can change where you place * them in the NIC onboard memory. */#define TG3_RX_RING_SIZE		512#define TG3_DEF_RX_RING_PENDING		200#define TG3_RX_JUMBO_RING_SIZE		256#define TG3_DEF_RX_JUMBO_RING_PENDING	100/* Do not place this n-ring entries value into the tp struct itself, * we really want to expose these constants to GCC so that modulo et * al.  operations are done with shifts and masks instead of with * hw multiply/modulo instructions.  Another solution would be to * replace things like '% foo' with '& (foo - 1)'. */#define TG3_RX_RCB_RING_SIZE(tp)	\	((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || \	  GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ? \	 512 : 1024)#define TG3_TX_RING_SIZE		512#define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)#define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \				 TG3_RX_RING_SIZE)#define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \			         TG3_RX_JUMBO_RING_SIZE)#define TG3_RX_RCB_RING_BYTES(tp) (sizeof(struct tg3_rx_buffer_desc) * \			           TG3_RX_RCB_RING_SIZE(tp))#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * \				 TG3_TX_RING_SIZE)#define TX_RING_GAP(TP)	\	(TG3_TX_RING_SIZE - (TP)->tx_pending)#define TX_BUFFS_AVAIL(TP)						\	(((TP)->tx_cons <= (TP)->tx_prod) ?				\	  (TP)->tx_cons + (TP)->tx_pending - (TP)->tx_prod :		\	  (TP)->tx_cons - (TP)->tx_prod - TX_RING_GAP(TP))#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))#define RX_PKT_BUF_SZ		(1536 + tp->rx_offset + 64)#define RX_JUMBO_PKT_BUF_SZ	(9046 + tp->rx_offset + 64)/* minimum number of free TX descriptors required to wake up TX process */#define TG3_TX_WAKEUP_THRESH		(TG3_TX_RING_SIZE / 4)/* number of ETHTOOL_GSTATS u64's */#define TG3_NUM_STATS		(sizeof(struct tg3_ethtool_stats)/sizeof(u64))static char version[] __devinitdata =	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");MODULE_LICENSE("GPL");MODULE_PARM(tg3_debug, "i");MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");static int tg3_debug = -1;	/* -1 == use TG3_DEF_MSG_ENABLE as value */static struct pci_device_id tg3_pci_tbl[] = {	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },	{ 0, }};MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);struct {	char string[ETH_GSTRING_LEN];} ethtool_stats_keys[TG3_NUM_STATS] = {	{ "rx_octets" },	{ "rx_fragments" },	{ "rx_ucast_packets" },	{ "rx_mcast_packets" },	{ "rx_bcast_packets" },	{ "rx_fcs_errors" },	{ "rx_align_errors" },	{ "rx_xon_pause_rcvd" },	{ "rx_xoff_pause_rcvd" },	{ "rx_mac_ctrl_rcvd" },	{ "rx_xoff_entered" },	{ "rx_frame_too_long_errors" },	{ "rx_jabbers" },	{ "rx_undersize_packets" },	{ "rx_in_length_errors" },	{ "rx_out_length_errors" },	{ "rx_64_or_less_octet_packets" },	{ "rx_65_to_127_octet_packets" },	{ "rx_128_to_255_octet_packets" },	{ "rx_256_to_511_octet_packets" },	{ "rx_512_to_1023_octet_packets" },	{ "rx_1024_to_1522_octet_packets" },	{ "rx_1523_to_2047_octet_packets" },	{ "rx_2048_to_4095_octet_packets" },	{ "rx_4096_to_8191_octet_packets" },	{ "rx_8192_to_9022_octet_packets" },	{ "tx_octets" },	{ "tx_collisions" },	{ "tx_xon_sent" },	{ "tx_xoff_sent" },	{ "tx_flow_control" },	{ "tx_mac_errors" },	{ "tx_single_collisions" },	{ "tx_mult_collisions" },	{ "tx_deferred" },	{ "tx_excessive_collisions" },	{ "tx_late_collisions" },	{ "tx_collide_2times" },	{ "tx_collide_3times" },	{ "tx_collide_4times" },	{ "tx_collide_5times" },	{ "tx_collide_6times" },	{ "tx_collide_7times" },	{ "tx_collide_8times" },	{ "tx_collide_9times" },	{ "tx_collide_10times" },	{ "tx_collide_11times" },	{ "tx_collide_12times" },	{ "tx_collide_13times" },	{ "tx_collide_14times" },	{ "tx_collide_15times" },	{ "tx_ucast_packets" },	{ "tx_mcast_packets" },	{ "tx_bcast_packets" },	{ "tx_carrier_sense_errors" },	{ "tx_discards" },	{ "tx_errors" },	{ "dma_writeq_full" },	{ "dma_write_prioq_full" },	{ "rxbds_empty" },	{ "rx_discards" },	{ "rx_errors" },	{ "rx_threshold_hit" },	{ "dma_readq_full" },	{ "dma_read_prioq_full" },	{ "tx_comp_queue_full" },	{ "ring_set_send_prod_index" },	{ "ring_status_update" },	{ "nic_irqs" },	{ "nic_avoided_irqs" },	{ "nic_tx_threshold_hit" }};static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val){	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {		unsigned long flags;		spin_lock_irqsave(&tp->indirect_lock, flags);		pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);		pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);		spin_unlock_irqrestore(&tp->indirect_lock, flags);	} else {		writel(val, tp->regs + off);		if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)			readl(tp->regs + off);	}}static void _tw32_flush(struct tg3 *tp, u32 off, u32 val){	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {		unsigned long flags;		spin_lock_irqsave(&tp->indirect_lock, flags);		pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);		pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);		spin_unlock_irqrestore(&tp->indirect_lock, flags);	} else {		void __iomem *dest = tp->regs + off;		writel(val, dest);		readl(dest);    /* always flush PCI write */	}}static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val){	void __iomem *mbox = tp->regs + off;	writel(val, mbox);	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)		readl(mbox);}static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val){	void __iomem *mbox = tp->regs + off;	writel(val, mbox);	if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)		writel(val, mbox);	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)		readl(mbox);}#define tw32_mailbox(reg, val)  writel(((val) & 0xffffffff), tp->regs + (reg))#define tw32_rx_mbox(reg, val)  _tw32_rx_mbox(tp, reg, val)#define tw32_tx_mbox(reg, val)  _tw32_tx_mbox(tp, reg, val)#define tw32(reg,val)		tg3_write_indirect_reg32(tp,(reg),(val))#define tw32_f(reg,val)		_tw32_flush(tp,(reg),(val))#define tw16(reg,val)		writew(((val) & 0xffff), tp->regs + (reg))#define tw8(reg,val)		writeb(((val) & 0xff), tp->regs + (reg))#define tr32(reg)		readl(tp->regs + (reg))#define tr16(reg)		readw(tp->regs + (reg))#define tr8(reg)		readb(tp->regs + (reg))static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val){	unsigned long flags;	spin_lock_irqsave(&tp->indirect_lock, flags);	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);	/* Always leave this as zero. */	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);	spin_unlock_irqrestore(&tp->indirect_lock, flags);}static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val){	unsigned long flags;	spin_lock_irqsave(&tp->indirect_lock, flags);	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);	pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);	/* Always leave this as zero. */	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);	spin_unlock_irqrestore(&tp->indirect_lock, flags);}static void tg3_disable_ints(struct tg3 *tp){	tw32(TG3PCI_MISC_HOST_CTRL,	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);}static inline void tg3_cond_int(struct tg3 *tp){	if (tp->hw_status->status & SD_STATUS_UPDATED)		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);}static void tg3_enable_ints(struct tg3 *tp){	tw32(TG3PCI_MISC_HOST_CTRL,	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);	tg3_cond_int(tp);}static inline void tg3_netif_stop(struct tg3 *tp){	netif_poll_disable(tp->dev);	netif_tx_disable(tp->dev);}static inline void tg3_netif_start(struct tg3 *tp){	netif_wake_queue(tp->dev);	/* NOTE: unconditional netif_wake_queue is only appropriate	 * so long as all callers are assured to have free tx slots	 * (such as after tg3_init_hw)	 */	netif_poll_enable(tp->dev);	tg3_cond_int(tp);}static void tg3_switch_clocks(struct tg3 *tp){	u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);	u32 orig_clock_ctrl;	orig_clock_ctrl = clock_ctrl;	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN |		       CLOCK_CTRL_CLKRUN_OENABLE |		       0x1f);	tp->pci_clock_ctrl = clock_ctrl;	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {		if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) {			tw32_f(TG3PCI_CLOCK_CTRL,			       clock_ctrl | CLOCK_CTRL_625_CORE);			udelay(40);		}	} else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) {		tw32_f(TG3PCI_CLOCK_CTRL,		     clock_ctrl |		     (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));		udelay(40);		tw32_f(TG3PCI_CLOCK_CTRL,		     clock_ctrl | (CLOCK_CTRL_ALTCLK));		udelay(40);	}	tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl);	udelay(40);}#define PHY_BUSY_LOOPS	5000static int tg3_readphy(struct tg3 *tp, int reg, u32 *val){	u32 frame_val;	int loops, ret;	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {		tw32_f(MAC_MI_MODE,		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));		udelay(80);	}	*val = 0xffffffff;	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &		      MI_COM_PHY_ADDR_MASK);	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &		      MI_COM_REG_ADDR_MASK);	frame_val |= (MI_COM_CMD_READ | MI_COM_START);		tw32_f(MAC_MI_COM, frame_val);	loops = PHY_BUSY_LOOPS;	while (loops-- > 0) {		udelay(10);		frame_val = tr32(MAC_MI_COM);		if ((frame_val & MI_COM_BUSY) == 0) {			udelay(5);			frame_val = tr32(MAC_MI_COM);

⌨️ 快捷键说明

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