📄 tulip.c
字号:
/* tulip.c: A DEC 21040-family ethernet driver for Linux. *//* Written 1994-1998 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. This driver is for the Digital "Tulip" ethernet adapter interface. It should work with most DEC 21*4*-based chips/ethercards, as well as PNIC and MXIC chips. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html*/#define SMP_CHECKstatic const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";/* A few user-configurable values. *//* Maximum events (Rx packets, etc.) to handle at each interrupt. */static int max_interrupt_work = 25;#define MAX_UNITS 8/* Used to pass the full-duplex flag, etc. */static int full_duplex[MAX_UNITS] = {0, };static int options[MAX_UNITS] = {0, };static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. *//* The possible media types that can be set in options[] are: */static const char * const medianame[] = { "10baseT", "10base2", "AUI", "100baseTx", "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",};/* Set if the PCI BIOS detects the chips on a multiport board backwards. */#ifdef REVERSE_PROBE_ORDERstatic int reverse_probe = 1;#elsestatic int reverse_probe = 0;#endif/* Keep the ring sizes a power of two for efficiency. Making the Tx ring too large decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */#define TX_RING_SIZE 16#define RX_RING_SIZE 32/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */#ifdef __alpha__static int rx_copybreak = 1518;#elsestatic int rx_copybreak = 100;#endif/* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (4*HZ)#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <asm/processor.h> /* Processor type for cache alignment. */#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>/* Kernel compatibility defines, common to David Hind's PCMCIA package. This is only in the support-all-kernels source code. */#include <linux/version.h> /* Evil, but neccessary */#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300#define RUN_AT(x) (x) /* What to put in timer->expires. */#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)#define virt_to_bus(addr) ((unsigned long)addr)#define bus_to_virt(addr) ((void*)addr)#else /* 1.3.0 and later */#define RUN_AT(x) (jiffies + (x))#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)#endif#if (LINUX_VERSION_CODE >= 0x10344)#define NEW_MULTICAST#include <linux/delay.h>#endif#ifdef SA_SHIRQ#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)#else#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)#endif#if (LINUX_VERSION_CODE < 0x20123)#define hard_smp_processor_id() smp_processor_id()#define test_and_set_bit(val, addr) set_bit(val, addr)#endif/* This my implementation of shared IRQs, now only used for 1.2.13. */#ifdef HAVE_SHARED_IRQ#define USE_SHARED_IRQ#include <linux/shared_irq.h>#endif/* The total size is unusually large: The 21040 aligns each of its 16 longword-wide registers on a quadword boundary. */#define TULIP_TOTAL_SIZE 0x80#ifdef HAVE_DEVLISTstruct netdev_entry tulip_drv ={"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};#endif#ifdef TULIP_DEBUGint tulip_debug = TULIP_DEBUG;#elseint tulip_debug = 1;#endif/* Theory of OperationI. Board CompatibilityThis device driver is designed for the DECchip "Tulip", Digital'ssingle-chip ethernet controllers for PCI. Supported members of the familyare the 21040, 21041, 21140, 21140A, 21142, and 21143. These chips are used onmany PCI boards including the SMC EtherPower series.II. Board-specific settingsPCI bus devices are configured by the system at boot time, so no jumpersneed to be set on the board. The system BIOS preferably should assign thePCI INTA signal to an otherwise unused system IRQ line.Note: Kernel versions earlier than 1.3.73 do not support shared PCIinterrupt lines.III. Driver operationIIIa. Ring buffersThe Tulip can use either ring buffers or lists of Tx and Rx descriptors.This driver uses statically allocated rings of Rx and Tx descriptors, set atcompile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffsfor the Rx ring buffers at open() time and passes the skb->data field to theTulip as receive data buffers. When an incoming frame is less thanRX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame iscopied to the new skbuff. When the incoming frame is larger, the skbuff ispassed directly up the protocol stack and replaced by a newly allocatedskbuff.The RX_COPYBREAK value is chosen to trade-off the memory wasted byusing a full-sized skbuff for small frames vs. the copying costs of largerframes. For small frames the copying cost is negligible (esp. consideringthat we are pre-loading the cache with immediately useful headerinformation). For large frames the copying cost is non-trivial, and thelarger copy might flush the cache of useful data. A subtle aspect of thischoice is that the Tulip only receives into longword aligned buffers, thusthe IP header at offset 14 isn't longword aligned for further processing.Copied frames are put into the new skbuff at an offset of "+2", thus copyinghas the beneficial effect of aligning the IP header and preloading thecache.IIIC. SynchronizationThe driver runs as two independent, single-threaded flows of control. Oneis the send-packet routine, which enforces single-threaded use by thedev->tbusy flag. The other thread is the interrupt handler, which is singlethreaded by the hardware and other software.The send packet thread has partial control over the Tx ring and 'dev->tbusy'flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the nextqueue slot is empty, it clears the tbusy flag when finished otherwise it setsthe 'tp->tx_full' flag.The interrupt handler has exclusive control over the Rx ring and records statsfrom the Tx ring. (The Tx-done interrupt can't be selectively turned off, sowe can't avoid the interrupt overhead by having the Tx routine reap the Txstats.) After reaping the stats, it marks the queue entry as empty by settingthe 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both thetx_full and tbusy flags.IV. NotesThanks to Duke Kamstra of SMC for providing an EtherPower board.IVb. Referenceshttp://cesdis.gsfc.nasa.gov/linux/misc/NWay.htmlhttp://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")http://www.national.com/pf/DP/DP83840.htmlIVc. ErrataThe DEC databook doesn't document which Rx filter settings accept broadcastpackets. Nor does it document how to configure the part to configure theserial subsystem for normal (vs. loopback) operation or how to have itautoswitch between internal 10baseT, SIA and AUI transceivers.The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the lastregister of the set CSR12-15 written. Hmmm, now how is that possible? *//* A few values that may be tweaked. */#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*//* 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 0x6969#ifndef PCI_VENDOR_ID_DEC /* Now defined in linux/pci.h */#define PCI_VENDOR_ID_DEC 0x1011#define PCI_DEVICE_ID_TULIP 0x0002 /* 21040. */#define PCI_DEVICE_ID_TULIP_FAST 0x0009 /* 21140. */#endif#ifndef PCI_DEVICE_ID_DEC_TULIP_PLUS#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 /* 21041. */#endif#ifndef PCI_DEVICE_ID_DEC_TULIP_21142#define PCI_DEVICE_ID_DEC_TULIP_21142 0x0019#endif#ifndef PCI_VENDOR_ID_LITEON#define PCI_VENDOR_ID_LITEON 0x11AD#endif#ifndef PCI_VENDOR_ID_MXIC#define PCI_VENDOR_ID_MXIC 0x10d9#define PCI_DEVICE_ID_MX98713 0x0512#define PCI_DEVICE_ID_MX98715 0x0531#define PCI_DEVICE_ID_MX98725 0x0531#endif/* The rest of these values should never change. */static void tulip_timer(unsigned long data);static void t21142_timer(unsigned long data);static void mxic_timer(unsigned long data);static void pnic_timer(unsigned long data);/* A table describing the chip types. */enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};static struct tulip_chip_table { int vendor_id, device_id; char *chip_name; int io_size; int valid_intrs; /* CSR7 interrupt enable settings */ int flags; void (*media_timer)(unsigned long data);} tulip_tbl[] = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE, t21142_timer }, { PCI_VENDOR_ID_LITEON, 0x0002, "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer }, { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ }, { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715, "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725, "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, {0, 0, 0, 0},};/* This matches the table above. */enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, LC82C168, MX98713, MX98715, MX98725};/* A full-duplex map for media types. */enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, MediaIs100=16};static const char media_cap[] ={0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };/* Offsets to the Command and Status Registers, "CSRs". All accesses must be longword instructions and quadword aligned. */enum tulip_offsets { CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };/* The bits in the CSR5 status registers, mostly interrupt sources. */enum status_bits { TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, NormalIntr=0x10000, AbnormalIntr=0x8000, RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,};/* The Tulip Rx and Tx buffer descriptors. */struct tulip_rx_desc { s32 status; s32 length; u32 buffer1, buffer2;};struct tulip_tx_desc { s32 status; s32 length; u32 buffer1, buffer2; /* We use only buffer 1. */};struct medialeaf { u8 type; u8 media; unsigned char *leafdata;};struct mediatable { u16 defaultmedia; u8 leafcount, csr12dir; /* General purpose pin directions. */ unsigned has_mii:1, has_nonmii:1; struct medialeaf mleaf[0];};struct mediainfo { struct mediainfo *next; int info_type; int index; unsigned char *info;};struct tulip_private { char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct device *next_module; struct tulip_rx_desc rx_ring[RX_RING_SIZE]; struct tulip_tx_desc tx_ring[TX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; char *rx_buffs; /* Address of temporary Rx buffers. */ u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */ int chip_id; int revision;#if LINUX_VERSION_CODE > 0x20139 struct net_device_stats stats;#else struct enet_statistics stats;#endif struct timer_list timer; /* Media selection timer. */ int interrupt; /* In-interrupt flag. */#ifdef SMP_CHECK int smp_proc_id; /* Which processor in IRQ handler. */#endif unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; unsigned int fake_addr:1; /* Multiport board faked address. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ unsigned int mediasense:1; /* Media sensing in progress. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -