11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Copyright 2001,2003 Jeff Garzik <jgarzik@pobox.com>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Copyright 1994, 1995 Digital Equipment Corporation.	    [de4x5.c]
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Written/copyright 1994-2001 by Donald Becker.		    [tulip.c]
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	This software may be used and distributed according to the terms of
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	the GNU General Public License (GPL), incorporated herein by reference.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Drivers based on or derived from this code fall under the GPL and must
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retain the authorship, copyright and license notice.  This file is not
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	a complete program and may only be used when the entire operating
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	system is licensed under the GPL.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	See the file COPYING in this distribution for more information.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TODO, in rough priority order:
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Support forcing media type with a module parameter,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  like dl2k.c/sundance.c
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Constants (module parms?) for Rx work limit
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Complete reset on PciErr
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Jumbo frames / dev->change_mtu
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	* Implement Tx software interrupt mitigation via
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  Tx descriptor bit
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME		"de2104x"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_VERSION		"0.7"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_RELDATE		"Mar 17, 2004"
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
41a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compiler.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/crc32.h>
485a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/unaligned.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These identify the driver base version and may not be removed. */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char version[] =
571c3319fb69c29376fe23c1aa0cd7cb6df91c7883Joe Perches"PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")";
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRV_VERSION);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug = -1;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param (debug, int, 0);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
698e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \
708e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches        defined(CONFIG_SPARC) || defined(__ia64__) ||		   \
718e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches        defined(__sh__) || defined(__mips__)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rx_copybreak = 1518;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rx_copybreak = 100;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param (rx_copybreak, int, 0);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_PROBE 	| \
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_LINK		| \
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_IFDOWN	| \
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_IFUP		| \
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_RX_ERR	| \
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 NETIF_MSG_TX_ERR)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen/* Descriptor skip length in 32 bit longwords. */
88b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#ifndef CONFIG_DE2104X_DSL
89b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#define DSL			0
90b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#else
91b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#define DSL			CONFIG_DE2104X_DSL
92b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#endif
93b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_RX_RING_SIZE		64
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_TX_RING_SIZE		64
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_RING_BYTES		\
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((sizeof(struct de_desc) * DE_RX_RING_SIZE) +	\
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(sizeof(struct de_desc) * DE_TX_RING_SIZE))
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_TX(N)		(((N) + 1) & (DE_TX_RING_SIZE - 1))
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NEXT_RX(N)		(((N) + 1) & (DE_RX_RING_SIZE - 1))
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_BUFFS_AVAIL(CP)					\
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(((CP)->tx_tail <= (CP)->tx_head) ?			\
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  (CP)->tx_tail + (DE_TX_RING_SIZE - 1) - (CP)->tx_head :	\
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  (CP)->tx_tail - (CP)->tx_head - 1)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_OFFSET		2
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_SETUP_SKB		((struct sk_buff *) 1)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_DUMMY_SKB		((struct sk_buff *) 2)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_SETUP_FRAME_WORDS	96
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_EEPROM_WORDS		256
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_EEPROM_SIZE		(DE_EEPROM_WORDS * sizeof(u16))
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MAX_MEDIA		5
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_TP_AUTO	0
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_BNC		1
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_AUI		2
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_TP		3
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_TP_FD		4
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_INVALID	DE_MAX_MEDIA
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_FIRST		0
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_MEDIA_LAST		(DE_MAX_MEDIA - 1)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_AUI_BNC		(SUPPORTED_AUI | SUPPORTED_BNC)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_TIMER_LINK		(60 * HZ)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_TIMER_NO_LINK	(5 * HZ)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_NUM_REGS		16
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_REGS_SIZE		(DE_NUM_REGS * sizeof(u32))
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DE_REGS_VER		1
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Time in jiffies before concluding the transmitter is hung. */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT		(6*HZ)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   to support a pre-NWay full-duplex signaling mechanism using short frames.
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   No one knows what it should be, but if left at its default value some
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   10base2(!) packets trigger a full-duplex-request interrupt. */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FULL_DUPLEX_MAGIC	0x6969
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* NIC registers */
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BusMode			= 0x00,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxPoll			= 0x08,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxPoll			= 0x10,
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxRingAddr		= 0x18,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxRingAddr		= 0x20,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MacStatus		= 0x28,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MacMode			= 0x30,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IntrMask		= 0x38,
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxMissed		= 0x40,
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ROMCmd			= 0x48,
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CSR11			= 0x58,
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIAStatus		= 0x60,
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CSR13			= 0x68,
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CSR14			= 0x70,
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CSR15			= 0x78,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCIPM			= 0x40,
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* BusMode bits */
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CmdReset		= (1 << 0),
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CacheAlign16		= 0x00008000,
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BurstLen4		= 0x00000400,
165b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen	DescSkipLen		= (DSL << 2),
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Rx/TxPoll bits */
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NormalTxPoll		= (1 << 0),
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NormalRxPoll		= (1 << 0),
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Tx/Rx descriptor status bits */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DescOwn			= (1 << 31),
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxError			= (1 << 15),
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxErrLong		= (1 << 7),
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxErrCRC		= (1 << 1),
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxErrFIFO		= (1 << 0),
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxErrRunt		= (1 << 11),
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxErrFrame		= (1 << 14),
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RingEnd			= (1 << 25),
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FirstFrag		= (1 << 29),
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LastFrag		= (1 << 30),
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxError			= (1 << 15),
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxFIFOUnder		= (1 << 1),
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxLinkFail		= (1 << 2) | (1 << 10) | (1 << 11),
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxMaxCol		= (1 << 8),
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxOWC			= (1 << 9),
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxJabber		= (1 << 14),
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SetupFrame		= (1 << 27),
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxSwInt			= (1 << 31),
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* MacStatus bits */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IntrOK			= (1 << 16),
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IntrErr			= (1 << 15),
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxIntr			= (1 << 6),
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxEmpty			= (1 << 7),
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxIntr			= (1 << 0),
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxEmpty			= (1 << 2),
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PciErr			= (1 << 13),
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxState			= (1 << 22) | (1 << 21) | (1 << 20),
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxState			= (1 << 19) | (1 << 18) | (1 << 17),
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LinkFail		= (1 << 12),
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LinkPass		= (1 << 4),
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxStopped		= (1 << 8),
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxStopped		= (1 << 1),
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* MacMode bits */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	TxEnable		= (1 << 13),
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxEnable		= (1 << 1),
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxTx			= TxEnable | RxEnable,
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FullDuplex		= (1 << 9),
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AcceptAllMulticast	= (1 << 7),
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AcceptAllPhys		= (1 << 6),
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BOCnt			= (1 << 5),
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MacModeClear		= (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) |
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast,
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ROMCmd bits */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_SHIFT_CLK		= 0x02,	/* EEPROM shift clock. */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_CS			= 0x01,	/* EEPROM chip select. */
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_DATA_WRITE		= 0x04,	/* Data from the Tulip to EEPROM. */
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_WRITE_0		= 0x01,
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_WRITE_1		= 0x05,
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_DATA_READ		= 0x08,	/* Data from the EEPROM chip. */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_ENB			= (0x4800 | EE_CS),
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The EEPROM commands include the alway-set leading bit. */
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EE_READ_CMD		= 6,
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* RxMissed bits */
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxMissedOver		= (1 << 16),
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RxMissedMask		= 0xffff,
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SROM-related bits */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SROMC0InfoLeaf		= 27,
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MediaBlockMask		= 0x3f,
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MediaCustomCSRs		= (1 << 6),
237f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PCIPM bits */
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PM_Sleep		= (1 << 31),
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PM_Snooze		= (1 << 30),
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PM_Mask			= PM_Sleep | PM_Snooze,
242f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* SIAStatus bits */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NWayState		= (1 << 14) | (1 << 13) | (1 << 12),
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NWayRestart		= (1 << 12),
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NonselPortActive	= (1 << 9),
247ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	SelPortActive		= (1 << 8),
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LinkFailStatus		= (1 << 2),
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NetCxnErr		= (1 << 1),
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u32 de_intr_mask =
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty |
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	LinkPass | LinkFail | PciErr;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the programmable burst length to 4 longwords for all:
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA errors result without these values. Cache align 16 long.
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
260b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominenstatic const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct de_srom_media_block {
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8			opts;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr13;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr14;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr15;
267ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct de_srom_info_leaf {
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			default_media;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8			n_blocks;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8			unused;
273ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct de_desc {
276c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro	__le32			opts1;
277c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro	__le32			opts2;
278c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro	__le32			addr1;
279c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro	__le32			addr2;
280b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#if DSL
281b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen	__le32			skip[DSL];
282b77e5228849fdcd7a5d73beb16b9ad99395236ecRisto Suominen#endif
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct media_info {
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			type;	/* DE_MEDIA_xxx */
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr13;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr14;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			csr15;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ring_info {
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff		*skb;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t		mapping;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct de_private {
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		tx_head;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		tx_tail;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		rx_tail;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void			__iomem *regs;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device	*dev;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t		lock;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_desc		*rx_ring;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_desc		*tx_ring;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ring_info	tx_skb[DE_TX_RING_SIZE];
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ring_info	rx_skb[DE_RX_RING_SIZE];
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		rx_buf_sz;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma_addr_t		ring_dma;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			msg_enable;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device_stats net_stats;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev		*pdev;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16			setup_frame[DE_SETUP_FRAME_WORDS];
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			media_type;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			media_supported;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32			media_advertise;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct media_info	media[DE_MAX_MEDIA];
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list	media_timer;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8			*ee_data;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		board_idx;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		de21040 : 1;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned		media_lock : 1;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_set_rx_mode (struct net_device *dev);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_tx (struct de_private *de);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_clean_rings (struct de_private *de);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_media_interrupt (struct de_private *de, u32 status);
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de21040_media_timer (unsigned long data);
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de21041_media_timer (unsigned long data);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
343a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(de_pci_tbl) = {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ },
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, de_pci_tbl);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char * const media_name[DE_MAX_MEDIA] = {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"10baseT auto",
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"BNC",
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"AUI",
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"10baseT-HD",
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"10baseT-FD"
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21040 transceiver register settings:
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, };
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, };
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, };
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
368387a85628782690b56492dae4bbf544639f5d4a9Ondrej Zarystatic u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
369e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary/* If on-chip autonegotiation is broken, use half-duplex (FF3F) instead */
370387a85628782690b56492dae4bbf544639f5d4a9Ondrej Zarystatic u16 t21041_csr14_brk[] = { 0xFF3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37484cc1535cb9043ea1921b81cb086138c0f2dc2b9Morten H. Larsen#define dr32(reg)	ioread32(de->regs + (reg))
37584cc1535cb9043ea1921b81cb086138c0f2dc2b9Morten H. Larsen#define dw32(reg, val)	iowrite32((val), de->regs + (reg))
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    u32 status, u32 len)
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
381726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netif_dbg(de, rx_err, de->dev,
382726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		  "rx err, slot %d status 0x%x len %d\n",
383726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		  rx_tail, status, len);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((status & 0x38000300) != 0x0300) {
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Ingore earlier buffers. */
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((status & 0xffff) != 0x7fff) {
388163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			netif_warn(de, rx_err, de->dev,
389163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
390163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   status);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->net_stats.rx_length_errors++;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (status & RxError) {
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* There was a fatal error. */
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->net_stats.rx_errors++; /* end of a packet.*/
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & 0x0890) de->net_stats.rx_length_errors++;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & RxErrCRC) de->net_stats.rx_crc_errors++;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & RxErrFIFO) de->net_stats.rx_fifo_errors++;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_rx (struct de_private *de)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned rx_tail = de->rx_tail;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned rx_work = DE_RX_RING_SIZE;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned drop = 0;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40946578a6913e6f5e69229561736b94c18c2e88ae4Roel Kluin	while (--rx_work) {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 status, len;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dma_addr_t mapping;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb, *copy_skb;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned copying_skb, buflen;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = de->rx_skb[rx_tail].skb;
4167e0b58f32fb5e9c958078a6d722a7d0b230346a7Eric Sesterhenn / snakebyte		BUG_ON(!skb);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rmb();
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = le32_to_cpu(de->rx_ring[rx_tail].opts1);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & DescOwn)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = ((status >> 16) & 0x7ff) - 4;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mapping = de->rx_skb[rx_tail].mapping;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(drop)) {
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->net_stats.rx_dropped++;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto rx_next;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely((status & 0x38008300) != 0x0300)) {
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de_rx_err_acct(de, rx_tail, status, len);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto rx_next;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		copying_skb = (len <= rx_copybreak);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
437726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		netif_dbg(de, rx_status, de->dev,
438726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			  "rx slot %d status 0x%x len %d copying? %d\n",
439726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches			  rx_tail, status, len, copying_skb);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz;
44221a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi		copy_skb = netdev_alloc_skb(de->dev, buflen);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(!copy_skb)) {
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->net_stats.rx_dropped++;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drop = 1;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rx_work = 100;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto rx_next;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!copying_skb) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_unmap_single(de->pdev, mapping,
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 buflen, PCI_DMA_FROMDEVICE);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_put(skb, len);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mapping =
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_skb[rx_tail].mapping =
457689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller				pci_map_single(de->pdev, copy_skb->data,
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       buflen, PCI_DMA_FROMDEVICE);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_skb[rx_tail].skb = copy_skb;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_reserve(copy_skb, RX_OFFSET);
463d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo			skb_copy_from_linear_data(skb, skb_put(copy_skb, len),
464d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo						  len);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* We'll reuse the original ring buffer. */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = copy_skb;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb->protocol = eth_type_trans (skb, de->dev);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->net_stats.rx_packets++;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->net_stats.rx_bytes += skb->len;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = netif_rx (skb);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc == NET_RX_DROP)
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			drop = 1;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrx_next:
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rx_tail == (DE_RX_RING_SIZE - 1))
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_ring[rx_tail].opts2 =
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu_to_le32(RingEnd | de->rx_buf_sz);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz);
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping);
486b991d2bc4a6e1821555bdc2a682f9aed24650c98Risto Suominen		wmb();
487b991d2bc4a6e1821555bdc2a682f9aed24650c98Risto Suominen		de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rx_tail = NEXT_RX(rx_tail);
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!rx_work)
492163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_warn(de->dev, "rx work limit reached\n");
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_tail = rx_tail;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4977d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t de_interrupt (int irq, void *dev_instance)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_instance;
5008f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = dr32(MacStatus);
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF))
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
507726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n",
508726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		  status, dr32(MacMode),
509726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		  de->rx_tail, de->tx_head, de->tx_tail);
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(MacStatus, status);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & (RxIntr | RxEmpty)) {
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_rx(de);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & RxEmpty)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dw32(RxPoll, NormalRxPoll);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&de->lock);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & (TxIntr | TxEmpty))
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_tx(de);
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & (LinkPass | LinkFail))
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_media_interrupt(de, status);
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&de->lock);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & PciErr) {
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u16 pci_status;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
534163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_err(de->dev,
535163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			   "PCI bus error, status=%08x, PCI status=%04x\n",
536163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			   status, pci_status);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_tx (struct de_private *de)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned tx_head = de->tx_head;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned tx_tail = de->tx_tail;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (tx_tail != tx_head) {
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 status;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rmb();
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = le32_to_cpu(de->tx_ring[tx_tail].opts1);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & DescOwn)
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb = de->tx_skb[tx_tail].skb;
5577e0b58f32fb5e9c958078a6d722a7d0b230346a7Eric Sesterhenn / snakebyte		BUG_ON(!skb);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(skb == DE_DUMMY_SKB))
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto next;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(skb == DE_SETUP_SKB)) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 sizeof(de->setup_frame), PCI_DMA_TODEVICE);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto next;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 skb->len, PCI_DMA_TODEVICE);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & LastFrag) {
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (status & TxError) {
572726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				netif_dbg(de, tx_err, de->dev,
573726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					  "tx err, status 0x%x\n",
574726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					  status);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				de->net_stats.tx_errors++;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TxOWC)
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->net_stats.tx_window_errors++;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TxMaxCol)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->net_stats.tx_aborted_errors++;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TxLinkFail)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->net_stats.tx_carrier_errors++;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (status & TxFIFOUnder)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->net_stats.tx_fifo_errors++;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				de->net_stats.tx_packets++;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				de->net_stats.tx_bytes += skb->len;
587726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches				netif_dbg(de, tx_done, de->dev,
588726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches					  "tx done, slot %d\n", tx_tail);
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb_irq(skb);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnext:
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->tx_skb[tx_tail].skb = NULL;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tx_tail = NEXT_TX(tx_tail);
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_tail = tx_tail;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_queue_stopped(de->dev) && (TX_BUFFS_AVAIL(de) > (DE_TX_RING_SIZE / 4)))
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_wake_queue(de->dev);
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
605ad096463f7ff809389454ea4219058a36564d55eStephen Hemmingerstatic netdev_tx_t de_start_xmit (struct sk_buff *skb,
606ad096463f7ff809389454ea4219058a36564d55eStephen Hemminger					struct net_device *dev)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6088f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int entry, tx_free;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mapping, len, flags = FirstFrag | LastFrag;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_desc *txd;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_free = TX_BUFFS_AVAIL(de);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tx_free == 0) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irq(&de->lock);
6195b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy		return NETDEV_TX_BUSY;
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tx_free--;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = de->tx_head;
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd = &de->tx_ring[entry];
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = skb->len;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mapping = pci_map_single(de->pdev, skb->data, len, PCI_DMA_TODEVICE);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (entry == (DE_TX_RING_SIZE - 1))
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flags |= RingEnd;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tx_free || (tx_free == (DE_TX_RING_SIZE / 2)))
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flags |= TxSwInt;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags |= len;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd->opts2 = cpu_to_le32(flags);
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd->addr1 = cpu_to_le32(mapping);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_skb[entry].skb = skb;
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_skb[entry].mapping = mapping;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd->opts1 = cpu_to_le32(DescOwn);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_head = NEXT_TX(entry);
645726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n",
646726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		  entry, skb->len);
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tx_free == 0)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate transmit demand. */
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(TxPoll, NormalTxPoll);
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6566ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Note that we only use exclusion around actually queueing the
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   new frame, not around filling de->setup_frame.  This is non-deterministic
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   when re-entered but still correct. */
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef set_bit_le
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6698f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 hash_table[32];
67122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 *eaddrs;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(hash_table, 0, sizeof(hash_table));
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_bit_le(255, hash_table); 			/* Broadcast entry */
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This should work on big-endian machines as well. */
67822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, dev) {
67922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit_le(index, hash_table);
6824302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko	}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6844302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko	for (i = 0; i < 32; i++) {
6854302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko		*setup_frm++ = hash_table[i];
6864302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko		*setup_frm++ = hash_table[i];
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6884302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko	setup_frm = &de->setup_frame[13*6];
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill the final entry with our physical address. */
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	eaddrs = (u16 *)dev->dev_addr;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6998f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
70022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 *eaddrs;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We have <= 14 addresses so we can use the wonderful
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   16 address perfect filtering of the Tulip. */
70522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, dev) {
70622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		eaddrs = (u16 *) ha->addr;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill the unused entries with the broadcast address. */
7124302b67e041ea81c8fc233bee1296516e1294a27Jiri Pirko	memset(setup_frm, 0xff, (15 - netdev_mc_count(dev)) * 12);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setup_frm = &de->setup_frame[15*6];
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Fill the final entry with our physical address. */
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	eaddrs = (u16 *)dev->dev_addr;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __de_set_rx_mode (struct net_device *dev)
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7258f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 macmode;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int entry;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mapping;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_desc *txd;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_desc *dummy_txd = NULL;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		macmode |= AcceptAllMulticast | AcceptAllPhys;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7394cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) {
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Too many to filter well -- accept all multicasts. */
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		macmode |= AcceptAllMulticast;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Note that only the low-address shortword of setup_frame is valid!
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The values are doubled for big-endian architectures. */
7474cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	if (netdev_mc_count(dev) > 14)	/* Must use a multicast hash table. */
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		build_setup_frame_hash (de->setup_frame, dev);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		build_setup_frame_perfect (de->setup_frame, dev);
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Now add this frame to the Tx list.
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	entry = de->tx_head;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Avoid a chip errata by prefixing a dummy entry. */
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (entry != 0) {
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->tx_skb[entry].skb = DE_DUMMY_SKB;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dummy_txd = &de->tx_ring[entry];
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dummy_txd->opts2 = (entry == (DE_TX_RING_SIZE - 1)) ?
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   cpu_to_le32(RingEnd) : 0;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dummy_txd->addr1 = 0;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Must set DescOwned later to avoid race with chip */
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		entry = NEXT_TX(entry);
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_skb[entry].skb = DE_SETUP_SKB;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_skb[entry].mapping = mapping =
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    pci_map_single (de->pdev, de->setup_frame,
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    sizeof (de->setup_frame), PCI_DMA_TODEVICE);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Put the setup frame on the Tx list. */
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd = &de->tx_ring[entry];
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (entry == (DE_TX_RING_SIZE - 1))
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txd->opts2 = cpu_to_le32(SetupFrame | RingEnd | sizeof (de->setup_frame));
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		txd->opts2 = cpu_to_le32(SetupFrame | sizeof (de->setup_frame));
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd->addr1 = cpu_to_le32(mapping);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	txd->opts1 = cpu_to_le32(DescOwn);
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dummy_txd) {
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dummy_txd->opts1 = cpu_to_le32(DescOwn);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		wmb();
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_head = NEXT_TX(entry);
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (TX_BUFFS_AVAIL(de) == 0)
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Trigger an immediate transmit demand. */
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(TxPoll, NormalTxPoll);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (macmode != dr32(MacMode))
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dw32(MacMode, macmode);
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_set_rx_mode (struct net_device *dev)
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
8108f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave (&de->lock, flags);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__de_set_rx_mode(dev);
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore (&de->lock, flags);
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void de_rx_missed(struct de_private *de, u32 rx_missed)
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (unlikely(rx_missed & RxMissedOver))
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->net_stats.rx_missed_errors += RxMissedMask;
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->net_stats.rx_missed_errors += (rx_missed & RxMissedMask);
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __de_get_stats(struct de_private *de)
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 tmp = dr32(RxMissed); /* self-clearing */
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_rx_missed(de, tmp);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *de_get_stats(struct net_device *dev)
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8348f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* The chip only need report frame silently dropped. */
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 	if (netif_running(dev) && netif_device_present(dev))
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 		__de_get_stats(de);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return &de->net_stats;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int de_is_running (struct de_private *de)
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (dr32(MacStatus) & (RxState | TxState)) ? 1 : 0;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_stop_rxtx (struct de_private *de)
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 macmode;
85369cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	unsigned int i = 1300/100;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	macmode = dr32(MacMode);
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (macmode & RxTx) {
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dw32(MacMode, macmode & ~RxTx);
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dr32(MacMode);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
86169cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	/* wait until in-flight frame completes.
86269cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	 * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin)
86369cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	 * Typically expect this loop to end in < 50 us on 100BT.
86469cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	 */
86569cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler	while (--i) {
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!de_is_running(de))
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
86869cac988f2d8506d0b479c5ae7903b9067d7641dGrant Grundler		udelay(100);
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
870f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
871163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netdev_warn(de->dev, "timeout expired, stopping DMA\n");
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void de_start_rxtx (struct de_private *de)
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 macmode;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	macmode = dr32(MacMode);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((macmode & RxTx) != RxTx) {
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dw32(MacMode, macmode | RxTx);
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dr32(MacMode);
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_stop_hw (struct de_private *de)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(5);
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(IntrMask, 0);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_rxtx(de);
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(MacStatus, dr32(MacStatus));
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(10);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_tail = 0;
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_head = de->tx_tail = 0;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_link_up(struct de_private *de)
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!netif_carrier_ok(de->dev)) {
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_carrier_on(de->dev);
905163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netif_info(de, link, de->dev, "link up, media %s\n",
906163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			   media_name[de->media_type]);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_link_down(struct de_private *de)
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_carrier_ok(de->dev)) {
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_carrier_off(de->dev);
914163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netif_info(de, link, de->dev, "link down\n");
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_set_media (struct de_private *de)
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned media = de->media_type;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 macmode = dr32(MacMode);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
923f25f0f8dcd99e954dc0acf2fcb556cbcd7394549Ondrej Zary	if (de_is_running(de))
924163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_warn(de->dev, "chip is running while changing media!\n");
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040)
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dw32(CSR11, FULL_DUPLEX_MAGIC);
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(CSR13, 0); /* Reset phy */
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(CSR14, de->media[media].csr14);
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(CSR15, de->media[media].csr15);
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(CSR13, de->media[media].csr13);
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* must delay 10ms before writing to other registers,
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * especially CSR6
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(10);
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (media == DE_MEDIA_TP_FD)
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		macmode |= FullDuplex;
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		macmode &= ~FullDuplex;
942f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
943163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, link, de->dev, "set link %s\n", media_name[media]);
944163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
945163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   dr32(MacMode), dr32(SIAStatus),
946163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   dr32(CSR13), dr32(CSR14), dr32(CSR15));
947163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
948163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   macmode, de->media[media].csr13,
949163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   de->media[media].csr14, de->media[media].csr15);
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (macmode != dr32(MacMode))
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dw32(MacMode, macmode);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
954215faf9c5f6e319e97edea9e178123e07825c14dJoe Perchesstatic void de_next_media (struct de_private *de, const u32 *media,
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   unsigned int n_media)
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < n_media; i++) {
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de_ok_to_advertise(de, media[i])) {
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_type = media[i];
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de21040_media_timer (unsigned long data)
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_private *de = (struct de_private *) data;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = de->dev;
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status = dr32(SIAStatus);
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int carrier;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
974f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	carrier = (status & NetCxnErr) ? 0 : 1;
976f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (carrier) {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus))
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_link_yet;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media_timer.expires = jiffies + DE_TIMER_LINK;
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&de->media_timer);
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!netif_carrier_ok(dev))
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de_link_up(de);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
986163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			netif_info(de, timer, dev, "%s link ok, status %x\n",
987163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   media_name[de->media_type], status);
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik	de_link_down(de);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_lock)
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_type == DE_MEDIA_AUI) {
997215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		static const u32 next_state = DE_MEDIA_TP;
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_next_media(de, &next_state, 1);
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1000215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		static const u32 next_state = DE_MEDIA_AUI;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_next_media(de, &next_state, 1);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&de->lock, flags);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_rxtx(de);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&de->lock, flags);
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_set_media(de);
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_start_rxtx(de);
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_link_yet:
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&de->media_timer);
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1014163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
1015163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   media_name[de->media_type], status);
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (new_media) {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_TP_AUTO:
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & ADVERTISED_Autoneg))
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full)))
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_BNC:
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & ADVERTISED_BNC))
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_AUI:
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & ADVERTISED_AUI))
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_TP:
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & ADVERTISED_10baseT_Half))
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_TP_FD:
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(de->media_advertise & ADVERTISED_10baseT_Full))
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1044f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de21041_media_timer (unsigned long data)
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_private *de = (struct de_private *) data;
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = de->dev;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status = dr32(SIAStatus);
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int carrier;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1055f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
1056ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	/* clear port active bits */
1057ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	dw32(SIAStatus, NonselPortActive | SelPortActive);
1058ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	carrier = (status & NetCxnErr) ? 0 : 1;
1060f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (carrier) {
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((de->media_type == DE_MEDIA_TP_AUTO ||
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     de->media_type == DE_MEDIA_TP ||
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     de->media_type == DE_MEDIA_TP_FD) &&
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (status & LinkFailStatus))
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_link_yet;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media_timer.expires = jiffies + DE_TIMER_LINK;
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&de->media_timer);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!netif_carrier_ok(dev))
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de_link_up(de);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
1073163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			netif_info(de, timer, dev,
1074163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   "%s link ok, mode %x status %x\n",
1075163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   media_name[de->media_type],
1076163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				   dr32(MacMode), status);
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1080f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik	de_link_down(de);
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if media type locked, don't switch media */
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_lock)
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto set_media;
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* if activity detected, use that as hint for new media type */
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & NonselPortActive) {
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int have_media = 1;
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* if AUI/BNC selected, then activity is on TP port */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de->media_type == DE_MEDIA_AUI ||
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    de->media_type == DE_MEDIA_BNC) {
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				de->media_type = DE_MEDIA_TP_AUTO;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				have_media = 0;
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* TP selected.  If there is only TP and BNC, then it's BNC */
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 de_ok_to_advertise(de, DE_MEDIA_BNC))
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_type = DE_MEDIA_BNC;
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* TP selected.  If there is only TP and AUI, then it's AUI */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 de_ok_to_advertise(de, DE_MEDIA_AUI))
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_type = DE_MEDIA_AUI;
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* otherwise, ignore the hint */
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			have_media = 0;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (have_media)
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto set_media;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Absent or ambiguous activity hint, move to next advertised
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * media state.  If de->media_type is left unchanged, this
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * simply resets the PHY and reloads the current media settings.
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_type == DE_MEDIA_AUI) {
1123215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		static const u32 next_states[] = {
1124215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches			DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
1125215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		};
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_next_media(de, next_states, ARRAY_SIZE(next_states));
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (de->media_type == DE_MEDIA_BNC) {
1128215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		static const u32 next_states[] = {
1129215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches			DE_MEDIA_TP_AUTO, DE_MEDIA_AUI
1130215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		};
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_next_media(de, next_states, ARRAY_SIZE(next_states));
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1133215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		static const u32 next_states[] = {
1134215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches			DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
1135215faf9c5f6e319e97edea9e178123e07825c14dJoe Perches		};
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_next_media(de, next_states, ARRAY_SIZE(next_states));
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1138f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_media:
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&de->lock, flags);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_rxtx(de);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&de->lock, flags);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_set_media(de);
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_start_rxtx(de);
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_link_yet:
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&de->media_timer);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1150163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
1151163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   media_name[de->media_type], status);
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_media_interrupt (struct de_private *de, u32 status)
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & LinkPass) {
1157ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		/* Ignore if current media is AUI or BNC and we can't use TP */
1158ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		if ((de->media_type == DE_MEDIA_AUI ||
1159ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		     de->media_type == DE_MEDIA_BNC) &&
1160ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		    (de->media_lock ||
1161ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		     !de_ok_to_advertise(de, DE_MEDIA_TP_AUTO)))
1162ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary			return;
1163ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		/* If current media is not TP, change it to TP */
1164ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		if ((de->media_type == DE_MEDIA_AUI ||
1165ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		     de->media_type == DE_MEDIA_BNC)) {
1166ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary			de->media_type = DE_MEDIA_TP_AUTO;
1167ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary			de_stop_rxtx(de);
1168ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary			de_set_media(de);
1169ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary			de_start_rxtx(de);
1170ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary		}
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_link_up(de);
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1175f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
11767e0b58f32fb5e9c958078a6d722a7d0b230346a7Eric Sesterhenn / snakebyte	BUG_ON(!(status & LinkFail));
1177ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	/* Mark the link as down only if current media is TP */
1178ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	if (netif_carrier_ok(de->dev) && de->media_type != DE_MEDIA_AUI &&
1179ca9a783575d2affed30ef27a3427a7705527ddacOndrej Zary	    de->media_type != DE_MEDIA_BNC) {
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_link_down(de);
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_reset_mac (struct de_private *de)
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status, tmp;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Reset MAC.  de4x5.c and tulip.c examined for "advice"
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * in this area.
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dr32(BusMode) == 0xffffffff)
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32 (BusMode, CmdReset);
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay (1);
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32 (BusMode, de_bus_mode);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay (1);
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (tmp = 0; tmp < 5; tmp++) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dr32 (BusMode);
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay (1);
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay (1);
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = dr32(MacStatus);
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & (RxState | TxState))
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status == 0xffffffff)
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_adapter_wake (struct de_private *de)
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pmctl;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040)
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pmctl & PM_Mask) {
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pmctl &= ~PM_Mask;
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_dword(de->pdev, PCIPM, pmctl);
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* de4x5.c delays, so we do too */
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep(10);
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_adapter_sleep (struct de_private *de)
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 pmctl;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040)
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1243b0255a02351b00ca55f4eb2588d05a5db9dd1a58Ondrej Zary	dw32(CSR13, 0); /* Reset phy */
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pmctl |= PM_Sleep;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword(de->pdev, PCIPM, pmctl);
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_init_hw (struct de_private *de)
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = de->dev;
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 macmode;
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_adapter_wake(de);
1256f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	macmode = dr32(MacMode) & ~MacModeClear;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = de_reset_mac(de);
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_set_media(de); /* reset phy */
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(RxRingAddr, de->ring_dma);
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(MacMode, RxTx | macmode);
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dr32(RxMissed); /* self-clearing */
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(IntrMask, de_intr_mask);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_set_rx_mode(dev);
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_refill_rx (struct de_private *de)
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i;
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_RX_RING_SIZE; i++) {
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
128621a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi		skb = netdev_alloc_skb(de->dev, de->rx_buf_sz);
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!skb)
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto err_out;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_skb[i].mapping = pci_map_single(de->pdev,
1291689be43945e9ca7dd704522e55af1b8a73a994d3David S. Miller			skb->data, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_skb[i].skb = skb;
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i == (DE_RX_RING_SIZE - 1))
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_ring[i].opts2 =
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cpu_to_le32(RingEnd | de->rx_buf_sz);
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz);
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping);
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->rx_ring[i].addr2 = 0;
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out:
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_clean_rings(de);
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_init_rings (struct de_private *de)
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_tail = 0;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_head = de->tx_tail = 0;
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return de_refill_rx (de);
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_alloc_rings (struct de_private *de)
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_ring = pci_alloc_consistent(de->pdev, DE_RING_BYTES, &de->ring_dma);
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!de->rx_ring)
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE];
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return de_init_rings(de);
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_clean_rings (struct de_private *de)
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i;
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE);
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wmb();
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_RX_RING_SIZE; i++) {
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de->rx_skb[i].skb) {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pci_unmap_single(de->pdev, de->rx_skb[i].mapping,
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					 de->rx_buf_sz, PCI_DMA_FROMDEVICE);
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_kfree_skb(de->rx_skb[i].skb);
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_TX_RING_SIZE; i++) {
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *skb = de->tx_skb[i].skb;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((skb) && (skb != DE_DUMMY_SKB)) {
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (skb != DE_SETUP_SKB) {
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				de->net_stats.tx_dropped++;
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_unmap_single(de->pdev,
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->tx_skb[i].mapping,
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					skb->len, PCI_DMA_TODEVICE);
13585185c7c20a4b88892f868ad8d92d1b640b1edba9Eric Sesterhenn				dev_kfree_skb(skb);
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pci_unmap_single(de->pdev,
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					de->tx_skb[i].mapping,
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					sizeof(de->setup_frame),
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					PCI_DMA_TODEVICE);
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE);
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE);
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_free_rings (struct de_private *de)
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_clean_rings(de);
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_free_consistent(de->pdev, DE_RING_BYTES, de->rx_ring, de->ring_dma);
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_ring = NULL;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->tx_ring = NULL;
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_open (struct net_device *dev)
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13828f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1385726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netif_dbg(de, ifup, dev, "enabling interface\n");
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = de_alloc_rings(de);
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
1391163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_err(dev, "ring allocation failure, err=%d\n", rc);
13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13953f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu	dw32(IntrMask, 0);
13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13971fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner	rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev);
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
1399163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_err(dev, "IRQ %d request failure, err=%d\n",
1400163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			   dev->irq, rc);
14013f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu		goto err_out_free;
14023f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu	}
14033f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu
14043f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu	rc = de_init_hw(de);
14053f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu	if (rc) {
1406163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_err(dev, "h/w init failure, err=%d\n", rc);
14073f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu		goto err_out_free_irq;
14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_start_queue(dev);
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14153f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieuerr_out_free_irq:
14163f735b76a4e654bee652cbbeb405b9b3ef950316Francois Romieu	free_irq(dev->irq, dev);
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free:
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_free_rings(de);
14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_close (struct net_device *dev)
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14248f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1427726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netif_dbg(de, ifdown, dev, "disabling interface\n");
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&de->media_timer);
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&de->lock, flags);
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_hw(de);
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_carrier_off(dev);
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&de->lock, flags);
1436f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(dev->irq, dev);
14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_free_rings(de);
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_adapter_sleep(de);
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_tx_timeout (struct net_device *dev)
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14468f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1448726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches	netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
1449726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		   dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
1450726b65ad444dd142e34d0087fcbba03d16b34ca6Joe Perches		   de->rx_tail, de->tx_head, de->tx_tail);
14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&de->media_timer);
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_irq(dev->irq);
14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_hw(de);
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_stop_queue(dev);
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_carrier_off(dev);
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_irq(dev->irq);
1463f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Update the error counts. */
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__de_get_stats(de);
14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	synchronize_irq(dev->irq);
14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_clean_rings(de);
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147039bf4295bb4bcb0c108f74b72dd2eb5b9b9dfaccFrancois Romieu	de_init_rings(de);
147139bf4295bb4bcb0c108f74b72dd2eb5b9b9dfaccFrancois Romieu
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_init_hw(de);
1473f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_wake_queue(dev);
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __de_get_regs(struct de_private *de, u8 *buf)
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *rbuf = (u32 *)buf;
1481f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* read all CSRs */
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_NUM_REGS; i++)
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rbuf[i] = dr32(i * 8);
14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* handle self-clearing RxMissed counter, CSR8 */
14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_rx_missed(de, rbuf[8]);
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecmd->supported = de->media_supported;
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecmd->transceiver = XCVR_INTERNAL;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecmd->phy_address = 0;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ecmd->advertising = de->media_advertise;
1496f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (de->media_type) {
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_AUI:
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->port = PORT_AUI;
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case DE_MEDIA_BNC:
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->port = PORT_BNC;
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->port = PORT_TP;
15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1508f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
1509fbef7139a8b89a7f49ba1410593ed894b4c8b017David Decotigny	ethtool_cmd_speed_set(ecmd, 10);
1510fbef7139a8b89a7f49ba1410593ed894b4c8b017David Decotigny
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dr32(MacMode) & FullDuplex)
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->duplex = DUPLEX_FULL;
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->duplex = DUPLEX_HALF;
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_lock)
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->autoneg = AUTONEG_DISABLE;
15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ecmd->autoneg = AUTONEG_ENABLE;
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ignore maxtxpkt, maxrxpkt for now */
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 new_media;
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int media_lock;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531fbef7139a8b89a7f49ba1410593ed894b4c8b017David Decotigny	if (ethtool_cmd_speed(ecmd) != 10)
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI && ecmd->port != PORT_BNC)
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040 && ecmd->port == PORT_BNC)
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->transceiver != XCVR_INTERNAL)
15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->advertising & ~de->media_supported)
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ecmd->autoneg == AUTONEG_ENABLE &&
15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (!(ecmd->advertising & ADVERTISED_Autoneg)))
15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1548f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ecmd->port) {
15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PORT_AUI:
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_media = DE_MEDIA_AUI;
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ecmd->advertising & ADVERTISED_AUI))
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PORT_BNC:
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new_media = DE_MEDIA_BNC;
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ecmd->advertising & ADVERTISED_BNC))
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ecmd->autoneg == AUTONEG_ENABLE)
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_media = DE_MEDIA_TP_AUTO;
15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (ecmd->duplex == DUPLEX_FULL)
15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_media = DE_MEDIA_TP_FD;
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			new_media = DE_MEDIA_TP;
15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ecmd->advertising & ADVERTISED_TP))
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(ecmd->advertising & (ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half)))
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1573f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1;
1575f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((new_media == de->media_type) &&
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (media_lock == de->media_lock) &&
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (ecmd->advertising == de->media_advertise))
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0; /* nothing to change */
1580f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_link_down(de);
1582387a85628782690b56492dae4bbf544639f5d4a9Ondrej Zary	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_stop_rxtx(de);
1584f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_type = new_media;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_lock = media_lock;
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_advertise = ecmd->advertising;
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_set_media(de);
1589387a85628782690b56492dae4bbf544639f5d4a9Ondrej Zary	if (netif_running(de->dev))
1590387a85628782690b56492dae4bbf544639f5d4a9Ondrej Zary		de_start_rxtx(de);
1591f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15978f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159968aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
160068aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
160168aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones	strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	info->eedump_len = DE_EEPROM_SIZE;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_get_regs_len(struct net_device *dev)
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return DE_REGS_SIZE;
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16128f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = __de_get_settings(de, ecmd);
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16248f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = __de_set_settings(de, ecmd);
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 de_get_msglevel(struct net_device *dev)
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16368f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return de->msg_enable;
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_set_msglevel(struct net_device *dev, u32 msglvl)
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16438f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->msg_enable = msglvl;
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_get_eeprom(struct net_device *dev,
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 struct ethtool_eeprom *eeprom, u8 *data)
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16518f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!de->ee_data)
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EOPNOTSUPP;
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((eeprom->offset != 0) || (eeprom->magic != 0) ||
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (eeprom->len != DE_EEPROM_SIZE))
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(data, de->ee_data, eeprom->len);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_nway_reset(struct net_device *dev)
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16658f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 status;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->media_type != DE_MEDIA_TP_AUTO)
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_carrier_ok(de->dev))
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_link_down(de);
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = dr32(SIAStatus);
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
1675163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netif_info(de, link, dev, "link nway restart, status %x,%x\n",
1676163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		   status, dr32(SIAStatus));
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			void *data)
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16838f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->version = (DE_REGS_VER << 2) | de->de21040;
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irq(&de->lock);
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__de_get_regs(de, data);
16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irq(&de->lock);
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16927282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops de_ethtool_ops = {
16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_link		= ethtool_op_get_link,
16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_drvinfo		= de_get_drvinfo,
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_regs_len		= de_get_regs_len,
16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_settings		= de_get_settings,
16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_settings		= de_set_settings,
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_msglevel		= de_get_msglevel,
16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_msglevel		= de_set_msglevel,
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_eeprom		= de_get_eeprom,
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.nway_reset		= de_nway_reset,
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_regs		= de_get_regs,
17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17054c44fd009ae79fc04e2c049f708792ad83400ddePrarit Bhargavastatic void __devinit de21040_get_mac_address (struct de_private *de)
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i;
17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dw32 (ROMCmd, 0);	/* Reset the pointer with a dummy write. */
1710bc0da3fcec1cec11dc451b8fcb9c9ad7e4ca6e12Martin Langer	udelay(5);
17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i++) {
17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int value, boguscnt = 100000;
1714ec1d1ebbb3bdc9807474be28c29efa155d15b850Hannes Eder		do {
17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			value = dr32(ROMCmd);
171684cc1535cb9043ea1921b81cb086138c0f2dc2b9Morten H. Larsen			rmb();
1717ec1d1ebbb3bdc9807474be28c29efa155d15b850Hannes Eder		} while (value < 0 && --boguscnt > 0);
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->dev->dev_addr[i] = value;
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (boguscnt <= 0)
1721163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			pr_warn("timeout reading 21040 MAC address byte %u\n",
1722163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				i);
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17264c44fd009ae79fc04e2c049f708792ad83400ddePrarit Bhargavastatic void __devinit de21040_get_media_info(struct de_private *de)
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_type = DE_MEDIA_TP;
17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       SUPPORTED_10baseT_Half | SUPPORTED_AUI;
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_advertise = de->media_supported;
17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_MAX_MEDIA; i++) {
17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (i) {
17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case DE_MEDIA_AUI:
17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case DE_MEDIA_TP:
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case DE_MEDIA_TP_FD:
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].type = i;
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].csr13 = t21040_csr13[i];
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].csr14 = t21040_csr14[i];
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].csr15 = t21040_csr15[i];
17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].type = DE_MEDIA_INVALID;
17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: this routine returns extra data bits for size detection. */
17534a1d2d81fa327d095a0a8a1f961bace5b0a2f7daHelge Dellerstatic unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned retval = 0;
17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *ee_addr = regs + ROMCmd;
17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int read_cmd = location | (EE_READ_CMD << addr_len);
17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(EE_ENB & ~EE_CS, ee_addr);
17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(EE_ENB, ee_addr);
17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Shift the read command bits out. */
17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 4 + addr_len; i >= 0; i--) {
17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(EE_ENB | dataval, ee_addr);
17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		readl(ee_addr);
17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		readl(ee_addr);
17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(EE_ENB, ee_addr);
17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	readl(ee_addr);
17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 16; i > 0; i--) {
17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(EE_ENB | EE_SHIFT_CLK, ee_addr);
17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		readl(ee_addr);
17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(EE_ENB, ee_addr);
17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		readl(ee_addr);
17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Terminate the EEPROM access. */
17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(EE_ENB & ~EE_CS, ee_addr);
17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17884c44fd009ae79fc04e2c049f708792ad83400ddePrarit Bhargavastatic void __devinit de21041_get_srom_info (struct de_private *de)
17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned i, sa_offset = 0, ofs;
17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 ee_data[DE_EEPROM_SIZE + 6] = {};
17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_srom_info_leaf *il;
17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *bufp;
17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* download entire eeprom */
17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_EEPROM_WORDS; i++)
1798c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro		((__le16 *)ee_data)[i] =
1799c559a5bc9417c00ba2df59397a27eaf8d8e52aecAl Viro			cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size));
18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* DEC now has a specification but early board makers
18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   just put the address in the first EEPROM locations. */
18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This does  memcmp(eedata, eedata+16, 8) */
1804bc053d45cb0ca5daeaa69ae9ac43cdea42693f60Ralf Baechle
1805bc053d45cb0ca5daeaa69ae9ac43cdea42693f60Ralf Baechle#ifndef CONFIG_MIPS_COBALT
1806bc053d45cb0ca5daeaa69ae9ac43cdea42693f60Ralf Baechle
18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 8; i ++)
18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ee_data[i] != ee_data[16+i])
18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa_offset = 20;
18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811bc053d45cb0ca5daeaa69ae9ac43cdea42693f60Ralf Baechle#endif
1812bc053d45cb0ca5daeaa69ae9ac43cdea42693f60Ralf Baechle
18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* store MAC address */
18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 6; i ++)
18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->dev->dev_addr[i] = ee_data[i + sa_offset];
18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get offset of controller 0 info leaf.  ignore 2nd byte. */
18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ofs = ee_data[SROMC0InfoLeaf];
18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ofs >= (sizeof(ee_data) - sizeof(struct de_srom_info_leaf) - sizeof(struct de_srom_media_block)))
18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_srom;
18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get pointer to info leaf */
18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	il = (struct de_srom_info_leaf *) &ee_data[ofs];
18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* paranoia checks */
18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (il->n_blocks == 0)
18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_srom;
18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((sizeof(ee_data) - ofs) <
18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (sizeof(struct de_srom_info_leaf) + (sizeof(struct de_srom_media_block) * il->n_blocks)))
18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto bad_srom;
18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get default media type */
1833445854f4c46ff1fa8f4605334914ecd1a1ae574dHarvey Harrison	switch (get_unaligned(&il->default_media)) {
18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0001:  de->media_type = DE_MEDIA_BNC; break;
18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0002:  de->media_type = DE_MEDIA_AUI; break;
18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0204:  de->media_type = DE_MEDIA_TP_FD; break;
18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default: de->media_type = DE_MEDIA_TP_AUTO; break;
18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1839f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_msg_probe(de))
1841f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		pr_info("de%d: SROM leaf offset %u, default media %s\n",
1842f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		       de->board_idx, ofs, media_name[de->media_type]);
18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* init SIA register values to defaults */
18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_MAX_MEDIA; i++) {
18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[i].type = DE_MEDIA_INVALID;
18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[i].csr13 = 0xffff;
18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[i].csr14 = 0xffff;
18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[i].csr15 = 0xffff;
18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* parse media blocks to see what medias are supported,
18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and if any custom CSR values are provided
18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bufp = ((void *)il) + sizeof(*il);
18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < il->n_blocks; i++) {
18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct de_srom_media_block *ib = bufp;
18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned idx;
18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* index based on media type in media block */
18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(ib->opts & MediaBlockMask) {
18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0: /* 10baseT */
18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half
18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  | SUPPORTED_Autoneg;
18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			idx = DE_MEDIA_TP;
18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 1: /* BNC */
18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_supported |= SUPPORTED_BNC;
18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			idx = DE_MEDIA_BNC;
18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 2: /* AUI */
18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_supported |= SUPPORTED_AUI;
18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			idx = DE_MEDIA_AUI;
18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 4: /* 10baseT-FD */
18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full
18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  | SUPPORTED_Autoneg;
18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			idx = DE_MEDIA_TP_FD;
18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto bad_srom;
18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[idx].type = idx;
18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (netif_msg_probe(de))
1889f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches			pr_info("de%d:   media block #%u: %s",
1890f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches				de->board_idx, i,
1891f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches				media_name[de->media[idx].type]);
18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufp += sizeof (ib->opts);
18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ib->opts & MediaCustomCSRs) {
1896445854f4c46ff1fa8f4605334914ecd1a1ae574dHarvey Harrison			de->media[idx].csr13 = get_unaligned(&ib->csr13);
1897445854f4c46ff1fa8f4605334914ecd1a1ae574dHarvey Harrison			de->media[idx].csr14 = get_unaligned(&ib->csr14);
1898445854f4c46ff1fa8f4605334914ecd1a1ae574dHarvey Harrison			de->media[idx].csr15 = get_unaligned(&ib->csr15);
18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(ib->csr15);
19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (netif_msg_probe(de))
1903f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches				pr_cont(" (%x,%x,%x)\n",
1904f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches					de->media[idx].csr13,
1905f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches					de->media[idx].csr14,
1906f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches					de->media[idx].csr15);
1907f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
1908163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		} else {
1909163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches			if (netif_msg_probe(de))
1910163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches				pr_cont("\n");
1911163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		}
19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_advertise = de->media_supported;
19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfill_defaults:
19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* fill in defaults, for cases where custom CSRs not used */
19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_MAX_MEDIA; i++) {
19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de->media[i].csr13 == 0xffff)
19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].csr13 = t21041_csr13[i];
1924e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary		if (de->media[i].csr14 == 0xffff) {
1925e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary			/* autonegotiation is broken at least on some chip
1926e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary			   revisions - rev. 0x21 works, 0x11 does not */
1927e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary			if (de->pdev->revision < 0x20)
1928e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary				de->media[i].csr14 = t21041_csr14_brk[i];
1929e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary			else
1930e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary				de->media[i].csr14 = t21041_csr14[i];
1931e0f9c4f332c99b213d4a0b7cd21dc0781ceb3d86Ondrej Zary		}
19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (de->media[i].csr15 == 0xffff)
19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			de->media[i].csr15 = t21041_csr15[i];
19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1936c3a9392e4f3b9d97803b067871d66bc143369dbfEric Sesterhenn	de->ee_data = kmemdup(&ee_data[0], DE_EEPROM_SIZE, GFP_KERNEL);
19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad_srom:
19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for error cases, it's ok to assume we support all these */
19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < DE_MAX_MEDIA; i++)
19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media[i].type = i;
19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_supported =
19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_10baseT_Half |
19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_10baseT_Full |
19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_Autoneg |
19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_TP |
19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_AUI |
19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SUPPORTED_BNC;
19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto fill_defaults;
19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
195490d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemmingerstatic const struct net_device_ops de_netdev_ops = {
195590d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_open		= de_open,
195690d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_stop		= de_close,
1957afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= de_set_rx_mode,
195890d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_start_xmit		= de_start_xmit,
195990d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_get_stats		= de_get_stats,
196090d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_tx_timeout 	= de_tx_timeout,
196190d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_change_mtu		= eth_change_mtu,
196290d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_set_mac_address 	= eth_mac_addr,
196390d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
196490d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger};
196590d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger
19664a1d2d81fa327d095a0a8a1f961bace5b0a2f7daHelge Dellerstatic int __devinit de_init_one (struct pci_dev *pdev,
19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  const struct pci_device_id *ent)
19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct de_private *de;
19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __iomem *regs;
1973afc7097f45bdfddc2a0d375ef4a2c38b6e09c339Jeff Garzik	unsigned long pciaddr;
19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int board_idx = -1;
19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	board_idx++;
19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (board_idx == 0)
19801c3319fb69c29376fe23c1aa0cd7cb6df91c7883Joe Perches		pr_info("%s\n", version);
19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allocate a new ethernet device structure, and fill in defaults */
19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = alloc_etherdev(sizeof(struct de_private));
19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198890d8743d03593520ceb5e8fd8cf3b86072518f83Stephen Hemminger	dev->netdev_ops = &de_netdev_ops;
19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SET_NETDEV_DEV(dev, &pdev->dev);
19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->ethtool_ops = &de_ethtool_ops;
19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->watchdog_timeo = TX_TIMEOUT;
19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19938f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	de = netdev_priv(dev);
19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->de21040 = ent->driver_data == 0 ? 1 : 0;
19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->pdev = pdev;
19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->dev = dev;
19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->msg_enable = (debug < 0 ? DE_DEF_MSG_ENABLE : debug);
19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->board_idx = board_idx;
19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init (&de->lock);
20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&de->media_timer);
20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040)
20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media_timer.function = de21040_media_timer;
20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de->media_timer.function = de21041_media_timer;
20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->media_timer.data = (unsigned long) de;
20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_carrier_off(dev);
20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* wake up device, assign resources */
20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = pci_enable_device(pdev);
20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_free;
20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reserve PCI resources to ensure driver atomicity */
20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = pci_request_regions(pdev, DRV_NAME);
20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_disable;
20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for invalid IRQ value */
20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->irq < 2) {
20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
2022163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		pr_err("invalid irq (%d) for pci dev %s\n",
20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       pdev->irq, pci_name(pdev));
20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_res;
20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = pdev->irq;
20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* obtain and check validity of PCI I/O address */
20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pciaddr = pci_resource_start(pdev, 1);
20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pciaddr) {
20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
2033163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev));
20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_res;
20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
2038163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		pr_err("MMIO resource (%llx) too small on pci dev %s\n",
2039f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		       (unsigned long long)pci_resource_len(pdev, 1),
2040f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		       pci_name(pdev));
20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_res;
20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* remap CSR registers */
20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!regs) {
20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EIO;
2048163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
2049f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		       (unsigned long long)pci_resource_len(pdev, 1),
2050f639dc7dadcbd97f1d666d5ffe00eab1ea3c0f6dJoe Perches		       pciaddr, pci_name(pdev));
20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_res;
20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = (unsigned long) regs;
20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de->regs = regs;
20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_adapter_wake(de);
20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure hardware is not running */
20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = de_reset_mac(de);
20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
2061163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev));
20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_iomap;
20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get MAC address, initialize default media type and
20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * get list of supported media
20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (de->de21040) {
20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de21040_get_mac_address(de);
20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de21040_get_media_info(de);
20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de21041_get_srom_info(de);
20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* register new network interface with kernel */
20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = register_netdev(dev);
20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_out_iomap;
20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* print info about board and interface just registered */
2081163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches	netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n",
2082163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		    de->de21040 ? "21040" : "21041",
2083163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		    dev->base_addr,
2084163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		    dev->dev_addr,
2085163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		    dev->irq);
20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(pdev, dev);
20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* enable busmastering */
20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master(pdev);
20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* put adapter to sleep */
20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	de_adapter_sleep(de);
20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_iomap:
2098b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	kfree(de->ee_data);
20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(regs);
21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_res:
21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_release_regions(pdev);
21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_disable:
21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_disable_device(pdev);
21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_out_free:
21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21094a1d2d81fa327d095a0a8a1f961bace5b0a2f7daHelge Dellerstatic void __devexit de_remove_one (struct pci_dev *pdev)
21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = pci_get_drvdata(pdev);
21128f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21147e0b58f32fb5e9c958078a6d722a7d0b230346a7Eric Sesterhenn / snakebyte	BUG_ON(!dev);
21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(dev);
2116b4558ea93d66a43f7990d26f145fd4c54a01c9bfJesper Juhl	kfree(de->ee_data);
21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iounmap(de->regs);
21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_release_regions(pdev);
21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_disable_device(pdev);
21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_drvdata(pdev, NULL);
21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212605adc3b7458e97a1d0180828000207a403083389Pavel Machekstatic int de_suspend (struct pci_dev *pdev, pm_message_t state)
21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = pci_get_drvdata (pdev);
21298f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtnl_lock();
21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_running (dev)) {
21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		del_timer_sync(&de->media_timer);
21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		disable_irq(dev->irq);
21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock_irq(&de->lock);
21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_stop_hw(de);
21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_stop_queue(dev);
21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_device_detach(dev);
21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_carrier_off(dev);
21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irq(&de->lock);
21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enable_irq(dev->irq);
2145f3b197ac26ed0e57989856494c495818dcc7f9acJeff Garzik
21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Update the error counts. */
21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__de_get_stats(de);
21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		synchronize_irq(dev->irq);
21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_clean_rings(de);
21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		de_adapter_sleep(de);
21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_disable_device(pdev);
21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		netif_device_detach(dev);
21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtnl_unlock();
21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int de_resume (struct pci_dev *pdev)
21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = pci_get_drvdata (pdev);
21648f15ea42b64941001a401cf855a0869e24f3a845Wang Chen	struct de_private *de = netdev_priv(dev);
21659f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson	int retval = 0;
21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtnl_lock();
21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (netif_device_present(dev))
21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
21709f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson	if (!netif_running(dev))
21719f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson		goto out_attach;
21729f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson	if ((retval = pci_enable_device(pdev))) {
2173163ef0b5922b14751e93218bdf2c9fe8f74b9c9dJoe Perches		netdev_err(dev, "pci_enable_device failed in resume\n");
21749f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson		goto out;
21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2176b0255a02351b00ca55f4eb2588d05a5db9dd1a58Ondrej Zary	pci_set_master(pdev);
2177b0255a02351b00ca55f4eb2588d05a5db9dd1a58Ondrej Zary	de_init_rings(de);
21789f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson	de_init_hw(de);
21799f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Hensonout_attach:
21809f486ae1d9ea700a952b77a8881de05ebc1610c3Valerie Henson	netif_device_attach(dev);
21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rtnl_unlock();
21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PM */
21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver de_driver = {
21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= DRV_NAME,
21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= de_pci_tbl,
21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= de_init_one,
21924a1d2d81fa327d095a0a8a1f961bace5b0a2f7daHelge Deller	.remove		= __devexit_p(de_remove_one),
21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM
21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.suspend	= de_suspend,
21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.resume		= de_resume,
21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init de_init (void)
22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
22021c3319fb69c29376fe23c1aa0cd7cb6df91c7883Joe Perches	pr_info("%s\n", version);
22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2204299176206b266f204be859adf9e66efd06628ab2Jeff Garzik	return pci_register_driver(&de_driver);
22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit de_exit (void)
22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver (&de_driver);
22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(de_init);
22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(de_exit);
2214