xref: /linux/drivers/net/ethernet/packetengines/yellowfin.c (revision 3a8e87ec2376f8844af1a1b924a19e151a85d65a)
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, &ethtool_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