11da177e4SLinus Torvalds /* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */ 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds Written 1997-2001 by Donald Becker. 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds This software may be used and distributed according to the terms of 61da177e4SLinus Torvalds the GNU General Public License (GPL), incorporated herein by reference. 71da177e4SLinus Torvalds Drivers based on or derived from this code fall under the GPL and must 81da177e4SLinus Torvalds retain the authorship, copyright and license notice. This file is not 91da177e4SLinus Torvalds a complete program and may only be used when the entire operating 101da177e4SLinus Torvalds system is licensed under the GPL. 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter. 131da177e4SLinus Torvalds It also supports the Symbios Logic version of the same chip core. 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds The author may be reached as becker@scyld.com, or C/O 161da177e4SLinus Torvalds Scyld Computing Corporation 171da177e4SLinus Torvalds 410 Severn Ave., Suite 210 181da177e4SLinus Torvalds Annapolis MD 21403 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds Support and updates available at 211da177e4SLinus Torvalds http://www.scyld.com/network/yellowfin.html 2203a8c661SJeff Garzik [link no longer provides useful info -jgarzik] 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 26acbbf1f1SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 27acbbf1f1SJoe Perches 281da177e4SLinus Torvalds #define DRV_NAME "yellowfin" 29d5b20697SAndy Gospodarek #define DRV_VERSION "2.1" 30d5b20697SAndy Gospodarek #define DRV_RELDATE "Sep 11, 2006" 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* The user-configurable values. 331da177e4SLinus Torvalds These may be modified when a driver module is loaded.*/ 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ 361da177e4SLinus Torvalds /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ 371da177e4SLinus Torvalds static int max_interrupt_work = 20; 381da177e4SLinus Torvalds static int mtu; 391da177e4SLinus Torvalds #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ 401da177e4SLinus Torvalds /* System-wide count of bogus-rx frames. */ 411da177e4SLinus Torvalds static int bogus_rx; 421da177e4SLinus Torvalds static int dma_ctrl = 0x004A0263; /* Constrained by errata */ 431da177e4SLinus Torvalds static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ 441da177e4SLinus Torvalds #elif defined(YF_NEW) /* A future perfect board :->. */ 451da177e4SLinus Torvalds static int dma_ctrl = 0x00CAC277; /* Override when loading module! */ 461da177e4SLinus Torvalds static int fifo_cfg = 0x0028; 471da177e4SLinus Torvalds #else 48f71e1309SArjan van de Ven static const int dma_ctrl = 0x004A0263; /* Constrained by errata */ 49f71e1309SArjan van de Ven static const int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ 501da177e4SLinus Torvalds #endif 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds /* Set the copy breakpoint for the copy-only-tiny-frames scheme. 531da177e4SLinus Torvalds Setting to > 1514 effectively disables this feature. */ 541da177e4SLinus Torvalds static int rx_copybreak; 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* Used to pass the media type, etc. 571da177e4SLinus Torvalds No media types are currently defined. These exist for driver 581da177e4SLinus Torvalds interoperability. 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds #define MAX_UNITS 8 /* More are supported, limit only on options */ 611da177e4SLinus Torvalds static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 621da177e4SLinus Torvalds static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* Do ugly workaround for GX server chipset errata. */ 651da177e4SLinus Torvalds static int gx_fix; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* Operational parameters that are set at compile time. */ 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* Keep the ring sizes a power of two for efficiency. 701da177e4SLinus Torvalds Making the Tx ring too long decreases the effectiveness of channel 711da177e4SLinus Torvalds bonding and packet priority. 721da177e4SLinus Torvalds There are no ill effects from too-large receive rings. */ 731da177e4SLinus Torvalds #define TX_RING_SIZE 16 741da177e4SLinus Torvalds #define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */ 751da177e4SLinus Torvalds #define RX_RING_SIZE 64 761da177e4SLinus Torvalds #define STATUS_TOTAL_SIZE TX_RING_SIZE*sizeof(struct tx_status_words) 771da177e4SLinus Torvalds #define TX_TOTAL_SIZE 2*TX_RING_SIZE*sizeof(struct yellowfin_desc) 781da177e4SLinus Torvalds #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct yellowfin_desc) 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* Operational parameters that usually are not changed. */ 811da177e4SLinus Torvalds /* Time in jiffies before concluding the transmitter is hung. */ 821da177e4SLinus Torvalds #define TX_TIMEOUT (2*HZ) 831da177e4SLinus Torvalds #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds #define yellowfin_debug debug 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds #include <linux/module.h> 881da177e4SLinus Torvalds #include <linux/kernel.h> 891da177e4SLinus Torvalds #include <linux/string.h> 901da177e4SLinus Torvalds #include <linux/timer.h> 911da177e4SLinus Torvalds #include <linux/errno.h> 921da177e4SLinus Torvalds #include <linux/ioport.h> 931da177e4SLinus Torvalds #include <linux/interrupt.h> 941da177e4SLinus Torvalds #include <linux/pci.h> 951da177e4SLinus Torvalds #include <linux/init.h> 961da177e4SLinus Torvalds #include <linux/mii.h> 971da177e4SLinus Torvalds #include <linux/netdevice.h> 981da177e4SLinus Torvalds #include <linux/etherdevice.h> 991da177e4SLinus Torvalds #include <linux/skbuff.h> 1001da177e4SLinus Torvalds #include <linux/ethtool.h> 1011da177e4SLinus Torvalds #include <linux/crc32.h> 1021da177e4SLinus Torvalds #include <linux/bitops.h> 1031da177e4SLinus Torvalds #include <asm/uaccess.h> 1041da177e4SLinus Torvalds #include <asm/processor.h> /* Processor type for cache alignment. */ 1051da177e4SLinus Torvalds #include <asm/unaligned.h> 1061da177e4SLinus Torvalds #include <asm/io.h> 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* These identify the driver base version and may not be removed. */ 109134c1f15SBill Pemberton static const char version[] = 1101da177e4SLinus Torvalds KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n" 111ad361c98SJoe Perches " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n"; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); 1141da177e4SLinus Torvalds MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); 1151da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds module_param(max_interrupt_work, int, 0); 1181da177e4SLinus Torvalds module_param(mtu, int, 0); 1191da177e4SLinus Torvalds module_param(debug, int, 0); 1201da177e4SLinus Torvalds module_param(rx_copybreak, int, 0); 1211da177e4SLinus Torvalds module_param_array(options, int, NULL, 0); 1221da177e4SLinus Torvalds module_param_array(full_duplex, int, NULL, 0); 1231da177e4SLinus Torvalds module_param(gx_fix, int, 0); 1241da177e4SLinus Torvalds MODULE_PARM_DESC(max_interrupt_work, "G-NIC maximum events handled per interrupt"); 1251da177e4SLinus Torvalds MODULE_PARM_DESC(mtu, "G-NIC MTU (all boards)"); 1261da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "G-NIC debug level (0-7)"); 1271da177e4SLinus Torvalds MODULE_PARM_DESC(rx_copybreak, "G-NIC copy breakpoint for copy-only-tiny-frames"); 1281da177e4SLinus Torvalds MODULE_PARM_DESC(options, "G-NIC: Bits 0-3: media type, bit 17: full duplex"); 1291da177e4SLinus Torvalds MODULE_PARM_DESC(full_duplex, "G-NIC full duplex setting(s) (1)"); 1301da177e4SLinus Torvalds MODULE_PARM_DESC(gx_fix, "G-NIC: enable GX server chipset bug workaround (0-1)"); 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds /* 1331da177e4SLinus Torvalds Theory of Operation 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds I. Board Compatibility 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds This device driver is designed for the Packet Engines "Yellowfin" Gigabit 1381da177e4SLinus Torvalds Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the 1391da177e4SLinus Torvalds Symbios 53C885E dual function chip. 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds II. Board-specific settings 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds PCI bus devices are configured by the system at boot time, so no jumpers 1441da177e4SLinus Torvalds need to be set on the board. The system BIOS preferably should assign the 1451da177e4SLinus Torvalds PCI INTA signal to an otherwise unused system IRQ line. 1461da177e4SLinus Torvalds Note: Kernel versions earlier than 1.3.73 do not support shared PCI 1471da177e4SLinus Torvalds interrupt lines. 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds III. Driver operation 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds IIIa. Ring buffers 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds The Yellowfin uses the Descriptor Based DMA Architecture specified by Apple. 1541da177e4SLinus Torvalds This is a descriptor list scheme similar to that used by the EEPro100 and 1551da177e4SLinus Torvalds Tulip. This driver uses two statically allocated fixed-size descriptor lists 1561da177e4SLinus Torvalds formed into rings by a branch from the final descriptor to the beginning of 1571da177e4SLinus Torvalds the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds The driver allocates full frame size skbuffs for the Rx ring buffers at 1601da177e4SLinus Torvalds open() time and passes the skb->data field to the Yellowfin as receive data 1611da177e4SLinus Torvalds buffers. When an incoming frame is less than RX_COPYBREAK bytes long, 1621da177e4SLinus Torvalds a fresh skbuff is allocated and the frame is copied to the new skbuff. 1631da177e4SLinus Torvalds When the incoming frame is larger, the skbuff is passed directly up the 1641da177e4SLinus Torvalds protocol stack and replaced by a newly allocated skbuff. 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds The RX_COPYBREAK value is chosen to trade-off the memory wasted by 1671da177e4SLinus Torvalds using a full-sized skbuff for small frames vs. the copying costs of larger 1681da177e4SLinus Torvalds frames. For small frames the copying cost is negligible (esp. considering 1691da177e4SLinus Torvalds that we are pre-loading the cache with immediately useful header 1701da177e4SLinus Torvalds information). For large frames the copying cost is non-trivial, and the 1711da177e4SLinus Torvalds larger copy might flush the cache of useful data. 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds IIIC. Synchronization 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds The driver runs as two independent, single-threaded flows of control. One 1761da177e4SLinus Torvalds is the send-packet routine, which enforces single-threaded use by the 1771da177e4SLinus Torvalds dev->tbusy flag. The other thread is the interrupt handler, which is single 1781da177e4SLinus Torvalds threaded by the hardware and other software. 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds The send packet thread has partial control over the Tx ring and 'dev->tbusy' 1811da177e4SLinus Torvalds flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next 1821da177e4SLinus Torvalds queue slot is empty, it clears the tbusy flag when finished otherwise it sets 1831da177e4SLinus Torvalds the 'yp->tx_full' flag. 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds The interrupt handler has exclusive control over the Rx ring and records stats 1861da177e4SLinus Torvalds from the Tx ring. After reaping the stats, it marks the Tx queue entry as 1871da177e4SLinus Torvalds empty by incrementing the dirty_tx mark. Iff the 'yp->tx_full' flag is set, it 1881da177e4SLinus Torvalds clears both the tx_full and tbusy flags. 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds IV. Notes 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds Thanks to Kim Stearns of Packet Engines for providing a pair of G-NIC boards. 1931da177e4SLinus Torvalds Thanks to Bruce Faust of Digitalscape for providing both their SYM53C885 board 1941da177e4SLinus Torvalds and an AlphaStation to verifty the Alpha port! 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds IVb. References 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds Yellowfin Engineering Design Specification, 4/23/97 Preliminary/Confidential 1991da177e4SLinus Torvalds Symbios SYM53C885 PCI-SCSI/Fast Ethernet Multifunction Controller Preliminary 2001da177e4SLinus Torvalds Data Manual v3.0 2011da177e4SLinus Torvalds http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html 2021da177e4SLinus Torvalds http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds IVc. Errata 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds See Packet Engines confidential appendix (prototype chips only). 2071da177e4SLinus Torvalds */ 2081da177e4SLinus Torvalds 2096aa20a22SJeff Garzik 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds enum capability_flags { 2121da177e4SLinus Torvalds HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, 2131da177e4SLinus Torvalds HasMACAddrBug=32, /* Only on early revs. */ 2141da177e4SLinus Torvalds DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */ 2151da177e4SLinus Torvalds }; 216c3d8e682SJeff Garzik 2171da177e4SLinus Torvalds /* The PCI I/O space extent. */ 218c3d8e682SJeff Garzik enum { 219c3d8e682SJeff Garzik YELLOWFIN_SIZE = 0x100, 220c3d8e682SJeff Garzik }; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds struct pci_id_info { 2231da177e4SLinus Torvalds const char *name; 2241da177e4SLinus Torvalds struct match_info { 2251da177e4SLinus Torvalds int pci, pci_mask, subsystem, subsystem_mask; 2261da177e4SLinus Torvalds int revision, revision_mask; /* Only 8 bits. */ 2271da177e4SLinus Torvalds } id; 2281da177e4SLinus Torvalds int drv_flags; /* Driver use, intended as capability flags. */ 2291da177e4SLinus Torvalds }; 2301da177e4SLinus Torvalds 231f71e1309SArjan van de Ven static const struct pci_id_info pci_id_tbl[] = { 2321da177e4SLinus Torvalds {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, 2331da177e4SLinus Torvalds FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom}, 2341da177e4SLinus Torvalds {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, 235c3d8e682SJeff Garzik HasMII | DontUseEeprom }, 2361f1bd5fcSJeff Garzik { } 2371da177e4SLinus Torvalds }; 2381da177e4SLinus Torvalds 239a3aa1884SAlexey Dobriyan static DEFINE_PCI_DEVICE_TABLE(yellowfin_pci_tbl) = { 2401da177e4SLinus Torvalds { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 2411da177e4SLinus Torvalds { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, 2421f1bd5fcSJeff Garzik { } 2431da177e4SLinus Torvalds }; 2441da177e4SLinus Torvalds MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* Offsets to the Yellowfin registers. Various sizes and alignments. */ 2481da177e4SLinus Torvalds enum yellowfin_offsets { 2491da177e4SLinus Torvalds TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C, 2501da177e4SLinus Torvalds TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18, 2511da177e4SLinus Torvalds RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C, 2521da177e4SLinus Torvalds RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58, 2531da177e4SLinus Torvalds EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86, 2541da177e4SLinus Torvalds ChipRev=0x8C, DMACtrl=0x90, TxThreshold=0x94, 2551da177e4SLinus Torvalds Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4, 2561da177e4SLinus Torvalds MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, 2571da177e4SLinus Torvalds MII_Status=0xAE, 2581da177e4SLinus Torvalds RxDepth=0xB8, FlowCtrl=0xBC, 2591da177e4SLinus Torvalds AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8, 2601da177e4SLinus Torvalds EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4, 2611da177e4SLinus Torvalds EEFeature=0xF5, 2621da177e4SLinus Torvalds }; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds /* The Yellowfin Rx and Tx buffer descriptors. 2651da177e4SLinus Torvalds Elements are written as 32 bit for endian portability. */ 2661da177e4SLinus Torvalds struct yellowfin_desc { 267e5a31421SAl Viro __le32 dbdma_cmd; 268e5a31421SAl Viro __le32 addr; 269e5a31421SAl Viro __le32 branch_addr; 270e5a31421SAl Viro __le32 result_status; 2711da177e4SLinus Torvalds }; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds struct tx_status_words { 2741da177e4SLinus Torvalds #ifdef __BIG_ENDIAN 2751da177e4SLinus Torvalds u16 tx_errs; 2761da177e4SLinus Torvalds u16 tx_cnt; 2771da177e4SLinus Torvalds u16 paused; 2781da177e4SLinus Torvalds u16 total_tx_cnt; 2791da177e4SLinus Torvalds #else /* Little endian chips. */ 2801da177e4SLinus Torvalds u16 tx_cnt; 2811da177e4SLinus Torvalds u16 tx_errs; 2821da177e4SLinus Torvalds u16 total_tx_cnt; 2831da177e4SLinus Torvalds u16 paused; 2841da177e4SLinus Torvalds #endif /* __BIG_ENDIAN */ 2851da177e4SLinus Torvalds }; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* Bits in yellowfin_desc.cmd */ 2881da177e4SLinus Torvalds enum desc_cmd_bits { 2891da177e4SLinus Torvalds CMD_TX_PKT=0x10000000, CMD_RX_BUF=0x20000000, CMD_TXSTATUS=0x30000000, 2901da177e4SLinus Torvalds CMD_NOP=0x60000000, CMD_STOP=0x70000000, 2911da177e4SLinus Torvalds BRANCH_ALWAYS=0x0C0000, INTR_ALWAYS=0x300000, WAIT_ALWAYS=0x030000, 2921da177e4SLinus Torvalds BRANCH_IFTRUE=0x040000, 2931da177e4SLinus Torvalds }; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* Bits in yellowfin_desc.status */ 2961da177e4SLinus Torvalds enum desc_status_bits { RX_EOP=0x0040, }; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds /* Bits in the interrupt status/mask registers. */ 2991da177e4SLinus Torvalds enum intr_status_bits { 3001da177e4SLinus Torvalds IntrRxDone=0x01, IntrRxInvalid=0x02, IntrRxPCIFault=0x04,IntrRxPCIErr=0x08, 3011da177e4SLinus Torvalds IntrTxDone=0x10, IntrTxInvalid=0x20, IntrTxPCIFault=0x40,IntrTxPCIErr=0x80, 3021da177e4SLinus Torvalds IntrEarlyRx=0x100, IntrWakeup=0x200, }; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds #define PRIV_ALIGN 31 /* Required alignment mask */ 3051da177e4SLinus Torvalds #define MII_CNT 4 3061da177e4SLinus Torvalds struct yellowfin_private { 3071da177e4SLinus Torvalds /* Descriptor rings first for alignment. 3081da177e4SLinus Torvalds Tx requires a second descriptor for status. */ 3091da177e4SLinus Torvalds struct yellowfin_desc *rx_ring; 3101da177e4SLinus Torvalds struct yellowfin_desc *tx_ring; 3111da177e4SLinus Torvalds struct sk_buff* rx_skbuff[RX_RING_SIZE]; 3121da177e4SLinus Torvalds struct sk_buff* tx_skbuff[TX_RING_SIZE]; 3131da177e4SLinus Torvalds dma_addr_t rx_ring_dma; 3141da177e4SLinus Torvalds dma_addr_t tx_ring_dma; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds struct tx_status_words *tx_status; 3171da177e4SLinus Torvalds dma_addr_t tx_status_dma; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds struct timer_list timer; /* Media selection timer. */ 3201da177e4SLinus Torvalds /* Frequently used and paired value: keep adjacent for cache effect. */ 3211da177e4SLinus Torvalds int chip_id, drv_flags; 3221da177e4SLinus Torvalds struct pci_dev *pci_dev; 3231da177e4SLinus Torvalds unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ 3241da177e4SLinus Torvalds unsigned int rx_buf_sz; /* Based on MTU+slack. */ 3251da177e4SLinus Torvalds struct tx_status_words *tx_tail_desc; 3261da177e4SLinus Torvalds unsigned int cur_tx, dirty_tx; 3271da177e4SLinus Torvalds int tx_threshold; 3281da177e4SLinus Torvalds unsigned int tx_full:1; /* The Tx queue is full. */ 3291da177e4SLinus Torvalds unsigned int full_duplex:1; /* Full-duplex operation requested. */ 3301da177e4SLinus Torvalds unsigned int duplex_lock:1; 3311da177e4SLinus Torvalds unsigned int medialock:1; /* Do not sense media. */ 3321da177e4SLinus Torvalds unsigned int default_port:4; /* Last dev->if_port value. */ 3331da177e4SLinus Torvalds /* MII transceiver section. */ 3341da177e4SLinus Torvalds int mii_cnt; /* MII device addresses. */ 3351da177e4SLinus Torvalds u16 advertising; /* NWay media advertisement */ 3361da177e4SLinus Torvalds unsigned char phys[MII_CNT]; /* MII device addresses, only first one used */ 3371da177e4SLinus Torvalds spinlock_t lock; 3381da177e4SLinus Torvalds void __iomem *base; 3391da177e4SLinus Torvalds }; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds static int read_eeprom(void __iomem *ioaddr, int location); 3421da177e4SLinus Torvalds static int mdio_read(void __iomem *ioaddr, int phy_id, int location); 3431da177e4SLinus Torvalds static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value); 3441da177e4SLinus Torvalds static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 3451da177e4SLinus Torvalds static int yellowfin_open(struct net_device *dev); 3461da177e4SLinus Torvalds static void yellowfin_timer(unsigned long data); 3471da177e4SLinus Torvalds static void yellowfin_tx_timeout(struct net_device *dev); 348e7a5965aSRoel Kluin static int yellowfin_init_ring(struct net_device *dev); 34961357325SStephen Hemminger static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, 35061357325SStephen Hemminger struct net_device *dev); 3517d12e780SDavid Howells static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance); 3521da177e4SLinus Torvalds static int yellowfin_rx(struct net_device *dev); 3531da177e4SLinus Torvalds static void yellowfin_error(struct net_device *dev, int intr_status); 3541da177e4SLinus Torvalds static int yellowfin_close(struct net_device *dev); 3551da177e4SLinus Torvalds static void set_rx_mode(struct net_device *dev); 3567282d491SJeff Garzik static const struct ethtool_ops ethtool_ops; 3571da177e4SLinus Torvalds 358bfd82c35SStephen Hemminger static const struct net_device_ops netdev_ops = { 359bfd82c35SStephen Hemminger .ndo_open = yellowfin_open, 360bfd82c35SStephen Hemminger .ndo_stop = yellowfin_close, 361bfd82c35SStephen Hemminger .ndo_start_xmit = yellowfin_start_xmit, 362afc4b13dSJiri Pirko .ndo_set_rx_mode = set_rx_mode, 363bfd82c35SStephen Hemminger .ndo_change_mtu = eth_change_mtu, 364bfd82c35SStephen Hemminger .ndo_validate_addr = eth_validate_addr, 365fe96aaa1SStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 366bfd82c35SStephen Hemminger .ndo_do_ioctl = netdev_ioctl, 367bfd82c35SStephen Hemminger .ndo_tx_timeout = yellowfin_tx_timeout, 368bfd82c35SStephen Hemminger }; 3691da177e4SLinus Torvalds 370134c1f15SBill Pemberton static int yellowfin_init_one(struct pci_dev *pdev, 3711da177e4SLinus Torvalds const struct pci_device_id *ent) 3721da177e4SLinus Torvalds { 3731da177e4SLinus Torvalds struct net_device *dev; 3741da177e4SLinus Torvalds struct yellowfin_private *np; 3751da177e4SLinus Torvalds int irq; 3761da177e4SLinus Torvalds int chip_idx = ent->driver_data; 3771da177e4SLinus Torvalds static int find_cnt; 3781da177e4SLinus Torvalds void __iomem *ioaddr; 3791da177e4SLinus Torvalds int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; 3801da177e4SLinus Torvalds int drv_flags = pci_id_tbl[chip_idx].drv_flags; 3811da177e4SLinus Torvalds void *ring_space; 3821da177e4SLinus Torvalds dma_addr_t ring_dma; 3831da177e4SLinus Torvalds #ifdef USE_IO_OPS 3841da177e4SLinus Torvalds int bar = 0; 3851da177e4SLinus Torvalds #else 3861da177e4SLinus Torvalds int bar = 1; 3871da177e4SLinus Torvalds #endif 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* when built into the kernel, we only print version if device is found */ 3901da177e4SLinus Torvalds #ifndef MODULE 3911da177e4SLinus Torvalds static int printed_version; 3921da177e4SLinus Torvalds if (!printed_version++) 3931da177e4SLinus Torvalds printk(version); 3941da177e4SLinus Torvalds #endif 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds i = pci_enable_device(pdev); 3971da177e4SLinus Torvalds if (i) return i; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds dev = alloc_etherdev(sizeof(*np)); 40041de8d4cSJoe Perches if (!dev) 4011da177e4SLinus Torvalds return -ENOMEM; 40241de8d4cSJoe Perches 4031da177e4SLinus Torvalds SET_NETDEV_DEV(dev, &pdev->dev); 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds np = netdev_priv(dev); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds if (pci_request_regions(pdev, DRV_NAME)) 4081da177e4SLinus Torvalds goto err_out_free_netdev; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds pci_set_master (pdev); 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds ioaddr = pci_iomap(pdev, bar, YELLOWFIN_SIZE); 4131da177e4SLinus Torvalds if (!ioaddr) 4141da177e4SLinus Torvalds goto err_out_free_res; 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds irq = pdev->irq; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds if (drv_flags & DontUseEeprom) 4191da177e4SLinus Torvalds for (i = 0; i < 6; i++) 4201da177e4SLinus Torvalds dev->dev_addr[i] = ioread8(ioaddr + StnAddr + i); 4211da177e4SLinus Torvalds else { 4221da177e4SLinus Torvalds int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); 4231da177e4SLinus Torvalds for (i = 0; i < 6; i++) 4241da177e4SLinus Torvalds dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /* Reset the chip. */ 4281da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + DMACtrl); 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds pci_set_drvdata(pdev, dev); 4311da177e4SLinus Torvalds spin_lock_init(&np->lock); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds np->pci_dev = pdev; 4341da177e4SLinus Torvalds np->chip_id = chip_idx; 4351da177e4SLinus Torvalds np->drv_flags = drv_flags; 4361da177e4SLinus Torvalds np->base = ioaddr; 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); 4391da177e4SLinus Torvalds if (!ring_space) 4401da177e4SLinus Torvalds goto err_out_cleardev; 44143d620c8SJoe Perches np->tx_ring = ring_space; 4421da177e4SLinus Torvalds np->tx_ring_dma = ring_dma; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); 4451da177e4SLinus Torvalds if (!ring_space) 4461da177e4SLinus Torvalds goto err_out_unmap_tx; 44743d620c8SJoe Perches np->rx_ring = ring_space; 4481da177e4SLinus Torvalds np->rx_ring_dma = ring_dma; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds ring_space = pci_alloc_consistent(pdev, STATUS_TOTAL_SIZE, &ring_dma); 4511da177e4SLinus Torvalds if (!ring_space) 4521da177e4SLinus Torvalds goto err_out_unmap_rx; 45343d620c8SJoe Perches np->tx_status = ring_space; 4541da177e4SLinus Torvalds np->tx_status_dma = ring_dma; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds if (dev->mem_start) 4571da177e4SLinus Torvalds option = dev->mem_start; 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds /* The lower four bits are the media type. */ 4601da177e4SLinus Torvalds if (option > 0) { 4611da177e4SLinus Torvalds if (option & 0x200) 4621da177e4SLinus Torvalds np->full_duplex = 1; 4631da177e4SLinus Torvalds np->default_port = option & 15; 4641da177e4SLinus Torvalds if (np->default_port) 4651da177e4SLinus Torvalds np->medialock = 1; 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) 4681da177e4SLinus Torvalds np->full_duplex = 1; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds if (np->full_duplex) 4711da177e4SLinus Torvalds np->duplex_lock = 1; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds /* The Yellowfin-specific entries in the device structure. */ 474bfd82c35SStephen Hemminger dev->netdev_ops = &netdev_ops; 4751da177e4SLinus Torvalds SET_ETHTOOL_OPS(dev, ðtool_ops); 4761da177e4SLinus Torvalds dev->watchdog_timeo = TX_TIMEOUT; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds if (mtu) 4791da177e4SLinus Torvalds dev->mtu = mtu; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds i = register_netdev(dev); 4821da177e4SLinus Torvalds if (i) 4831da177e4SLinus Torvalds goto err_out_unmap_status; 4841da177e4SLinus Torvalds 485acbbf1f1SJoe Perches netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n", 486acbbf1f1SJoe Perches pci_id_tbl[chip_idx].name, 4870795af57SJoe Perches ioread32(ioaddr + ChipRev), ioaddr, 488e174961cSJohannes Berg dev->dev_addr, irq); 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds if (np->drv_flags & HasMII) { 4911da177e4SLinus Torvalds int phy, phy_idx = 0; 4921da177e4SLinus Torvalds for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { 4931da177e4SLinus Torvalds int mii_status = mdio_read(ioaddr, phy, 1); 4941da177e4SLinus Torvalds if (mii_status != 0xffff && mii_status != 0x0000) { 4951da177e4SLinus Torvalds np->phys[phy_idx++] = phy; 4961da177e4SLinus Torvalds np->advertising = mdio_read(ioaddr, phy, 4); 497acbbf1f1SJoe Perches netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n", 498acbbf1f1SJoe Perches phy, mii_status, np->advertising); 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds np->mii_cnt = phy_idx; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds find_cnt++; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds return 0; 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds err_out_unmap_status: 5091da177e4SLinus Torvalds pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, 5101da177e4SLinus Torvalds np->tx_status_dma); 5111da177e4SLinus Torvalds err_out_unmap_rx: 5121da177e4SLinus Torvalds pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); 5131da177e4SLinus Torvalds err_out_unmap_tx: 5141da177e4SLinus Torvalds pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); 5151da177e4SLinus Torvalds err_out_cleardev: 5161da177e4SLinus Torvalds pci_iounmap(pdev, ioaddr); 5171da177e4SLinus Torvalds err_out_free_res: 5181da177e4SLinus Torvalds pci_release_regions(pdev); 5191da177e4SLinus Torvalds err_out_free_netdev: 5201da177e4SLinus Torvalds free_netdev (dev); 5211da177e4SLinus Torvalds return -ENODEV; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 524134c1f15SBill Pemberton static int read_eeprom(void __iomem *ioaddr, int location) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */ 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds iowrite8(location, ioaddr + EEAddr); 5291da177e4SLinus Torvalds iowrite8(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); 5301da177e4SLinus Torvalds while ((ioread8(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) 5311da177e4SLinus Torvalds ; 5321da177e4SLinus Torvalds return ioread8(ioaddr + EERead); 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds /* MII Managemen Data I/O accesses. 5361da177e4SLinus Torvalds These routines assume the MDIO controller is idle, and do not exit until 5371da177e4SLinus Torvalds the command is finished. */ 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds static int mdio_read(void __iomem *ioaddr, int phy_id, int location) 5401da177e4SLinus Torvalds { 5411da177e4SLinus Torvalds int i; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds iowrite16((phy_id<<8) + location, ioaddr + MII_Addr); 5441da177e4SLinus Torvalds iowrite16(1, ioaddr + MII_Cmd); 5451da177e4SLinus Torvalds for (i = 10000; i >= 0; i--) 5461da177e4SLinus Torvalds if ((ioread16(ioaddr + MII_Status) & 1) == 0) 5471da177e4SLinus Torvalds break; 5481da177e4SLinus Torvalds return ioread16(ioaddr + MII_Rd_Data); 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value) 5521da177e4SLinus Torvalds { 5531da177e4SLinus Torvalds int i; 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds iowrite16((phy_id<<8) + location, ioaddr + MII_Addr); 5561da177e4SLinus Torvalds iowrite16(value, ioaddr + MII_Wr_Data); 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* Wait for the command to finish. */ 5591da177e4SLinus Torvalds for (i = 10000; i >= 0; i--) 5601da177e4SLinus Torvalds if ((ioread16(ioaddr + MII_Status) & 1) == 0) 5611da177e4SLinus Torvalds break; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5646aa20a22SJeff Garzik 5651da177e4SLinus Torvalds static int yellowfin_open(struct net_device *dev) 5661da177e4SLinus Torvalds { 5671da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 5680c18acc1SFrancois Romieu const int irq = yp->pci_dev->irq; 5691da177e4SLinus Torvalds void __iomem *ioaddr = yp->base; 5700c18acc1SFrancois Romieu int i, rc; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds /* Reset the chip. */ 5731da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + DMACtrl); 5741da177e4SLinus Torvalds 5750c18acc1SFrancois Romieu rc = request_irq(irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev); 5760c18acc1SFrancois Romieu if (rc) 5770c18acc1SFrancois Romieu return rc; 5781da177e4SLinus Torvalds 5790c18acc1SFrancois Romieu rc = yellowfin_init_ring(dev); 5800c18acc1SFrancois Romieu if (rc < 0) 5810c18acc1SFrancois Romieu goto err_free_irq; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds iowrite32(yp->rx_ring_dma, ioaddr + RxPtr); 5841da177e4SLinus Torvalds iowrite32(yp->tx_ring_dma, ioaddr + TxPtr); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds for (i = 0; i < 6; i++) 5871da177e4SLinus Torvalds iowrite8(dev->dev_addr[i], ioaddr + StnAddr + i); 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds /* Set up various condition 'select' registers. 5901da177e4SLinus Torvalds There are no options here. */ 5911da177e4SLinus Torvalds iowrite32(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ 5921da177e4SLinus Torvalds iowrite32(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ 5931da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ 5941da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ 5951da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ 5961da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* Initialize other registers: with so many this eventually this will 5991da177e4SLinus Torvalds converted to an offset/value list. */ 6001da177e4SLinus Torvalds iowrite32(dma_ctrl, ioaddr + DMACtrl); 6011da177e4SLinus Torvalds iowrite16(fifo_cfg, ioaddr + FIFOcfg); 6021da177e4SLinus Torvalds /* Enable automatic generation of flow control frames, period 0xffff. */ 6031da177e4SLinus Torvalds iowrite32(0x0030FFFF, ioaddr + FlowCtrl); 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds yp->tx_threshold = 32; 6061da177e4SLinus Torvalds iowrite32(yp->tx_threshold, ioaddr + TxThreshold); 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds if (dev->if_port == 0) 6091da177e4SLinus Torvalds dev->if_port = yp->default_port; 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds netif_start_queue(dev); 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds /* Setting the Rx mode will start the Rx process. */ 6141da177e4SLinus Torvalds if (yp->drv_flags & IsGigabit) { 6151da177e4SLinus Torvalds /* We are always in full-duplex mode with gigabit! */ 6161da177e4SLinus Torvalds yp->full_duplex = 1; 6171da177e4SLinus Torvalds iowrite16(0x01CF, ioaddr + Cnfg); 6181da177e4SLinus Torvalds } else { 6191da177e4SLinus Torvalds iowrite16(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ 6201da177e4SLinus Torvalds iowrite16(0x1018, ioaddr + FrameGap1); 6211da177e4SLinus Torvalds iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds set_rx_mode(dev); 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds /* Enable interrupts by setting the interrupt mask. */ 6261da177e4SLinus Torvalds iowrite16(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ 6271da177e4SLinus Torvalds iowrite16(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ 6281da177e4SLinus Torvalds iowrite32(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ 6291da177e4SLinus Torvalds iowrite32(0x80008000, ioaddr + TxCtrl); 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds if (yellowfin_debug > 2) { 632acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Done %s()\n", __func__); 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds /* Set the timer to check for link beat. */ 6361da177e4SLinus Torvalds init_timer(&yp->timer); 6371da177e4SLinus Torvalds yp->timer.expires = jiffies + 3*HZ; 6381da177e4SLinus Torvalds yp->timer.data = (unsigned long)dev; 639c061b18dSJoe Perches yp->timer.function = yellowfin_timer; /* timer handler */ 6401da177e4SLinus Torvalds add_timer(&yp->timer); 6410c18acc1SFrancois Romieu out: 6420c18acc1SFrancois Romieu return rc; 6431da177e4SLinus Torvalds 6440c18acc1SFrancois Romieu err_free_irq: 6450c18acc1SFrancois Romieu free_irq(irq, dev); 6460c18acc1SFrancois Romieu goto out; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds static void yellowfin_timer(unsigned long data) 6501da177e4SLinus Torvalds { 6511da177e4SLinus Torvalds struct net_device *dev = (struct net_device *)data; 6521da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 6531da177e4SLinus Torvalds void __iomem *ioaddr = yp->base; 6541da177e4SLinus Torvalds int next_tick = 60*HZ; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds if (yellowfin_debug > 3) { 657acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n", 658acbbf1f1SJoe Perches ioread16(ioaddr + IntrStatus)); 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds if (yp->mii_cnt) { 6621da177e4SLinus Torvalds int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR); 6631da177e4SLinus Torvalds int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA); 6641da177e4SLinus Torvalds int negotiated = lpa & yp->advertising; 6651da177e4SLinus Torvalds if (yellowfin_debug > 1) 666acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n", 667acbbf1f1SJoe Perches yp->phys[0], bmsr, lpa); 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated); 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds if (bmsr & BMSR_LSTATUS) 6741da177e4SLinus Torvalds next_tick = 60*HZ; 6751da177e4SLinus Torvalds else 6761da177e4SLinus Torvalds next_tick = 3*HZ; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds yp->timer.expires = jiffies + next_tick; 6801da177e4SLinus Torvalds add_timer(&yp->timer); 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds static void yellowfin_tx_timeout(struct net_device *dev) 6841da177e4SLinus Torvalds { 6851da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 6861da177e4SLinus Torvalds void __iomem *ioaddr = yp->base; 6871da177e4SLinus Torvalds 688acbbf1f1SJoe Perches netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n", 689acbbf1f1SJoe Perches yp->cur_tx, yp->dirty_tx, 690acbbf1f1SJoe Perches ioread32(ioaddr + TxStatus), 691acbbf1f1SJoe Perches ioread32(ioaddr + RxStatus)); 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* Note: these should be KERN_DEBUG. */ 6941da177e4SLinus Torvalds if (yellowfin_debug) { 6951da177e4SLinus Torvalds int i; 696acbbf1f1SJoe Perches pr_warning(" Rx ring %p: ", yp->rx_ring); 6971da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) 698acbbf1f1SJoe Perches pr_cont(" %08x", yp->rx_ring[i].result_status); 699acbbf1f1SJoe Perches pr_cont("\n"); 700acbbf1f1SJoe Perches pr_warning(" Tx ring %p: ", yp->tx_ring); 7011da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) 702acbbf1f1SJoe Perches pr_cont(" %04x /%08x", 703ad361c98SJoe Perches yp->tx_status[i].tx_errs, 7041da177e4SLinus Torvalds yp->tx_ring[i].result_status); 705acbbf1f1SJoe Perches pr_cont("\n"); 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds /* If the hardware is found to hang regularly, we will update the code 7091da177e4SLinus Torvalds to reinitialize the chip here. */ 7101da177e4SLinus Torvalds dev->if_port = 0; 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* Wake the potentially-idle transmit channel. */ 7131da177e4SLinus Torvalds iowrite32(0x10001000, yp->base + TxCtrl); 7141da177e4SLinus Torvalds if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) 7151da177e4SLinus Torvalds netif_wake_queue (dev); /* Typical path */ 7161da177e4SLinus Torvalds 717cdd0db05SEric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 71809f75cd7SJeff Garzik dev->stats.tx_errors++; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ 722e7a5965aSRoel Kluin static int yellowfin_init_ring(struct net_device *dev) 7231da177e4SLinus Torvalds { 7241da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 725e7a5965aSRoel Kluin int i, j; 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds yp->tx_full = 0; 7281da177e4SLinus Torvalds yp->cur_rx = yp->cur_tx = 0; 7291da177e4SLinus Torvalds yp->dirty_tx = 0; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) { 7341da177e4SLinus Torvalds yp->rx_ring[i].dbdma_cmd = 7351da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); 7361da177e4SLinus Torvalds yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma + 7371da177e4SLinus Torvalds ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc)); 7381da177e4SLinus Torvalds } 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) { 741dae2e9f4SPradeep A. Dalvi struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2); 7421da177e4SLinus Torvalds yp->rx_skbuff[i] = skb; 7431da177e4SLinus Torvalds if (skb == NULL) 7441da177e4SLinus Torvalds break; 7451da177e4SLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header. */ 7461da177e4SLinus Torvalds yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 747689be439SDavid S. Miller skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); 7481da177e4SLinus Torvalds } 749e7a5965aSRoel Kluin if (i != RX_RING_SIZE) { 750e7a5965aSRoel Kluin for (j = 0; j < i; j++) 751e7a5965aSRoel Kluin dev_kfree_skb(yp->rx_skbuff[j]); 752e7a5965aSRoel Kluin return -ENOMEM; 753e7a5965aSRoel Kluin } 7541da177e4SLinus Torvalds yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); 7551da177e4SLinus Torvalds yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds #define NO_TXSTATS 7581da177e4SLinus Torvalds #ifdef NO_TXSTATS 7591da177e4SLinus Torvalds /* In this mode the Tx ring needs only a single descriptor. */ 7601da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) { 7611da177e4SLinus Torvalds yp->tx_skbuff[i] = NULL; 7621da177e4SLinus Torvalds yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); 7631da177e4SLinus Torvalds yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma + 7641da177e4SLinus Torvalds ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc)); 7651da177e4SLinus Torvalds } 7661da177e4SLinus Torvalds /* Wrap ring */ 7671da177e4SLinus Torvalds yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS); 7681da177e4SLinus Torvalds #else 7691da177e4SLinus Torvalds { 7701da177e4SLinus Torvalds /* Tx ring needs a pair of descriptors, the second for the status. */ 7711da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) { 7721da177e4SLinus Torvalds j = 2*i; 7731da177e4SLinus Torvalds yp->tx_skbuff[i] = 0; 7741da177e4SLinus Torvalds /* Branch on Tx error. */ 7751da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP); 7761da177e4SLinus Torvalds yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + 77780950f8bSMariusz Kozlowski (j+1)*sizeof(struct yellowfin_desc)); 7781da177e4SLinus Torvalds j++; 7791da177e4SLinus Torvalds if (yp->flags & FullTxStatus) { 7801da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd = 7811da177e4SLinus Torvalds cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status)); 7821da177e4SLinus Torvalds yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status); 7831da177e4SLinus Torvalds yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + 78480950f8bSMariusz Kozlowski i*sizeof(struct tx_status_words)); 7851da177e4SLinus Torvalds } else { 7861da177e4SLinus Torvalds /* Symbios chips write only tx_errs word. */ 7871da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd = 7881da177e4SLinus Torvalds cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2); 7891da177e4SLinus Torvalds yp->tx_ring[j].request_cnt = 2; 7901da177e4SLinus Torvalds /* Om pade ummmmm... */ 7911da177e4SLinus Torvalds yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + 7921da177e4SLinus Torvalds i*sizeof(struct tx_status_words) + 7931da177e4SLinus Torvalds &(yp->tx_status[0].tx_errs) - 7941da177e4SLinus Torvalds &(yp->tx_status[0])); 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + 7971da177e4SLinus Torvalds ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc)); 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds /* Wrap ring */ 8001da177e4SLinus Torvalds yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS); 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds #endif 8031da177e4SLinus Torvalds yp->tx_tail_desc = &yp->tx_status[0]; 804e7a5965aSRoel Kluin return 0; 8051da177e4SLinus Torvalds } 8061da177e4SLinus Torvalds 80761357325SStephen Hemminger static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb, 80861357325SStephen Hemminger struct net_device *dev) 8091da177e4SLinus Torvalds { 8101da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 8111da177e4SLinus Torvalds unsigned entry; 8121da177e4SLinus Torvalds int len = skb->len; 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds netif_stop_queue (dev); 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds /* Note: Ordering is important here, set the field with the 8171da177e4SLinus Torvalds "ownership" bit last, and only then increment cur_tx. */ 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds /* Calculate the next Tx descriptor entry. */ 8201da177e4SLinus Torvalds entry = yp->cur_tx % TX_RING_SIZE; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */ 8231da177e4SLinus Torvalds int cacheline_end = ((unsigned long)skb->data + skb->len) % 32; 8241da177e4SLinus Torvalds /* Fix GX chipset errata. */ 8251da177e4SLinus Torvalds if (cacheline_end > 24 || cacheline_end == 0) { 8261da177e4SLinus Torvalds len = skb->len + 32 - cacheline_end + 1; 8275b057c6bSHerbert Xu if (skb_padto(skb, len)) { 8281da177e4SLinus Torvalds yp->tx_skbuff[entry] = NULL; 8291da177e4SLinus Torvalds netif_wake_queue(dev); 8306ed10654SPatrick McHardy return NETDEV_TX_OK; 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds } 8335b057c6bSHerbert Xu } 8341da177e4SLinus Torvalds yp->tx_skbuff[entry] = skb; 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds #ifdef NO_TXSTATS 8371da177e4SLinus Torvalds yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 8381da177e4SLinus Torvalds skb->data, len, PCI_DMA_TODEVICE)); 8391da177e4SLinus Torvalds yp->tx_ring[entry].result_status = 0; 8401da177e4SLinus Torvalds if (entry >= TX_RING_SIZE-1) { 8411da177e4SLinus Torvalds /* New stop command. */ 8421da177e4SLinus Torvalds yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP); 8431da177e4SLinus Torvalds yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd = 8441da177e4SLinus Torvalds cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | len); 8451da177e4SLinus Torvalds } else { 8461da177e4SLinus Torvalds yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP); 8471da177e4SLinus Torvalds yp->tx_ring[entry].dbdma_cmd = 8481da177e4SLinus Torvalds cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | len); 8491da177e4SLinus Torvalds } 8501da177e4SLinus Torvalds yp->cur_tx++; 8511da177e4SLinus Torvalds #else 8521da177e4SLinus Torvalds yp->tx_ring[entry<<1].request_cnt = len; 8531da177e4SLinus Torvalds yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 8541da177e4SLinus Torvalds skb->data, len, PCI_DMA_TODEVICE)); 8551da177e4SLinus Torvalds /* The input_last (status-write) command is constant, but we must 8561da177e4SLinus Torvalds rewrite the subsequent 'stop' command. */ 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds yp->cur_tx++; 8591da177e4SLinus Torvalds { 8601da177e4SLinus Torvalds unsigned next_entry = yp->cur_tx % TX_RING_SIZE; 8611da177e4SLinus Torvalds yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP); 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds /* Final step -- overwrite the old 'stop' command. */ 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds yp->tx_ring[entry<<1].dbdma_cmd = 8661da177e4SLinus Torvalds cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE : 8671da177e4SLinus Torvalds CMD_TX_PKT | BRANCH_IFTRUE) | len); 8681da177e4SLinus Torvalds #endif 8691da177e4SLinus Torvalds 8701da177e4SLinus Torvalds /* Non-x86 Todo: explicitly flush cache lines here. */ 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds /* Wake the potentially-idle transmit channel. */ 8731da177e4SLinus Torvalds iowrite32(0x10001000, yp->base + TxCtrl); 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) 8761da177e4SLinus Torvalds netif_start_queue (dev); /* Typical path */ 8771da177e4SLinus Torvalds else 8781da177e4SLinus Torvalds yp->tx_full = 1; 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds if (yellowfin_debug > 4) { 881acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin transmit frame #%d queued in slot %d\n", 882acbbf1f1SJoe Perches yp->cur_tx, entry); 8831da177e4SLinus Torvalds } 8846ed10654SPatrick McHardy return NETDEV_TX_OK; 8851da177e4SLinus Torvalds } 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds /* The interrupt handler does all of the Rx thread work and cleans up 8881da177e4SLinus Torvalds after the Tx thread. */ 8897d12e780SDavid Howells static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) 8901da177e4SLinus Torvalds { 8911da177e4SLinus Torvalds struct net_device *dev = dev_instance; 8921da177e4SLinus Torvalds struct yellowfin_private *yp; 8931da177e4SLinus Torvalds void __iomem *ioaddr; 8941da177e4SLinus Torvalds int boguscnt = max_interrupt_work; 8951da177e4SLinus Torvalds unsigned int handled = 0; 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds yp = netdev_priv(dev); 8981da177e4SLinus Torvalds ioaddr = yp->base; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds spin_lock (&yp->lock); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds do { 9031da177e4SLinus Torvalds u16 intr_status = ioread16(ioaddr + IntrClear); 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds if (yellowfin_debug > 4) 906acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n", 907acbbf1f1SJoe Perches intr_status); 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds if (intr_status == 0) 9101da177e4SLinus Torvalds break; 9111da177e4SLinus Torvalds handled = 1; 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds if (intr_status & (IntrRxDone | IntrEarlyRx)) { 9141da177e4SLinus Torvalds yellowfin_rx(dev); 9151da177e4SLinus Torvalds iowrite32(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds #ifdef NO_TXSTATS 9191da177e4SLinus Torvalds for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) { 9201da177e4SLinus Torvalds int entry = yp->dirty_tx % TX_RING_SIZE; 9211da177e4SLinus Torvalds struct sk_buff *skb; 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds if (yp->tx_ring[entry].result_status == 0) 9241da177e4SLinus Torvalds break; 9251da177e4SLinus Torvalds skb = yp->tx_skbuff[entry]; 92609f75cd7SJeff Garzik dev->stats.tx_packets++; 92709f75cd7SJeff Garzik dev->stats.tx_bytes += skb->len; 9281da177e4SLinus Torvalds /* Free the original skb. */ 929e5a31421SAl Viro pci_unmap_single(yp->pci_dev, le32_to_cpu(yp->tx_ring[entry].addr), 9301da177e4SLinus Torvalds skb->len, PCI_DMA_TODEVICE); 9311da177e4SLinus Torvalds dev_kfree_skb_irq(skb); 9321da177e4SLinus Torvalds yp->tx_skbuff[entry] = NULL; 9331da177e4SLinus Torvalds } 9348e95a202SJoe Perches if (yp->tx_full && 9358e95a202SJoe Perches yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { 9361da177e4SLinus Torvalds /* The ring is no longer full, clear tbusy. */ 9371da177e4SLinus Torvalds yp->tx_full = 0; 9381da177e4SLinus Torvalds netif_wake_queue(dev); 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds #else 9411da177e4SLinus Torvalds if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) { 9421da177e4SLinus Torvalds unsigned dirty_tx = yp->dirty_tx; 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0; 9451da177e4SLinus Torvalds dirty_tx++) { 9461da177e4SLinus Torvalds /* Todo: optimize this. */ 9471da177e4SLinus Torvalds int entry = dirty_tx % TX_RING_SIZE; 9481da177e4SLinus Torvalds u16 tx_errs = yp->tx_status[entry].tx_errs; 9491da177e4SLinus Torvalds struct sk_buff *skb; 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds #ifndef final_version 9521da177e4SLinus Torvalds if (yellowfin_debug > 5) 953acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Tx queue %d check, Tx status %04x %04x %04x %04x\n", 954acbbf1f1SJoe Perches entry, 9551da177e4SLinus Torvalds yp->tx_status[entry].tx_cnt, 9561da177e4SLinus Torvalds yp->tx_status[entry].tx_errs, 9571da177e4SLinus Torvalds yp->tx_status[entry].total_tx_cnt, 9581da177e4SLinus Torvalds yp->tx_status[entry].paused); 9591da177e4SLinus Torvalds #endif 9601da177e4SLinus Torvalds if (tx_errs == 0) 9611da177e4SLinus Torvalds break; /* It still hasn't been Txed */ 9621da177e4SLinus Torvalds skb = yp->tx_skbuff[entry]; 9631da177e4SLinus Torvalds if (tx_errs & 0xF810) { 9641da177e4SLinus Torvalds /* There was an major error, log it. */ 9651da177e4SLinus Torvalds #ifndef final_version 9661da177e4SLinus Torvalds if (yellowfin_debug > 1) 967acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Transmit error, Tx status %04x\n", 968acbbf1f1SJoe Perches tx_errs); 9691da177e4SLinus Torvalds #endif 97009f75cd7SJeff Garzik dev->stats.tx_errors++; 97109f75cd7SJeff Garzik if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++; 97209f75cd7SJeff Garzik if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++; 97309f75cd7SJeff Garzik if (tx_errs & 0x2000) dev->stats.tx_window_errors++; 97409f75cd7SJeff Garzik if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++; 9751da177e4SLinus Torvalds } else { 9761da177e4SLinus Torvalds #ifndef final_version 9771da177e4SLinus Torvalds if (yellowfin_debug > 4) 978acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Normal transmit, Tx status %04x\n", 979acbbf1f1SJoe Perches tx_errs); 9801da177e4SLinus Torvalds #endif 98109f75cd7SJeff Garzik dev->stats.tx_bytes += skb->len; 98209f75cd7SJeff Garzik dev->stats.collisions += tx_errs & 15; 98309f75cd7SJeff Garzik dev->stats.tx_packets++; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds /* Free the original skb. */ 9861da177e4SLinus Torvalds pci_unmap_single(yp->pci_dev, 9871da177e4SLinus Torvalds yp->tx_ring[entry<<1].addr, skb->len, 9881da177e4SLinus Torvalds PCI_DMA_TODEVICE); 9891da177e4SLinus Torvalds dev_kfree_skb_irq(skb); 9901da177e4SLinus Torvalds yp->tx_skbuff[entry] = 0; 9911da177e4SLinus Torvalds /* Mark status as empty. */ 9921da177e4SLinus Torvalds yp->tx_status[entry].tx_errs = 0; 9931da177e4SLinus Torvalds } 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds #ifndef final_version 9961da177e4SLinus Torvalds if (yp->cur_tx - dirty_tx > TX_RING_SIZE) { 997acbbf1f1SJoe Perches netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d, full=%d\n", 998acbbf1f1SJoe Perches dirty_tx, yp->cur_tx, yp->tx_full); 9991da177e4SLinus Torvalds dirty_tx += TX_RING_SIZE; 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds #endif 10021da177e4SLinus Torvalds 10038e95a202SJoe Perches if (yp->tx_full && 10048e95a202SJoe Perches yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { 10051da177e4SLinus Torvalds /* The ring is no longer full, clear tbusy. */ 10061da177e4SLinus Torvalds yp->tx_full = 0; 10071da177e4SLinus Torvalds netif_wake_queue(dev); 10081da177e4SLinus Torvalds } 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds yp->dirty_tx = dirty_tx; 10111da177e4SLinus Torvalds yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE]; 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds #endif 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds /* Log errors and other uncommon events. */ 10161da177e4SLinus Torvalds if (intr_status & 0x2ee) /* Abnormal error summary. */ 10171da177e4SLinus Torvalds yellowfin_error(dev, intr_status); 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds if (--boguscnt < 0) { 1020acbbf1f1SJoe Perches netdev_warn(dev, "Too much work at interrupt, status=%#04x\n", 1021acbbf1f1SJoe Perches intr_status); 10221da177e4SLinus Torvalds break; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds } while (1); 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds if (yellowfin_debug > 3) 1027acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "exiting interrupt, status=%#04x\n", 1028acbbf1f1SJoe Perches ioread16(ioaddr + IntrStatus)); 10291da177e4SLinus Torvalds 10301da177e4SLinus Torvalds spin_unlock (&yp->lock); 10311da177e4SLinus Torvalds return IRQ_RETVAL(handled); 10321da177e4SLinus Torvalds } 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds /* This routine is logically part of the interrupt handler, but separated 10351da177e4SLinus Torvalds for clarity and better register allocation. */ 10361da177e4SLinus Torvalds static int yellowfin_rx(struct net_device *dev) 10371da177e4SLinus Torvalds { 10381da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 10391da177e4SLinus Torvalds int entry = yp->cur_rx % RX_RING_SIZE; 10401da177e4SLinus Torvalds int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx; 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds if (yellowfin_debug > 4) { 1043acbbf1f1SJoe Perches printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n", 10441da177e4SLinus Torvalds entry, yp->rx_ring[entry].result_status); 1045acbbf1f1SJoe Perches printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n", 10461da177e4SLinus Torvalds entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr, 10471da177e4SLinus Torvalds yp->rx_ring[entry].result_status); 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds 10501da177e4SLinus Torvalds /* If EOP is set on the next entry, it's a new packet. Send it up. */ 10511da177e4SLinus Torvalds while (1) { 10521da177e4SLinus Torvalds struct yellowfin_desc *desc = &yp->rx_ring[entry]; 10531da177e4SLinus Torvalds struct sk_buff *rx_skb = yp->rx_skbuff[entry]; 10541da177e4SLinus Torvalds s16 frame_status; 10551da177e4SLinus Torvalds u16 desc_status; 1056*3a8e87ecSdingtianhong int data_size, yf_size; 10571da177e4SLinus Torvalds u8 *buf_addr; 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds if(!desc->result_status) 10601da177e4SLinus Torvalds break; 1061e5a31421SAl Viro pci_dma_sync_single_for_cpu(yp->pci_dev, le32_to_cpu(desc->addr), 10621da177e4SLinus Torvalds yp->rx_buf_sz, PCI_DMA_FROMDEVICE); 10631da177e4SLinus Torvalds desc_status = le32_to_cpu(desc->result_status) >> 16; 1064689be439SDavid S. Miller buf_addr = rx_skb->data; 10651da177e4SLinus Torvalds data_size = (le32_to_cpu(desc->dbdma_cmd) - 10661da177e4SLinus Torvalds le32_to_cpu(desc->result_status)) & 0xffff; 10676caf52a4SHarvey Harrison frame_status = get_unaligned_le16(&(buf_addr[data_size - 2])); 10681da177e4SLinus Torvalds if (yellowfin_debug > 4) 1069acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() status was %04x\n", 1070acbbf1f1SJoe Perches __func__, frame_status); 10711da177e4SLinus Torvalds if (--boguscnt < 0) 10721da177e4SLinus Torvalds break; 1073*3a8e87ecSdingtianhong 1074*3a8e87ecSdingtianhong yf_size = sizeof(struct yellowfin_desc); 1075*3a8e87ecSdingtianhong 10761da177e4SLinus Torvalds if ( ! (desc_status & RX_EOP)) { 10771da177e4SLinus Torvalds if (data_size != 0) 1078acbbf1f1SJoe Perches netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %04x, data_size %d!\n", 1079acbbf1f1SJoe Perches desc_status, data_size); 108009f75cd7SJeff Garzik dev->stats.rx_length_errors++; 10811da177e4SLinus Torvalds } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { 10821da177e4SLinus Torvalds /* There was a error. */ 10831da177e4SLinus Torvalds if (yellowfin_debug > 3) 1084acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() Rx error was %04x\n", 1085acbbf1f1SJoe Perches __func__, frame_status); 108609f75cd7SJeff Garzik dev->stats.rx_errors++; 108709f75cd7SJeff Garzik if (frame_status & 0x0060) dev->stats.rx_length_errors++; 108809f75cd7SJeff Garzik if (frame_status & 0x0008) dev->stats.rx_frame_errors++; 108909f75cd7SJeff Garzik if (frame_status & 0x0010) dev->stats.rx_crc_errors++; 109009f75cd7SJeff Garzik if (frame_status < 0) dev->stats.rx_dropped++; 10911da177e4SLinus Torvalds } else if ( !(yp->drv_flags & IsGigabit) && 10921da177e4SLinus Torvalds ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { 10931da177e4SLinus Torvalds u8 status1 = buf_addr[data_size-2]; 10941da177e4SLinus Torvalds u8 status2 = buf_addr[data_size-1]; 109509f75cd7SJeff Garzik dev->stats.rx_errors++; 109609f75cd7SJeff Garzik if (status1 & 0xC0) dev->stats.rx_length_errors++; 109709f75cd7SJeff Garzik if (status2 & 0x03) dev->stats.rx_frame_errors++; 109809f75cd7SJeff Garzik if (status2 & 0x04) dev->stats.rx_crc_errors++; 109909f75cd7SJeff Garzik if (status2 & 0x80) dev->stats.rx_dropped++; 11001da177e4SLinus Torvalds #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ 11011da177e4SLinus Torvalds } else if ((yp->flags & HasMACAddrBug) && 1102*3a8e87ecSdingtianhong !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma + 1103*3a8e87ecSdingtianhong entry * yf_size), 1104*3a8e87ecSdingtianhong dev->dev_addr) && 1105*3a8e87ecSdingtianhong !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma + 1106*3a8e87ecSdingtianhong entry * yf_size), 1107*3a8e87ecSdingtianhong "\377\377\377\377\377\377")) { 1108e174961cSJohannes Berg if (bogus_rx++ == 0) 1109acbbf1f1SJoe Perches netdev_warn(dev, "Bad frame to %pM\n", 1110acbbf1f1SJoe Perches buf_addr); 11111da177e4SLinus Torvalds #endif 11121da177e4SLinus Torvalds } else { 11131da177e4SLinus Torvalds struct sk_buff *skb; 11141da177e4SLinus Torvalds int pkt_len = data_size - 11151da177e4SLinus Torvalds (yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]); 11161da177e4SLinus Torvalds /* To verify: Yellowfin Length should omit the CRC! */ 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds #ifndef final_version 11191da177e4SLinus Torvalds if (yellowfin_debug > 4) 1120acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() normal Rx pkt length %d of %d, bogus_cnt %d\n", 1121acbbf1f1SJoe Perches __func__, pkt_len, data_size, boguscnt); 11221da177e4SLinus Torvalds #endif 11231da177e4SLinus Torvalds /* Check if the packet is long enough to just pass up the skbuff 11241da177e4SLinus Torvalds without copying to a properly sized skbuff. */ 11251da177e4SLinus Torvalds if (pkt_len > rx_copybreak) { 11261da177e4SLinus Torvalds skb_put(skb = rx_skb, pkt_len); 11271da177e4SLinus Torvalds pci_unmap_single(yp->pci_dev, 1128e5a31421SAl Viro le32_to_cpu(yp->rx_ring[entry].addr), 11291da177e4SLinus Torvalds yp->rx_buf_sz, 11301da177e4SLinus Torvalds PCI_DMA_FROMDEVICE); 11311da177e4SLinus Torvalds yp->rx_skbuff[entry] = NULL; 11321da177e4SLinus Torvalds } else { 1133dae2e9f4SPradeep A. Dalvi skb = netdev_alloc_skb(dev, pkt_len + 2); 11341da177e4SLinus Torvalds if (skb == NULL) 11351da177e4SLinus Torvalds break; 11361da177e4SLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header */ 11378c7b7faaSDavid S. Miller skb_copy_to_linear_data(skb, rx_skb->data, pkt_len); 11381da177e4SLinus Torvalds skb_put(skb, pkt_len); 1139e5a31421SAl Viro pci_dma_sync_single_for_device(yp->pci_dev, 1140e5a31421SAl Viro le32_to_cpu(desc->addr), 11411da177e4SLinus Torvalds yp->rx_buf_sz, 11421da177e4SLinus Torvalds PCI_DMA_FROMDEVICE); 11431da177e4SLinus Torvalds } 11441da177e4SLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 11451da177e4SLinus Torvalds netif_rx(skb); 114609f75cd7SJeff Garzik dev->stats.rx_packets++; 114709f75cd7SJeff Garzik dev->stats.rx_bytes += pkt_len; 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds entry = (++yp->cur_rx) % RX_RING_SIZE; 11501da177e4SLinus Torvalds } 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds /* Refill the Rx ring buffers. */ 11531da177e4SLinus Torvalds for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) { 11541da177e4SLinus Torvalds entry = yp->dirty_rx % RX_RING_SIZE; 11551da177e4SLinus Torvalds if (yp->rx_skbuff[entry] == NULL) { 1156dae2e9f4SPradeep A. Dalvi struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2); 11571da177e4SLinus Torvalds if (skb == NULL) 11581da177e4SLinus Torvalds break; /* Better luck next round. */ 11591da177e4SLinus Torvalds yp->rx_skbuff[entry] = skb; 11601da177e4SLinus Torvalds skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ 11611da177e4SLinus Torvalds yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 1162689be439SDavid S. Miller skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); 11631da177e4SLinus Torvalds } 11641da177e4SLinus Torvalds yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP); 11651da177e4SLinus Torvalds yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */ 11661da177e4SLinus Torvalds if (entry != 0) 11671da177e4SLinus Torvalds yp->rx_ring[entry - 1].dbdma_cmd = 11681da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); 11691da177e4SLinus Torvalds else 11701da177e4SLinus Torvalds yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd = 11711da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS 11721da177e4SLinus Torvalds | yp->rx_buf_sz); 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds return 0; 11761da177e4SLinus Torvalds } 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds static void yellowfin_error(struct net_device *dev, int intr_status) 11791da177e4SLinus Torvalds { 1180acbbf1f1SJoe Perches netdev_err(dev, "Something Wicked happened! %04x\n", intr_status); 11811da177e4SLinus Torvalds /* Hmmmmm, it's not clear what to do here. */ 11821da177e4SLinus Torvalds if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) 118309f75cd7SJeff Garzik dev->stats.tx_errors++; 11841da177e4SLinus Torvalds if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) 118509f75cd7SJeff Garzik dev->stats.rx_errors++; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds static int yellowfin_close(struct net_device *dev) 11891da177e4SLinus Torvalds { 11901da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 11911da177e4SLinus Torvalds void __iomem *ioaddr = yp->base; 11921da177e4SLinus Torvalds int i; 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds netif_stop_queue (dev); 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds if (yellowfin_debug > 1) { 1197acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Shutting down ethercard, status was Tx %04x Rx %04x Int %02x\n", 1198acbbf1f1SJoe Perches ioread16(ioaddr + TxStatus), 11991da177e4SLinus Torvalds ioread16(ioaddr + RxStatus), 12001da177e4SLinus Torvalds ioread16(ioaddr + IntrStatus)); 1201acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n", 1202acbbf1f1SJoe Perches yp->cur_tx, yp->dirty_tx, 1203acbbf1f1SJoe Perches yp->cur_rx, yp->dirty_rx); 12041da177e4SLinus Torvalds } 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds /* Disable interrupts by clearing the interrupt mask. */ 12071da177e4SLinus Torvalds iowrite16(0x0000, ioaddr + IntrEnb); 12081da177e4SLinus Torvalds 12091da177e4SLinus Torvalds /* Stop the chip's Tx and Rx processes. */ 12101da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + RxCtrl); 12111da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + TxCtrl); 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds del_timer(&yp->timer); 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds #if defined(__i386__) 12161da177e4SLinus Torvalds if (yellowfin_debug > 2) { 1217acbbf1f1SJoe Perches printk(KERN_DEBUG " Tx ring at %08llx:\n", 12181da177e4SLinus Torvalds (unsigned long long)yp->tx_ring_dma); 12191da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE*2; i++) 1220acbbf1f1SJoe Perches printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x %08x\n", 12211da177e4SLinus Torvalds ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', 12221da177e4SLinus Torvalds i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr, 12231da177e4SLinus Torvalds yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status); 12241da177e4SLinus Torvalds printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status); 12251da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) 1226acbbf1f1SJoe Perches printk(KERN_DEBUG " #%d status %04x %04x %04x %04x\n", 12271da177e4SLinus Torvalds i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs, 12281da177e4SLinus Torvalds yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused); 12291da177e4SLinus Torvalds 1230acbbf1f1SJoe Perches printk(KERN_DEBUG " Rx ring %08llx:\n", 12311da177e4SLinus Torvalds (unsigned long long)yp->rx_ring_dma); 12321da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) { 1233acbbf1f1SJoe Perches printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x\n", 12341da177e4SLinus Torvalds ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', 12351da177e4SLinus Torvalds i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr, 12361da177e4SLinus Torvalds yp->rx_ring[i].result_status); 12371da177e4SLinus Torvalds if (yellowfin_debug > 6) { 12381da177e4SLinus Torvalds if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) { 12391da177e4SLinus Torvalds int j; 1240acbbf1f1SJoe Perches 1241acbbf1f1SJoe Perches printk(KERN_DEBUG); 12421da177e4SLinus Torvalds for (j = 0; j < 0x50; j++) 1243acbbf1f1SJoe Perches pr_cont(" %04x", 12441da177e4SLinus Torvalds get_unaligned(((u16*)yp->rx_ring[i].addr) + j)); 1245acbbf1f1SJoe Perches pr_cont("\n"); 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds } 12501da177e4SLinus Torvalds #endif /* __i386__ debugging only */ 12511da177e4SLinus Torvalds 12520c18acc1SFrancois Romieu free_irq(yp->pci_dev->irq, dev); 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* Free all the skbuffs in the Rx queue. */ 12551da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) { 12561da177e4SLinus Torvalds yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); 1257e5a31421SAl Viro yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ 12581da177e4SLinus Torvalds if (yp->rx_skbuff[i]) { 12591da177e4SLinus Torvalds dev_kfree_skb(yp->rx_skbuff[i]); 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds yp->rx_skbuff[i] = NULL; 12621da177e4SLinus Torvalds } 12631da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) { 12641da177e4SLinus Torvalds if (yp->tx_skbuff[i]) 12651da177e4SLinus Torvalds dev_kfree_skb(yp->tx_skbuff[i]); 12661da177e4SLinus Torvalds yp->tx_skbuff[i] = NULL; 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ 12701da177e4SLinus Torvalds if (yellowfin_debug > 0) { 1271acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n", 1272acbbf1f1SJoe Perches bogus_rx); 12731da177e4SLinus Torvalds } 12741da177e4SLinus Torvalds #endif 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds return 0; 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds /* Set or clear the multicast filter for this adaptor. */ 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds static void set_rx_mode(struct net_device *dev) 12821da177e4SLinus Torvalds { 12831da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev); 12841da177e4SLinus Torvalds void __iomem *ioaddr = yp->base; 12851da177e4SLinus Torvalds u16 cfg_value = ioread16(ioaddr + Cnfg); 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds /* Stop the Rx process to change any value. */ 12881da177e4SLinus Torvalds iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg); 12891da177e4SLinus Torvalds if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 12901da177e4SLinus Torvalds iowrite16(0x000F, ioaddr + AddrMode); 12914cd24eafSJiri Pirko } else if ((netdev_mc_count(dev) > 64) || 12924cd24eafSJiri Pirko (dev->flags & IFF_ALLMULTI)) { 12931da177e4SLinus Torvalds /* Too many to filter well, or accept all multicasts. */ 12941da177e4SLinus Torvalds iowrite16(0x000B, ioaddr + AddrMode); 12954cd24eafSJiri Pirko } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */ 129622bedad3SJiri Pirko struct netdev_hw_addr *ha; 12971da177e4SLinus Torvalds u16 hash_table[4]; 12981da177e4SLinus Torvalds int i; 1299567ec874SJiri Pirko 13001da177e4SLinus Torvalds memset(hash_table, 0, sizeof(hash_table)); 130122bedad3SJiri Pirko netdev_for_each_mc_addr(ha, dev) { 13021da177e4SLinus Torvalds unsigned int bit; 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds /* Due to a bug in the early chip versions, multiple filter 13051da177e4SLinus Torvalds slots must be set for each address. */ 13061da177e4SLinus Torvalds if (yp->drv_flags & HasMulticastBug) { 130722bedad3SJiri Pirko bit = (ether_crc_le(3, ha->addr) >> 3) & 0x3f; 13081da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit); 130922bedad3SJiri Pirko bit = (ether_crc_le(4, ha->addr) >> 3) & 0x3f; 13101da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit); 131122bedad3SJiri Pirko bit = (ether_crc_le(5, ha->addr) >> 3) & 0x3f; 13121da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit); 13131da177e4SLinus Torvalds } 131422bedad3SJiri Pirko bit = (ether_crc_le(6, ha->addr) >> 3) & 0x3f; 13151da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit); 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds /* Copy the hash table to the chip. */ 13181da177e4SLinus Torvalds for (i = 0; i < 4; i++) 13191da177e4SLinus Torvalds iowrite16(hash_table[i], ioaddr + HashTbl + i*2); 13201da177e4SLinus Torvalds iowrite16(0x0003, ioaddr + AddrMode); 13211da177e4SLinus Torvalds } else { /* Normal, unicast/broadcast-only mode. */ 13221da177e4SLinus Torvalds iowrite16(0x0001, ioaddr + AddrMode); 13231da177e4SLinus Torvalds } 13241da177e4SLinus Torvalds /* Restart the Rx process. */ 13251da177e4SLinus Torvalds iowrite16(cfg_value | 0x1000, ioaddr + Cnfg); 13261da177e4SLinus Torvalds } 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 13291da177e4SLinus Torvalds { 13301da177e4SLinus Torvalds struct yellowfin_private *np = netdev_priv(dev); 13317826d43fSJiri Pirko 13327826d43fSJiri Pirko strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 13337826d43fSJiri Pirko strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 13347826d43fSJiri Pirko strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13377282d491SJeff Garzik static const struct ethtool_ops ethtool_ops = { 13381da177e4SLinus Torvalds .get_drvinfo = yellowfin_get_drvinfo 13391da177e4SLinus Torvalds }; 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 13421da177e4SLinus Torvalds { 13431da177e4SLinus Torvalds struct yellowfin_private *np = netdev_priv(dev); 13441da177e4SLinus Torvalds void __iomem *ioaddr = np->base; 13451da177e4SLinus Torvalds struct mii_ioctl_data *data = if_mii(rq); 13461da177e4SLinus Torvalds 13471da177e4SLinus Torvalds switch(cmd) { 13481da177e4SLinus Torvalds case SIOCGMIIPHY: /* Get address of MII PHY in use. */ 13491da177e4SLinus Torvalds data->phy_id = np->phys[0] & 0x1f; 13501da177e4SLinus Torvalds /* Fall Through */ 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds case SIOCGMIIREG: /* Read MII PHY register. */ 13531da177e4SLinus Torvalds data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); 13541da177e4SLinus Torvalds return 0; 13551da177e4SLinus Torvalds 13561da177e4SLinus Torvalds case SIOCSMIIREG: /* Write MII PHY register. */ 13571da177e4SLinus Torvalds if (data->phy_id == np->phys[0]) { 13581da177e4SLinus Torvalds u16 value = data->val_in; 13591da177e4SLinus Torvalds switch (data->reg_num) { 13601da177e4SLinus Torvalds case 0: 13611da177e4SLinus Torvalds /* Check for autonegotiation on or reset. */ 13621da177e4SLinus Torvalds np->medialock = (value & 0x9000) ? 0 : 1; 13631da177e4SLinus Torvalds if (np->medialock) 13641da177e4SLinus Torvalds np->full_duplex = (value & 0x0100) ? 1 : 0; 13651da177e4SLinus Torvalds break; 13661da177e4SLinus Torvalds case 4: np->advertising = value; break; 13671da177e4SLinus Torvalds } 13681da177e4SLinus Torvalds /* Perhaps check_duplex(dev), depending on chip semantics. */ 13691da177e4SLinus Torvalds } 13701da177e4SLinus Torvalds mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); 13711da177e4SLinus Torvalds return 0; 13721da177e4SLinus Torvalds default: 13731da177e4SLinus Torvalds return -EOPNOTSUPP; 13741da177e4SLinus Torvalds } 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds 1378134c1f15SBill Pemberton static void yellowfin_remove_one(struct pci_dev *pdev) 13791da177e4SLinus Torvalds { 13801da177e4SLinus Torvalds struct net_device *dev = pci_get_drvdata(pdev); 13811da177e4SLinus Torvalds struct yellowfin_private *np; 13821da177e4SLinus Torvalds 13835d9428deSEric Sesterhenn BUG_ON(!dev); 13841da177e4SLinus Torvalds np = netdev_priv(dev); 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, 13871da177e4SLinus Torvalds np->tx_status_dma); 13881da177e4SLinus Torvalds pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); 13891da177e4SLinus Torvalds pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); 13901da177e4SLinus Torvalds unregister_netdev (dev); 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds pci_iounmap(pdev, np->base); 13931da177e4SLinus Torvalds 13941da177e4SLinus Torvalds pci_release_regions (pdev); 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds free_netdev (dev); 13971da177e4SLinus Torvalds } 13981da177e4SLinus Torvalds 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds static struct pci_driver yellowfin_driver = { 14011da177e4SLinus Torvalds .name = DRV_NAME, 14021da177e4SLinus Torvalds .id_table = yellowfin_pci_tbl, 14031da177e4SLinus Torvalds .probe = yellowfin_init_one, 1404134c1f15SBill Pemberton .remove = yellowfin_remove_one, 14051da177e4SLinus Torvalds }; 14061da177e4SLinus Torvalds 14071da177e4SLinus Torvalds 14081da177e4SLinus Torvalds static int __init yellowfin_init (void) 14091da177e4SLinus Torvalds { 14101da177e4SLinus Torvalds /* when a module, this is printed whether or not devices are found in probe */ 14111da177e4SLinus Torvalds #ifdef MODULE 14121da177e4SLinus Torvalds printk(version); 14131da177e4SLinus Torvalds #endif 141429917620SJeff Garzik return pci_register_driver(&yellowfin_driver); 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds static void __exit yellowfin_cleanup (void) 14191da177e4SLinus Torvalds { 14201da177e4SLinus Torvalds pci_unregister_driver (&yellowfin_driver); 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds 14241da177e4SLinus Torvalds module_init(yellowfin_init); 14251da177e4SLinus Torvalds module_exit(yellowfin_cleanup); 1426