📄 de2104x.c
字号:
/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. *//* Copyright 2001,2003 Jeff Garzik <jgarzik@pobox.com> Copyright 1994, 1995 Digital Equipment Corporation. [de4x5.c] Written/copyright 1994-2001 by Donald Becker. [tulip.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. TODO, in rough priority order: * Support forcing media type with a module parameter, like dl2k.c/sundance.c * Constants (module parms?) for Rx work limit * Complete reset on PciErr * Jumbo frames / dev->change_mtu * 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 */#define DRV_NAME "de2104x"#define DRV_VERSION "0.7"#define DRV_RELDATE "Mar 17, 2004"#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.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/compiler.h>#include <linux/rtnetlink.h>#include <linux/crc32.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/unaligned.h>/* These identify the driver base version and may not be removed. */static char version[] =KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);static int debug = -1;module_param (debug, int, 0);MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ || defined(__sparc_) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__)static int rx_copybreak = 1518;#elsestatic int rx_copybreak = 100;#endifmodule_param (rx_copybreak, int, 0);MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");#define PFX DRV_NAME ": "#define DE_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ NETIF_MSG_LINK | \ NETIF_MSG_IFDOWN | \ NETIF_MSG_IFUP | \ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR)#define DE_RX_RING_SIZE 64#define DE_TX_RING_SIZE 64#define DE_RING_BYTES \ ((sizeof(struct de_desc) * DE_RX_RING_SIZE) + \ (sizeof(struct de_desc) * DE_TX_RING_SIZE))#define NEXT_TX(N) (((N) + 1) & (DE_TX_RING_SIZE - 1))#define NEXT_RX(N) (((N) + 1) & (DE_RX_RING_SIZE - 1))#define TX_BUFFS_AVAIL(CP) \ (((CP)->tx_tail <= (CP)->tx_head) ? \ (CP)->tx_tail + (DE_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 DE_SETUP_SKB ((struct sk_buff *) 1)#define DE_DUMMY_SKB ((struct sk_buff *) 2)#define DE_SETUP_FRAME_WORDS 96#define DE_EEPROM_WORDS 256#define DE_EEPROM_SIZE (DE_EEPROM_WORDS * sizeof(u16))#define DE_MAX_MEDIA 5#define DE_MEDIA_TP_AUTO 0#define DE_MEDIA_BNC 1#define DE_MEDIA_AUI 2#define DE_MEDIA_TP 3#define DE_MEDIA_TP_FD 4#define DE_MEDIA_INVALID DE_MAX_MEDIA#define DE_MEDIA_FIRST 0#define DE_MEDIA_LAST (DE_MAX_MEDIA - 1)#define DE_AUI_BNC (SUPPORTED_AUI | SUPPORTED_BNC)#define DE_TIMER_LINK (60 * HZ)#define DE_TIMER_NO_LINK (5 * HZ)#define DE_NUM_REGS 16#define DE_REGS_SIZE (DE_NUM_REGS * sizeof(u32))#define DE_REGS_VER 1/* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (6*HZ)#define DE_UNALIGNED_16(a) (u16)(get_unaligned((u16 *)(a)))/* This is a mysterious value that can be written to CSR11 in the 21040 (only) to support a pre-NWay full-duplex signaling mechanism using short frames. No one knows what it should be, but if left at its default value some 10base2(!) packets trigger a full-duplex-request interrupt. */#define FULL_DUPLEX_MAGIC 0x6969enum { /* NIC registers */ BusMode = 0x00, TxPoll = 0x08, RxPoll = 0x10, RxRingAddr = 0x18, TxRingAddr = 0x20, MacStatus = 0x28, MacMode = 0x30, IntrMask = 0x38, RxMissed = 0x40, ROMCmd = 0x48, CSR11 = 0x58, SIAStatus = 0x60, CSR13 = 0x68, CSR14 = 0x70, CSR15 = 0x78, PCIPM = 0x40, /* BusMode bits */ CmdReset = (1 << 0), CacheAlign16 = 0x00008000, BurstLen4 = 0x00000400, /* Rx/TxPoll bits */ NormalTxPoll = (1 << 0), NormalRxPoll = (1 << 0), /* Tx/Rx descriptor status bits */ DescOwn = (1 << 31), RxError = (1 << 15), RxErrLong = (1 << 7), RxErrCRC = (1 << 1), RxErrFIFO = (1 << 0), RxErrRunt = (1 << 11), RxErrFrame = (1 << 14), RingEnd = (1 << 25), FirstFrag = (1 << 29), LastFrag = (1 << 30), TxError = (1 << 15), TxFIFOUnder = (1 << 1), TxLinkFail = (1 << 2) | (1 << 10) | (1 << 11), TxMaxCol = (1 << 8), TxOWC = (1 << 9), TxJabber = (1 << 14), SetupFrame = (1 << 27), TxSwInt = (1 << 31), /* MacStatus bits */ IntrOK = (1 << 16), IntrErr = (1 << 15), RxIntr = (1 << 6), RxEmpty = (1 << 7), TxIntr = (1 << 0), TxEmpty = (1 << 2), PciErr = (1 << 13), TxState = (1 << 22) | (1 << 21) | (1 << 20), RxState = (1 << 19) | (1 << 18) | (1 << 17), LinkFail = (1 << 12), LinkPass = (1 << 4), RxStopped = (1 << 8), TxStopped = (1 << 1), /* MacMode bits */ TxEnable = (1 << 13), RxEnable = (1 << 1), RxTx = TxEnable | RxEnable, FullDuplex = (1 << 9), AcceptAllMulticast = (1 << 7), AcceptAllPhys = (1 << 6), BOCnt = (1 << 5), MacModeClear = (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) | RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast, /* ROMCmd bits */ EE_SHIFT_CLK = 0x02, /* EEPROM shift clock. */ EE_CS = 0x01, /* EEPROM chip select. */ EE_DATA_WRITE = 0x04, /* Data from the Tulip to EEPROM. */ EE_WRITE_0 = 0x01, EE_WRITE_1 = 0x05, EE_DATA_READ = 0x08, /* Data from the EEPROM chip. */ EE_ENB = (0x4800 | EE_CS), /* The EEPROM commands include the alway-set leading bit. */ EE_READ_CMD = 6, /* RxMissed bits */ RxMissedOver = (1 << 16), RxMissedMask = 0xffff, /* SROM-related bits */ SROMC0InfoLeaf = 27, MediaBlockMask = 0x3f, MediaCustomCSRs = (1 << 6), /* PCIPM bits */ PM_Sleep = (1 << 31), PM_Snooze = (1 << 30), PM_Mask = PM_Sleep | PM_Snooze, /* SIAStatus bits */ NWayState = (1 << 14) | (1 << 13) | (1 << 12), NWayRestart = (1 << 12), NonselPortActive = (1 << 9), LinkFailStatus = (1 << 2), NetCxnErr = (1 << 1),};static const u32 de_intr_mask = IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty | LinkPass | LinkFail | PciErr;/* * Set the programmable burst length to 4 longwords for all: * DMA errors result without these values. Cache align 16 long. */static const u32 de_bus_mode = CacheAlign16 | BurstLen4;struct de_srom_media_block { u8 opts; u16 csr13; u16 csr14; u16 csr15;} __attribute__((packed));struct de_srom_info_leaf { u16 default_media; u8 n_blocks; u8 unused;} __attribute__((packed));struct de_desc { u32 opts1; u32 opts2; u32 addr1; u32 addr2;};struct media_info { u16 type; /* DE_MEDIA_xxx */ u16 csr13; u16 csr14; u16 csr15;};struct ring_info { struct sk_buff *skb; dma_addr_t mapping;};struct de_private { unsigned tx_head; unsigned tx_tail; unsigned rx_tail; void __iomem *regs; struct net_device *dev; spinlock_t lock; struct de_desc *rx_ring; struct de_desc *tx_ring; struct ring_info tx_skb[DE_TX_RING_SIZE]; struct ring_info rx_skb[DE_RX_RING_SIZE]; unsigned rx_buf_sz; dma_addr_t ring_dma; u32 msg_enable; struct net_device_stats net_stats; struct pci_dev *pdev; u16 setup_frame[DE_SETUP_FRAME_WORDS]; u32 media_type; u32 media_supported; u32 media_advertise; struct media_info media[DE_MAX_MEDIA]; struct timer_list media_timer; u8 *ee_data; unsigned board_idx; unsigned de21040 : 1; unsigned media_lock : 1;};static void de_set_rx_mode (struct net_device *dev);static void de_tx (struct de_private *de);static void de_clean_rings (struct de_private *de);static void de_media_interrupt (struct de_private *de, u32 status);static void de21040_media_timer (unsigned long data);static void de21041_media_timer (unsigned long data);static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);static struct pci_device_id de_pci_tbl[] = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { },};MODULE_DEVICE_TABLE(pci, de_pci_tbl);static const char * const media_name[DE_MAX_MEDIA] = { "10baseT auto", "BNC", "AUI", "10baseT-HD", "10baseT-FD"};/* 21040 transceiver register settings: * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/static u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, };static u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, };static u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, };/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x6F3F, 0x6F3D, };static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };#define dr32(reg) readl(de->regs + (reg))#define dw32(reg,val) writel((val), de->regs + (reg))static void de_rx_err_acct (struct de_private *de, unsigned rx_tail, u32 status, u32 len){ if (netif_msg_rx_err (de)) printk (KERN_DEBUG "%s: rx err, slot %d status 0x%x len %d\n", de->dev->name, rx_tail, status, len); if ((status & 0x38000300) != 0x0300) { /* Ingore earlier buffers. */ if ((status & 0xffff) != 0x7fff) { if (netif_msg_rx_err(de)) printk(KERN_WARNING "%s: Oversized Ethernet frame " "spanned multiple buffers, status %8.8x!\n", de->dev->name, status); de->net_stats.rx_length_errors++; } } else if (status & RxError) { /* There was a fatal error. */ de->net_stats.rx_errors++; /* end of a packet.*/ if (status & 0x0890) de->net_stats.rx_length_errors++; if (status & RxErrCRC) de->net_stats.rx_crc_errors++; if (status & RxErrFIFO) de->net_stats.rx_fifo_errors++; }}static void de_rx (struct de_private *de){ unsigned rx_tail = de->rx_tail; unsigned rx_work = DE_RX_RING_SIZE; unsigned drop = 0; int rc; while (rx_work--) { u32 status, len; dma_addr_t mapping; struct sk_buff *skb, *copy_skb; unsigned copying_skb, buflen; skb = de->rx_skb[rx_tail].skb; if (!skb) BUG(); rmb(); status = le32_to_cpu(de->rx_ring[rx_tail].opts1); if (status & DescOwn) break; len = ((status >> 16) & 0x7ff) - 4; mapping = de->rx_skb[rx_tail].mapping; if (unlikely(drop)) { de->net_stats.rx_dropped++; goto rx_next; } if (unlikely((status & 0x38008300) != 0x0300)) { de_rx_err_acct(de, rx_tail, status, len); goto rx_next; } copying_skb = (len <= rx_copybreak); if (unlikely(netif_msg_rx_status(de))) printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n", de->dev->name, rx_tail, status, len, copying_skb); buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz; copy_skb = dev_alloc_skb (buflen); if (unlikely(!copy_skb)) { de->net_stats.rx_dropped++; drop = 1; rx_work = 100; goto rx_next; } copy_skb->dev = de->dev; if (!copying_skb) { pci_unmap_single(de->pdev, mapping, buflen, PCI_DMA_FROMDEVICE); skb_put(skb, len); mapping = de->rx_skb[rx_tail].mapping = pci_map_single(de->pdev, copy_skb->data, buflen, PCI_DMA_FROMDEVICE); de->rx_skb[rx_tail].skb = copy_skb; } else { pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); memcpy(skb_put(copy_skb, len), skb->data, len); pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; } skb->protocol = eth_type_trans (skb, de->dev); de->net_stats.rx_packets++; de->net_stats.rx_bytes += skb->len; de->dev->last_rx = jiffies; rc = netif_rx (skb); if (rc == NET_RX_DROP) drop = 1;rx_next: de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn); if (rx_tail == (DE_RX_RING_SIZE - 1)) de->rx_ring[rx_tail].opts2 = cpu_to_le32(RingEnd | de->rx_buf_sz); else de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz); de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping); rx_tail = NEXT_RX(rx_tail); } if (!rx_work) printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name); de->rx_tail = rx_tail;}static irqreturn_t de_interrupt (int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = dev_instance; struct de_private *de = dev->priv; u32 status; status = dr32(MacStatus); if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF)) return IRQ_NONE; if (netif_msg_intr(de)) printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n", dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail); dw32(MacStatus, status); if (status & (RxIntr | RxEmpty)) { de_rx(de); if (status & RxEmpty) dw32(RxPoll, NormalRxPoll); } spin_lock(&de->lock); if (status & (TxIntr | TxEmpty)) de_tx(de); if (status & (LinkPass | LinkFail)) de_media_interrupt(de, status); spin_unlock(&de->lock); if (status & PciErr) { u16 pci_status; pci_read_config_word(de->pdev, PCI_STATUS, &pci_status); pci_write_config_word(de->pdev, PCI_STATUS, pci_status); printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n", dev->name, status, pci_status); } return IRQ_HANDLED;}static void de_tx (struct de_private *de){ unsigned tx_head = de->tx_head; unsigned tx_tail = de->tx_tail; while (tx_tail != tx_head) { struct sk_buff *skb; u32 status; rmb(); status = le32_to_cpu(de->tx_ring[tx_tail].opts1); if (status & DescOwn) break; skb = de->tx_skb[tx_tail].skb; if (!skb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -