162306a36Sopenharmony_ci/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Copyright 2001,2003 Jeff Garzik <jgarzik@pobox.com>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci	Copyright 1994, 1995 Digital Equipment Corporation.	    [de4x5.c]
662306a36Sopenharmony_ci	Written/copyright 1994-2001 by Donald Becker.		    [tulip.c]
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci	This software may be used and distributed according to the terms of
962306a36Sopenharmony_ci	the GNU General Public License (GPL), incorporated herein by reference.
1062306a36Sopenharmony_ci	Drivers based on or derived from this code fall under the GPL and must
1162306a36Sopenharmony_ci	retain the authorship, copyright and license notice.  This file is not
1262306a36Sopenharmony_ci	a complete program and may only be used when the entire operating
1362306a36Sopenharmony_ci	system is licensed under the GPL.
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	See the file COPYING in this distribution for more information.
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	TODO, in rough priority order:
1862306a36Sopenharmony_ci	* Support forcing media type with a module parameter,
1962306a36Sopenharmony_ci	  like dl2k.c/sundance.c
2062306a36Sopenharmony_ci	* Constants (module parms?) for Rx work limit
2162306a36Sopenharmony_ci	* Complete reset on PciErr
2262306a36Sopenharmony_ci	* Jumbo frames / dev->change_mtu
2362306a36Sopenharmony_ci	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
2462306a36Sopenharmony_ci	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
2562306a36Sopenharmony_ci	* Implement Tx software interrupt mitigation via
2662306a36Sopenharmony_ci	  Tx descriptor bit
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define DRV_NAME		"de2104x"
3362306a36Sopenharmony_ci#define DRV_RELDATE		"Mar 17, 2004"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/module.h>
3662306a36Sopenharmony_ci#include <linux/kernel.h>
3762306a36Sopenharmony_ci#include <linux/netdevice.h>
3862306a36Sopenharmony_ci#include <linux/etherdevice.h>
3962306a36Sopenharmony_ci#include <linux/init.h>
4062306a36Sopenharmony_ci#include <linux/interrupt.h>
4162306a36Sopenharmony_ci#include <linux/pci.h>
4262306a36Sopenharmony_ci#include <linux/delay.h>
4362306a36Sopenharmony_ci#include <linux/ethtool.h>
4462306a36Sopenharmony_ci#include <linux/compiler.h>
4562306a36Sopenharmony_ci#include <linux/rtnetlink.h>
4662306a36Sopenharmony_ci#include <linux/crc32.h>
4762306a36Sopenharmony_ci#include <linux/slab.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <asm/io.h>
5062306a36Sopenharmony_ci#include <asm/irq.h>
5162306a36Sopenharmony_ci#include <linux/uaccess.h>
5262306a36Sopenharmony_ci#include <asm/unaligned.h>
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
5562306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");
5662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int debug = -1;
5962306a36Sopenharmony_cimodule_param (debug, int, 0);
6062306a36Sopenharmony_ciMODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
6362306a36Sopenharmony_ci#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \
6462306a36Sopenharmony_ci        defined(CONFIG_SPARC) || defined(__ia64__) ||		   \
6562306a36Sopenharmony_ci        defined(__sh__) || defined(__mips__)
6662306a36Sopenharmony_cistatic int rx_copybreak = 1518;
6762306a36Sopenharmony_ci#else
6862306a36Sopenharmony_cistatic int rx_copybreak = 100;
6962306a36Sopenharmony_ci#endif
7062306a36Sopenharmony_cimodule_param (rx_copybreak, int, 0);
7162306a36Sopenharmony_ciMODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define DE_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
7462306a36Sopenharmony_ci				 NETIF_MSG_PROBE 	| \
7562306a36Sopenharmony_ci				 NETIF_MSG_LINK		| \
7662306a36Sopenharmony_ci				 NETIF_MSG_IFDOWN	| \
7762306a36Sopenharmony_ci				 NETIF_MSG_IFUP		| \
7862306a36Sopenharmony_ci				 NETIF_MSG_RX_ERR	| \
7962306a36Sopenharmony_ci				 NETIF_MSG_TX_ERR)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Descriptor skip length in 32 bit longwords. */
8262306a36Sopenharmony_ci#ifndef CONFIG_DE2104X_DSL
8362306a36Sopenharmony_ci#define DSL			0
8462306a36Sopenharmony_ci#else
8562306a36Sopenharmony_ci#define DSL			CONFIG_DE2104X_DSL
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define DE_RX_RING_SIZE		128
8962306a36Sopenharmony_ci#define DE_TX_RING_SIZE		64
9062306a36Sopenharmony_ci#define DE_RING_BYTES		\
9162306a36Sopenharmony_ci		((sizeof(struct de_desc) * DE_RX_RING_SIZE) +	\
9262306a36Sopenharmony_ci		(sizeof(struct de_desc) * DE_TX_RING_SIZE))
9362306a36Sopenharmony_ci#define NEXT_TX(N)		(((N) + 1) & (DE_TX_RING_SIZE - 1))
9462306a36Sopenharmony_ci#define NEXT_RX(N)		(((N) + 1) & (DE_RX_RING_SIZE - 1))
9562306a36Sopenharmony_ci#define TX_BUFFS_AVAIL(CP)					\
9662306a36Sopenharmony_ci	(((CP)->tx_tail <= (CP)->tx_head) ?			\
9762306a36Sopenharmony_ci	  (CP)->tx_tail + (DE_TX_RING_SIZE - 1) - (CP)->tx_head :	\
9862306a36Sopenharmony_ci	  (CP)->tx_tail - (CP)->tx_head - 1)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
10162306a36Sopenharmony_ci#define RX_OFFSET		2
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define DE_SETUP_SKB		((struct sk_buff *) 1)
10462306a36Sopenharmony_ci#define DE_DUMMY_SKB		((struct sk_buff *) 2)
10562306a36Sopenharmony_ci#define DE_SETUP_FRAME_WORDS	96
10662306a36Sopenharmony_ci#define DE_EEPROM_WORDS		256
10762306a36Sopenharmony_ci#define DE_EEPROM_SIZE		(DE_EEPROM_WORDS * sizeof(u16))
10862306a36Sopenharmony_ci#define DE_MAX_MEDIA		5
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define DE_MEDIA_TP_AUTO	0
11162306a36Sopenharmony_ci#define DE_MEDIA_BNC		1
11262306a36Sopenharmony_ci#define DE_MEDIA_AUI		2
11362306a36Sopenharmony_ci#define DE_MEDIA_TP		3
11462306a36Sopenharmony_ci#define DE_MEDIA_TP_FD		4
11562306a36Sopenharmony_ci#define DE_MEDIA_INVALID	DE_MAX_MEDIA
11662306a36Sopenharmony_ci#define DE_MEDIA_FIRST		0
11762306a36Sopenharmony_ci#define DE_MEDIA_LAST		(DE_MAX_MEDIA - 1)
11862306a36Sopenharmony_ci#define DE_AUI_BNC		(SUPPORTED_AUI | SUPPORTED_BNC)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define DE_TIMER_LINK		(60 * HZ)
12162306a36Sopenharmony_ci#define DE_TIMER_NO_LINK	(5 * HZ)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define DE_NUM_REGS		16
12462306a36Sopenharmony_ci#define DE_REGS_SIZE		(DE_NUM_REGS * sizeof(u32))
12562306a36Sopenharmony_ci#define DE_REGS_VER		1
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
12862306a36Sopenharmony_ci#define TX_TIMEOUT		(6*HZ)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
13162306a36Sopenharmony_ci   to support a pre-NWay full-duplex signaling mechanism using short frames.
13262306a36Sopenharmony_ci   No one knows what it should be, but if left at its default value some
13362306a36Sopenharmony_ci   10base2(!) packets trigger a full-duplex-request interrupt. */
13462306a36Sopenharmony_ci#define FULL_DUPLEX_MAGIC	0x6969
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cienum {
13762306a36Sopenharmony_ci	/* NIC registers */
13862306a36Sopenharmony_ci	BusMode			= 0x00,
13962306a36Sopenharmony_ci	TxPoll			= 0x08,
14062306a36Sopenharmony_ci	RxPoll			= 0x10,
14162306a36Sopenharmony_ci	RxRingAddr		= 0x18,
14262306a36Sopenharmony_ci	TxRingAddr		= 0x20,
14362306a36Sopenharmony_ci	MacStatus		= 0x28,
14462306a36Sopenharmony_ci	MacMode			= 0x30,
14562306a36Sopenharmony_ci	IntrMask		= 0x38,
14662306a36Sopenharmony_ci	RxMissed		= 0x40,
14762306a36Sopenharmony_ci	ROMCmd			= 0x48,
14862306a36Sopenharmony_ci	CSR11			= 0x58,
14962306a36Sopenharmony_ci	SIAStatus		= 0x60,
15062306a36Sopenharmony_ci	CSR13			= 0x68,
15162306a36Sopenharmony_ci	CSR14			= 0x70,
15262306a36Sopenharmony_ci	CSR15			= 0x78,
15362306a36Sopenharmony_ci	PCIPM			= 0x40,
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* BusMode bits */
15662306a36Sopenharmony_ci	CmdReset		= (1 << 0),
15762306a36Sopenharmony_ci	CacheAlign16		= 0x00008000,
15862306a36Sopenharmony_ci	BurstLen4		= 0x00000400,
15962306a36Sopenharmony_ci	DescSkipLen		= (DSL << 2),
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Rx/TxPoll bits */
16262306a36Sopenharmony_ci	NormalTxPoll		= (1 << 0),
16362306a36Sopenharmony_ci	NormalRxPoll		= (1 << 0),
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Tx/Rx descriptor status bits */
16662306a36Sopenharmony_ci	DescOwn			= (1 << 31),
16762306a36Sopenharmony_ci	RxError			= (1 << 15),
16862306a36Sopenharmony_ci	RxErrLong		= (1 << 7),
16962306a36Sopenharmony_ci	RxErrCRC		= (1 << 1),
17062306a36Sopenharmony_ci	RxErrFIFO		= (1 << 0),
17162306a36Sopenharmony_ci	RxErrRunt		= (1 << 11),
17262306a36Sopenharmony_ci	RxErrFrame		= (1 << 14),
17362306a36Sopenharmony_ci	RingEnd			= (1 << 25),
17462306a36Sopenharmony_ci	FirstFrag		= (1 << 29),
17562306a36Sopenharmony_ci	LastFrag		= (1 << 30),
17662306a36Sopenharmony_ci	TxError			= (1 << 15),
17762306a36Sopenharmony_ci	TxFIFOUnder		= (1 << 1),
17862306a36Sopenharmony_ci	TxLinkFail		= (1 << 2) | (1 << 10) | (1 << 11),
17962306a36Sopenharmony_ci	TxMaxCol		= (1 << 8),
18062306a36Sopenharmony_ci	TxOWC			= (1 << 9),
18162306a36Sopenharmony_ci	TxJabber		= (1 << 14),
18262306a36Sopenharmony_ci	SetupFrame		= (1 << 27),
18362306a36Sopenharmony_ci	TxSwInt			= (1 << 31),
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* MacStatus bits */
18662306a36Sopenharmony_ci	IntrOK			= (1 << 16),
18762306a36Sopenharmony_ci	IntrErr			= (1 << 15),
18862306a36Sopenharmony_ci	RxIntr			= (1 << 6),
18962306a36Sopenharmony_ci	RxEmpty			= (1 << 7),
19062306a36Sopenharmony_ci	TxIntr			= (1 << 0),
19162306a36Sopenharmony_ci	TxEmpty			= (1 << 2),
19262306a36Sopenharmony_ci	PciErr			= (1 << 13),
19362306a36Sopenharmony_ci	TxState			= (1 << 22) | (1 << 21) | (1 << 20),
19462306a36Sopenharmony_ci	RxState			= (1 << 19) | (1 << 18) | (1 << 17),
19562306a36Sopenharmony_ci	LinkFail		= (1 << 12),
19662306a36Sopenharmony_ci	LinkPass		= (1 << 4),
19762306a36Sopenharmony_ci	RxStopped		= (1 << 8),
19862306a36Sopenharmony_ci	TxStopped		= (1 << 1),
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* MacMode bits */
20162306a36Sopenharmony_ci	TxEnable		= (1 << 13),
20262306a36Sopenharmony_ci	RxEnable		= (1 << 1),
20362306a36Sopenharmony_ci	RxTx			= TxEnable | RxEnable,
20462306a36Sopenharmony_ci	FullDuplex		= (1 << 9),
20562306a36Sopenharmony_ci	AcceptAllMulticast	= (1 << 7),
20662306a36Sopenharmony_ci	AcceptAllPhys		= (1 << 6),
20762306a36Sopenharmony_ci	BOCnt			= (1 << 5),
20862306a36Sopenharmony_ci	MacModeClear		= (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) |
20962306a36Sopenharmony_ci				  RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast,
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* ROMCmd bits */
21262306a36Sopenharmony_ci	EE_SHIFT_CLK		= 0x02,	/* EEPROM shift clock. */
21362306a36Sopenharmony_ci	EE_CS			= 0x01,	/* EEPROM chip select. */
21462306a36Sopenharmony_ci	EE_DATA_WRITE		= 0x04,	/* Data from the Tulip to EEPROM. */
21562306a36Sopenharmony_ci	EE_WRITE_0		= 0x01,
21662306a36Sopenharmony_ci	EE_WRITE_1		= 0x05,
21762306a36Sopenharmony_ci	EE_DATA_READ		= 0x08,	/* Data from the EEPROM chip. */
21862306a36Sopenharmony_ci	EE_ENB			= (0x4800 | EE_CS),
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* The EEPROM commands include the alway-set leading bit. */
22162306a36Sopenharmony_ci	EE_READ_CMD		= 6,
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* RxMissed bits */
22462306a36Sopenharmony_ci	RxMissedOver		= (1 << 16),
22562306a36Sopenharmony_ci	RxMissedMask		= 0xffff,
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* SROM-related bits */
22862306a36Sopenharmony_ci	SROMC0InfoLeaf		= 27,
22962306a36Sopenharmony_ci	MediaBlockMask		= 0x3f,
23062306a36Sopenharmony_ci	MediaCustomCSRs		= (1 << 6),
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* PCIPM bits */
23362306a36Sopenharmony_ci	PM_Sleep		= (1 << 31),
23462306a36Sopenharmony_ci	PM_Snooze		= (1 << 30),
23562306a36Sopenharmony_ci	PM_Mask			= PM_Sleep | PM_Snooze,
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* SIAStatus bits */
23862306a36Sopenharmony_ci	NWayState		= (1 << 14) | (1 << 13) | (1 << 12),
23962306a36Sopenharmony_ci	NWayRestart		= (1 << 12),
24062306a36Sopenharmony_ci	NonselPortActive	= (1 << 9),
24162306a36Sopenharmony_ci	SelPortActive		= (1 << 8),
24262306a36Sopenharmony_ci	LinkFailStatus		= (1 << 2),
24362306a36Sopenharmony_ci	NetCxnErr		= (1 << 1),
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic const u32 de_intr_mask =
24762306a36Sopenharmony_ci	IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty |
24862306a36Sopenharmony_ci	LinkPass | LinkFail | PciErr;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/*
25162306a36Sopenharmony_ci * Set the programmable burst length to 4 longwords for all:
25262306a36Sopenharmony_ci * DMA errors result without these values. Cache align 16 long.
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_cistatic const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistruct de_srom_media_block {
25762306a36Sopenharmony_ci	u8			opts;
25862306a36Sopenharmony_ci	u16			csr13;
25962306a36Sopenharmony_ci	u16			csr14;
26062306a36Sopenharmony_ci	u16			csr15;
26162306a36Sopenharmony_ci} __packed;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistruct de_srom_info_leaf {
26462306a36Sopenharmony_ci	u16			default_media;
26562306a36Sopenharmony_ci	u8			n_blocks;
26662306a36Sopenharmony_ci	u8			unused;
26762306a36Sopenharmony_ci} __packed;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistruct de_desc {
27062306a36Sopenharmony_ci	__le32			opts1;
27162306a36Sopenharmony_ci	__le32			opts2;
27262306a36Sopenharmony_ci	__le32			addr1;
27362306a36Sopenharmony_ci	__le32			addr2;
27462306a36Sopenharmony_ci#if DSL
27562306a36Sopenharmony_ci	__le32			skip[DSL];
27662306a36Sopenharmony_ci#endif
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistruct media_info {
28062306a36Sopenharmony_ci	u16			type;	/* DE_MEDIA_xxx */
28162306a36Sopenharmony_ci	u16			csr13;
28262306a36Sopenharmony_ci	u16			csr14;
28362306a36Sopenharmony_ci	u16			csr15;
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct ring_info {
28762306a36Sopenharmony_ci	struct sk_buff		*skb;
28862306a36Sopenharmony_ci	dma_addr_t		mapping;
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistruct de_private {
29262306a36Sopenharmony_ci	unsigned		tx_head;
29362306a36Sopenharmony_ci	unsigned		tx_tail;
29462306a36Sopenharmony_ci	unsigned		rx_tail;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	void			__iomem *regs;
29762306a36Sopenharmony_ci	struct net_device	*dev;
29862306a36Sopenharmony_ci	spinlock_t		lock;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	struct de_desc		*rx_ring;
30162306a36Sopenharmony_ci	struct de_desc		*tx_ring;
30262306a36Sopenharmony_ci	struct ring_info	tx_skb[DE_TX_RING_SIZE];
30362306a36Sopenharmony_ci	struct ring_info	rx_skb[DE_RX_RING_SIZE];
30462306a36Sopenharmony_ci	unsigned		rx_buf_sz;
30562306a36Sopenharmony_ci	dma_addr_t		ring_dma;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	u32			msg_enable;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	struct pci_dev		*pdev;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	u16			setup_frame[DE_SETUP_FRAME_WORDS];
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	u32			media_type;
31462306a36Sopenharmony_ci	u32			media_supported;
31562306a36Sopenharmony_ci	u32			media_advertise;
31662306a36Sopenharmony_ci	struct media_info	media[DE_MAX_MEDIA];
31762306a36Sopenharmony_ci	struct timer_list	media_timer;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	u8			*ee_data;
32062306a36Sopenharmony_ci	unsigned		board_idx;
32162306a36Sopenharmony_ci	unsigned		de21040 : 1;
32262306a36Sopenharmony_ci	unsigned		media_lock : 1;
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void de_set_rx_mode (struct net_device *dev);
32762306a36Sopenharmony_cistatic void de_tx (struct de_private *de);
32862306a36Sopenharmony_cistatic void de_clean_rings (struct de_private *de);
32962306a36Sopenharmony_cistatic void de_media_interrupt (struct de_private *de, u32 status);
33062306a36Sopenharmony_cistatic void de21040_media_timer (struct timer_list *t);
33162306a36Sopenharmony_cistatic void de21041_media_timer (struct timer_list *t);
33262306a36Sopenharmony_cistatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic const struct pci_device_id de_pci_tbl[] = {
33662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
33762306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
33862306a36Sopenharmony_ci	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
33962306a36Sopenharmony_ci	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
34062306a36Sopenharmony_ci	{ },
34162306a36Sopenharmony_ci};
34262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, de_pci_tbl);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic const char * const media_name[DE_MAX_MEDIA] = {
34562306a36Sopenharmony_ci	"10baseT auto",
34662306a36Sopenharmony_ci	"BNC",
34762306a36Sopenharmony_ci	"AUI",
34862306a36Sopenharmony_ci	"10baseT-HD",
34962306a36Sopenharmony_ci	"10baseT-FD"
35062306a36Sopenharmony_ci};
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/* 21040 transceiver register settings:
35362306a36Sopenharmony_ci * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/
35462306a36Sopenharmony_cistatic u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, };
35562306a36Sopenharmony_cistatic u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, };
35662306a36Sopenharmony_cistatic u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, };
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/
35962306a36Sopenharmony_cistatic u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
36062306a36Sopenharmony_cistatic u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
36162306a36Sopenharmony_ci/* If on-chip autonegotiation is broken, use half-duplex (FF3F) instead */
36262306a36Sopenharmony_cistatic u16 t21041_csr14_brk[] = { 0xFF3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
36362306a36Sopenharmony_cistatic u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci#define dr32(reg)	ioread32(de->regs + (reg))
36762306a36Sopenharmony_ci#define dw32(reg, val)	iowrite32((val), de->regs + (reg))
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
37162306a36Sopenharmony_ci			    u32 status, u32 len)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	netif_dbg(de, rx_err, de->dev,
37462306a36Sopenharmony_ci		  "rx err, slot %d status 0x%x len %d\n",
37562306a36Sopenharmony_ci		  rx_tail, status, len);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if ((status & 0x38000300) != 0x0300) {
37862306a36Sopenharmony_ci		/* Ingore earlier buffers. */
37962306a36Sopenharmony_ci		if ((status & 0xffff) != 0x7fff) {
38062306a36Sopenharmony_ci			netif_warn(de, rx_err, de->dev,
38162306a36Sopenharmony_ci				   "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
38262306a36Sopenharmony_ci				   status);
38362306a36Sopenharmony_ci			de->dev->stats.rx_length_errors++;
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci	} else if (status & RxError) {
38662306a36Sopenharmony_ci		/* There was a fatal error. */
38762306a36Sopenharmony_ci		de->dev->stats.rx_errors++; /* end of a packet.*/
38862306a36Sopenharmony_ci		if (status & 0x0890) de->dev->stats.rx_length_errors++;
38962306a36Sopenharmony_ci		if (status & RxErrCRC) de->dev->stats.rx_crc_errors++;
39062306a36Sopenharmony_ci		if (status & RxErrFIFO) de->dev->stats.rx_fifo_errors++;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void de_rx (struct de_private *de)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	unsigned rx_tail = de->rx_tail;
39762306a36Sopenharmony_ci	unsigned rx_work = DE_RX_RING_SIZE;
39862306a36Sopenharmony_ci	unsigned drop = 0;
39962306a36Sopenharmony_ci	int rc;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	while (--rx_work) {
40262306a36Sopenharmony_ci		u32 status, len;
40362306a36Sopenharmony_ci		dma_addr_t mapping;
40462306a36Sopenharmony_ci		struct sk_buff *skb, *copy_skb;
40562306a36Sopenharmony_ci		unsigned copying_skb, buflen;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		skb = de->rx_skb[rx_tail].skb;
40862306a36Sopenharmony_ci		BUG_ON(!skb);
40962306a36Sopenharmony_ci		rmb();
41062306a36Sopenharmony_ci		status = le32_to_cpu(de->rx_ring[rx_tail].opts1);
41162306a36Sopenharmony_ci		if (status & DescOwn)
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		/* the length is actually a 15 bit value here according
41562306a36Sopenharmony_ci		 * to Table 4-1 in the DE2104x spec so mask is 0x7fff
41662306a36Sopenharmony_ci		 */
41762306a36Sopenharmony_ci		len = ((status >> 16) & 0x7fff) - 4;
41862306a36Sopenharmony_ci		mapping = de->rx_skb[rx_tail].mapping;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci		if (unlikely(drop)) {
42162306a36Sopenharmony_ci			de->dev->stats.rx_dropped++;
42262306a36Sopenharmony_ci			goto rx_next;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (unlikely((status & 0x38008300) != 0x0300)) {
42662306a36Sopenharmony_ci			de_rx_err_acct(de, rx_tail, status, len);
42762306a36Sopenharmony_ci			goto rx_next;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		copying_skb = (len <= rx_copybreak);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		netif_dbg(de, rx_status, de->dev,
43362306a36Sopenharmony_ci			  "rx slot %d status 0x%x len %d copying? %d\n",
43462306a36Sopenharmony_ci			  rx_tail, status, len, copying_skb);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz;
43762306a36Sopenharmony_ci		copy_skb = netdev_alloc_skb(de->dev, buflen);
43862306a36Sopenharmony_ci		if (unlikely(!copy_skb)) {
43962306a36Sopenharmony_ci			de->dev->stats.rx_dropped++;
44062306a36Sopenharmony_ci			drop = 1;
44162306a36Sopenharmony_ci			rx_work = 100;
44262306a36Sopenharmony_ci			goto rx_next;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		if (!copying_skb) {
44662306a36Sopenharmony_ci			dma_unmap_single(&de->pdev->dev, mapping, buflen,
44762306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
44862306a36Sopenharmony_ci			skb_put(skb, len);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			mapping =
45162306a36Sopenharmony_ci			de->rx_skb[rx_tail].mapping =
45262306a36Sopenharmony_ci				dma_map_single(&de->pdev->dev, copy_skb->data,
45362306a36Sopenharmony_ci					       buflen, DMA_FROM_DEVICE);
45462306a36Sopenharmony_ci			de->rx_skb[rx_tail].skb = copy_skb;
45562306a36Sopenharmony_ci		} else {
45662306a36Sopenharmony_ci			dma_sync_single_for_cpu(&de->pdev->dev, mapping, len,
45762306a36Sopenharmony_ci						DMA_FROM_DEVICE);
45862306a36Sopenharmony_ci			skb_reserve(copy_skb, RX_OFFSET);
45962306a36Sopenharmony_ci			skb_copy_from_linear_data(skb, skb_put(copy_skb, len),
46062306a36Sopenharmony_ci						  len);
46162306a36Sopenharmony_ci			dma_sync_single_for_device(&de->pdev->dev, mapping,
46262306a36Sopenharmony_ci						   len, DMA_FROM_DEVICE);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci			/* We'll reuse the original ring buffer. */
46562306a36Sopenharmony_ci			skb = copy_skb;
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		skb->protocol = eth_type_trans (skb, de->dev);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		de->dev->stats.rx_packets++;
47162306a36Sopenharmony_ci		de->dev->stats.rx_bytes += skb->len;
47262306a36Sopenharmony_ci		rc = netif_rx (skb);
47362306a36Sopenharmony_ci		if (rc == NET_RX_DROP)
47462306a36Sopenharmony_ci			drop = 1;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cirx_next:
47762306a36Sopenharmony_ci		if (rx_tail == (DE_RX_RING_SIZE - 1))
47862306a36Sopenharmony_ci			de->rx_ring[rx_tail].opts2 =
47962306a36Sopenharmony_ci				cpu_to_le32(RingEnd | de->rx_buf_sz);
48062306a36Sopenharmony_ci		else
48162306a36Sopenharmony_ci			de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz);
48262306a36Sopenharmony_ci		de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping);
48362306a36Sopenharmony_ci		wmb();
48462306a36Sopenharmony_ci		de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn);
48562306a36Sopenharmony_ci		rx_tail = NEXT_RX(rx_tail);
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (!rx_work)
48962306a36Sopenharmony_ci		netdev_warn(de->dev, "rx work limit reached\n");
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	de->rx_tail = rx_tail;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic irqreturn_t de_interrupt (int irq, void *dev_instance)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct net_device *dev = dev_instance;
49762306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
49862306a36Sopenharmony_ci	u32 status;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	status = dr32(MacStatus);
50162306a36Sopenharmony_ci	if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF))
50262306a36Sopenharmony_ci		return IRQ_NONE;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n",
50562306a36Sopenharmony_ci		  status, dr32(MacMode),
50662306a36Sopenharmony_ci		  de->rx_tail, de->tx_head, de->tx_tail);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	dw32(MacStatus, status);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (status & (RxIntr | RxEmpty)) {
51162306a36Sopenharmony_ci		de_rx(de);
51262306a36Sopenharmony_ci		if (status & RxEmpty)
51362306a36Sopenharmony_ci			dw32(RxPoll, NormalRxPoll);
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	spin_lock(&de->lock);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (status & (TxIntr | TxEmpty))
51962306a36Sopenharmony_ci		de_tx(de);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (status & (LinkPass | LinkFail))
52262306a36Sopenharmony_ci		de_media_interrupt(de, status);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	spin_unlock(&de->lock);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (status & PciErr) {
52762306a36Sopenharmony_ci		u16 pci_status;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
53062306a36Sopenharmony_ci		pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
53162306a36Sopenharmony_ci		netdev_err(de->dev,
53262306a36Sopenharmony_ci			   "PCI bus error, status=%08x, PCI status=%04x\n",
53362306a36Sopenharmony_ci			   status, pci_status);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return IRQ_HANDLED;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic void de_tx (struct de_private *de)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	unsigned tx_head = de->tx_head;
54262306a36Sopenharmony_ci	unsigned tx_tail = de->tx_tail;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	while (tx_tail != tx_head) {
54562306a36Sopenharmony_ci		struct sk_buff *skb;
54662306a36Sopenharmony_ci		u32 status;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		rmb();
54962306a36Sopenharmony_ci		status = le32_to_cpu(de->tx_ring[tx_tail].opts1);
55062306a36Sopenharmony_ci		if (status & DescOwn)
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		skb = de->tx_skb[tx_tail].skb;
55462306a36Sopenharmony_ci		BUG_ON(!skb);
55562306a36Sopenharmony_ci		if (unlikely(skb == DE_DUMMY_SKB))
55662306a36Sopenharmony_ci			goto next;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		if (unlikely(skb == DE_SETUP_SKB)) {
55962306a36Sopenharmony_ci			dma_unmap_single(&de->pdev->dev,
56062306a36Sopenharmony_ci					 de->tx_skb[tx_tail].mapping,
56162306a36Sopenharmony_ci					 sizeof(de->setup_frame),
56262306a36Sopenharmony_ci					 DMA_TO_DEVICE);
56362306a36Sopenharmony_ci			goto next;
56462306a36Sopenharmony_ci		}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		dma_unmap_single(&de->pdev->dev, de->tx_skb[tx_tail].mapping,
56762306a36Sopenharmony_ci				 skb->len, DMA_TO_DEVICE);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		if (status & LastFrag) {
57062306a36Sopenharmony_ci			if (status & TxError) {
57162306a36Sopenharmony_ci				netif_dbg(de, tx_err, de->dev,
57262306a36Sopenharmony_ci					  "tx err, status 0x%x\n",
57362306a36Sopenharmony_ci					  status);
57462306a36Sopenharmony_ci				de->dev->stats.tx_errors++;
57562306a36Sopenharmony_ci				if (status & TxOWC)
57662306a36Sopenharmony_ci					de->dev->stats.tx_window_errors++;
57762306a36Sopenharmony_ci				if (status & TxMaxCol)
57862306a36Sopenharmony_ci					de->dev->stats.tx_aborted_errors++;
57962306a36Sopenharmony_ci				if (status & TxLinkFail)
58062306a36Sopenharmony_ci					de->dev->stats.tx_carrier_errors++;
58162306a36Sopenharmony_ci				if (status & TxFIFOUnder)
58262306a36Sopenharmony_ci					de->dev->stats.tx_fifo_errors++;
58362306a36Sopenharmony_ci			} else {
58462306a36Sopenharmony_ci				de->dev->stats.tx_packets++;
58562306a36Sopenharmony_ci				de->dev->stats.tx_bytes += skb->len;
58662306a36Sopenharmony_ci				netif_dbg(de, tx_done, de->dev,
58762306a36Sopenharmony_ci					  "tx done, slot %d\n", tx_tail);
58862306a36Sopenharmony_ci			}
58962306a36Sopenharmony_ci			dev_consume_skb_irq(skb);
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cinext:
59362306a36Sopenharmony_ci		de->tx_skb[tx_tail].skb = NULL;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci		tx_tail = NEXT_TX(tx_tail);
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	de->tx_tail = tx_tail;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if (netif_queue_stopped(de->dev) && (TX_BUFFS_AVAIL(de) > (DE_TX_RING_SIZE / 4)))
60162306a36Sopenharmony_ci		netif_wake_queue(de->dev);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic netdev_tx_t de_start_xmit (struct sk_buff *skb,
60562306a36Sopenharmony_ci					struct net_device *dev)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
60862306a36Sopenharmony_ci	unsigned int entry, tx_free;
60962306a36Sopenharmony_ci	u32 mapping, len, flags = FirstFrag | LastFrag;
61062306a36Sopenharmony_ci	struct de_desc *txd;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	tx_free = TX_BUFFS_AVAIL(de);
61562306a36Sopenharmony_ci	if (tx_free == 0) {
61662306a36Sopenharmony_ci		netif_stop_queue(dev);
61762306a36Sopenharmony_ci		spin_unlock_irq(&de->lock);
61862306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	tx_free--;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	entry = de->tx_head;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	txd = &de->tx_ring[entry];
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	len = skb->len;
62762306a36Sopenharmony_ci	mapping = dma_map_single(&de->pdev->dev, skb->data, len,
62862306a36Sopenharmony_ci				 DMA_TO_DEVICE);
62962306a36Sopenharmony_ci	if (entry == (DE_TX_RING_SIZE - 1))
63062306a36Sopenharmony_ci		flags |= RingEnd;
63162306a36Sopenharmony_ci	if (!tx_free || (tx_free == (DE_TX_RING_SIZE / 2)))
63262306a36Sopenharmony_ci		flags |= TxSwInt;
63362306a36Sopenharmony_ci	flags |= len;
63462306a36Sopenharmony_ci	txd->opts2 = cpu_to_le32(flags);
63562306a36Sopenharmony_ci	txd->addr1 = cpu_to_le32(mapping);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	de->tx_skb[entry].skb = skb;
63862306a36Sopenharmony_ci	de->tx_skb[entry].mapping = mapping;
63962306a36Sopenharmony_ci	wmb();
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	txd->opts1 = cpu_to_le32(DescOwn);
64262306a36Sopenharmony_ci	wmb();
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	de->tx_head = NEXT_TX(entry);
64562306a36Sopenharmony_ci	netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n",
64662306a36Sopenharmony_ci		  entry, skb->len);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (tx_free == 0)
64962306a36Sopenharmony_ci		netif_stop_queue(dev);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Trigger an immediate transmit demand. */
65462306a36Sopenharmony_ci	dw32(TxPoll, NormalTxPoll);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return NETDEV_TX_OK;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/* Set or clear the multicast filter for this adaptor.
66062306a36Sopenharmony_ci   Note that we only use exclusion around actually queueing the
66162306a36Sopenharmony_ci   new frame, not around filling de->setup_frame.  This is non-deterministic
66262306a36Sopenharmony_ci   when re-entered but still correct. */
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
66762306a36Sopenharmony_ci	u16 hash_table[32];
66862306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
66962306a36Sopenharmony_ci	const u16 *eaddrs;
67062306a36Sopenharmony_ci	int i;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	memset(hash_table, 0, sizeof(hash_table));
67362306a36Sopenharmony_ci	__set_bit_le(255, hash_table);			/* Broadcast entry */
67462306a36Sopenharmony_ci	/* This should work on big-endian machines as well. */
67562306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
67662306a36Sopenharmony_ci		int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		__set_bit_le(index, hash_table);
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	for (i = 0; i < 32; i++) {
68262306a36Sopenharmony_ci		*setup_frm++ = hash_table[i];
68362306a36Sopenharmony_ci		*setup_frm++ = hash_table[i];
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci	setup_frm = &de->setup_frame[13*6];
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Fill the final entry with our physical address. */
68862306a36Sopenharmony_ci	eaddrs = (const u16 *)dev->dev_addr;
68962306a36Sopenharmony_ci	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
69062306a36Sopenharmony_ci	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
69162306a36Sopenharmony_ci	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
69762306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
69862306a36Sopenharmony_ci	const u16 *eaddrs;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* We have <= 14 addresses so we can use the wonderful
70162306a36Sopenharmony_ci	   16 address perfect filtering of the Tulip. */
70262306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
70362306a36Sopenharmony_ci		eaddrs = (u16 *) ha->addr;
70462306a36Sopenharmony_ci		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
70562306a36Sopenharmony_ci		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
70662306a36Sopenharmony_ci		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	/* Fill the unused entries with the broadcast address. */
70962306a36Sopenharmony_ci	memset(setup_frm, 0xff, (15 - netdev_mc_count(dev)) * 12);
71062306a36Sopenharmony_ci	setup_frm = &de->setup_frame[15*6];
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/* Fill the final entry with our physical address. */
71362306a36Sopenharmony_ci	eaddrs = (const u16 *)dev->dev_addr;
71462306a36Sopenharmony_ci	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
71562306a36Sopenharmony_ci	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
71662306a36Sopenharmony_ci	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void __de_set_rx_mode (struct net_device *dev)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
72362306a36Sopenharmony_ci	u32 macmode;
72462306a36Sopenharmony_ci	unsigned int entry;
72562306a36Sopenharmony_ci	u32 mapping;
72662306a36Sopenharmony_ci	struct de_desc *txd;
72762306a36Sopenharmony_ci	struct de_desc *dummy_txd = NULL;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
73262306a36Sopenharmony_ci		macmode |= AcceptAllMulticast | AcceptAllPhys;
73362306a36Sopenharmony_ci		goto out;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if ((netdev_mc_count(dev) > 1000) || (dev->flags & IFF_ALLMULTI)) {
73762306a36Sopenharmony_ci		/* Too many to filter well -- accept all multicasts. */
73862306a36Sopenharmony_ci		macmode |= AcceptAllMulticast;
73962306a36Sopenharmony_ci		goto out;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Note that only the low-address shortword of setup_frame is valid!
74362306a36Sopenharmony_ci	   The values are doubled for big-endian architectures. */
74462306a36Sopenharmony_ci	if (netdev_mc_count(dev) > 14)	/* Must use a multicast hash table. */
74562306a36Sopenharmony_ci		build_setup_frame_hash (de->setup_frame, dev);
74662306a36Sopenharmony_ci	else
74762306a36Sopenharmony_ci		build_setup_frame_perfect (de->setup_frame, dev);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/*
75062306a36Sopenharmony_ci	 * Now add this frame to the Tx list.
75162306a36Sopenharmony_ci	 */
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	entry = de->tx_head;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* Avoid a chip errata by prefixing a dummy entry. */
75662306a36Sopenharmony_ci	if (entry != 0) {
75762306a36Sopenharmony_ci		de->tx_skb[entry].skb = DE_DUMMY_SKB;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		dummy_txd = &de->tx_ring[entry];
76062306a36Sopenharmony_ci		dummy_txd->opts2 = (entry == (DE_TX_RING_SIZE - 1)) ?
76162306a36Sopenharmony_ci				   cpu_to_le32(RingEnd) : 0;
76262306a36Sopenharmony_ci		dummy_txd->addr1 = 0;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		/* Must set DescOwned later to avoid race with chip */
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		entry = NEXT_TX(entry);
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	de->tx_skb[entry].skb = DE_SETUP_SKB;
77062306a36Sopenharmony_ci	de->tx_skb[entry].mapping = mapping =
77162306a36Sopenharmony_ci	    dma_map_single(&de->pdev->dev, de->setup_frame,
77262306a36Sopenharmony_ci			   sizeof(de->setup_frame), DMA_TO_DEVICE);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Put the setup frame on the Tx list. */
77562306a36Sopenharmony_ci	txd = &de->tx_ring[entry];
77662306a36Sopenharmony_ci	if (entry == (DE_TX_RING_SIZE - 1))
77762306a36Sopenharmony_ci		txd->opts2 = cpu_to_le32(SetupFrame | RingEnd | sizeof (de->setup_frame));
77862306a36Sopenharmony_ci	else
77962306a36Sopenharmony_ci		txd->opts2 = cpu_to_le32(SetupFrame | sizeof (de->setup_frame));
78062306a36Sopenharmony_ci	txd->addr1 = cpu_to_le32(mapping);
78162306a36Sopenharmony_ci	wmb();
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	txd->opts1 = cpu_to_le32(DescOwn);
78462306a36Sopenharmony_ci	wmb();
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (dummy_txd) {
78762306a36Sopenharmony_ci		dummy_txd->opts1 = cpu_to_le32(DescOwn);
78862306a36Sopenharmony_ci		wmb();
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	de->tx_head = NEXT_TX(entry);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (TX_BUFFS_AVAIL(de) == 0)
79462306a36Sopenharmony_ci		netif_stop_queue(dev);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* Trigger an immediate transmit demand. */
79762306a36Sopenharmony_ci	dw32(TxPoll, NormalTxPoll);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ciout:
80062306a36Sopenharmony_ci	if (macmode != dr32(MacMode))
80162306a36Sopenharmony_ci		dw32(MacMode, macmode);
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cistatic void de_set_rx_mode (struct net_device *dev)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	unsigned long flags;
80762306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	spin_lock_irqsave (&de->lock, flags);
81062306a36Sopenharmony_ci	__de_set_rx_mode(dev);
81162306a36Sopenharmony_ci	spin_unlock_irqrestore (&de->lock, flags);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic inline void de_rx_missed(struct de_private *de, u32 rx_missed)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	if (unlikely(rx_missed & RxMissedOver))
81762306a36Sopenharmony_ci		de->dev->stats.rx_missed_errors += RxMissedMask;
81862306a36Sopenharmony_ci	else
81962306a36Sopenharmony_ci		de->dev->stats.rx_missed_errors += (rx_missed & RxMissedMask);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic void __de_get_stats(struct de_private *de)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	u32 tmp = dr32(RxMissed); /* self-clearing */
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	de_rx_missed(de, tmp);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic struct net_device_stats *de_get_stats(struct net_device *dev)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	/* The chip only need report frame silently dropped. */
83462306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
83562306a36Sopenharmony_ci	if (netif_running(dev) && netif_device_present(dev))
83662306a36Sopenharmony_ci		__de_get_stats(de);
83762306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	return &dev->stats;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic inline int de_is_running (struct de_private *de)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	return (dr32(MacStatus) & (RxState | TxState)) ? 1 : 0;
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic void de_stop_rxtx (struct de_private *de)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u32 macmode;
85062306a36Sopenharmony_ci	unsigned int i = 1300/100;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	macmode = dr32(MacMode);
85362306a36Sopenharmony_ci	if (macmode & RxTx) {
85462306a36Sopenharmony_ci		dw32(MacMode, macmode & ~RxTx);
85562306a36Sopenharmony_ci		dr32(MacMode);
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* wait until in-flight frame completes.
85962306a36Sopenharmony_ci	 * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin)
86062306a36Sopenharmony_ci	 * Typically expect this loop to end in < 50 us on 100BT.
86162306a36Sopenharmony_ci	 */
86262306a36Sopenharmony_ci	while (--i) {
86362306a36Sopenharmony_ci		if (!de_is_running(de))
86462306a36Sopenharmony_ci			return;
86562306a36Sopenharmony_ci		udelay(100);
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	netdev_warn(de->dev, "timeout expired, stopping DMA\n");
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic inline void de_start_rxtx (struct de_private *de)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	u32 macmode;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	macmode = dr32(MacMode);
87662306a36Sopenharmony_ci	if ((macmode & RxTx) != RxTx) {
87762306a36Sopenharmony_ci		dw32(MacMode, macmode | RxTx);
87862306a36Sopenharmony_ci		dr32(MacMode);
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic void de_stop_hw (struct de_private *de)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	udelay(5);
88662306a36Sopenharmony_ci	dw32(IntrMask, 0);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	de_stop_rxtx(de);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	dw32(MacStatus, dr32(MacStatus));
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	udelay(10);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	de->rx_tail = 0;
89562306a36Sopenharmony_ci	de->tx_head = de->tx_tail = 0;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_cistatic void de_link_up(struct de_private *de)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	if (!netif_carrier_ok(de->dev)) {
90162306a36Sopenharmony_ci		netif_carrier_on(de->dev);
90262306a36Sopenharmony_ci		netif_info(de, link, de->dev, "link up, media %s\n",
90362306a36Sopenharmony_ci			   media_name[de->media_type]);
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic void de_link_down(struct de_private *de)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	if (netif_carrier_ok(de->dev)) {
91062306a36Sopenharmony_ci		netif_carrier_off(de->dev);
91162306a36Sopenharmony_ci		netif_info(de, link, de->dev, "link down\n");
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic void de_set_media (struct de_private *de)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	unsigned media = de->media_type;
91862306a36Sopenharmony_ci	u32 macmode = dr32(MacMode);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (de_is_running(de))
92162306a36Sopenharmony_ci		netdev_warn(de->dev, "chip is running while changing media!\n");
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (de->de21040)
92462306a36Sopenharmony_ci		dw32(CSR11, FULL_DUPLEX_MAGIC);
92562306a36Sopenharmony_ci	dw32(CSR13, 0); /* Reset phy */
92662306a36Sopenharmony_ci	dw32(CSR14, de->media[media].csr14);
92762306a36Sopenharmony_ci	dw32(CSR15, de->media[media].csr15);
92862306a36Sopenharmony_ci	dw32(CSR13, de->media[media].csr13);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/* must delay 10ms before writing to other registers,
93162306a36Sopenharmony_ci	 * especially CSR6
93262306a36Sopenharmony_ci	 */
93362306a36Sopenharmony_ci	mdelay(10);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (media == DE_MEDIA_TP_FD)
93662306a36Sopenharmony_ci		macmode |= FullDuplex;
93762306a36Sopenharmony_ci	else
93862306a36Sopenharmony_ci		macmode &= ~FullDuplex;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	netif_info(de, link, de->dev, "set link %s\n", media_name[media]);
94162306a36Sopenharmony_ci	netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
94262306a36Sopenharmony_ci		   dr32(MacMode), dr32(SIAStatus),
94362306a36Sopenharmony_ci		   dr32(CSR13), dr32(CSR14), dr32(CSR15));
94462306a36Sopenharmony_ci	netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
94562306a36Sopenharmony_ci		   macmode, de->media[media].csr13,
94662306a36Sopenharmony_ci		   de->media[media].csr14, de->media[media].csr15);
94762306a36Sopenharmony_ci	if (macmode != dr32(MacMode))
94862306a36Sopenharmony_ci		dw32(MacMode, macmode);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic void de_next_media (struct de_private *de, const u32 *media,
95262306a36Sopenharmony_ci			   unsigned int n_media)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	unsigned int i;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	for (i = 0; i < n_media; i++) {
95762306a36Sopenharmony_ci		if (de_ok_to_advertise(de, media[i])) {
95862306a36Sopenharmony_ci			de->media_type = media[i];
95962306a36Sopenharmony_ci			return;
96062306a36Sopenharmony_ci		}
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic void de21040_media_timer (struct timer_list *t)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct de_private *de = from_timer(de, t, media_timer);
96762306a36Sopenharmony_ci	struct net_device *dev = de->dev;
96862306a36Sopenharmony_ci	u32 status = dr32(SIAStatus);
96962306a36Sopenharmony_ci	unsigned int carrier;
97062306a36Sopenharmony_ci	unsigned long flags;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	carrier = (status & NetCxnErr) ? 0 : 1;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (carrier) {
97562306a36Sopenharmony_ci		if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus))
97662306a36Sopenharmony_ci			goto no_link_yet;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		de->media_timer.expires = jiffies + DE_TIMER_LINK;
97962306a36Sopenharmony_ci		add_timer(&de->media_timer);
98062306a36Sopenharmony_ci		if (!netif_carrier_ok(dev))
98162306a36Sopenharmony_ci			de_link_up(de);
98262306a36Sopenharmony_ci		else
98362306a36Sopenharmony_ci			netif_info(de, timer, dev, "%s link ok, status %x\n",
98462306a36Sopenharmony_ci				   media_name[de->media_type], status);
98562306a36Sopenharmony_ci		return;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	de_link_down(de);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (de->media_lock)
99162306a36Sopenharmony_ci		return;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (de->media_type == DE_MEDIA_AUI) {
99462306a36Sopenharmony_ci		static const u32 next_state = DE_MEDIA_TP;
99562306a36Sopenharmony_ci		de_next_media(de, &next_state, 1);
99662306a36Sopenharmony_ci	} else {
99762306a36Sopenharmony_ci		static const u32 next_state = DE_MEDIA_AUI;
99862306a36Sopenharmony_ci		de_next_media(de, &next_state, 1);
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	spin_lock_irqsave(&de->lock, flags);
100262306a36Sopenharmony_ci	de_stop_rxtx(de);
100362306a36Sopenharmony_ci	spin_unlock_irqrestore(&de->lock, flags);
100462306a36Sopenharmony_ci	de_set_media(de);
100562306a36Sopenharmony_ci	de_start_rxtx(de);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cino_link_yet:
100862306a36Sopenharmony_ci	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
100962306a36Sopenharmony_ci	add_timer(&de->media_timer);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
101262306a36Sopenharmony_ci		   media_name[de->media_type], status);
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	switch (new_media) {
101862306a36Sopenharmony_ci	case DE_MEDIA_TP_AUTO:
101962306a36Sopenharmony_ci		if (!(de->media_advertise & ADVERTISED_Autoneg))
102062306a36Sopenharmony_ci			return 0;
102162306a36Sopenharmony_ci		if (!(de->media_advertise & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full)))
102262306a36Sopenharmony_ci			return 0;
102362306a36Sopenharmony_ci		break;
102462306a36Sopenharmony_ci	case DE_MEDIA_BNC:
102562306a36Sopenharmony_ci		if (!(de->media_advertise & ADVERTISED_BNC))
102662306a36Sopenharmony_ci			return 0;
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	case DE_MEDIA_AUI:
102962306a36Sopenharmony_ci		if (!(de->media_advertise & ADVERTISED_AUI))
103062306a36Sopenharmony_ci			return 0;
103162306a36Sopenharmony_ci		break;
103262306a36Sopenharmony_ci	case DE_MEDIA_TP:
103362306a36Sopenharmony_ci		if (!(de->media_advertise & ADVERTISED_10baseT_Half))
103462306a36Sopenharmony_ci			return 0;
103562306a36Sopenharmony_ci		break;
103662306a36Sopenharmony_ci	case DE_MEDIA_TP_FD:
103762306a36Sopenharmony_ci		if (!(de->media_advertise & ADVERTISED_10baseT_Full))
103862306a36Sopenharmony_ci			return 0;
103962306a36Sopenharmony_ci		break;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return 1;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic void de21041_media_timer (struct timer_list *t)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct de_private *de = from_timer(de, t, media_timer);
104862306a36Sopenharmony_ci	struct net_device *dev = de->dev;
104962306a36Sopenharmony_ci	u32 status = dr32(SIAStatus);
105062306a36Sopenharmony_ci	unsigned int carrier;
105162306a36Sopenharmony_ci	unsigned long flags;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* clear port active bits */
105462306a36Sopenharmony_ci	dw32(SIAStatus, NonselPortActive | SelPortActive);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	carrier = (status & NetCxnErr) ? 0 : 1;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (carrier) {
105962306a36Sopenharmony_ci		if ((de->media_type == DE_MEDIA_TP_AUTO ||
106062306a36Sopenharmony_ci		     de->media_type == DE_MEDIA_TP ||
106162306a36Sopenharmony_ci		     de->media_type == DE_MEDIA_TP_FD) &&
106262306a36Sopenharmony_ci		    (status & LinkFailStatus))
106362306a36Sopenharmony_ci			goto no_link_yet;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		de->media_timer.expires = jiffies + DE_TIMER_LINK;
106662306a36Sopenharmony_ci		add_timer(&de->media_timer);
106762306a36Sopenharmony_ci		if (!netif_carrier_ok(dev))
106862306a36Sopenharmony_ci			de_link_up(de);
106962306a36Sopenharmony_ci		else
107062306a36Sopenharmony_ci			netif_info(de, timer, dev,
107162306a36Sopenharmony_ci				   "%s link ok, mode %x status %x\n",
107262306a36Sopenharmony_ci				   media_name[de->media_type],
107362306a36Sopenharmony_ci				   dr32(MacMode), status);
107462306a36Sopenharmony_ci		return;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	de_link_down(de);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* if media type locked, don't switch media */
108062306a36Sopenharmony_ci	if (de->media_lock)
108162306a36Sopenharmony_ci		goto set_media;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* if activity detected, use that as hint for new media type */
108462306a36Sopenharmony_ci	if (status & NonselPortActive) {
108562306a36Sopenharmony_ci		unsigned int have_media = 1;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci		/* if AUI/BNC selected, then activity is on TP port */
108862306a36Sopenharmony_ci		if (de->media_type == DE_MEDIA_AUI ||
108962306a36Sopenharmony_ci		    de->media_type == DE_MEDIA_BNC) {
109062306a36Sopenharmony_ci			if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
109162306a36Sopenharmony_ci				de->media_type = DE_MEDIA_TP_AUTO;
109262306a36Sopenharmony_ci			else
109362306a36Sopenharmony_ci				have_media = 0;
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		/* TP selected.  If there is only TP and BNC, then it's BNC */
109762306a36Sopenharmony_ci		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
109862306a36Sopenharmony_ci			 de_ok_to_advertise(de, DE_MEDIA_BNC))
109962306a36Sopenharmony_ci			de->media_type = DE_MEDIA_BNC;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		/* TP selected.  If there is only TP and AUI, then it's AUI */
110262306a36Sopenharmony_ci		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
110362306a36Sopenharmony_ci			 de_ok_to_advertise(de, DE_MEDIA_AUI))
110462306a36Sopenharmony_ci			de->media_type = DE_MEDIA_AUI;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		/* otherwise, ignore the hint */
110762306a36Sopenharmony_ci		else
110862306a36Sopenharmony_ci			have_media = 0;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		if (have_media)
111162306a36Sopenharmony_ci			goto set_media;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	/*
111562306a36Sopenharmony_ci	 * Absent or ambiguous activity hint, move to next advertised
111662306a36Sopenharmony_ci	 * media state.  If de->media_type is left unchanged, this
111762306a36Sopenharmony_ci	 * simply resets the PHY and reloads the current media settings.
111862306a36Sopenharmony_ci	 */
111962306a36Sopenharmony_ci	if (de->media_type == DE_MEDIA_AUI) {
112062306a36Sopenharmony_ci		static const u32 next_states[] = {
112162306a36Sopenharmony_ci			DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
112262306a36Sopenharmony_ci		};
112362306a36Sopenharmony_ci		de_next_media(de, next_states, ARRAY_SIZE(next_states));
112462306a36Sopenharmony_ci	} else if (de->media_type == DE_MEDIA_BNC) {
112562306a36Sopenharmony_ci		static const u32 next_states[] = {
112662306a36Sopenharmony_ci			DE_MEDIA_TP_AUTO, DE_MEDIA_AUI
112762306a36Sopenharmony_ci		};
112862306a36Sopenharmony_ci		de_next_media(de, next_states, ARRAY_SIZE(next_states));
112962306a36Sopenharmony_ci	} else {
113062306a36Sopenharmony_ci		static const u32 next_states[] = {
113162306a36Sopenharmony_ci			DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO
113262306a36Sopenharmony_ci		};
113362306a36Sopenharmony_ci		de_next_media(de, next_states, ARRAY_SIZE(next_states));
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ciset_media:
113762306a36Sopenharmony_ci	spin_lock_irqsave(&de->lock, flags);
113862306a36Sopenharmony_ci	de_stop_rxtx(de);
113962306a36Sopenharmony_ci	spin_unlock_irqrestore(&de->lock, flags);
114062306a36Sopenharmony_ci	de_set_media(de);
114162306a36Sopenharmony_ci	de_start_rxtx(de);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cino_link_yet:
114462306a36Sopenharmony_ci	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
114562306a36Sopenharmony_ci	add_timer(&de->media_timer);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
114862306a36Sopenharmony_ci		   media_name[de->media_type], status);
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic void de_media_interrupt (struct de_private *de, u32 status)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	if (status & LinkPass) {
115462306a36Sopenharmony_ci		/* Ignore if current media is AUI or BNC and we can't use TP */
115562306a36Sopenharmony_ci		if ((de->media_type == DE_MEDIA_AUI ||
115662306a36Sopenharmony_ci		     de->media_type == DE_MEDIA_BNC) &&
115762306a36Sopenharmony_ci		    (de->media_lock ||
115862306a36Sopenharmony_ci		     !de_ok_to_advertise(de, DE_MEDIA_TP_AUTO)))
115962306a36Sopenharmony_ci			return;
116062306a36Sopenharmony_ci		/* If current media is not TP, change it to TP */
116162306a36Sopenharmony_ci		if ((de->media_type == DE_MEDIA_AUI ||
116262306a36Sopenharmony_ci		     de->media_type == DE_MEDIA_BNC)) {
116362306a36Sopenharmony_ci			de->media_type = DE_MEDIA_TP_AUTO;
116462306a36Sopenharmony_ci			de_stop_rxtx(de);
116562306a36Sopenharmony_ci			de_set_media(de);
116662306a36Sopenharmony_ci			de_start_rxtx(de);
116762306a36Sopenharmony_ci		}
116862306a36Sopenharmony_ci		de_link_up(de);
116962306a36Sopenharmony_ci		mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
117062306a36Sopenharmony_ci		return;
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	BUG_ON(!(status & LinkFail));
117462306a36Sopenharmony_ci	/* Mark the link as down only if current media is TP */
117562306a36Sopenharmony_ci	if (netif_carrier_ok(de->dev) && de->media_type != DE_MEDIA_AUI &&
117662306a36Sopenharmony_ci	    de->media_type != DE_MEDIA_BNC) {
117762306a36Sopenharmony_ci		de_link_down(de);
117862306a36Sopenharmony_ci		mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic int de_reset_mac (struct de_private *de)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci	u32 status, tmp;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/*
118762306a36Sopenharmony_ci	 * Reset MAC.  de4x5.c and tulip.c examined for "advice"
118862306a36Sopenharmony_ci	 * in this area.
118962306a36Sopenharmony_ci	 */
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (dr32(BusMode) == 0xffffffff)
119262306a36Sopenharmony_ci		return -EBUSY;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
119562306a36Sopenharmony_ci	dw32 (BusMode, CmdReset);
119662306a36Sopenharmony_ci	mdelay (1);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	dw32 (BusMode, de_bus_mode);
119962306a36Sopenharmony_ci	mdelay (1);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	for (tmp = 0; tmp < 5; tmp++) {
120262306a36Sopenharmony_ci		dr32 (BusMode);
120362306a36Sopenharmony_ci		mdelay (1);
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	mdelay (1);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	status = dr32(MacStatus);
120962306a36Sopenharmony_ci	if (status & (RxState | TxState))
121062306a36Sopenharmony_ci		return -EBUSY;
121162306a36Sopenharmony_ci	if (status == 0xffffffff)
121262306a36Sopenharmony_ci		return -ENODEV;
121362306a36Sopenharmony_ci	return 0;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic void de_adapter_wake (struct de_private *de)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	u32 pmctl;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if (de->de21040)
122162306a36Sopenharmony_ci		return;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
122462306a36Sopenharmony_ci	if (pmctl & PM_Mask) {
122562306a36Sopenharmony_ci		pmctl &= ~PM_Mask;
122662306a36Sopenharmony_ci		pci_write_config_dword(de->pdev, PCIPM, pmctl);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		/* de4x5.c delays, so we do too */
122962306a36Sopenharmony_ci		msleep(10);
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic void de_adapter_sleep (struct de_private *de)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	u32 pmctl;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (de->de21040)
123862306a36Sopenharmony_ci		return;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	dw32(CSR13, 0); /* Reset phy */
124162306a36Sopenharmony_ci	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
124262306a36Sopenharmony_ci	pmctl |= PM_Sleep;
124362306a36Sopenharmony_ci	pci_write_config_dword(de->pdev, PCIPM, pmctl);
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic int de_init_hw (struct de_private *de)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	struct net_device *dev = de->dev;
124962306a36Sopenharmony_ci	u32 macmode;
125062306a36Sopenharmony_ci	int rc;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	de_adapter_wake(de);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	macmode = dr32(MacMode) & ~MacModeClear;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	rc = de_reset_mac(de);
125762306a36Sopenharmony_ci	if (rc)
125862306a36Sopenharmony_ci		return rc;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	de_set_media(de); /* reset phy */
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	dw32(RxRingAddr, de->ring_dma);
126362306a36Sopenharmony_ci	dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	dw32(MacMode, RxTx | macmode);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	dr32(RxMissed); /* self-clearing */
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	dw32(IntrMask, de_intr_mask);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	de_set_rx_mode(dev);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	return 0;
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cistatic int de_refill_rx (struct de_private *de)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	unsigned i;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	for (i = 0; i < DE_RX_RING_SIZE; i++) {
128162306a36Sopenharmony_ci		struct sk_buff *skb;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		skb = netdev_alloc_skb(de->dev, de->rx_buf_sz);
128462306a36Sopenharmony_ci		if (!skb)
128562306a36Sopenharmony_ci			goto err_out;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		de->rx_skb[i].mapping = dma_map_single(&de->pdev->dev,
128862306a36Sopenharmony_ci						       skb->data,
128962306a36Sopenharmony_ci						       de->rx_buf_sz,
129062306a36Sopenharmony_ci						       DMA_FROM_DEVICE);
129162306a36Sopenharmony_ci		de->rx_skb[i].skb = skb;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci		de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
129462306a36Sopenharmony_ci		if (i == (DE_RX_RING_SIZE - 1))
129562306a36Sopenharmony_ci			de->rx_ring[i].opts2 =
129662306a36Sopenharmony_ci				cpu_to_le32(RingEnd | de->rx_buf_sz);
129762306a36Sopenharmony_ci		else
129862306a36Sopenharmony_ci			de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz);
129962306a36Sopenharmony_ci		de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping);
130062306a36Sopenharmony_ci		de->rx_ring[i].addr2 = 0;
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	return 0;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cierr_out:
130662306a36Sopenharmony_ci	de_clean_rings(de);
130762306a36Sopenharmony_ci	return -ENOMEM;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic int de_init_rings (struct de_private *de)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
131362306a36Sopenharmony_ci	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	de->rx_tail = 0;
131662306a36Sopenharmony_ci	de->tx_head = de->tx_tail = 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return de_refill_rx (de);
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic int de_alloc_rings (struct de_private *de)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	de->rx_ring = dma_alloc_coherent(&de->pdev->dev, DE_RING_BYTES,
132462306a36Sopenharmony_ci					 &de->ring_dma, GFP_KERNEL);
132562306a36Sopenharmony_ci	if (!de->rx_ring)
132662306a36Sopenharmony_ci		return -ENOMEM;
132762306a36Sopenharmony_ci	de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE];
132862306a36Sopenharmony_ci	return de_init_rings(de);
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic void de_clean_rings (struct de_private *de)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	unsigned i;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE);
133662306a36Sopenharmony_ci	de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
133762306a36Sopenharmony_ci	wmb();
133862306a36Sopenharmony_ci	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
133962306a36Sopenharmony_ci	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
134062306a36Sopenharmony_ci	wmb();
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	for (i = 0; i < DE_RX_RING_SIZE; i++) {
134362306a36Sopenharmony_ci		if (de->rx_skb[i].skb) {
134462306a36Sopenharmony_ci			dma_unmap_single(&de->pdev->dev,
134562306a36Sopenharmony_ci					 de->rx_skb[i].mapping, de->rx_buf_sz,
134662306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
134762306a36Sopenharmony_ci			dev_kfree_skb(de->rx_skb[i].skb);
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	for (i = 0; i < DE_TX_RING_SIZE; i++) {
135262306a36Sopenharmony_ci		struct sk_buff *skb = de->tx_skb[i].skb;
135362306a36Sopenharmony_ci		if ((skb) && (skb != DE_DUMMY_SKB)) {
135462306a36Sopenharmony_ci			if (skb != DE_SETUP_SKB) {
135562306a36Sopenharmony_ci				de->dev->stats.tx_dropped++;
135662306a36Sopenharmony_ci				dma_unmap_single(&de->pdev->dev,
135762306a36Sopenharmony_ci						 de->tx_skb[i].mapping,
135862306a36Sopenharmony_ci						 skb->len, DMA_TO_DEVICE);
135962306a36Sopenharmony_ci				dev_kfree_skb(skb);
136062306a36Sopenharmony_ci			} else {
136162306a36Sopenharmony_ci				dma_unmap_single(&de->pdev->dev,
136262306a36Sopenharmony_ci						 de->tx_skb[i].mapping,
136362306a36Sopenharmony_ci						 sizeof(de->setup_frame),
136462306a36Sopenharmony_ci						 DMA_TO_DEVICE);
136562306a36Sopenharmony_ci			}
136662306a36Sopenharmony_ci		}
136762306a36Sopenharmony_ci	}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE);
137062306a36Sopenharmony_ci	memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE);
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cistatic void de_free_rings (struct de_private *de)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	de_clean_rings(de);
137662306a36Sopenharmony_ci	dma_free_coherent(&de->pdev->dev, DE_RING_BYTES, de->rx_ring,
137762306a36Sopenharmony_ci			  de->ring_dma);
137862306a36Sopenharmony_ci	de->rx_ring = NULL;
137962306a36Sopenharmony_ci	de->tx_ring = NULL;
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic int de_open (struct net_device *dev)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
138562306a36Sopenharmony_ci	const int irq = de->pdev->irq;
138662306a36Sopenharmony_ci	int rc;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	netif_dbg(de, ifup, dev, "enabling interface\n");
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	rc = de_alloc_rings(de);
139362306a36Sopenharmony_ci	if (rc) {
139462306a36Sopenharmony_ci		netdev_err(dev, "ring allocation failure, err=%d\n", rc);
139562306a36Sopenharmony_ci		return rc;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	dw32(IntrMask, 0);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	rc = request_irq(irq, de_interrupt, IRQF_SHARED, dev->name, dev);
140162306a36Sopenharmony_ci	if (rc) {
140262306a36Sopenharmony_ci		netdev_err(dev, "IRQ %d request failure, err=%d\n", irq, rc);
140362306a36Sopenharmony_ci		goto err_out_free;
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	rc = de_init_hw(de);
140762306a36Sopenharmony_ci	if (rc) {
140862306a36Sopenharmony_ci		netdev_err(dev, "h/w init failure, err=%d\n", rc);
140962306a36Sopenharmony_ci		goto err_out_free_irq;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	netif_start_queue(dev);
141362306a36Sopenharmony_ci	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	return 0;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cierr_out_free_irq:
141862306a36Sopenharmony_ci	free_irq(irq, dev);
141962306a36Sopenharmony_cierr_out_free:
142062306a36Sopenharmony_ci	de_free_rings(de);
142162306a36Sopenharmony_ci	return rc;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic int de_close (struct net_device *dev)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
142762306a36Sopenharmony_ci	unsigned long flags;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	netif_dbg(de, ifdown, dev, "disabling interface\n");
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	del_timer_sync(&de->media_timer);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	spin_lock_irqsave(&de->lock, flags);
143462306a36Sopenharmony_ci	de_stop_hw(de);
143562306a36Sopenharmony_ci	netif_stop_queue(dev);
143662306a36Sopenharmony_ci	netif_carrier_off(dev);
143762306a36Sopenharmony_ci	spin_unlock_irqrestore(&de->lock, flags);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	free_irq(de->pdev->irq, dev);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	de_free_rings(de);
144262306a36Sopenharmony_ci	de_adapter_sleep(de);
144362306a36Sopenharmony_ci	return 0;
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic void de_tx_timeout (struct net_device *dev, unsigned int txqueue)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
144962306a36Sopenharmony_ci	const int irq = de->pdev->irq;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
145262306a36Sopenharmony_ci		   dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
145362306a36Sopenharmony_ci		   de->rx_tail, de->tx_head, de->tx_tail);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	del_timer_sync(&de->media_timer);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	disable_irq(irq);
145862306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	de_stop_hw(de);
146162306a36Sopenharmony_ci	netif_stop_queue(dev);
146262306a36Sopenharmony_ci	netif_carrier_off(dev);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
146562306a36Sopenharmony_ci	enable_irq(irq);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/* Update the error counts. */
146862306a36Sopenharmony_ci	__de_get_stats(de);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	synchronize_irq(irq);
147162306a36Sopenharmony_ci	de_clean_rings(de);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	de_init_rings(de);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	de_init_hw(de);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	netif_wake_queue(dev);
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cistatic void __de_get_regs(struct de_private *de, u8 *buf)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	int i;
148362306a36Sopenharmony_ci	u32 *rbuf = (u32 *)buf;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	/* read all CSRs */
148662306a36Sopenharmony_ci	for (i = 0; i < DE_NUM_REGS; i++)
148762306a36Sopenharmony_ci		rbuf[i] = dr32(i * 8);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	/* handle self-clearing RxMissed counter, CSR8 */
149062306a36Sopenharmony_ci	de_rx_missed(de, rbuf[8]);
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic void __de_get_link_ksettings(struct de_private *de,
149462306a36Sopenharmony_ci				    struct ethtool_link_ksettings *cmd)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
149762306a36Sopenharmony_ci						de->media_supported);
149862306a36Sopenharmony_ci	cmd->base.phy_address = 0;
149962306a36Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
150062306a36Sopenharmony_ci						de->media_advertise);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	switch (de->media_type) {
150362306a36Sopenharmony_ci	case DE_MEDIA_AUI:
150462306a36Sopenharmony_ci		cmd->base.port = PORT_AUI;
150562306a36Sopenharmony_ci		break;
150662306a36Sopenharmony_ci	case DE_MEDIA_BNC:
150762306a36Sopenharmony_ci		cmd->base.port = PORT_BNC;
150862306a36Sopenharmony_ci		break;
150962306a36Sopenharmony_ci	default:
151062306a36Sopenharmony_ci		cmd->base.port = PORT_TP;
151162306a36Sopenharmony_ci		break;
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	cmd->base.speed = 10;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	if (dr32(MacMode) & FullDuplex)
151762306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_FULL;
151862306a36Sopenharmony_ci	else
151962306a36Sopenharmony_ci		cmd->base.duplex = DUPLEX_HALF;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	if (de->media_lock)
152262306a36Sopenharmony_ci		cmd->base.autoneg = AUTONEG_DISABLE;
152362306a36Sopenharmony_ci	else
152462306a36Sopenharmony_ci		cmd->base.autoneg = AUTONEG_ENABLE;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* ignore maxtxpkt, maxrxpkt for now */
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic int __de_set_link_ksettings(struct de_private *de,
153062306a36Sopenharmony_ci				   const struct ethtool_link_ksettings *cmd)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	u32 new_media;
153362306a36Sopenharmony_ci	unsigned int media_lock;
153462306a36Sopenharmony_ci	u8 duplex = cmd->base.duplex;
153562306a36Sopenharmony_ci	u8 port = cmd->base.port;
153662306a36Sopenharmony_ci	u8 autoneg = cmd->base.autoneg;
153762306a36Sopenharmony_ci	u32 advertising;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	ethtool_convert_link_mode_to_legacy_u32(&advertising,
154062306a36Sopenharmony_ci						cmd->link_modes.advertising);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (cmd->base.speed != 10)
154362306a36Sopenharmony_ci		return -EINVAL;
154462306a36Sopenharmony_ci	if (duplex != DUPLEX_HALF && duplex != DUPLEX_FULL)
154562306a36Sopenharmony_ci		return -EINVAL;
154662306a36Sopenharmony_ci	if (port != PORT_TP && port != PORT_AUI && port != PORT_BNC)
154762306a36Sopenharmony_ci		return -EINVAL;
154862306a36Sopenharmony_ci	if (de->de21040 && port == PORT_BNC)
154962306a36Sopenharmony_ci		return -EINVAL;
155062306a36Sopenharmony_ci	if (autoneg != AUTONEG_DISABLE && autoneg != AUTONEG_ENABLE)
155162306a36Sopenharmony_ci		return -EINVAL;
155262306a36Sopenharmony_ci	if (advertising & ~de->media_supported)
155362306a36Sopenharmony_ci		return -EINVAL;
155462306a36Sopenharmony_ci	if (autoneg == AUTONEG_ENABLE &&
155562306a36Sopenharmony_ci	    (!(advertising & ADVERTISED_Autoneg)))
155662306a36Sopenharmony_ci		return -EINVAL;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	switch (port) {
155962306a36Sopenharmony_ci	case PORT_AUI:
156062306a36Sopenharmony_ci		new_media = DE_MEDIA_AUI;
156162306a36Sopenharmony_ci		if (!(advertising & ADVERTISED_AUI))
156262306a36Sopenharmony_ci			return -EINVAL;
156362306a36Sopenharmony_ci		break;
156462306a36Sopenharmony_ci	case PORT_BNC:
156562306a36Sopenharmony_ci		new_media = DE_MEDIA_BNC;
156662306a36Sopenharmony_ci		if (!(advertising & ADVERTISED_BNC))
156762306a36Sopenharmony_ci			return -EINVAL;
156862306a36Sopenharmony_ci		break;
156962306a36Sopenharmony_ci	default:
157062306a36Sopenharmony_ci		if (autoneg == AUTONEG_ENABLE)
157162306a36Sopenharmony_ci			new_media = DE_MEDIA_TP_AUTO;
157262306a36Sopenharmony_ci		else if (duplex == DUPLEX_FULL)
157362306a36Sopenharmony_ci			new_media = DE_MEDIA_TP_FD;
157462306a36Sopenharmony_ci		else
157562306a36Sopenharmony_ci			new_media = DE_MEDIA_TP;
157662306a36Sopenharmony_ci		if (!(advertising & ADVERTISED_TP))
157762306a36Sopenharmony_ci			return -EINVAL;
157862306a36Sopenharmony_ci		if (!(advertising & (ADVERTISED_10baseT_Full |
157962306a36Sopenharmony_ci				     ADVERTISED_10baseT_Half)))
158062306a36Sopenharmony_ci			return -EINVAL;
158162306a36Sopenharmony_ci		break;
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	media_lock = (autoneg == AUTONEG_ENABLE) ? 0 : 1;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	if ((new_media == de->media_type) &&
158762306a36Sopenharmony_ci	    (media_lock == de->media_lock) &&
158862306a36Sopenharmony_ci	    (advertising == de->media_advertise))
158962306a36Sopenharmony_ci		return 0; /* nothing to change */
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	de_link_down(de);
159262306a36Sopenharmony_ci	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
159362306a36Sopenharmony_ci	de_stop_rxtx(de);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	de->media_type = new_media;
159662306a36Sopenharmony_ci	de->media_lock = media_lock;
159762306a36Sopenharmony_ci	de->media_advertise = advertising;
159862306a36Sopenharmony_ci	de_set_media(de);
159962306a36Sopenharmony_ci	if (netif_running(de->dev))
160062306a36Sopenharmony_ci		de_start_rxtx(de);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	return 0;
160362306a36Sopenharmony_ci}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_cistatic void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
161062306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_cistatic int de_get_regs_len(struct net_device *dev)
161462306a36Sopenharmony_ci{
161562306a36Sopenharmony_ci	return DE_REGS_SIZE;
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_cistatic int de_get_link_ksettings(struct net_device *dev,
161962306a36Sopenharmony_ci				 struct ethtool_link_ksettings *cmd)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
162462306a36Sopenharmony_ci	__de_get_link_ksettings(de, cmd);
162562306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	return 0;
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_cistatic int de_set_link_ksettings(struct net_device *dev,
163162306a36Sopenharmony_ci				 const struct ethtool_link_ksettings *cmd)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
163462306a36Sopenharmony_ci	int rc;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
163762306a36Sopenharmony_ci	rc = __de_set_link_ksettings(de, cmd);
163862306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	return rc;
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_cistatic u32 de_get_msglevel(struct net_device *dev)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	return de->msg_enable;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic void de_set_msglevel(struct net_device *dev, u32 msglvl)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	de->msg_enable = msglvl;
165562306a36Sopenharmony_ci}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_cistatic int de_get_eeprom(struct net_device *dev,
165862306a36Sopenharmony_ci			 struct ethtool_eeprom *eeprom, u8 *data)
165962306a36Sopenharmony_ci{
166062306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	if (!de->ee_data)
166362306a36Sopenharmony_ci		return -EOPNOTSUPP;
166462306a36Sopenharmony_ci	if ((eeprom->offset != 0) || (eeprom->magic != 0) ||
166562306a36Sopenharmony_ci	    (eeprom->len != DE_EEPROM_SIZE))
166662306a36Sopenharmony_ci		return -EINVAL;
166762306a36Sopenharmony_ci	memcpy(data, de->ee_data, eeprom->len);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return 0;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cistatic int de_nway_reset(struct net_device *dev)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
167562306a36Sopenharmony_ci	u32 status;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	if (de->media_type != DE_MEDIA_TP_AUTO)
167862306a36Sopenharmony_ci		return -EINVAL;
167962306a36Sopenharmony_ci	if (netif_carrier_ok(de->dev))
168062306a36Sopenharmony_ci		de_link_down(de);
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	status = dr32(SIAStatus);
168362306a36Sopenharmony_ci	dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
168462306a36Sopenharmony_ci	netif_info(de, link, dev, "link nway restart, status %x,%x\n",
168562306a36Sopenharmony_ci		   status, dr32(SIAStatus));
168662306a36Sopenharmony_ci	return 0;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
169062306a36Sopenharmony_ci			void *data)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	regs->version = (DE_REGS_VER << 2) | de->de21040;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	spin_lock_irq(&de->lock);
169762306a36Sopenharmony_ci	__de_get_regs(de, data);
169862306a36Sopenharmony_ci	spin_unlock_irq(&de->lock);
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_cistatic const struct ethtool_ops de_ethtool_ops = {
170262306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
170362306a36Sopenharmony_ci	.get_drvinfo		= de_get_drvinfo,
170462306a36Sopenharmony_ci	.get_regs_len		= de_get_regs_len,
170562306a36Sopenharmony_ci	.get_msglevel		= de_get_msglevel,
170662306a36Sopenharmony_ci	.set_msglevel		= de_set_msglevel,
170762306a36Sopenharmony_ci	.get_eeprom		= de_get_eeprom,
170862306a36Sopenharmony_ci	.nway_reset		= de_nway_reset,
170962306a36Sopenharmony_ci	.get_regs		= de_get_regs,
171062306a36Sopenharmony_ci	.get_link_ksettings	= de_get_link_ksettings,
171162306a36Sopenharmony_ci	.set_link_ksettings	= de_set_link_ksettings,
171262306a36Sopenharmony_ci};
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic void de21040_get_mac_address(struct de_private *de)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	u8 addr[ETH_ALEN];
171762306a36Sopenharmony_ci	unsigned i;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	dw32 (ROMCmd, 0);	/* Reset the pointer with a dummy write. */
172062306a36Sopenharmony_ci	udelay(5);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
172362306a36Sopenharmony_ci		int value, boguscnt = 100000;
172462306a36Sopenharmony_ci		do {
172562306a36Sopenharmony_ci			value = dr32(ROMCmd);
172662306a36Sopenharmony_ci			rmb();
172762306a36Sopenharmony_ci		} while (value < 0 && --boguscnt > 0);
172862306a36Sopenharmony_ci		addr[i] = value;
172962306a36Sopenharmony_ci		udelay(1);
173062306a36Sopenharmony_ci		if (boguscnt <= 0)
173162306a36Sopenharmony_ci			pr_warn("timeout reading 21040 MAC address byte %u\n",
173262306a36Sopenharmony_ci				i);
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci	eth_hw_addr_set(de->dev, addr);
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic void de21040_get_media_info(struct de_private *de)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	unsigned int i;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	de->media_type = DE_MEDIA_TP;
174262306a36Sopenharmony_ci	de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
174362306a36Sopenharmony_ci			       SUPPORTED_10baseT_Half | SUPPORTED_AUI;
174462306a36Sopenharmony_ci	de->media_advertise = de->media_supported;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	for (i = 0; i < DE_MAX_MEDIA; i++) {
174762306a36Sopenharmony_ci		switch (i) {
174862306a36Sopenharmony_ci		case DE_MEDIA_AUI:
174962306a36Sopenharmony_ci		case DE_MEDIA_TP:
175062306a36Sopenharmony_ci		case DE_MEDIA_TP_FD:
175162306a36Sopenharmony_ci			de->media[i].type = i;
175262306a36Sopenharmony_ci			de->media[i].csr13 = t21040_csr13[i];
175362306a36Sopenharmony_ci			de->media[i].csr14 = t21040_csr14[i];
175462306a36Sopenharmony_ci			de->media[i].csr15 = t21040_csr15[i];
175562306a36Sopenharmony_ci			break;
175662306a36Sopenharmony_ci		default:
175762306a36Sopenharmony_ci			de->media[i].type = DE_MEDIA_INVALID;
175862306a36Sopenharmony_ci			break;
175962306a36Sopenharmony_ci		}
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci/* Note: this routine returns extra data bits for size detection. */
176462306a36Sopenharmony_cistatic unsigned tulip_read_eeprom(void __iomem *regs, int location,
176562306a36Sopenharmony_ci				  int addr_len)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	int i;
176862306a36Sopenharmony_ci	unsigned retval = 0;
176962306a36Sopenharmony_ci	void __iomem *ee_addr = regs + ROMCmd;
177062306a36Sopenharmony_ci	int read_cmd = location | (EE_READ_CMD << addr_len);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	writel(EE_ENB & ~EE_CS, ee_addr);
177362306a36Sopenharmony_ci	writel(EE_ENB, ee_addr);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	/* Shift the read command bits out. */
177662306a36Sopenharmony_ci	for (i = 4 + addr_len; i >= 0; i--) {
177762306a36Sopenharmony_ci		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
177862306a36Sopenharmony_ci		writel(EE_ENB | dataval, ee_addr);
177962306a36Sopenharmony_ci		readl(ee_addr);
178062306a36Sopenharmony_ci		writel(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
178162306a36Sopenharmony_ci		readl(ee_addr);
178262306a36Sopenharmony_ci		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	writel(EE_ENB, ee_addr);
178562306a36Sopenharmony_ci	readl(ee_addr);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	for (i = 16; i > 0; i--) {
178862306a36Sopenharmony_ci		writel(EE_ENB | EE_SHIFT_CLK, ee_addr);
178962306a36Sopenharmony_ci		readl(ee_addr);
179062306a36Sopenharmony_ci		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
179162306a36Sopenharmony_ci		writel(EE_ENB, ee_addr);
179262306a36Sopenharmony_ci		readl(ee_addr);
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* Terminate the EEPROM access. */
179662306a36Sopenharmony_ci	writel(EE_ENB & ~EE_CS, ee_addr);
179762306a36Sopenharmony_ci	return retval;
179862306a36Sopenharmony_ci}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_cistatic void de21041_get_srom_info(struct de_private *de)
180162306a36Sopenharmony_ci{
180262306a36Sopenharmony_ci	unsigned i, sa_offset = 0, ofs;
180362306a36Sopenharmony_ci	u8 ee_data[DE_EEPROM_SIZE + 6] = {};
180462306a36Sopenharmony_ci	unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
180562306a36Sopenharmony_ci	struct de_srom_info_leaf *il;
180662306a36Sopenharmony_ci	void *bufp;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* download entire eeprom */
180962306a36Sopenharmony_ci	for (i = 0; i < DE_EEPROM_WORDS; i++)
181062306a36Sopenharmony_ci		((__le16 *)ee_data)[i] =
181162306a36Sopenharmony_ci			cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size));
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	/* DEC now has a specification but early board makers
181462306a36Sopenharmony_ci	   just put the address in the first EEPROM locations. */
181562306a36Sopenharmony_ci	/* This does  memcmp(eedata, eedata+16, 8) */
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci#ifndef CONFIG_MIPS_COBALT
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	for (i = 0; i < 8; i ++)
182062306a36Sopenharmony_ci		if (ee_data[i] != ee_data[16+i])
182162306a36Sopenharmony_ci			sa_offset = 20;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci#endif
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	/* store MAC address */
182662306a36Sopenharmony_ci	eth_hw_addr_set(de->dev, &ee_data[sa_offset]);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	/* get offset of controller 0 info leaf.  ignore 2nd byte. */
182962306a36Sopenharmony_ci	ofs = ee_data[SROMC0InfoLeaf];
183062306a36Sopenharmony_ci	if (ofs >= (sizeof(ee_data) - sizeof(struct de_srom_info_leaf) - sizeof(struct de_srom_media_block)))
183162306a36Sopenharmony_ci		goto bad_srom;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	/* get pointer to info leaf */
183462306a36Sopenharmony_ci	il = (struct de_srom_info_leaf *) &ee_data[ofs];
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	/* paranoia checks */
183762306a36Sopenharmony_ci	if (il->n_blocks == 0)
183862306a36Sopenharmony_ci		goto bad_srom;
183962306a36Sopenharmony_ci	if ((sizeof(ee_data) - ofs) <
184062306a36Sopenharmony_ci	    (sizeof(struct de_srom_info_leaf) + (sizeof(struct de_srom_media_block) * il->n_blocks)))
184162306a36Sopenharmony_ci		goto bad_srom;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	/* get default media type */
184462306a36Sopenharmony_ci	switch (get_unaligned(&il->default_media)) {
184562306a36Sopenharmony_ci	case 0x0001:  de->media_type = DE_MEDIA_BNC; break;
184662306a36Sopenharmony_ci	case 0x0002:  de->media_type = DE_MEDIA_AUI; break;
184762306a36Sopenharmony_ci	case 0x0204:  de->media_type = DE_MEDIA_TP_FD; break;
184862306a36Sopenharmony_ci	default: de->media_type = DE_MEDIA_TP_AUTO; break;
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	if (netif_msg_probe(de))
185262306a36Sopenharmony_ci		pr_info("de%d: SROM leaf offset %u, default media %s\n",
185362306a36Sopenharmony_ci		       de->board_idx, ofs, media_name[de->media_type]);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	/* init SIA register values to defaults */
185662306a36Sopenharmony_ci	for (i = 0; i < DE_MAX_MEDIA; i++) {
185762306a36Sopenharmony_ci		de->media[i].type = DE_MEDIA_INVALID;
185862306a36Sopenharmony_ci		de->media[i].csr13 = 0xffff;
185962306a36Sopenharmony_ci		de->media[i].csr14 = 0xffff;
186062306a36Sopenharmony_ci		de->media[i].csr15 = 0xffff;
186162306a36Sopenharmony_ci	}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/* parse media blocks to see what medias are supported,
186462306a36Sopenharmony_ci	 * and if any custom CSR values are provided
186562306a36Sopenharmony_ci	 */
186662306a36Sopenharmony_ci	bufp = ((void *)il) + sizeof(*il);
186762306a36Sopenharmony_ci	for (i = 0; i < il->n_blocks; i++) {
186862306a36Sopenharmony_ci		struct de_srom_media_block *ib = bufp;
186962306a36Sopenharmony_ci		unsigned idx;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci		/* index based on media type in media block */
187262306a36Sopenharmony_ci		switch(ib->opts & MediaBlockMask) {
187362306a36Sopenharmony_ci		case 0: /* 10baseT */
187462306a36Sopenharmony_ci			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half
187562306a36Sopenharmony_ci					  | SUPPORTED_Autoneg;
187662306a36Sopenharmony_ci			idx = DE_MEDIA_TP;
187762306a36Sopenharmony_ci			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
187862306a36Sopenharmony_ci			break;
187962306a36Sopenharmony_ci		case 1: /* BNC */
188062306a36Sopenharmony_ci			de->media_supported |= SUPPORTED_BNC;
188162306a36Sopenharmony_ci			idx = DE_MEDIA_BNC;
188262306a36Sopenharmony_ci			break;
188362306a36Sopenharmony_ci		case 2: /* AUI */
188462306a36Sopenharmony_ci			de->media_supported |= SUPPORTED_AUI;
188562306a36Sopenharmony_ci			idx = DE_MEDIA_AUI;
188662306a36Sopenharmony_ci			break;
188762306a36Sopenharmony_ci		case 4: /* 10baseT-FD */
188862306a36Sopenharmony_ci			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full
188962306a36Sopenharmony_ci					  | SUPPORTED_Autoneg;
189062306a36Sopenharmony_ci			idx = DE_MEDIA_TP_FD;
189162306a36Sopenharmony_ci			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
189262306a36Sopenharmony_ci			break;
189362306a36Sopenharmony_ci		default:
189462306a36Sopenharmony_ci			goto bad_srom;
189562306a36Sopenharmony_ci		}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci		de->media[idx].type = idx;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		if (netif_msg_probe(de))
190062306a36Sopenharmony_ci			pr_info("de%d:   media block #%u: %s",
190162306a36Sopenharmony_ci				de->board_idx, i,
190262306a36Sopenharmony_ci				media_name[de->media[idx].type]);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci		bufp += sizeof (ib->opts);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		if (ib->opts & MediaCustomCSRs) {
190762306a36Sopenharmony_ci			de->media[idx].csr13 = get_unaligned(&ib->csr13);
190862306a36Sopenharmony_ci			de->media[idx].csr14 = get_unaligned(&ib->csr14);
190962306a36Sopenharmony_ci			de->media[idx].csr15 = get_unaligned(&ib->csr15);
191062306a36Sopenharmony_ci			bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
191162306a36Sopenharmony_ci				sizeof(ib->csr15);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci			if (netif_msg_probe(de))
191462306a36Sopenharmony_ci				pr_cont(" (%x,%x,%x)\n",
191562306a36Sopenharmony_ci					de->media[idx].csr13,
191662306a36Sopenharmony_ci					de->media[idx].csr14,
191762306a36Sopenharmony_ci					de->media[idx].csr15);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci		} else {
192062306a36Sopenharmony_ci			if (netif_msg_probe(de))
192162306a36Sopenharmony_ci				pr_cont("\n");
192262306a36Sopenharmony_ci		}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
192562306a36Sopenharmony_ci			break;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	de->media_advertise = de->media_supported;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_cifill_defaults:
193162306a36Sopenharmony_ci	/* fill in defaults, for cases where custom CSRs not used */
193262306a36Sopenharmony_ci	for (i = 0; i < DE_MAX_MEDIA; i++) {
193362306a36Sopenharmony_ci		if (de->media[i].csr13 == 0xffff)
193462306a36Sopenharmony_ci			de->media[i].csr13 = t21041_csr13[i];
193562306a36Sopenharmony_ci		if (de->media[i].csr14 == 0xffff) {
193662306a36Sopenharmony_ci			/* autonegotiation is broken at least on some chip
193762306a36Sopenharmony_ci			   revisions - rev. 0x21 works, 0x11 does not */
193862306a36Sopenharmony_ci			if (de->pdev->revision < 0x20)
193962306a36Sopenharmony_ci				de->media[i].csr14 = t21041_csr14_brk[i];
194062306a36Sopenharmony_ci			else
194162306a36Sopenharmony_ci				de->media[i].csr14 = t21041_csr14[i];
194262306a36Sopenharmony_ci		}
194362306a36Sopenharmony_ci		if (de->media[i].csr15 == 0xffff)
194462306a36Sopenharmony_ci			de->media[i].csr15 = t21041_csr15[i];
194562306a36Sopenharmony_ci	}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	de->ee_data = kmemdup(&ee_data[0], DE_EEPROM_SIZE, GFP_KERNEL);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	return;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_cibad_srom:
195262306a36Sopenharmony_ci	/* for error cases, it's ok to assume we support all these */
195362306a36Sopenharmony_ci	for (i = 0; i < DE_MAX_MEDIA; i++)
195462306a36Sopenharmony_ci		de->media[i].type = i;
195562306a36Sopenharmony_ci	de->media_supported =
195662306a36Sopenharmony_ci		SUPPORTED_10baseT_Half |
195762306a36Sopenharmony_ci		SUPPORTED_10baseT_Full |
195862306a36Sopenharmony_ci		SUPPORTED_Autoneg |
195962306a36Sopenharmony_ci		SUPPORTED_TP |
196062306a36Sopenharmony_ci		SUPPORTED_AUI |
196162306a36Sopenharmony_ci		SUPPORTED_BNC;
196262306a36Sopenharmony_ci	goto fill_defaults;
196362306a36Sopenharmony_ci}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_cistatic const struct net_device_ops de_netdev_ops = {
196662306a36Sopenharmony_ci	.ndo_open		= de_open,
196762306a36Sopenharmony_ci	.ndo_stop		= de_close,
196862306a36Sopenharmony_ci	.ndo_set_rx_mode	= de_set_rx_mode,
196962306a36Sopenharmony_ci	.ndo_start_xmit		= de_start_xmit,
197062306a36Sopenharmony_ci	.ndo_get_stats		= de_get_stats,
197162306a36Sopenharmony_ci	.ndo_tx_timeout 	= de_tx_timeout,
197262306a36Sopenharmony_ci	.ndo_set_mac_address 	= eth_mac_addr,
197362306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
197462306a36Sopenharmony_ci};
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_cistatic int de_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	struct net_device *dev;
197962306a36Sopenharmony_ci	struct de_private *de;
198062306a36Sopenharmony_ci	int rc;
198162306a36Sopenharmony_ci	void __iomem *regs;
198262306a36Sopenharmony_ci	unsigned long pciaddr;
198362306a36Sopenharmony_ci	static int board_idx = -1;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	board_idx++;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	/* allocate a new ethernet device structure, and fill in defaults */
198862306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct de_private));
198962306a36Sopenharmony_ci	if (!dev)
199062306a36Sopenharmony_ci		return -ENOMEM;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	dev->netdev_ops = &de_netdev_ops;
199362306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
199462306a36Sopenharmony_ci	dev->ethtool_ops = &de_ethtool_ops;
199562306a36Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	de = netdev_priv(dev);
199862306a36Sopenharmony_ci	de->de21040 = ent->driver_data == 0 ? 1 : 0;
199962306a36Sopenharmony_ci	de->pdev = pdev;
200062306a36Sopenharmony_ci	de->dev = dev;
200162306a36Sopenharmony_ci	de->msg_enable = (debug < 0 ? DE_DEF_MSG_ENABLE : debug);
200262306a36Sopenharmony_ci	de->board_idx = board_idx;
200362306a36Sopenharmony_ci	spin_lock_init (&de->lock);
200462306a36Sopenharmony_ci	timer_setup(&de->media_timer,
200562306a36Sopenharmony_ci		    de->de21040 ? de21040_media_timer : de21041_media_timer,
200662306a36Sopenharmony_ci		    0);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	netif_carrier_off(dev);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	/* wake up device, assign resources */
201162306a36Sopenharmony_ci	rc = pci_enable_device(pdev);
201262306a36Sopenharmony_ci	if (rc)
201362306a36Sopenharmony_ci		goto err_out_free;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* reserve PCI resources to ensure driver atomicity */
201662306a36Sopenharmony_ci	rc = pci_request_regions(pdev, DRV_NAME);
201762306a36Sopenharmony_ci	if (rc)
201862306a36Sopenharmony_ci		goto err_out_disable;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	/* check for invalid IRQ value */
202162306a36Sopenharmony_ci	if (pdev->irq < 2) {
202262306a36Sopenharmony_ci		rc = -EIO;
202362306a36Sopenharmony_ci		pr_err("invalid irq (%d) for pci dev %s\n",
202462306a36Sopenharmony_ci		       pdev->irq, pci_name(pdev));
202562306a36Sopenharmony_ci		goto err_out_res;
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	/* obtain and check validity of PCI I/O address */
202962306a36Sopenharmony_ci	pciaddr = pci_resource_start(pdev, 1);
203062306a36Sopenharmony_ci	if (!pciaddr) {
203162306a36Sopenharmony_ci		rc = -EIO;
203262306a36Sopenharmony_ci		pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev));
203362306a36Sopenharmony_ci		goto err_out_res;
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci	if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
203662306a36Sopenharmony_ci		rc = -EIO;
203762306a36Sopenharmony_ci		pr_err("MMIO resource (%llx) too small on pci dev %s\n",
203862306a36Sopenharmony_ci		       (unsigned long long)pci_resource_len(pdev, 1),
203962306a36Sopenharmony_ci		       pci_name(pdev));
204062306a36Sopenharmony_ci		goto err_out_res;
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/* remap CSR registers */
204462306a36Sopenharmony_ci	regs = ioremap(pciaddr, DE_REGS_SIZE);
204562306a36Sopenharmony_ci	if (!regs) {
204662306a36Sopenharmony_ci		rc = -EIO;
204762306a36Sopenharmony_ci		pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
204862306a36Sopenharmony_ci		       (unsigned long long)pci_resource_len(pdev, 1),
204962306a36Sopenharmony_ci		       pciaddr, pci_name(pdev));
205062306a36Sopenharmony_ci		goto err_out_res;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci	de->regs = regs;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	de_adapter_wake(de);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* make sure hardware is not running */
205762306a36Sopenharmony_ci	rc = de_reset_mac(de);
205862306a36Sopenharmony_ci	if (rc) {
205962306a36Sopenharmony_ci		pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev));
206062306a36Sopenharmony_ci		goto err_out_iomap;
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	/* get MAC address, initialize default media type and
206462306a36Sopenharmony_ci	 * get list of supported media
206562306a36Sopenharmony_ci	 */
206662306a36Sopenharmony_ci	if (de->de21040) {
206762306a36Sopenharmony_ci		de21040_get_mac_address(de);
206862306a36Sopenharmony_ci		de21040_get_media_info(de);
206962306a36Sopenharmony_ci	} else {
207062306a36Sopenharmony_ci		de21041_get_srom_info(de);
207162306a36Sopenharmony_ci	}
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	/* register new network interface with kernel */
207462306a36Sopenharmony_ci	rc = register_netdev(dev);
207562306a36Sopenharmony_ci	if (rc)
207662306a36Sopenharmony_ci		goto err_out_iomap;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	/* print info about board and interface just registered */
207962306a36Sopenharmony_ci	netdev_info(dev, "%s at %p, %pM, IRQ %d\n",
208062306a36Sopenharmony_ci		    de->de21040 ? "21040" : "21041",
208162306a36Sopenharmony_ci		    regs, dev->dev_addr, pdev->irq);
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	/* enable busmastering */
208662306a36Sopenharmony_ci	pci_set_master(pdev);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	/* put adapter to sleep */
208962306a36Sopenharmony_ci	de_adapter_sleep(de);
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	return 0;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_cierr_out_iomap:
209462306a36Sopenharmony_ci	kfree(de->ee_data);
209562306a36Sopenharmony_ci	iounmap(regs);
209662306a36Sopenharmony_cierr_out_res:
209762306a36Sopenharmony_ci	pci_release_regions(pdev);
209862306a36Sopenharmony_cierr_out_disable:
209962306a36Sopenharmony_ci	pci_disable_device(pdev);
210062306a36Sopenharmony_cierr_out_free:
210162306a36Sopenharmony_ci	free_netdev(dev);
210262306a36Sopenharmony_ci	return rc;
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_cistatic void de_remove_one(struct pci_dev *pdev)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
210862306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	BUG_ON(!dev);
211162306a36Sopenharmony_ci	unregister_netdev(dev);
211262306a36Sopenharmony_ci	kfree(de->ee_data);
211362306a36Sopenharmony_ci	iounmap(de->regs);
211462306a36Sopenharmony_ci	pci_release_regions(pdev);
211562306a36Sopenharmony_ci	pci_disable_device(pdev);
211662306a36Sopenharmony_ci	free_netdev(dev);
211762306a36Sopenharmony_ci}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_cistatic int __maybe_unused de_suspend(struct device *dev_d)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev_d);
212262306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
212362306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	rtnl_lock();
212662306a36Sopenharmony_ci	if (netif_running (dev)) {
212762306a36Sopenharmony_ci		const int irq = pdev->irq;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci		del_timer_sync(&de->media_timer);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		disable_irq(irq);
213262306a36Sopenharmony_ci		spin_lock_irq(&de->lock);
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci		de_stop_hw(de);
213562306a36Sopenharmony_ci		netif_stop_queue(dev);
213662306a36Sopenharmony_ci		netif_device_detach(dev);
213762306a36Sopenharmony_ci		netif_carrier_off(dev);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci		spin_unlock_irq(&de->lock);
214062306a36Sopenharmony_ci		enable_irq(irq);
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci		/* Update the error counts. */
214362306a36Sopenharmony_ci		__de_get_stats(de);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci		synchronize_irq(irq);
214662306a36Sopenharmony_ci		de_clean_rings(de);
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci		de_adapter_sleep(de);
214962306a36Sopenharmony_ci	} else {
215062306a36Sopenharmony_ci		netif_device_detach(dev);
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci	rtnl_unlock();
215362306a36Sopenharmony_ci	return 0;
215462306a36Sopenharmony_ci}
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_cistatic int __maybe_unused de_resume(struct device *dev_d)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev_d);
215962306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
216062306a36Sopenharmony_ci	struct de_private *de = netdev_priv(dev);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	rtnl_lock();
216362306a36Sopenharmony_ci	if (netif_device_present(dev))
216462306a36Sopenharmony_ci		goto out;
216562306a36Sopenharmony_ci	if (!netif_running(dev))
216662306a36Sopenharmony_ci		goto out_attach;
216762306a36Sopenharmony_ci	pci_set_master(pdev);
216862306a36Sopenharmony_ci	de_init_rings(de);
216962306a36Sopenharmony_ci	de_init_hw(de);
217062306a36Sopenharmony_ciout_attach:
217162306a36Sopenharmony_ci	netif_device_attach(dev);
217262306a36Sopenharmony_ciout:
217362306a36Sopenharmony_ci	rtnl_unlock();
217462306a36Sopenharmony_ci	return 0;
217562306a36Sopenharmony_ci}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(de_pm_ops, de_suspend, de_resume);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic void de_shutdown(struct pci_dev *pdev)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	rtnl_lock();
218462306a36Sopenharmony_ci	dev_close(dev);
218562306a36Sopenharmony_ci	rtnl_unlock();
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic struct pci_driver de_driver = {
218962306a36Sopenharmony_ci	.name		= DRV_NAME,
219062306a36Sopenharmony_ci	.id_table	= de_pci_tbl,
219162306a36Sopenharmony_ci	.probe		= de_init_one,
219262306a36Sopenharmony_ci	.remove		= de_remove_one,
219362306a36Sopenharmony_ci	.shutdown	= de_shutdown,
219462306a36Sopenharmony_ci	.driver.pm	= &de_pm_ops,
219562306a36Sopenharmony_ci};
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cimodule_pci_driver(de_driver);
2198