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