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 + -
显示快捷键?