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>
1037c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
1041da177e4SLinus Torvalds #include <asm/processor.h> /* Processor type for cache alignment. */
1055f60d5f6SAl Viro #include <linux/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
194ebc0b8b5SJulia Lawall and an AlphaStation to verify 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
2399baa3c34SBenoit Taine static const struct pci_device_id 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);
3468089c6f4SKees Cook static void yellowfin_timer(struct timer_list *t);
3470290bd29SMichael S. Tsirkin static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue);
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_validate_addr = eth_validate_addr,
364fe96aaa1SStephen Hemminger .ndo_set_mac_address = eth_mac_addr,
365a7605370SArnd Bergmann .ndo_eth_ioctl = netdev_ioctl,
366bfd82c35SStephen Hemminger .ndo_tx_timeout = yellowfin_tx_timeout,
367bfd82c35SStephen Hemminger };
3681da177e4SLinus Torvalds
yellowfin_init_one(struct pci_dev * pdev,const struct pci_device_id * ent)369134c1f15SBill Pemberton static int yellowfin_init_one(struct pci_dev *pdev,
3701da177e4SLinus Torvalds const struct pci_device_id *ent)
3711da177e4SLinus Torvalds {
3721da177e4SLinus Torvalds struct net_device *dev;
3731da177e4SLinus Torvalds struct yellowfin_private *np;
3741da177e4SLinus Torvalds int irq;
3751da177e4SLinus Torvalds int chip_idx = ent->driver_data;
3761da177e4SLinus Torvalds static int find_cnt;
3771da177e4SLinus Torvalds void __iomem *ioaddr;
3781da177e4SLinus Torvalds int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
3791da177e4SLinus Torvalds int drv_flags = pci_id_tbl[chip_idx].drv_flags;
3801da177e4SLinus Torvalds void *ring_space;
3811da177e4SLinus Torvalds dma_addr_t ring_dma;
3821da177e4SLinus Torvalds #ifdef USE_IO_OPS
3831da177e4SLinus Torvalds int bar = 0;
3841da177e4SLinus Torvalds #else
3851da177e4SLinus Torvalds int bar = 1;
3861da177e4SLinus Torvalds #endif
3874abd7cffSJakub Kicinski u8 addr[ETH_ALEN];
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++)
4204abd7cffSJakub Kicinski 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++)
4244abd7cffSJakub Kicinski addr[i] = read_eeprom(ioaddr, ee_offset + i);
4251da177e4SLinus Torvalds }
4264abd7cffSJakub Kicinski eth_hw_addr_set(dev, addr);
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds /* Reset the chip. */
4291da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + DMACtrl);
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds pci_set_drvdata(pdev, dev);
4321da177e4SLinus Torvalds spin_lock_init(&np->lock);
4331da177e4SLinus Torvalds
4341da177e4SLinus Torvalds np->pci_dev = pdev;
4351da177e4SLinus Torvalds np->chip_id = chip_idx;
4361da177e4SLinus Torvalds np->drv_flags = drv_flags;
4371da177e4SLinus Torvalds np->base = ioaddr;
4381da177e4SLinus Torvalds
43973e283dfSChristophe JAILLET ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma,
44073e283dfSChristophe JAILLET GFP_KERNEL);
4411da177e4SLinus Torvalds if (!ring_space)
4421da177e4SLinus Torvalds goto err_out_cleardev;
44343d620c8SJoe Perches np->tx_ring = ring_space;
4441da177e4SLinus Torvalds np->tx_ring_dma = ring_dma;
4451da177e4SLinus Torvalds
44673e283dfSChristophe JAILLET ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma,
44773e283dfSChristophe JAILLET GFP_KERNEL);
4481da177e4SLinus Torvalds if (!ring_space)
4491da177e4SLinus Torvalds goto err_out_unmap_tx;
45043d620c8SJoe Perches np->rx_ring = ring_space;
4511da177e4SLinus Torvalds np->rx_ring_dma = ring_dma;
4521da177e4SLinus Torvalds
45373e283dfSChristophe JAILLET ring_space = dma_alloc_coherent(&pdev->dev, STATUS_TOTAL_SIZE,
45473e283dfSChristophe JAILLET &ring_dma, GFP_KERNEL);
4551da177e4SLinus Torvalds if (!ring_space)
4561da177e4SLinus Torvalds goto err_out_unmap_rx;
45743d620c8SJoe Perches np->tx_status = ring_space;
4581da177e4SLinus Torvalds np->tx_status_dma = ring_dma;
4591da177e4SLinus Torvalds
4601da177e4SLinus Torvalds if (dev->mem_start)
4611da177e4SLinus Torvalds option = dev->mem_start;
4621da177e4SLinus Torvalds
4631da177e4SLinus Torvalds /* The lower four bits are the media type. */
4641da177e4SLinus Torvalds if (option > 0) {
4651da177e4SLinus Torvalds if (option & 0x200)
4661da177e4SLinus Torvalds np->full_duplex = 1;
4671da177e4SLinus Torvalds np->default_port = option & 15;
4681da177e4SLinus Torvalds if (np->default_port)
4691da177e4SLinus Torvalds np->medialock = 1;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
4721da177e4SLinus Torvalds np->full_duplex = 1;
4731da177e4SLinus Torvalds
4741da177e4SLinus Torvalds if (np->full_duplex)
4751da177e4SLinus Torvalds np->duplex_lock = 1;
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds /* The Yellowfin-specific entries in the device structure. */
478bfd82c35SStephen Hemminger dev->netdev_ops = &netdev_ops;
4797ad24ea4SWilfried Klaebe dev->ethtool_ops = ðtool_ops;
4801da177e4SLinus Torvalds dev->watchdog_timeo = TX_TIMEOUT;
4811da177e4SLinus Torvalds
4821da177e4SLinus Torvalds if (mtu)
4831da177e4SLinus Torvalds dev->mtu = mtu;
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds i = register_netdev(dev);
4861da177e4SLinus Torvalds if (i)
4871da177e4SLinus Torvalds goto err_out_unmap_status;
4881da177e4SLinus Torvalds
489acbbf1f1SJoe Perches netdev_info(dev, "%s type %8x at %p, %pM, IRQ %d\n",
490acbbf1f1SJoe Perches pci_id_tbl[chip_idx].name,
4910795af57SJoe Perches ioread32(ioaddr + ChipRev), ioaddr,
492e174961cSJohannes Berg dev->dev_addr, irq);
4931da177e4SLinus Torvalds
4941da177e4SLinus Torvalds if (np->drv_flags & HasMII) {
4951da177e4SLinus Torvalds int phy, phy_idx = 0;
4961da177e4SLinus Torvalds for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
4971da177e4SLinus Torvalds int mii_status = mdio_read(ioaddr, phy, 1);
4981da177e4SLinus Torvalds if (mii_status != 0xffff && mii_status != 0x0000) {
4991da177e4SLinus Torvalds np->phys[phy_idx++] = phy;
5001da177e4SLinus Torvalds np->advertising = mdio_read(ioaddr, phy, 4);
501acbbf1f1SJoe Perches netdev_info(dev, "MII PHY found at address %d, status 0x%04x advertising %04x\n",
502acbbf1f1SJoe Perches phy, mii_status, np->advertising);
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds }
5051da177e4SLinus Torvalds np->mii_cnt = phy_idx;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds
5081da177e4SLinus Torvalds find_cnt++;
5091da177e4SLinus Torvalds
5101da177e4SLinus Torvalds return 0;
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds err_out_unmap_status:
51373e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status,
5141da177e4SLinus Torvalds np->tx_status_dma);
5151da177e4SLinus Torvalds err_out_unmap_rx:
51673e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring,
51773e283dfSChristophe JAILLET np->rx_ring_dma);
5181da177e4SLinus Torvalds err_out_unmap_tx:
51973e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
52073e283dfSChristophe JAILLET np->tx_ring_dma);
5211da177e4SLinus Torvalds err_out_cleardev:
5221da177e4SLinus Torvalds pci_iounmap(pdev, ioaddr);
5231da177e4SLinus Torvalds err_out_free_res:
5241da177e4SLinus Torvalds pci_release_regions(pdev);
5251da177e4SLinus Torvalds err_out_free_netdev:
5261da177e4SLinus Torvalds free_netdev (dev);
5271da177e4SLinus Torvalds return -ENODEV;
5281da177e4SLinus Torvalds }
5291da177e4SLinus Torvalds
read_eeprom(void __iomem * ioaddr,int location)530134c1f15SBill Pemberton static int read_eeprom(void __iomem *ioaddr, int location)
5311da177e4SLinus Torvalds {
5321da177e4SLinus Torvalds int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds iowrite8(location, ioaddr + EEAddr);
5351da177e4SLinus Torvalds iowrite8(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
5361da177e4SLinus Torvalds while ((ioread8(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0)
5371da177e4SLinus Torvalds ;
5381da177e4SLinus Torvalds return ioread8(ioaddr + EERead);
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds
5411da177e4SLinus Torvalds /* MII Managemen Data I/O accesses.
5421da177e4SLinus Torvalds These routines assume the MDIO controller is idle, and do not exit until
5431da177e4SLinus Torvalds the command is finished. */
5441da177e4SLinus Torvalds
mdio_read(void __iomem * ioaddr,int phy_id,int location)5451da177e4SLinus Torvalds static int mdio_read(void __iomem *ioaddr, int phy_id, int location)
5461da177e4SLinus Torvalds {
5471da177e4SLinus Torvalds int i;
5481da177e4SLinus Torvalds
5491da177e4SLinus Torvalds iowrite16((phy_id<<8) + location, ioaddr + MII_Addr);
5501da177e4SLinus Torvalds iowrite16(1, ioaddr + MII_Cmd);
5511da177e4SLinus Torvalds for (i = 10000; i >= 0; i--)
5521da177e4SLinus Torvalds if ((ioread16(ioaddr + MII_Status) & 1) == 0)
5531da177e4SLinus Torvalds break;
5541da177e4SLinus Torvalds return ioread16(ioaddr + MII_Rd_Data);
5551da177e4SLinus Torvalds }
5561da177e4SLinus Torvalds
mdio_write(void __iomem * ioaddr,int phy_id,int location,int value)5571da177e4SLinus Torvalds static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value)
5581da177e4SLinus Torvalds {
5591da177e4SLinus Torvalds int i;
5601da177e4SLinus Torvalds
5611da177e4SLinus Torvalds iowrite16((phy_id<<8) + location, ioaddr + MII_Addr);
5621da177e4SLinus Torvalds iowrite16(value, ioaddr + MII_Wr_Data);
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds /* Wait for the command to finish. */
5651da177e4SLinus Torvalds for (i = 10000; i >= 0; i--)
5661da177e4SLinus Torvalds if ((ioread16(ioaddr + MII_Status) & 1) == 0)
5671da177e4SLinus Torvalds break;
5681da177e4SLinus Torvalds }
5691da177e4SLinus Torvalds
5706aa20a22SJeff Garzik
yellowfin_open(struct net_device * dev)5711da177e4SLinus Torvalds static int yellowfin_open(struct net_device *dev)
5721da177e4SLinus Torvalds {
5731da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
5740c18acc1SFrancois Romieu const int irq = yp->pci_dev->irq;
5751da177e4SLinus Torvalds void __iomem *ioaddr = yp->base;
5760c18acc1SFrancois Romieu int i, rc;
5771da177e4SLinus Torvalds
5781da177e4SLinus Torvalds /* Reset the chip. */
5791da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + DMACtrl);
5801da177e4SLinus Torvalds
5810c18acc1SFrancois Romieu rc = request_irq(irq, yellowfin_interrupt, IRQF_SHARED, dev->name, dev);
5820c18acc1SFrancois Romieu if (rc)
5830c18acc1SFrancois Romieu return rc;
5841da177e4SLinus Torvalds
5850c18acc1SFrancois Romieu rc = yellowfin_init_ring(dev);
5860c18acc1SFrancois Romieu if (rc < 0)
5870c18acc1SFrancois Romieu goto err_free_irq;
5881da177e4SLinus Torvalds
5891da177e4SLinus Torvalds iowrite32(yp->rx_ring_dma, ioaddr + RxPtr);
5901da177e4SLinus Torvalds iowrite32(yp->tx_ring_dma, ioaddr + TxPtr);
5911da177e4SLinus Torvalds
5921da177e4SLinus Torvalds for (i = 0; i < 6; i++)
5931da177e4SLinus Torvalds iowrite8(dev->dev_addr[i], ioaddr + StnAddr + i);
5941da177e4SLinus Torvalds
5951da177e4SLinus Torvalds /* Set up various condition 'select' registers.
5961da177e4SLinus Torvalds There are no options here. */
5971da177e4SLinus Torvalds iowrite32(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */
5981da177e4SLinus Torvalds iowrite32(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */
5991da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */
6001da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */
6011da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */
6021da177e4SLinus Torvalds iowrite32(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds /* Initialize other registers: with so many this eventually this will
6051da177e4SLinus Torvalds converted to an offset/value list. */
6061da177e4SLinus Torvalds iowrite32(dma_ctrl, ioaddr + DMACtrl);
6071da177e4SLinus Torvalds iowrite16(fifo_cfg, ioaddr + FIFOcfg);
6081da177e4SLinus Torvalds /* Enable automatic generation of flow control frames, period 0xffff. */
6091da177e4SLinus Torvalds iowrite32(0x0030FFFF, ioaddr + FlowCtrl);
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds yp->tx_threshold = 32;
6121da177e4SLinus Torvalds iowrite32(yp->tx_threshold, ioaddr + TxThreshold);
6131da177e4SLinus Torvalds
6141da177e4SLinus Torvalds if (dev->if_port == 0)
6151da177e4SLinus Torvalds dev->if_port = yp->default_port;
6161da177e4SLinus Torvalds
6171da177e4SLinus Torvalds netif_start_queue(dev);
6181da177e4SLinus Torvalds
6191da177e4SLinus Torvalds /* Setting the Rx mode will start the Rx process. */
6201da177e4SLinus Torvalds if (yp->drv_flags & IsGigabit) {
6211da177e4SLinus Torvalds /* We are always in full-duplex mode with gigabit! */
6221da177e4SLinus Torvalds yp->full_duplex = 1;
6231da177e4SLinus Torvalds iowrite16(0x01CF, ioaddr + Cnfg);
6241da177e4SLinus Torvalds } else {
6251da177e4SLinus Torvalds iowrite16(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
6261da177e4SLinus Torvalds iowrite16(0x1018, ioaddr + FrameGap1);
6271da177e4SLinus Torvalds iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds set_rx_mode(dev);
6301da177e4SLinus Torvalds
6311da177e4SLinus Torvalds /* Enable interrupts by setting the interrupt mask. */
6321da177e4SLinus Torvalds iowrite16(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */
6331da177e4SLinus Torvalds iowrite16(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */
6341da177e4SLinus Torvalds iowrite32(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */
6351da177e4SLinus Torvalds iowrite32(0x80008000, ioaddr + TxCtrl);
6361da177e4SLinus Torvalds
6371da177e4SLinus Torvalds if (yellowfin_debug > 2) {
638acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Done %s()\n", __func__);
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds /* Set the timer to check for link beat. */
6428089c6f4SKees Cook timer_setup(&yp->timer, yellowfin_timer, 0);
6431da177e4SLinus Torvalds yp->timer.expires = jiffies + 3*HZ;
6441da177e4SLinus Torvalds add_timer(&yp->timer);
6450c18acc1SFrancois Romieu out:
6460c18acc1SFrancois Romieu return rc;
6471da177e4SLinus Torvalds
6480c18acc1SFrancois Romieu err_free_irq:
6490c18acc1SFrancois Romieu free_irq(irq, dev);
6500c18acc1SFrancois Romieu goto out;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds
yellowfin_timer(struct timer_list * t)6538089c6f4SKees Cook static void yellowfin_timer(struct timer_list *t)
6541da177e4SLinus Torvalds {
655*41cb0855SIngo Molnar struct yellowfin_private *yp = timer_container_of(yp, t, timer);
6568089c6f4SKees Cook struct net_device *dev = pci_get_drvdata(yp->pci_dev);
6571da177e4SLinus Torvalds void __iomem *ioaddr = yp->base;
6581da177e4SLinus Torvalds int next_tick = 60*HZ;
6591da177e4SLinus Torvalds
6601da177e4SLinus Torvalds if (yellowfin_debug > 3) {
661acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin timer tick, status %08x\n",
662acbbf1f1SJoe Perches ioread16(ioaddr + IntrStatus));
6631da177e4SLinus Torvalds }
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds if (yp->mii_cnt) {
6661da177e4SLinus Torvalds int bmsr = mdio_read(ioaddr, yp->phys[0], MII_BMSR);
6671da177e4SLinus Torvalds int lpa = mdio_read(ioaddr, yp->phys[0], MII_LPA);
6681da177e4SLinus Torvalds int negotiated = lpa & yp->advertising;
6691da177e4SLinus Torvalds if (yellowfin_debug > 1)
670acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "MII #%d status register is %04x, link partner capability %04x\n",
671acbbf1f1SJoe Perches yp->phys[0], bmsr, lpa);
6721da177e4SLinus Torvalds
6731da177e4SLinus Torvalds yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated);
6741da177e4SLinus Torvalds
6751da177e4SLinus Torvalds iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds if (bmsr & BMSR_LSTATUS)
6781da177e4SLinus Torvalds next_tick = 60*HZ;
6791da177e4SLinus Torvalds else
6801da177e4SLinus Torvalds next_tick = 3*HZ;
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds
6831da177e4SLinus Torvalds yp->timer.expires = jiffies + next_tick;
6841da177e4SLinus Torvalds add_timer(&yp->timer);
6851da177e4SLinus Torvalds }
6861da177e4SLinus Torvalds
yellowfin_tx_timeout(struct net_device * dev,unsigned int txqueue)6870290bd29SMichael S. Tsirkin static void yellowfin_tx_timeout(struct net_device *dev, unsigned int txqueue)
6881da177e4SLinus Torvalds {
6891da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
6901da177e4SLinus Torvalds void __iomem *ioaddr = yp->base;
6911da177e4SLinus Torvalds
692acbbf1f1SJoe Perches netdev_warn(dev, "Yellowfin transmit timed out at %d/%d Tx status %04x, Rx status %04x, resetting...\n",
693acbbf1f1SJoe Perches yp->cur_tx, yp->dirty_tx,
694acbbf1f1SJoe Perches ioread32(ioaddr + TxStatus),
695acbbf1f1SJoe Perches ioread32(ioaddr + RxStatus));
6961da177e4SLinus Torvalds
6971da177e4SLinus Torvalds /* Note: these should be KERN_DEBUG. */
6981da177e4SLinus Torvalds if (yellowfin_debug) {
6991da177e4SLinus Torvalds int i;
700fe3881cfSJoe Perches pr_warn(" Rx ring %p: ", yp->rx_ring);
7011da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++)
702acbbf1f1SJoe Perches pr_cont(" %08x", yp->rx_ring[i].result_status);
703acbbf1f1SJoe Perches pr_cont("\n");
704fe3881cfSJoe Perches pr_warn(" Tx ring %p: ", yp->tx_ring);
7051da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++)
706acbbf1f1SJoe Perches pr_cont(" %04x /%08x",
707ad361c98SJoe Perches yp->tx_status[i].tx_errs,
7081da177e4SLinus Torvalds yp->tx_ring[i].result_status);
709acbbf1f1SJoe Perches pr_cont("\n");
7101da177e4SLinus Torvalds }
7111da177e4SLinus Torvalds
7121da177e4SLinus Torvalds /* If the hardware is found to hang regularly, we will update the code
7131da177e4SLinus Torvalds to reinitialize the chip here. */
7141da177e4SLinus Torvalds dev->if_port = 0;
7151da177e4SLinus Torvalds
7161da177e4SLinus Torvalds /* Wake the potentially-idle transmit channel. */
7171da177e4SLinus Torvalds iowrite32(0x10001000, yp->base + TxCtrl);
7181da177e4SLinus Torvalds if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
7191da177e4SLinus Torvalds netif_wake_queue (dev); /* Typical path */
7201da177e4SLinus Torvalds
721860e9538SFlorian Westphal netif_trans_update(dev); /* prevent tx timeout */
72209f75cd7SJeff Garzik dev->stats.tx_errors++;
7231da177e4SLinus Torvalds }
7241da177e4SLinus Torvalds
7251da177e4SLinus Torvalds /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
yellowfin_init_ring(struct net_device * dev)726e7a5965aSRoel Kluin static int yellowfin_init_ring(struct net_device *dev)
7271da177e4SLinus Torvalds {
7281da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
729e7a5965aSRoel Kluin int i, j;
7301da177e4SLinus Torvalds
7311da177e4SLinus Torvalds yp->tx_full = 0;
7321da177e4SLinus Torvalds yp->cur_rx = yp->cur_tx = 0;
7331da177e4SLinus Torvalds yp->dirty_tx = 0;
7341da177e4SLinus Torvalds
7351da177e4SLinus Torvalds yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) {
7381da177e4SLinus Torvalds yp->rx_ring[i].dbdma_cmd =
7391da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
7401da177e4SLinus Torvalds yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma +
7411da177e4SLinus Torvalds ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc));
7421da177e4SLinus Torvalds }
7431da177e4SLinus Torvalds
7441da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) {
745dae2e9f4SPradeep A. Dalvi struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2);
7461da177e4SLinus Torvalds yp->rx_skbuff[i] = skb;
7471da177e4SLinus Torvalds if (skb == NULL)
7481da177e4SLinus Torvalds break;
7491da177e4SLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header. */
75073e283dfSChristophe JAILLET yp->rx_ring[i].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
75173e283dfSChristophe JAILLET skb->data,
75273e283dfSChristophe JAILLET yp->rx_buf_sz,
75373e283dfSChristophe JAILLET DMA_FROM_DEVICE));
7541da177e4SLinus Torvalds }
755e7a5965aSRoel Kluin if (i != RX_RING_SIZE) {
756e7a5965aSRoel Kluin for (j = 0; j < i; j++)
757e7a5965aSRoel Kluin dev_kfree_skb(yp->rx_skbuff[j]);
758e7a5965aSRoel Kluin return -ENOMEM;
759e7a5965aSRoel Kluin }
7601da177e4SLinus Torvalds yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
7611da177e4SLinus Torvalds yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
7621da177e4SLinus Torvalds
7631da177e4SLinus Torvalds #define NO_TXSTATS
7641da177e4SLinus Torvalds #ifdef NO_TXSTATS
7651da177e4SLinus Torvalds /* In this mode the Tx ring needs only a single descriptor. */
7661da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) {
7671da177e4SLinus Torvalds yp->tx_skbuff[i] = NULL;
7681da177e4SLinus Torvalds yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
7691da177e4SLinus Torvalds yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma +
7701da177e4SLinus Torvalds ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc));
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds /* Wrap ring */
7731da177e4SLinus Torvalds yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS);
7741da177e4SLinus Torvalds #else
7751da177e4SLinus Torvalds {
7761da177e4SLinus Torvalds /* Tx ring needs a pair of descriptors, the second for the status. */
7771da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) {
7781da177e4SLinus Torvalds j = 2*i;
7791da177e4SLinus Torvalds yp->tx_skbuff[i] = 0;
7801da177e4SLinus Torvalds /* Branch on Tx error. */
7811da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP);
7821da177e4SLinus Torvalds yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
78380950f8bSMariusz Kozlowski (j+1)*sizeof(struct yellowfin_desc));
7841da177e4SLinus Torvalds j++;
7851da177e4SLinus Torvalds if (yp->flags & FullTxStatus) {
7861da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd =
7871da177e4SLinus Torvalds cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status));
7881da177e4SLinus Torvalds yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status);
7891da177e4SLinus Torvalds yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
79080950f8bSMariusz Kozlowski i*sizeof(struct tx_status_words));
7911da177e4SLinus Torvalds } else {
7921da177e4SLinus Torvalds /* Symbios chips write only tx_errs word. */
7931da177e4SLinus Torvalds yp->tx_ring[j].dbdma_cmd =
7941da177e4SLinus Torvalds cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2);
7951da177e4SLinus Torvalds yp->tx_ring[j].request_cnt = 2;
7961da177e4SLinus Torvalds /* Om pade ummmmm... */
7971da177e4SLinus Torvalds yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
7981da177e4SLinus Torvalds i*sizeof(struct tx_status_words) +
7991da177e4SLinus Torvalds &(yp->tx_status[0].tx_errs) -
8001da177e4SLinus Torvalds &(yp->tx_status[0]));
8011da177e4SLinus Torvalds }
8021da177e4SLinus Torvalds yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
8031da177e4SLinus Torvalds ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc));
8041da177e4SLinus Torvalds }
8051da177e4SLinus Torvalds /* Wrap ring */
8061da177e4SLinus Torvalds yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS);
8071da177e4SLinus Torvalds }
8081da177e4SLinus Torvalds #endif
8091da177e4SLinus Torvalds yp->tx_tail_desc = &yp->tx_status[0];
810e7a5965aSRoel Kluin return 0;
8111da177e4SLinus Torvalds }
8121da177e4SLinus Torvalds
yellowfin_start_xmit(struct sk_buff * skb,struct net_device * dev)81361357325SStephen Hemminger static netdev_tx_t yellowfin_start_xmit(struct sk_buff *skb,
81461357325SStephen Hemminger struct net_device *dev)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
8171da177e4SLinus Torvalds unsigned entry;
8181da177e4SLinus Torvalds int len = skb->len;
8191da177e4SLinus Torvalds
8201da177e4SLinus Torvalds netif_stop_queue (dev);
8211da177e4SLinus Torvalds
8221da177e4SLinus Torvalds /* Note: Ordering is important here, set the field with the
8231da177e4SLinus Torvalds "ownership" bit last, and only then increment cur_tx. */
8241da177e4SLinus Torvalds
8251da177e4SLinus Torvalds /* Calculate the next Tx descriptor entry. */
8261da177e4SLinus Torvalds entry = yp->cur_tx % TX_RING_SIZE;
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */
8291da177e4SLinus Torvalds int cacheline_end = ((unsigned long)skb->data + skb->len) % 32;
8301da177e4SLinus Torvalds /* Fix GX chipset errata. */
8311da177e4SLinus Torvalds if (cacheline_end > 24 || cacheline_end == 0) {
8321da177e4SLinus Torvalds len = skb->len + 32 - cacheline_end + 1;
8335b057c6bSHerbert Xu if (skb_padto(skb, len)) {
8341da177e4SLinus Torvalds yp->tx_skbuff[entry] = NULL;
8351da177e4SLinus Torvalds netif_wake_queue(dev);
8366ed10654SPatrick McHardy return NETDEV_TX_OK;
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds }
8395b057c6bSHerbert Xu }
8401da177e4SLinus Torvalds yp->tx_skbuff[entry] = skb;
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds #ifdef NO_TXSTATS
84373e283dfSChristophe JAILLET yp->tx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
84473e283dfSChristophe JAILLET skb->data,
84573e283dfSChristophe JAILLET len, DMA_TO_DEVICE));
8461da177e4SLinus Torvalds yp->tx_ring[entry].result_status = 0;
8471da177e4SLinus Torvalds if (entry >= TX_RING_SIZE-1) {
8481da177e4SLinus Torvalds /* New stop command. */
8491da177e4SLinus Torvalds yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
8501da177e4SLinus Torvalds yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
8511da177e4SLinus Torvalds cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | len);
8521da177e4SLinus Torvalds } else {
8531da177e4SLinus Torvalds yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
8541da177e4SLinus Torvalds yp->tx_ring[entry].dbdma_cmd =
8551da177e4SLinus Torvalds cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | len);
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds yp->cur_tx++;
8581da177e4SLinus Torvalds #else
8591da177e4SLinus Torvalds yp->tx_ring[entry<<1].request_cnt = len;
86073e283dfSChristophe JAILLET yp->tx_ring[entry<<1].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
86173e283dfSChristophe JAILLET skb->data,
86273e283dfSChristophe JAILLET len, DMA_TO_DEVICE));
8631da177e4SLinus Torvalds /* The input_last (status-write) command is constant, but we must
8641da177e4SLinus Torvalds rewrite the subsequent 'stop' command. */
8651da177e4SLinus Torvalds
8661da177e4SLinus Torvalds yp->cur_tx++;
8671da177e4SLinus Torvalds {
8681da177e4SLinus Torvalds unsigned next_entry = yp->cur_tx % TX_RING_SIZE;
8691da177e4SLinus Torvalds yp->tx_ring[next_entry<<1].dbdma_cmd = cpu_to_le32(CMD_STOP);
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds /* Final step -- overwrite the old 'stop' command. */
8721da177e4SLinus Torvalds
8731da177e4SLinus Torvalds yp->tx_ring[entry<<1].dbdma_cmd =
8741da177e4SLinus Torvalds cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
8751da177e4SLinus Torvalds CMD_TX_PKT | BRANCH_IFTRUE) | len);
8761da177e4SLinus Torvalds #endif
8771da177e4SLinus Torvalds
8781da177e4SLinus Torvalds /* Non-x86 Todo: explicitly flush cache lines here. */
8791da177e4SLinus Torvalds
8801da177e4SLinus Torvalds /* Wake the potentially-idle transmit channel. */
8811da177e4SLinus Torvalds iowrite32(0x10001000, yp->base + TxCtrl);
8821da177e4SLinus Torvalds
8831da177e4SLinus Torvalds if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
8841da177e4SLinus Torvalds netif_start_queue (dev); /* Typical path */
8851da177e4SLinus Torvalds else
8861da177e4SLinus Torvalds yp->tx_full = 1;
8871da177e4SLinus Torvalds
8881da177e4SLinus Torvalds if (yellowfin_debug > 4) {
889acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin transmit frame #%d queued in slot %d\n",
890acbbf1f1SJoe Perches yp->cur_tx, entry);
8911da177e4SLinus Torvalds }
8926ed10654SPatrick McHardy return NETDEV_TX_OK;
8931da177e4SLinus Torvalds }
8941da177e4SLinus Torvalds
8951da177e4SLinus Torvalds /* The interrupt handler does all of the Rx thread work and cleans up
8961da177e4SLinus Torvalds after the Tx thread. */
yellowfin_interrupt(int irq,void * dev_instance)8977d12e780SDavid Howells static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
8981da177e4SLinus Torvalds {
8991da177e4SLinus Torvalds struct net_device *dev = dev_instance;
9001da177e4SLinus Torvalds struct yellowfin_private *yp;
9011da177e4SLinus Torvalds void __iomem *ioaddr;
9021da177e4SLinus Torvalds int boguscnt = max_interrupt_work;
9031da177e4SLinus Torvalds unsigned int handled = 0;
9041da177e4SLinus Torvalds
9051da177e4SLinus Torvalds yp = netdev_priv(dev);
9061da177e4SLinus Torvalds ioaddr = yp->base;
9071da177e4SLinus Torvalds
9081da177e4SLinus Torvalds spin_lock (&yp->lock);
9091da177e4SLinus Torvalds
9101da177e4SLinus Torvalds do {
9111da177e4SLinus Torvalds u16 intr_status = ioread16(ioaddr + IntrClear);
9121da177e4SLinus Torvalds
9131da177e4SLinus Torvalds if (yellowfin_debug > 4)
914acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Yellowfin interrupt, status %04x\n",
915acbbf1f1SJoe Perches intr_status);
9161da177e4SLinus Torvalds
9171da177e4SLinus Torvalds if (intr_status == 0)
9181da177e4SLinus Torvalds break;
9191da177e4SLinus Torvalds handled = 1;
9201da177e4SLinus Torvalds
9211da177e4SLinus Torvalds if (intr_status & (IntrRxDone | IntrEarlyRx)) {
9221da177e4SLinus Torvalds yellowfin_rx(dev);
9231da177e4SLinus Torvalds iowrite32(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds
9261da177e4SLinus Torvalds #ifdef NO_TXSTATS
9271da177e4SLinus Torvalds for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) {
9281da177e4SLinus Torvalds int entry = yp->dirty_tx % TX_RING_SIZE;
9291da177e4SLinus Torvalds struct sk_buff *skb;
9301da177e4SLinus Torvalds
9311da177e4SLinus Torvalds if (yp->tx_ring[entry].result_status == 0)
9321da177e4SLinus Torvalds break;
9331da177e4SLinus Torvalds skb = yp->tx_skbuff[entry];
93409f75cd7SJeff Garzik dev->stats.tx_packets++;
93509f75cd7SJeff Garzik dev->stats.tx_bytes += skb->len;
9361da177e4SLinus Torvalds /* Free the original skb. */
93773e283dfSChristophe JAILLET dma_unmap_single(&yp->pci_dev->dev,
93873e283dfSChristophe JAILLET le32_to_cpu(yp->tx_ring[entry].addr),
93973e283dfSChristophe JAILLET skb->len, DMA_TO_DEVICE);
9401bba6de1SYang Wei dev_consume_skb_irq(skb);
9411da177e4SLinus Torvalds yp->tx_skbuff[entry] = NULL;
9421da177e4SLinus Torvalds }
9438e95a202SJoe Perches if (yp->tx_full &&
9448e95a202SJoe Perches yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
9451da177e4SLinus Torvalds /* The ring is no longer full, clear tbusy. */
9461da177e4SLinus Torvalds yp->tx_full = 0;
9471da177e4SLinus Torvalds netif_wake_queue(dev);
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds #else
9501da177e4SLinus Torvalds if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) {
9511da177e4SLinus Torvalds unsigned dirty_tx = yp->dirty_tx;
9521da177e4SLinus Torvalds
9531da177e4SLinus Torvalds for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0;
9541da177e4SLinus Torvalds dirty_tx++) {
9551da177e4SLinus Torvalds /* Todo: optimize this. */
9561da177e4SLinus Torvalds int entry = dirty_tx % TX_RING_SIZE;
9571da177e4SLinus Torvalds u16 tx_errs = yp->tx_status[entry].tx_errs;
9581da177e4SLinus Torvalds struct sk_buff *skb;
9591da177e4SLinus Torvalds
9601da177e4SLinus Torvalds #ifndef final_version
9611da177e4SLinus Torvalds if (yellowfin_debug > 5)
962acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Tx queue %d check, Tx status %04x %04x %04x %04x\n",
963acbbf1f1SJoe Perches entry,
9641da177e4SLinus Torvalds yp->tx_status[entry].tx_cnt,
9651da177e4SLinus Torvalds yp->tx_status[entry].tx_errs,
9661da177e4SLinus Torvalds yp->tx_status[entry].total_tx_cnt,
9671da177e4SLinus Torvalds yp->tx_status[entry].paused);
9681da177e4SLinus Torvalds #endif
9691da177e4SLinus Torvalds if (tx_errs == 0)
9701da177e4SLinus Torvalds break; /* It still hasn't been Txed */
9711da177e4SLinus Torvalds skb = yp->tx_skbuff[entry];
9721da177e4SLinus Torvalds if (tx_errs & 0xF810) {
9731da177e4SLinus Torvalds /* There was an major error, log it. */
9741da177e4SLinus Torvalds #ifndef final_version
9751da177e4SLinus Torvalds if (yellowfin_debug > 1)
976acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Transmit error, Tx status %04x\n",
977acbbf1f1SJoe Perches tx_errs);
9781da177e4SLinus Torvalds #endif
97909f75cd7SJeff Garzik dev->stats.tx_errors++;
98009f75cd7SJeff Garzik if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
98109f75cd7SJeff Garzik if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++;
98209f75cd7SJeff Garzik if (tx_errs & 0x2000) dev->stats.tx_window_errors++;
98309f75cd7SJeff Garzik if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++;
9841da177e4SLinus Torvalds } else {
9851da177e4SLinus Torvalds #ifndef final_version
9861da177e4SLinus Torvalds if (yellowfin_debug > 4)
987acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Normal transmit, Tx status %04x\n",
988acbbf1f1SJoe Perches tx_errs);
9891da177e4SLinus Torvalds #endif
99009f75cd7SJeff Garzik dev->stats.tx_bytes += skb->len;
99109f75cd7SJeff Garzik dev->stats.collisions += tx_errs & 15;
99209f75cd7SJeff Garzik dev->stats.tx_packets++;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds /* Free the original skb. */
99573e283dfSChristophe JAILLET dma_unmap_single(&yp->pci_dev->dev,
99673e283dfSChristophe JAILLET yp->tx_ring[entry << 1].addr,
99773e283dfSChristophe JAILLET skb->len, DMA_TO_DEVICE);
9981bba6de1SYang Wei dev_consume_skb_irq(skb);
9991da177e4SLinus Torvalds yp->tx_skbuff[entry] = 0;
10001da177e4SLinus Torvalds /* Mark status as empty. */
10011da177e4SLinus Torvalds yp->tx_status[entry].tx_errs = 0;
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds #ifndef final_version
10051da177e4SLinus Torvalds if (yp->cur_tx - dirty_tx > TX_RING_SIZE) {
1006acbbf1f1SJoe Perches netdev_err(dev, "Out-of-sync dirty pointer, %d vs. %d, full=%d\n",
1007acbbf1f1SJoe Perches dirty_tx, yp->cur_tx, yp->tx_full);
10081da177e4SLinus Torvalds dirty_tx += TX_RING_SIZE;
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds #endif
10111da177e4SLinus Torvalds
10128e95a202SJoe Perches if (yp->tx_full &&
10138e95a202SJoe Perches yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
10141da177e4SLinus Torvalds /* The ring is no longer full, clear tbusy. */
10151da177e4SLinus Torvalds yp->tx_full = 0;
10161da177e4SLinus Torvalds netif_wake_queue(dev);
10171da177e4SLinus Torvalds }
10181da177e4SLinus Torvalds
10191da177e4SLinus Torvalds yp->dirty_tx = dirty_tx;
10201da177e4SLinus Torvalds yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
10211da177e4SLinus Torvalds }
10221da177e4SLinus Torvalds #endif
10231da177e4SLinus Torvalds
10241da177e4SLinus Torvalds /* Log errors and other uncommon events. */
10251da177e4SLinus Torvalds if (intr_status & 0x2ee) /* Abnormal error summary. */
10261da177e4SLinus Torvalds yellowfin_error(dev, intr_status);
10271da177e4SLinus Torvalds
10281da177e4SLinus Torvalds if (--boguscnt < 0) {
1029acbbf1f1SJoe Perches netdev_warn(dev, "Too much work at interrupt, status=%#04x\n",
1030acbbf1f1SJoe Perches intr_status);
10311da177e4SLinus Torvalds break;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds } while (1);
10341da177e4SLinus Torvalds
10351da177e4SLinus Torvalds if (yellowfin_debug > 3)
1036acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "exiting interrupt, status=%#04x\n",
1037acbbf1f1SJoe Perches ioread16(ioaddr + IntrStatus));
10381da177e4SLinus Torvalds
10391da177e4SLinus Torvalds spin_unlock (&yp->lock);
10401da177e4SLinus Torvalds return IRQ_RETVAL(handled);
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds
10431da177e4SLinus Torvalds /* This routine is logically part of the interrupt handler, but separated
10441da177e4SLinus Torvalds for clarity and better register allocation. */
yellowfin_rx(struct net_device * dev)10451da177e4SLinus Torvalds static int yellowfin_rx(struct net_device *dev)
10461da177e4SLinus Torvalds {
10471da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
10481da177e4SLinus Torvalds int entry = yp->cur_rx % RX_RING_SIZE;
10491da177e4SLinus Torvalds int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
10501da177e4SLinus Torvalds
10511da177e4SLinus Torvalds if (yellowfin_debug > 4) {
1052acbbf1f1SJoe Perches printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %08x\n",
10531da177e4SLinus Torvalds entry, yp->rx_ring[entry].result_status);
1054acbbf1f1SJoe Perches printk(KERN_DEBUG " #%d desc. %08x %08x %08x\n",
10551da177e4SLinus Torvalds entry, yp->rx_ring[entry].dbdma_cmd, yp->rx_ring[entry].addr,
10561da177e4SLinus Torvalds yp->rx_ring[entry].result_status);
10571da177e4SLinus Torvalds }
10581da177e4SLinus Torvalds
10591da177e4SLinus Torvalds /* If EOP is set on the next entry, it's a new packet. Send it up. */
10601da177e4SLinus Torvalds while (1) {
10611da177e4SLinus Torvalds struct yellowfin_desc *desc = &yp->rx_ring[entry];
10621da177e4SLinus Torvalds struct sk_buff *rx_skb = yp->rx_skbuff[entry];
10631da177e4SLinus Torvalds s16 frame_status;
10641da177e4SLinus Torvalds u16 desc_status;
1065d0ea5cbdSJesse Brandeburg int data_size, __maybe_unused yf_size;
10661da177e4SLinus Torvalds u8 *buf_addr;
10671da177e4SLinus Torvalds
10681da177e4SLinus Torvalds if(!desc->result_status)
10691da177e4SLinus Torvalds break;
107073e283dfSChristophe JAILLET dma_sync_single_for_cpu(&yp->pci_dev->dev,
107173e283dfSChristophe JAILLET le32_to_cpu(desc->addr),
107273e283dfSChristophe JAILLET yp->rx_buf_sz, DMA_FROM_DEVICE);
10731da177e4SLinus Torvalds desc_status = le32_to_cpu(desc->result_status) >> 16;
1074689be439SDavid S. Miller buf_addr = rx_skb->data;
10751da177e4SLinus Torvalds data_size = (le32_to_cpu(desc->dbdma_cmd) -
10761da177e4SLinus Torvalds le32_to_cpu(desc->result_status)) & 0xffff;
10776caf52a4SHarvey Harrison frame_status = get_unaligned_le16(&(buf_addr[data_size - 2]));
10781da177e4SLinus Torvalds if (yellowfin_debug > 4)
1079acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() status was %04x\n",
1080acbbf1f1SJoe Perches __func__, frame_status);
10811da177e4SLinus Torvalds if (--boguscnt < 0)
10821da177e4SLinus Torvalds break;
10833a8e87ecSdingtianhong
10843a8e87ecSdingtianhong yf_size = sizeof(struct yellowfin_desc);
10853a8e87ecSdingtianhong
10861da177e4SLinus Torvalds if ( ! (desc_status & RX_EOP)) {
10871da177e4SLinus Torvalds if (data_size != 0)
1088acbbf1f1SJoe Perches netdev_warn(dev, "Oversized Ethernet frame spanned multiple buffers, status %04x, data_size %d!\n",
1089acbbf1f1SJoe Perches desc_status, data_size);
109009f75cd7SJeff Garzik dev->stats.rx_length_errors++;
10911da177e4SLinus Torvalds } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
10921da177e4SLinus Torvalds /* There was a error. */
10931da177e4SLinus Torvalds if (yellowfin_debug > 3)
1094acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() Rx error was %04x\n",
1095acbbf1f1SJoe Perches __func__, frame_status);
109609f75cd7SJeff Garzik dev->stats.rx_errors++;
109709f75cd7SJeff Garzik if (frame_status & 0x0060) dev->stats.rx_length_errors++;
109809f75cd7SJeff Garzik if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
109909f75cd7SJeff Garzik if (frame_status & 0x0010) dev->stats.rx_crc_errors++;
110009f75cd7SJeff Garzik if (frame_status < 0) dev->stats.rx_dropped++;
11011da177e4SLinus Torvalds } else if ( !(yp->drv_flags & IsGigabit) &&
11021da177e4SLinus Torvalds ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
11031da177e4SLinus Torvalds u8 status1 = buf_addr[data_size-2];
11041da177e4SLinus Torvalds u8 status2 = buf_addr[data_size-1];
110509f75cd7SJeff Garzik dev->stats.rx_errors++;
110609f75cd7SJeff Garzik if (status1 & 0xC0) dev->stats.rx_length_errors++;
110709f75cd7SJeff Garzik if (status2 & 0x03) dev->stats.rx_frame_errors++;
110809f75cd7SJeff Garzik if (status2 & 0x04) dev->stats.rx_crc_errors++;
110909f75cd7SJeff Garzik if (status2 & 0x80) dev->stats.rx_dropped++;
11101da177e4SLinus Torvalds #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
11111da177e4SLinus Torvalds } else if ((yp->flags & HasMACAddrBug) &&
11123a8e87ecSdingtianhong !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma +
11133a8e87ecSdingtianhong entry * yf_size),
11143a8e87ecSdingtianhong dev->dev_addr) &&
11153a8e87ecSdingtianhong !ether_addr_equal(le32_to_cpu(yp->rx_ring_dma +
11163a8e87ecSdingtianhong entry * yf_size),
11173a8e87ecSdingtianhong "\377\377\377\377\377\377")) {
1118e174961cSJohannes Berg if (bogus_rx++ == 0)
1119acbbf1f1SJoe Perches netdev_warn(dev, "Bad frame to %pM\n",
1120acbbf1f1SJoe Perches buf_addr);
11211da177e4SLinus Torvalds #endif
11221da177e4SLinus Torvalds } else {
11231da177e4SLinus Torvalds struct sk_buff *skb;
11241da177e4SLinus Torvalds int pkt_len = data_size -
11251da177e4SLinus Torvalds (yp->chip_id ? 7 : 8 + buf_addr[data_size - 8]);
11261da177e4SLinus Torvalds /* To verify: Yellowfin Length should omit the CRC! */
11271da177e4SLinus Torvalds
11281da177e4SLinus Torvalds #ifndef final_version
11291da177e4SLinus Torvalds if (yellowfin_debug > 4)
1130acbbf1f1SJoe Perches printk(KERN_DEBUG " %s() normal Rx pkt length %d of %d, bogus_cnt %d\n",
1131acbbf1f1SJoe Perches __func__, pkt_len, data_size, boguscnt);
11321da177e4SLinus Torvalds #endif
11331da177e4SLinus Torvalds /* Check if the packet is long enough to just pass up the skbuff
11341da177e4SLinus Torvalds without copying to a properly sized skbuff. */
11351da177e4SLinus Torvalds if (pkt_len > rx_copybreak) {
11361da177e4SLinus Torvalds skb_put(skb = rx_skb, pkt_len);
113773e283dfSChristophe JAILLET dma_unmap_single(&yp->pci_dev->dev,
1138e5a31421SAl Viro le32_to_cpu(yp->rx_ring[entry].addr),
11391da177e4SLinus Torvalds yp->rx_buf_sz,
114073e283dfSChristophe JAILLET DMA_FROM_DEVICE);
11411da177e4SLinus Torvalds yp->rx_skbuff[entry] = NULL;
11421da177e4SLinus Torvalds } else {
1143dae2e9f4SPradeep A. Dalvi skb = netdev_alloc_skb(dev, pkt_len + 2);
11441da177e4SLinus Torvalds if (skb == NULL)
11451da177e4SLinus Torvalds break;
11461da177e4SLinus Torvalds skb_reserve(skb, 2); /* 16 byte align the IP header */
11478c7b7faaSDavid S. Miller skb_copy_to_linear_data(skb, rx_skb->data, pkt_len);
11481da177e4SLinus Torvalds skb_put(skb, pkt_len);
114973e283dfSChristophe JAILLET dma_sync_single_for_device(&yp->pci_dev->dev,
1150e5a31421SAl Viro le32_to_cpu(desc->addr),
11511da177e4SLinus Torvalds yp->rx_buf_sz,
115273e283dfSChristophe JAILLET DMA_FROM_DEVICE);
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds skb->protocol = eth_type_trans(skb, dev);
11551da177e4SLinus Torvalds netif_rx(skb);
115609f75cd7SJeff Garzik dev->stats.rx_packets++;
115709f75cd7SJeff Garzik dev->stats.rx_bytes += pkt_len;
11581da177e4SLinus Torvalds }
11591da177e4SLinus Torvalds entry = (++yp->cur_rx) % RX_RING_SIZE;
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds
11621da177e4SLinus Torvalds /* Refill the Rx ring buffers. */
11631da177e4SLinus Torvalds for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) {
11641da177e4SLinus Torvalds entry = yp->dirty_rx % RX_RING_SIZE;
11651da177e4SLinus Torvalds if (yp->rx_skbuff[entry] == NULL) {
1166dae2e9f4SPradeep A. Dalvi struct sk_buff *skb = netdev_alloc_skb(dev, yp->rx_buf_sz + 2);
11671da177e4SLinus Torvalds if (skb == NULL)
11681da177e4SLinus Torvalds break; /* Better luck next round. */
11691da177e4SLinus Torvalds yp->rx_skbuff[entry] = skb;
11701da177e4SLinus Torvalds skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
117173e283dfSChristophe JAILLET yp->rx_ring[entry].addr = cpu_to_le32(dma_map_single(&yp->pci_dev->dev,
117273e283dfSChristophe JAILLET skb->data,
117373e283dfSChristophe JAILLET yp->rx_buf_sz,
117473e283dfSChristophe JAILLET DMA_FROM_DEVICE));
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
11771da177e4SLinus Torvalds yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
11781da177e4SLinus Torvalds if (entry != 0)
11791da177e4SLinus Torvalds yp->rx_ring[entry - 1].dbdma_cmd =
11801da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz);
11811da177e4SLinus Torvalds else
11821da177e4SLinus Torvalds yp->rx_ring[RX_RING_SIZE - 1].dbdma_cmd =
11831da177e4SLinus Torvalds cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS
11841da177e4SLinus Torvalds | yp->rx_buf_sz);
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds
11871da177e4SLinus Torvalds return 0;
11881da177e4SLinus Torvalds }
11891da177e4SLinus Torvalds
yellowfin_error(struct net_device * dev,int intr_status)11901da177e4SLinus Torvalds static void yellowfin_error(struct net_device *dev, int intr_status)
11911da177e4SLinus Torvalds {
1192acbbf1f1SJoe Perches netdev_err(dev, "Something Wicked happened! %04x\n", intr_status);
11931da177e4SLinus Torvalds /* Hmmmmm, it's not clear what to do here. */
11941da177e4SLinus Torvalds if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
119509f75cd7SJeff Garzik dev->stats.tx_errors++;
11961da177e4SLinus Torvalds if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
119709f75cd7SJeff Garzik dev->stats.rx_errors++;
11981da177e4SLinus Torvalds }
11991da177e4SLinus Torvalds
yellowfin_close(struct net_device * dev)12001da177e4SLinus Torvalds static int yellowfin_close(struct net_device *dev)
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
12031da177e4SLinus Torvalds void __iomem *ioaddr = yp->base;
12041da177e4SLinus Torvalds int i;
12051da177e4SLinus Torvalds
12061da177e4SLinus Torvalds netif_stop_queue (dev);
12071da177e4SLinus Torvalds
12081da177e4SLinus Torvalds if (yellowfin_debug > 1) {
1209acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Shutting down ethercard, status was Tx %04x Rx %04x Int %02x\n",
1210acbbf1f1SJoe Perches ioread16(ioaddr + TxStatus),
12111da177e4SLinus Torvalds ioread16(ioaddr + RxStatus),
12121da177e4SLinus Torvalds ioread16(ioaddr + IntrStatus));
1213acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n",
1214acbbf1f1SJoe Perches yp->cur_tx, yp->dirty_tx,
1215acbbf1f1SJoe Perches yp->cur_rx, yp->dirty_rx);
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds
12181da177e4SLinus Torvalds /* Disable interrupts by clearing the interrupt mask. */
12191da177e4SLinus Torvalds iowrite16(0x0000, ioaddr + IntrEnb);
12201da177e4SLinus Torvalds
12211da177e4SLinus Torvalds /* Stop the chip's Tx and Rx processes. */
12221da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + RxCtrl);
12231da177e4SLinus Torvalds iowrite32(0x80000000, ioaddr + TxCtrl);
12241da177e4SLinus Torvalds
12258fa7292fSThomas Gleixner timer_delete(&yp->timer);
12261da177e4SLinus Torvalds
12271da177e4SLinus Torvalds #if defined(__i386__)
12281da177e4SLinus Torvalds if (yellowfin_debug > 2) {
1229acbbf1f1SJoe Perches printk(KERN_DEBUG " Tx ring at %08llx:\n",
12301da177e4SLinus Torvalds (unsigned long long)yp->tx_ring_dma);
12311da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE*2; i++)
1232acbbf1f1SJoe Perches printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x %08x\n",
12331da177e4SLinus Torvalds ioread32(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
12341da177e4SLinus Torvalds i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
12351da177e4SLinus Torvalds yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
12361da177e4SLinus Torvalds printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status);
12371da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++)
1238acbbf1f1SJoe Perches printk(KERN_DEBUG " #%d status %04x %04x %04x %04x\n",
12391da177e4SLinus Torvalds i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
12401da177e4SLinus Torvalds yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
12411da177e4SLinus Torvalds
1242acbbf1f1SJoe Perches printk(KERN_DEBUG " Rx ring %08llx:\n",
12431da177e4SLinus Torvalds (unsigned long long)yp->rx_ring_dma);
12441da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) {
1245acbbf1f1SJoe Perches printk(KERN_DEBUG " %c #%d desc. %08x %08x %08x\n",
12461da177e4SLinus Torvalds ioread32(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
12471da177e4SLinus Torvalds i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
12481da177e4SLinus Torvalds yp->rx_ring[i].result_status);
12491da177e4SLinus Torvalds if (yellowfin_debug > 6) {
12501da177e4SLinus Torvalds if (get_unaligned((u8*)yp->rx_ring[i].addr) != 0x69) {
12511da177e4SLinus Torvalds int j;
1252acbbf1f1SJoe Perches
1253acbbf1f1SJoe Perches printk(KERN_DEBUG);
12541da177e4SLinus Torvalds for (j = 0; j < 0x50; j++)
1255acbbf1f1SJoe Perches pr_cont(" %04x",
12561da177e4SLinus Torvalds get_unaligned(((u16*)yp->rx_ring[i].addr) + j));
1257acbbf1f1SJoe Perches pr_cont("\n");
12581da177e4SLinus Torvalds }
12591da177e4SLinus Torvalds }
12601da177e4SLinus Torvalds }
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds #endif /* __i386__ debugging only */
12631da177e4SLinus Torvalds
12640c18acc1SFrancois Romieu free_irq(yp->pci_dev->irq, dev);
12651da177e4SLinus Torvalds
12661da177e4SLinus Torvalds /* Free all the skbuffs in the Rx queue. */
12671da177e4SLinus Torvalds for (i = 0; i < RX_RING_SIZE; i++) {
12681da177e4SLinus Torvalds yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP);
1269e5a31421SAl Viro yp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
12701da177e4SLinus Torvalds if (yp->rx_skbuff[i]) {
12711da177e4SLinus Torvalds dev_kfree_skb(yp->rx_skbuff[i]);
12721da177e4SLinus Torvalds }
12731da177e4SLinus Torvalds yp->rx_skbuff[i] = NULL;
12741da177e4SLinus Torvalds }
12751da177e4SLinus Torvalds for (i = 0; i < TX_RING_SIZE; i++) {
12761da177e4SLinus Torvalds dev_kfree_skb(yp->tx_skbuff[i]);
12771da177e4SLinus Torvalds yp->tx_skbuff[i] = NULL;
12781da177e4SLinus Torvalds }
12791da177e4SLinus Torvalds
12801da177e4SLinus Torvalds #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
12811da177e4SLinus Torvalds if (yellowfin_debug > 0) {
1282acbbf1f1SJoe Perches netdev_printk(KERN_DEBUG, dev, "Received %d frames that we should not have\n",
1283acbbf1f1SJoe Perches bogus_rx);
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds #endif
12861da177e4SLinus Torvalds
12871da177e4SLinus Torvalds return 0;
12881da177e4SLinus Torvalds }
12891da177e4SLinus Torvalds
12901da177e4SLinus Torvalds /* Set or clear the multicast filter for this adaptor. */
12911da177e4SLinus Torvalds
set_rx_mode(struct net_device * dev)12921da177e4SLinus Torvalds static void set_rx_mode(struct net_device *dev)
12931da177e4SLinus Torvalds {
12941da177e4SLinus Torvalds struct yellowfin_private *yp = netdev_priv(dev);
12951da177e4SLinus Torvalds void __iomem *ioaddr = yp->base;
12961da177e4SLinus Torvalds u16 cfg_value = ioread16(ioaddr + Cnfg);
12971da177e4SLinus Torvalds
12981da177e4SLinus Torvalds /* Stop the Rx process to change any value. */
12991da177e4SLinus Torvalds iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);
13001da177e4SLinus Torvalds if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
13011da177e4SLinus Torvalds iowrite16(0x000F, ioaddr + AddrMode);
13024cd24eafSJiri Pirko } else if ((netdev_mc_count(dev) > 64) ||
13034cd24eafSJiri Pirko (dev->flags & IFF_ALLMULTI)) {
13041da177e4SLinus Torvalds /* Too many to filter well, or accept all multicasts. */
13051da177e4SLinus Torvalds iowrite16(0x000B, ioaddr + AddrMode);
13064cd24eafSJiri Pirko } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */
130722bedad3SJiri Pirko struct netdev_hw_addr *ha;
13081da177e4SLinus Torvalds u16 hash_table[4];
13091da177e4SLinus Torvalds int i;
1310567ec874SJiri Pirko
13111da177e4SLinus Torvalds memset(hash_table, 0, sizeof(hash_table));
131222bedad3SJiri Pirko netdev_for_each_mc_addr(ha, dev) {
13131da177e4SLinus Torvalds unsigned int bit;
13141da177e4SLinus Torvalds
13151da177e4SLinus Torvalds /* Due to a bug in the early chip versions, multiple filter
13161da177e4SLinus Torvalds slots must be set for each address. */
13171da177e4SLinus Torvalds if (yp->drv_flags & HasMulticastBug) {
131822bedad3SJiri Pirko bit = (ether_crc_le(3, ha->addr) >> 3) & 0x3f;
13191da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit);
132022bedad3SJiri Pirko bit = (ether_crc_le(4, ha->addr) >> 3) & 0x3f;
13211da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit);
132222bedad3SJiri Pirko bit = (ether_crc_le(5, ha->addr) >> 3) & 0x3f;
13231da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit);
13241da177e4SLinus Torvalds }
132522bedad3SJiri Pirko bit = (ether_crc_le(6, ha->addr) >> 3) & 0x3f;
13261da177e4SLinus Torvalds hash_table[bit >> 4] |= (1 << bit);
13271da177e4SLinus Torvalds }
13281da177e4SLinus Torvalds /* Copy the hash table to the chip. */
13291da177e4SLinus Torvalds for (i = 0; i < 4; i++)
13301da177e4SLinus Torvalds iowrite16(hash_table[i], ioaddr + HashTbl + i*2);
13311da177e4SLinus Torvalds iowrite16(0x0003, ioaddr + AddrMode);
13321da177e4SLinus Torvalds } else { /* Normal, unicast/broadcast-only mode. */
13331da177e4SLinus Torvalds iowrite16(0x0001, ioaddr + AddrMode);
13341da177e4SLinus Torvalds }
13351da177e4SLinus Torvalds /* Restart the Rx process. */
13361da177e4SLinus Torvalds iowrite16(cfg_value | 0x1000, ioaddr + Cnfg);
13371da177e4SLinus Torvalds }
13381da177e4SLinus Torvalds
yellowfin_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)13391da177e4SLinus Torvalds static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
13401da177e4SLinus Torvalds {
13411da177e4SLinus Torvalds struct yellowfin_private *np = netdev_priv(dev);
13427826d43fSJiri Pirko
1343f029c781SWolfram Sang strscpy(info->driver, DRV_NAME, sizeof(info->driver));
1344f029c781SWolfram Sang strscpy(info->version, DRV_VERSION, sizeof(info->version));
1345f029c781SWolfram Sang strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds
13487282d491SJeff Garzik static const struct ethtool_ops ethtool_ops = {
13491da177e4SLinus Torvalds .get_drvinfo = yellowfin_get_drvinfo
13501da177e4SLinus Torvalds };
13511da177e4SLinus Torvalds
netdev_ioctl(struct net_device * dev,struct ifreq * rq,int cmd)13521da177e4SLinus Torvalds static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
13531da177e4SLinus Torvalds {
13541da177e4SLinus Torvalds struct yellowfin_private *np = netdev_priv(dev);
13551da177e4SLinus Torvalds void __iomem *ioaddr = np->base;
13561da177e4SLinus Torvalds struct mii_ioctl_data *data = if_mii(rq);
13571da177e4SLinus Torvalds
13581da177e4SLinus Torvalds switch(cmd) {
13591da177e4SLinus Torvalds case SIOCGMIIPHY: /* Get address of MII PHY in use. */
13601da177e4SLinus Torvalds data->phy_id = np->phys[0] & 0x1f;
1361df561f66SGustavo A. R. Silva fallthrough;
13621da177e4SLinus Torvalds
13631da177e4SLinus Torvalds case SIOCGMIIREG: /* Read MII PHY register. */
13641da177e4SLinus Torvalds data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
13651da177e4SLinus Torvalds return 0;
13661da177e4SLinus Torvalds
13671da177e4SLinus Torvalds case SIOCSMIIREG: /* Write MII PHY register. */
13681da177e4SLinus Torvalds if (data->phy_id == np->phys[0]) {
13691da177e4SLinus Torvalds u16 value = data->val_in;
13701da177e4SLinus Torvalds switch (data->reg_num) {
13711da177e4SLinus Torvalds case 0:
13721da177e4SLinus Torvalds /* Check for autonegotiation on or reset. */
13731da177e4SLinus Torvalds np->medialock = (value & 0x9000) ? 0 : 1;
13741da177e4SLinus Torvalds if (np->medialock)
13751da177e4SLinus Torvalds np->full_duplex = (value & 0x0100) ? 1 : 0;
13761da177e4SLinus Torvalds break;
13771da177e4SLinus Torvalds case 4: np->advertising = value; break;
13781da177e4SLinus Torvalds }
13791da177e4SLinus Torvalds /* Perhaps check_duplex(dev), depending on chip semantics. */
13801da177e4SLinus Torvalds }
13811da177e4SLinus Torvalds mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
13821da177e4SLinus Torvalds return 0;
13831da177e4SLinus Torvalds default:
13841da177e4SLinus Torvalds return -EOPNOTSUPP;
13851da177e4SLinus Torvalds }
13861da177e4SLinus Torvalds }
13871da177e4SLinus Torvalds
13881da177e4SLinus Torvalds
yellowfin_remove_one(struct pci_dev * pdev)1389134c1f15SBill Pemberton static void yellowfin_remove_one(struct pci_dev *pdev)
13901da177e4SLinus Torvalds {
13911da177e4SLinus Torvalds struct net_device *dev = pci_get_drvdata(pdev);
13921da177e4SLinus Torvalds struct yellowfin_private *np;
13931da177e4SLinus Torvalds
13945d9428deSEric Sesterhenn BUG_ON(!dev);
13951da177e4SLinus Torvalds np = netdev_priv(dev);
13961da177e4SLinus Torvalds
139773e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, STATUS_TOTAL_SIZE, np->tx_status,
13981da177e4SLinus Torvalds np->tx_status_dma);
139973e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring,
140073e283dfSChristophe JAILLET np->rx_ring_dma);
140173e283dfSChristophe JAILLET dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
140273e283dfSChristophe JAILLET np->tx_ring_dma);
14031da177e4SLinus Torvalds unregister_netdev (dev);
14041da177e4SLinus Torvalds
14051da177e4SLinus Torvalds pci_iounmap(pdev, np->base);
14061da177e4SLinus Torvalds
14071da177e4SLinus Torvalds pci_release_regions (pdev);
14081da177e4SLinus Torvalds
14091da177e4SLinus Torvalds free_netdev (dev);
14101da177e4SLinus Torvalds }
14111da177e4SLinus Torvalds
14121da177e4SLinus Torvalds
14131da177e4SLinus Torvalds static struct pci_driver yellowfin_driver = {
14141da177e4SLinus Torvalds .name = DRV_NAME,
14151da177e4SLinus Torvalds .id_table = yellowfin_pci_tbl,
14161da177e4SLinus Torvalds .probe = yellowfin_init_one,
1417134c1f15SBill Pemberton .remove = yellowfin_remove_one,
14181da177e4SLinus Torvalds };
14191da177e4SLinus Torvalds
14201da177e4SLinus Torvalds
yellowfin_init(void)14211da177e4SLinus Torvalds static int __init yellowfin_init (void)
14221da177e4SLinus Torvalds {
14231da177e4SLinus Torvalds /* when a module, this is printed whether or not devices are found in probe */
14241da177e4SLinus Torvalds #ifdef MODULE
14251da177e4SLinus Torvalds printk(version);
14261da177e4SLinus Torvalds #endif
142729917620SJeff Garzik return pci_register_driver(&yellowfin_driver);
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds
14301da177e4SLinus Torvalds
yellowfin_cleanup(void)14311da177e4SLinus Torvalds static void __exit yellowfin_cleanup (void)
14321da177e4SLinus Torvalds {
14331da177e4SLinus Torvalds pci_unregister_driver (&yellowfin_driver);
14341da177e4SLinus Torvalds }
14351da177e4SLinus Torvalds
14361da177e4SLinus Torvalds
14371da177e4SLinus Torvalds module_init(yellowfin_init);
14381da177e4SLinus Torvalds module_exit(yellowfin_cleanup);
1439