📄 starfire.c
字号:
/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. *//* Written/Copyright 1998-2003 by Donald Becker. 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. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 914 Bay Ridge Road, Suite 220 Annapolis MD 21403 Support information and updates available at http://www.scyld.com/network/starfire.html*//* These identify the driver base version and may not be removed. */static const char version1[] ="starfire.c:v1.09 7/22/2003 Copyright by Donald Becker <becker@scyld.com>\n";static const char version2[] =" Updates and info at http://www.scyld.com/network/starfire.html\n";/* The user-configurable values. These may be modified when a driver module is loaded.*//* Used for tuning interrupt latency vs. overhead. */static int interrupt_mitigation = 0x0;/* Message enable level: 0..31 = no..all messages. See NETIF_MSG docs. */static int debug = 2;/* Maximum events (Rx packets, etc.) to handle at each interrupt. */static int max_interrupt_work = 20;/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Starfire has a 512 element hash table based on the Ethernet CRC. */static int multicast_filter_limit = 32;/* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */static int rx_copybreak = 0;/* Used to pass the media type, etc. Both 'options[]' and 'full_duplex[]' exist for driver interoperability, however full_duplex[] should never be used in new configurations. The media type is usually passed in 'options[]'. The default is autonegotation for speed and duplex. This should rarely be overridden. Use option values 0x10/0x20 for 10Mbps, 0x100,0x200 for 100Mbps. Use option values 0x10 and 0x100 for forcing half duplex fixed speed. Use option values 0x20 and 0x200 for forcing full duplex operation.*/#define MAX_UNITS 8 /* More are supported, limit only on options */static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};/* Automatically extracted configuration info:probe-func: starfire_probeconfig-in: tristate 'Adaptec DuraLAN ("starfire") series PCI Ethernet support' CONFIG_DURLANc-help-name: Adaptec DuraLAN ("starfire") series PCI Ethernet supportc-help-symbol: CONFIG_DURALANc-help: This driver is for the Adaptec DuraLAN series, the 6915, 62022c-help: and 62044 boards.c-help: Design information, usage details and updates are available fromc-help: http://www.scyld.com/network/starfire.html*//* Operational parameters that are set at compile time. *//* The "native" ring sizes are either 256 or 2048. However in some modes a descriptor may be marked to wrap the ring earlier. The driver allocates a single page for each descriptor ring, constraining the maximum size in an architecture-dependent way.*/#define RX_RING_SIZE 256#define TX_RING_SIZE 32/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */#define DONE_Q_SIZE 1024/* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (6*HZ)/* Allocation size of Rx buffers with normal sized Ethernet frames. Do not change this value without good reason. This is not a limit, but a way to keep a consistent allocation size among drivers. */#define PKT_BUF_SZ 1536#ifndef __KERNEL__#define __KERNEL__#endif#if !defined(__OPTIMIZE__)#warning You must compile this file with the correct options!#warning See the last lines of the source file.#error You must compile this driver with "-O".#endif/* Include files, designed to support most kernel versions 2.0.0 and later. */#include <linux/config.h>#if defined(CONFIG_SMP) && ! defined(__SMP__)#define __SMP__#endif#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)#define MODVERSIONS#endif#include <linux/version.h>#if defined(MODVERSIONS)#include <linux/modversions.h>#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#if LINUX_VERSION_CODE >= 0x20400#include <linux/slab.h>#else#include <linux/malloc.h>#endif#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/processor.h> /* Processor type for cache alignment. */#include <asm/bitops.h>#include <asm/io.h>#ifdef INLINE_PCISCAN#include "k_compat.h"#else#include "pci-scan.h"#include "kern_compat.h"#endif/* Condensed operations for readability. Compatibility defines are in kern_compat.h */#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))#if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE)char kernel_version[] = UTS_RELEASE;#endifMODULE_AUTHOR("Donald Becker <becker@scyld.com>");MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");MODULE_LICENSE("GPL");MODULE_PARM(debug, "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(multicast_filter_limit, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM_DESC(debug, "Driver message enable level (0-31)");MODULE_PARM_DESC(options, "Force transceiver type or fixed speed+duplex");MODULE_PARM_DESC(max_interrupt_work, "Driver maximum events handled per interrupt");MODULE_PARM_DESC(full_duplex, "Non-zero to set forced full duplex (deprecated).");MODULE_PARM_DESC(rx_copybreak, "Breakpoint in bytes for copy-only-tiny-frames");MODULE_PARM_DESC(multicast_filter_limit, "Multicast addresses before switching to Rx-all-multicast");/* Theory of OperationI. Board CompatibilityThis driver is for the Adaptec 6915 DuraLAN "Starfire" 64 bit PCI Ethernetadapter, and the multiport boards using the same chip.II. Board-specific settingsIII. Driver operationIIIa. Ring buffersThe Starfire hardware uses multiple fixed-size descriptor queues/rings. Thering sizes are set fixed by the hardware, but may optionally be wrappedearlier by the END bit in the descriptor.This driver uses that hardware queue size for the Rx ring, where a largenumber of entries has no ill effect beyond increases the potential backlog.The Tx ring is wrapped with the END bit, since a large hardware Tx queuedisables the queue layer priority ordering and we have no mechanism toutilize the hardware two-level priority queue. When modifying theRX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warninglevels.IIIb/c. Transmit/Receive StructureSee the Adaptec manual for the many possible structures, and options foreach structure. There are far too many to document here.For transmit this driver uses type 1 transmit descriptors, and relies onautomatic minimum-length padding. It does not use the completion queueconsumer index, but instead checks for non-zero status entries.For receive this driver uses type 0 receive descriptors. The driverallocates full frame size skbuffs for the Rx ring buffers, so all framesshould fit in a single descriptor. The driver does not use the completionqueue consumer index, but instead checks for non-zero status entries.When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuffis allocated and the frame is copied to the new skbuff. When the incomingframe is larger, the skbuff is passed directly up the protocol stack.Buffers consumed this way are replaced by newly allocated skbuffs in a laterphase of receive.A notable aspect of operation is that unaligned buffers are not permitted bythe Starfire hardware. The IP header at offset 14 in an ethernet frame thusisn't longword aligned, which may cause problems on some machinee.g. Alphas. Copied frames are put into the skbuff at an offset of "+2",16-byte aligning the IP header.IIId. 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 interrupt handling 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 'lp->tx_full' flag.The interrupt handler has exclusive control over the Rx ring and records statsfrom the Tx ring. After reaping the stats, it marks the Tx queue entry asempty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, itclears both the tx_full and tbusy flags.IV. NotesIVb. ReferencesThe Adaptec Starfire manuals, available only from Adaptec.http://www.scyld.com/expert/100mbps.htmlhttp://www.scyld.com/expert/NWay.htmlIVc. Errata*/static void *starfire_probe1(struct pci_dev *pdev, void *init_dev, long ioaddr, int irq, int chip_idx, int find_cnt);static int starfire_pwr_event(void *dev_instance, int event);enum chip_capability_flags {CanHaveMII=1, };#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)/* And maps in 0.5MB(!) -- no I/O mapping here! */#define MEM_ADDR_SZ 0x80000#if 0 && (defined(__x86_64) || defined(__alpha__))/* Enable 64 bit address modes. */#define STARFIRE_ADDR_64BITS 1#endifstatic struct pci_id_info pci_id_tbl[] = { {"Adaptec Starfire 6915", { 0x69159004, 0xffffffff, }, PCI_IOTYPE, MEM_ADDR_SZ, CanHaveMII}, {0,}, /* 0 terminated list. */};struct drv_id_info starfire_drv_id = { "starfire", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_id_tbl, starfire_probe1, starfire_pwr_event };/* Offsets to the device registers. Unlike software-only systems, device drivers interact with complex hardware. It's not useful to define symbolic names for every register bit in the device. The name can only partially document the semantics and make the driver longer and more difficult to read. In general, only the important configuration values or bits changed multiple times should be defined symbolically.*/enum register_offsets { PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074, IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088, MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000, TxDescCtrl=0x50090, TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */ TxRingHiAddr=0x5009C, /* 64 bit address extension. */ TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4, TxThreshold=0x500B0, CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8, RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0, CompletionQConsumerIdx=0x500C4, RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0, RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4, TxMode=0x55000,};/* Bits in the interrupt status/mask registers. */enum intr_status_bits { IntrNormalSummary=0x8000, IntrAbnormalSummary=0x02000000, IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000, IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000, StatsMax=0x08000000, LinkChange=0xf0000000, IntrTxDataLow=0x00040000, IntrPCIPin=0x01,};/* Bits in the RxFilterMode register. */enum rx_mode_bits { AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01, AcceptMulticast=0x10, AcceptMyPhys=0xE040,};/* Misc. bits. Symbolic names so that may be searched for. */enum misc_bits { ChipResetCmd=1, /* PCIDeviceConfig */ PCIIntEnb=0x00800000, /* PCIDeviceConfig */ TxEnable=0x0A, RxEnable=0x05, SoftIntr=0x100, /* GenCtrl */};/* The Rx and Tx buffer descriptors. */struct starfire_rx_desc { u32 rxaddr; /* Optionally 64 bits. */#if defined(STARFIRE_ADDR_64BITS) u32 rxaddr_hi; /* Optionally 64 bits. */#endif};enum rx_desc_bits { RxDescValid=1, RxDescEndRing=2,};/* Completion queue entry. You must update the page allocation, init_ring and the shift count in rx() if using a larger format. */struct rx_done_desc { u32 status; /* Low 16 bits is length. */#ifdef full_rx_status u32 status2; u16 vlanid; u16 csum; /* partial checksum */ u32 timestamp;#endif};enum rx_done_bits { RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,};/* Type 1 Tx descriptor. */struct starfire_tx_desc { u32 status; /* Upper bits are status, lower 16 length. */ u32 addr;};enum tx_desc_bits { TxDescID=0xB1010000, /* Also marks single fragment, add CRC. */ TxDescIntr=0x08000000, TxRingWrap=0x04000000,};struct tx_done_report { u32 status; /* timestamp, index. */#if 0 u32 intrstatus; /* interrupt status */#endif};#define PRIV_ALIGN 15 /* Required alignment mask */struct netdev_private { /* Descriptor rings first for alignment. */ struct starfire_rx_desc *rx_ring; struct starfire_tx_desc *tx_ring; struct net_device *next_module; /* Link for devices of this type. */ void *priv_addr; /* Unaligned address for kfree */ const char *product_name; /* The addresses of rx/tx-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; u8 pad0[100]; /* Impact padding */ /* Pointers to completion queues (full pages). Cache line pad.. */ struct rx_done_desc *rx_done_q __attribute__((aligned (L1_CACHE_BYTES)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -