162306a36Sopenharmony_ci/* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Copyright 2001-2004 Jeff Garzik <jgarzik@pobox.com>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
662306a36Sopenharmony_ci	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
762306a36Sopenharmony_ci	Copyright 2001 Manfred Spraul				    [natsemi.c]
862306a36Sopenharmony_ci	Copyright 1999-2001 by Donald Becker.			    [natsemi.c]
962306a36Sopenharmony_ci	Written 1997-2001 by Donald Becker.			    [8139too.c]
1062306a36Sopenharmony_ci	Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. [acenic.c]
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci	This software may be used and distributed according to the terms of
1362306a36Sopenharmony_ci	the GNU General Public License (GPL), incorporated herein by reference.
1462306a36Sopenharmony_ci	Drivers based on or derived from this code fall under the GPL and must
1562306a36Sopenharmony_ci	retain the authorship, copyright and license notice.  This file is not
1662306a36Sopenharmony_ci	a complete program and may only be used when the entire operating
1762306a36Sopenharmony_ci	system is licensed under the GPL.
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	See the file COPYING in this distribution for more information.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	Contributors:
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		Wake-on-LAN support - Felipe Damasio <felipewd@terra.com.br>
2462306a36Sopenharmony_ci		PCI suspend/resume  - Felipe Damasio <felipewd@terra.com.br>
2562306a36Sopenharmony_ci		LinkChg interrupt   - Felipe Damasio <felipewd@terra.com.br>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	TODO:
2862306a36Sopenharmony_ci	* Test Tx checksumming thoroughly
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	Low priority TODO:
3162306a36Sopenharmony_ci	* Complete reset on PciErr
3262306a36Sopenharmony_ci	* Consider Rx interrupt mitigation using TimerIntr
3362306a36Sopenharmony_ci	* Investigate using skb->priority with h/w VLAN priority
3462306a36Sopenharmony_ci	* Investigate using High Priority Tx Queue with skb->priority
3562306a36Sopenharmony_ci	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
3662306a36Sopenharmony_ci	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
3762306a36Sopenharmony_ci	* Implement Tx software interrupt mitigation via
3862306a36Sopenharmony_ci	  Tx descriptor bit
3962306a36Sopenharmony_ci	* The real minimum of CP_MIN_MTU is 4 bytes.  However,
4062306a36Sopenharmony_ci	  for this to be supported, one must(?) turn on packet padding.
4162306a36Sopenharmony_ci	* Support external MII transceivers (patch available)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	NOTES:
4462306a36Sopenharmony_ci	* TX checksumming is considered experimental.  It is off by
4562306a36Sopenharmony_ci	  default, use ethtool to turn it on.
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define DRV_NAME		"8139cp"
5262306a36Sopenharmony_ci#define DRV_VERSION		"1.3"
5362306a36Sopenharmony_ci#define DRV_RELDATE		"Mar 22, 2004"
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#include <linux/module.h>
5762306a36Sopenharmony_ci#include <linux/moduleparam.h>
5862306a36Sopenharmony_ci#include <linux/kernel.h>
5962306a36Sopenharmony_ci#include <linux/compiler.h>
6062306a36Sopenharmony_ci#include <linux/netdevice.h>
6162306a36Sopenharmony_ci#include <linux/etherdevice.h>
6262306a36Sopenharmony_ci#include <linux/init.h>
6362306a36Sopenharmony_ci#include <linux/interrupt.h>
6462306a36Sopenharmony_ci#include <linux/pci.h>
6562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
6662306a36Sopenharmony_ci#include <linux/delay.h>
6762306a36Sopenharmony_ci#include <linux/ethtool.h>
6862306a36Sopenharmony_ci#include <linux/gfp.h>
6962306a36Sopenharmony_ci#include <linux/mii.h>
7062306a36Sopenharmony_ci#include <linux/if_vlan.h>
7162306a36Sopenharmony_ci#include <linux/crc32.h>
7262306a36Sopenharmony_ci#include <linux/in.h>
7362306a36Sopenharmony_ci#include <linux/ip.h>
7462306a36Sopenharmony_ci#include <linux/tcp.h>
7562306a36Sopenharmony_ci#include <linux/udp.h>
7662306a36Sopenharmony_ci#include <linux/cache.h>
7762306a36Sopenharmony_ci#include <asm/io.h>
7862306a36Sopenharmony_ci#include <asm/irq.h>
7962306a36Sopenharmony_ci#include <linux/uaccess.h>
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* These identify the driver base version and may not be removed. */
8262306a36Sopenharmony_cistatic char version[] =
8362306a36Sopenharmony_ciDRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
8662306a36Sopenharmony_ciMODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
8762306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
8862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int debug = -1;
9162306a36Sopenharmony_cimodule_param(debug, int, 0);
9262306a36Sopenharmony_ciMODULE_PARM_DESC (debug, "8139cp: bitmapped message enable number");
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
9562306a36Sopenharmony_ci   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
9662306a36Sopenharmony_cistatic int multicast_filter_limit = 32;
9762306a36Sopenharmony_cimodule_param(multicast_filter_limit, int, 0);
9862306a36Sopenharmony_ciMODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered multicast addresses");
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
10162306a36Sopenharmony_ci				 NETIF_MSG_PROBE 	| \
10262306a36Sopenharmony_ci				 NETIF_MSG_LINK)
10362306a36Sopenharmony_ci#define CP_NUM_STATS		14	/* struct cp_dma_stats, plus one */
10462306a36Sopenharmony_ci#define CP_STATS_SIZE		64	/* size in bytes of DMA stats block */
10562306a36Sopenharmony_ci#define CP_REGS_SIZE		(0xff + 1)
10662306a36Sopenharmony_ci#define CP_REGS_VER		1		/* version 1 */
10762306a36Sopenharmony_ci#define CP_RX_RING_SIZE		64
10862306a36Sopenharmony_ci#define CP_TX_RING_SIZE		64
10962306a36Sopenharmony_ci#define CP_RING_BYTES		\
11062306a36Sopenharmony_ci		((sizeof(struct cp_desc) * CP_RX_RING_SIZE) +	\
11162306a36Sopenharmony_ci		 (sizeof(struct cp_desc) * CP_TX_RING_SIZE) +	\
11262306a36Sopenharmony_ci		 CP_STATS_SIZE)
11362306a36Sopenharmony_ci#define NEXT_TX(N)		(((N) + 1) & (CP_TX_RING_SIZE - 1))
11462306a36Sopenharmony_ci#define NEXT_RX(N)		(((N) + 1) & (CP_RX_RING_SIZE - 1))
11562306a36Sopenharmony_ci#define TX_BUFFS_AVAIL(CP)					\
11662306a36Sopenharmony_ci	(((CP)->tx_tail <= (CP)->tx_head) ?			\
11762306a36Sopenharmony_ci	  (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head :	\
11862306a36Sopenharmony_ci	  (CP)->tx_tail - (CP)->tx_head - 1)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
12162306a36Sopenharmony_ci#define CP_INTERNAL_PHY		32
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
12462306a36Sopenharmony_ci#define RX_FIFO_THRESH		5	/* Rx buffer level before first PCI xfer.  */
12562306a36Sopenharmony_ci#define RX_DMA_BURST		4	/* Maximum PCI burst, '4' is 256 */
12662306a36Sopenharmony_ci#define TX_DMA_BURST		6	/* Maximum PCI burst, '6' is 1024 */
12762306a36Sopenharmony_ci#define TX_EARLY_THRESH		256	/* Early Tx threshold, in bytes */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
13062306a36Sopenharmony_ci#define TX_TIMEOUT		(6*HZ)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* hardware minimum and maximum for a single frame's data payload */
13362306a36Sopenharmony_ci#define CP_MIN_MTU		60	/* TODO: allow lower, but pad */
13462306a36Sopenharmony_ci#define CP_MAX_MTU		4096
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cienum {
13762306a36Sopenharmony_ci	/* NIC register offsets */
13862306a36Sopenharmony_ci	MAC0		= 0x00,	/* Ethernet hardware address. */
13962306a36Sopenharmony_ci	MAR0		= 0x08,	/* Multicast filter. */
14062306a36Sopenharmony_ci	StatsAddr	= 0x10,	/* 64-bit start addr of 64-byte DMA stats blk */
14162306a36Sopenharmony_ci	TxRingAddr	= 0x20, /* 64-bit start addr of Tx ring */
14262306a36Sopenharmony_ci	HiTxRingAddr	= 0x28, /* 64-bit start addr of high priority Tx ring */
14362306a36Sopenharmony_ci	Cmd		= 0x37, /* Command register */
14462306a36Sopenharmony_ci	IntrMask	= 0x3C, /* Interrupt mask */
14562306a36Sopenharmony_ci	IntrStatus	= 0x3E, /* Interrupt status */
14662306a36Sopenharmony_ci	TxConfig	= 0x40, /* Tx configuration */
14762306a36Sopenharmony_ci	ChipVersion	= 0x43, /* 8-bit chip version, inside TxConfig */
14862306a36Sopenharmony_ci	RxConfig	= 0x44, /* Rx configuration */
14962306a36Sopenharmony_ci	RxMissed	= 0x4C,	/* 24 bits valid, write clears */
15062306a36Sopenharmony_ci	Cfg9346		= 0x50, /* EEPROM select/control; Cfg reg [un]lock */
15162306a36Sopenharmony_ci	Config1		= 0x52, /* Config1 */
15262306a36Sopenharmony_ci	Config3		= 0x59, /* Config3 */
15362306a36Sopenharmony_ci	Config4		= 0x5A, /* Config4 */
15462306a36Sopenharmony_ci	MultiIntr	= 0x5C, /* Multiple interrupt select */
15562306a36Sopenharmony_ci	BasicModeCtrl	= 0x62,	/* MII BMCR */
15662306a36Sopenharmony_ci	BasicModeStatus	= 0x64, /* MII BMSR */
15762306a36Sopenharmony_ci	NWayAdvert	= 0x66, /* MII ADVERTISE */
15862306a36Sopenharmony_ci	NWayLPAR	= 0x68, /* MII LPA */
15962306a36Sopenharmony_ci	NWayExpansion	= 0x6A, /* MII Expansion */
16062306a36Sopenharmony_ci	TxDmaOkLowDesc  = 0x82, /* Low 16 bit address of a Tx descriptor. */
16162306a36Sopenharmony_ci	Config5		= 0xD8,	/* Config5 */
16262306a36Sopenharmony_ci	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
16362306a36Sopenharmony_ci	RxMaxSize	= 0xDA, /* Max size of an Rx packet (8169 only) */
16462306a36Sopenharmony_ci	CpCmd		= 0xE0, /* C+ Command register (C+ mode only) */
16562306a36Sopenharmony_ci	IntrMitigate	= 0xE2,	/* rx/tx interrupt mitigation control */
16662306a36Sopenharmony_ci	RxRingAddr	= 0xE4, /* 64-bit start addr of Rx ring */
16762306a36Sopenharmony_ci	TxThresh	= 0xEC, /* Early Tx threshold */
16862306a36Sopenharmony_ci	OldRxBufAddr	= 0x30, /* DMA address of Rx ring buffer (C mode) */
16962306a36Sopenharmony_ci	OldTSD0		= 0x10, /* DMA address of first Tx desc (C mode) */
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Tx and Rx status descriptors */
17262306a36Sopenharmony_ci	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */
17362306a36Sopenharmony_ci	RingEnd		= (1 << 30), /* End of descriptor ring */
17462306a36Sopenharmony_ci	FirstFrag	= (1 << 29), /* First segment of a packet */
17562306a36Sopenharmony_ci	LastFrag	= (1 << 28), /* Final segment of a packet */
17662306a36Sopenharmony_ci	LargeSend	= (1 << 27), /* TCP Large Send Offload (TSO) */
17762306a36Sopenharmony_ci	MSSShift	= 16,	     /* MSS value position */
17862306a36Sopenharmony_ci	MSSMask		= 0x7ff,     /* MSS value: 11 bits */
17962306a36Sopenharmony_ci	TxError		= (1 << 23), /* Tx error summary */
18062306a36Sopenharmony_ci	RxError		= (1 << 20), /* Rx error summary */
18162306a36Sopenharmony_ci	IPCS		= (1 << 18), /* Calculate IP checksum */
18262306a36Sopenharmony_ci	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */
18362306a36Sopenharmony_ci	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */
18462306a36Sopenharmony_ci	TxVlanTag	= (1 << 17), /* Add VLAN tag */
18562306a36Sopenharmony_ci	RxVlanTagged	= (1 << 16), /* Rx VLAN tag available */
18662306a36Sopenharmony_ci	IPFail		= (1 << 15), /* IP checksum failed */
18762306a36Sopenharmony_ci	UDPFail		= (1 << 14), /* UDP/IP checksum failed */
18862306a36Sopenharmony_ci	TCPFail		= (1 << 13), /* TCP/IP checksum failed */
18962306a36Sopenharmony_ci	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
19062306a36Sopenharmony_ci	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
19162306a36Sopenharmony_ci	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
19262306a36Sopenharmony_ci	RxProtoTCP	= 1,
19362306a36Sopenharmony_ci	RxProtoUDP	= 2,
19462306a36Sopenharmony_ci	RxProtoIP	= 3,
19562306a36Sopenharmony_ci	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
19662306a36Sopenharmony_ci	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
19762306a36Sopenharmony_ci	TxLinkFail	= (1 << 21), /* Link failed during Tx of packet */
19862306a36Sopenharmony_ci	TxMaxCol	= (1 << 20), /* Tx aborted due to excessive collisions */
19962306a36Sopenharmony_ci	TxColCntShift	= 16,	     /* Shift, to get 4-bit Tx collision cnt */
20062306a36Sopenharmony_ci	TxColCntMask	= 0x01 | 0x02 | 0x04 | 0x08, /* 4-bit collision count */
20162306a36Sopenharmony_ci	RxErrFrame	= (1 << 27), /* Rx frame alignment error */
20262306a36Sopenharmony_ci	RxMcast		= (1 << 26), /* Rx multicast packet rcv'd */
20362306a36Sopenharmony_ci	RxErrCRC	= (1 << 18), /* Rx CRC error */
20462306a36Sopenharmony_ci	RxErrRunt	= (1 << 19), /* Rx error, packet < 64 bytes */
20562306a36Sopenharmony_ci	RxErrLong	= (1 << 21), /* Rx error, packet > 4096 bytes */
20662306a36Sopenharmony_ci	RxErrFIFO	= (1 << 22), /* Rx error, FIFO overflowed, pkt bad */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* StatsAddr register */
20962306a36Sopenharmony_ci	DumpStats	= (1 << 3),  /* Begin stats dump */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* RxConfig register */
21262306a36Sopenharmony_ci	RxCfgFIFOShift	= 13,	     /* Shift, to get Rx FIFO thresh value */
21362306a36Sopenharmony_ci	RxCfgDMAShift	= 8,	     /* Shift, to get Rx Max DMA value */
21462306a36Sopenharmony_ci	AcceptErr	= 0x20,	     /* Accept packets with CRC errors */
21562306a36Sopenharmony_ci	AcceptRunt	= 0x10,	     /* Accept runt (<64 bytes) packets */
21662306a36Sopenharmony_ci	AcceptBroadcast	= 0x08,	     /* Accept broadcast packets */
21762306a36Sopenharmony_ci	AcceptMulticast	= 0x04,	     /* Accept multicast packets */
21862306a36Sopenharmony_ci	AcceptMyPhys	= 0x02,	     /* Accept pkts with our MAC as dest */
21962306a36Sopenharmony_ci	AcceptAllPhys	= 0x01,	     /* Accept all pkts w/ physical dest */
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* IntrMask / IntrStatus registers */
22262306a36Sopenharmony_ci	PciErr		= (1 << 15), /* System error on the PCI bus */
22362306a36Sopenharmony_ci	TimerIntr	= (1 << 14), /* Asserted when TCTR reaches TimerInt value */
22462306a36Sopenharmony_ci	LenChg		= (1 << 13), /* Cable length change */
22562306a36Sopenharmony_ci	SWInt		= (1 << 8),  /* Software-requested interrupt */
22662306a36Sopenharmony_ci	TxEmpty		= (1 << 7),  /* No Tx descriptors available */
22762306a36Sopenharmony_ci	RxFIFOOvr	= (1 << 6),  /* Rx FIFO Overflow */
22862306a36Sopenharmony_ci	LinkChg		= (1 << 5),  /* Packet underrun, or link change */
22962306a36Sopenharmony_ci	RxEmpty		= (1 << 4),  /* No Rx descriptors available */
23062306a36Sopenharmony_ci	TxErr		= (1 << 3),  /* Tx error */
23162306a36Sopenharmony_ci	TxOK		= (1 << 2),  /* Tx packet sent */
23262306a36Sopenharmony_ci	RxErr		= (1 << 1),  /* Rx error */
23362306a36Sopenharmony_ci	RxOK		= (1 << 0),  /* Rx packet received */
23462306a36Sopenharmony_ci	IntrResvd	= (1 << 10), /* reserved, according to RealTek engineers,
23562306a36Sopenharmony_ci					but hardware likes to raise it */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	IntrAll		= PciErr | TimerIntr | LenChg | SWInt | TxEmpty |
23862306a36Sopenharmony_ci			  RxFIFOOvr | LinkChg | RxEmpty | TxErr | TxOK |
23962306a36Sopenharmony_ci			  RxErr | RxOK | IntrResvd,
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* C mode command register */
24262306a36Sopenharmony_ci	CmdReset	= (1 << 4),  /* Enable to reset; self-clearing */
24362306a36Sopenharmony_ci	RxOn		= (1 << 3),  /* Rx mode enable */
24462306a36Sopenharmony_ci	TxOn		= (1 << 2),  /* Tx mode enable */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* C+ mode command register */
24762306a36Sopenharmony_ci	RxVlanOn	= (1 << 6),  /* Rx VLAN de-tagging enable */
24862306a36Sopenharmony_ci	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */
24962306a36Sopenharmony_ci	PCIDAC		= (1 << 4),  /* PCI Dual Address Cycle (64-bit PCI) */
25062306a36Sopenharmony_ci	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */
25162306a36Sopenharmony_ci	CpRxOn		= (1 << 1),  /* Rx mode enable */
25262306a36Sopenharmony_ci	CpTxOn		= (1 << 0),  /* Tx mode enable */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* Cfg9436 EEPROM control register */
25562306a36Sopenharmony_ci	Cfg9346_Lock	= 0x00,	     /* Lock ConfigX/MII register access */
25662306a36Sopenharmony_ci	Cfg9346_Unlock	= 0xC0,	     /* Unlock ConfigX/MII register access */
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* TxConfig register */
25962306a36Sopenharmony_ci	IFG		= (1 << 25) | (1 << 24), /* standard IEEE interframe gap */
26062306a36Sopenharmony_ci	TxDMAShift	= 8,	     /* DMA burst value (0-7) is shift this many bits */
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Early Tx Threshold register */
26362306a36Sopenharmony_ci	TxThreshMask	= 0x3f,	     /* Mask bits 5-0 */
26462306a36Sopenharmony_ci	TxThreshMax	= 2048,	     /* Max early Tx threshold */
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* Config1 register */
26762306a36Sopenharmony_ci	DriverLoaded	= (1 << 5),  /* Software marker, driver is loaded */
26862306a36Sopenharmony_ci	LWACT           = (1 << 4),  /* LWAKE active mode */
26962306a36Sopenharmony_ci	PMEnable	= (1 << 0),  /* Enable various PM features of chip */
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Config3 register */
27262306a36Sopenharmony_ci	PARMEnable	= (1 << 6),  /* Enable auto-loading of PHY parms */
27362306a36Sopenharmony_ci	MagicPacket     = (1 << 5),  /* Wake up when receives a Magic Packet */
27462306a36Sopenharmony_ci	LinkUp          = (1 << 4),  /* Wake up when the cable connection is re-established */
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* Config4 register */
27762306a36Sopenharmony_ci	LWPTN           = (1 << 1),  /* LWAKE Pattern */
27862306a36Sopenharmony_ci	LWPME           = (1 << 4),  /* LANWAKE vs PMEB */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Config5 register */
28162306a36Sopenharmony_ci	BWF             = (1 << 6),  /* Accept Broadcast wakeup frame */
28262306a36Sopenharmony_ci	MWF             = (1 << 5),  /* Accept Multicast wakeup frame */
28362306a36Sopenharmony_ci	UWF             = (1 << 4),  /* Accept Unicast wakeup frame */
28462306a36Sopenharmony_ci	LANWake         = (1 << 1),  /* Enable LANWake signal */
28562306a36Sopenharmony_ci	PMEStatus	= (1 << 0),  /* PME status can be reset by PCI RST# */
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	cp_norx_intr_mask = PciErr | LinkChg | TxOK | TxErr | TxEmpty,
28862306a36Sopenharmony_ci	cp_rx_intr_mask = RxOK | RxErr | RxEmpty | RxFIFOOvr,
28962306a36Sopenharmony_ci	cp_intr_mask = cp_rx_intr_mask | cp_norx_intr_mask,
29062306a36Sopenharmony_ci};
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic const unsigned int cp_rx_config =
29362306a36Sopenharmony_ci	  (RX_FIFO_THRESH << RxCfgFIFOShift) |
29462306a36Sopenharmony_ci	  (RX_DMA_BURST << RxCfgDMAShift);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistruct cp_desc {
29762306a36Sopenharmony_ci	__le32		opts1;
29862306a36Sopenharmony_ci	__le32		opts2;
29962306a36Sopenharmony_ci	__le64		addr;
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistruct cp_dma_stats {
30362306a36Sopenharmony_ci	__le64			tx_ok;
30462306a36Sopenharmony_ci	__le64			rx_ok;
30562306a36Sopenharmony_ci	__le64			tx_err;
30662306a36Sopenharmony_ci	__le32			rx_err;
30762306a36Sopenharmony_ci	__le16			rx_fifo;
30862306a36Sopenharmony_ci	__le16			frame_align;
30962306a36Sopenharmony_ci	__le32			tx_ok_1col;
31062306a36Sopenharmony_ci	__le32			tx_ok_mcol;
31162306a36Sopenharmony_ci	__le64			rx_ok_phys;
31262306a36Sopenharmony_ci	__le64			rx_ok_bcast;
31362306a36Sopenharmony_ci	__le32			rx_ok_mcast;
31462306a36Sopenharmony_ci	__le16			tx_abort;
31562306a36Sopenharmony_ci	__le16			tx_underrun;
31662306a36Sopenharmony_ci} __packed;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistruct cp_extra_stats {
31962306a36Sopenharmony_ci	unsigned long		rx_frags;
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistruct cp_private {
32362306a36Sopenharmony_ci	void			__iomem *regs;
32462306a36Sopenharmony_ci	struct net_device	*dev;
32562306a36Sopenharmony_ci	spinlock_t		lock;
32662306a36Sopenharmony_ci	u32			msg_enable;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	struct napi_struct	napi;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	struct pci_dev		*pdev;
33162306a36Sopenharmony_ci	u32			rx_config;
33262306a36Sopenharmony_ci	u16			cpcmd;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	struct cp_extra_stats	cp_stats;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	unsigned		rx_head		____cacheline_aligned;
33762306a36Sopenharmony_ci	unsigned		rx_tail;
33862306a36Sopenharmony_ci	struct cp_desc		*rx_ring;
33962306a36Sopenharmony_ci	struct sk_buff		*rx_skb[CP_RX_RING_SIZE];
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	unsigned		tx_head		____cacheline_aligned;
34262306a36Sopenharmony_ci	unsigned		tx_tail;
34362306a36Sopenharmony_ci	struct cp_desc		*tx_ring;
34462306a36Sopenharmony_ci	struct sk_buff		*tx_skb[CP_TX_RING_SIZE];
34562306a36Sopenharmony_ci	u32			tx_opts[CP_TX_RING_SIZE];
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	unsigned		rx_buf_sz;
34862306a36Sopenharmony_ci	unsigned		wol_enabled : 1; /* Is Wake-on-LAN enabled? */
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	dma_addr_t		ring_dma;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	struct mii_if_info	mii_if;
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci#define cpr8(reg)	readb(cp->regs + (reg))
35662306a36Sopenharmony_ci#define cpr16(reg)	readw(cp->regs + (reg))
35762306a36Sopenharmony_ci#define cpr32(reg)	readl(cp->regs + (reg))
35862306a36Sopenharmony_ci#define cpw8(reg,val)	writeb((val), cp->regs + (reg))
35962306a36Sopenharmony_ci#define cpw16(reg,val)	writew((val), cp->regs + (reg))
36062306a36Sopenharmony_ci#define cpw32(reg,val)	writel((val), cp->regs + (reg))
36162306a36Sopenharmony_ci#define cpw8_f(reg,val) do {			\
36262306a36Sopenharmony_ci	writeb((val), cp->regs + (reg));	\
36362306a36Sopenharmony_ci	readb(cp->regs + (reg));		\
36462306a36Sopenharmony_ci	} while (0)
36562306a36Sopenharmony_ci#define cpw16_f(reg,val) do {			\
36662306a36Sopenharmony_ci	writew((val), cp->regs + (reg));	\
36762306a36Sopenharmony_ci	readw(cp->regs + (reg));		\
36862306a36Sopenharmony_ci	} while (0)
36962306a36Sopenharmony_ci#define cpw32_f(reg,val) do {			\
37062306a36Sopenharmony_ci	writel((val), cp->regs + (reg));	\
37162306a36Sopenharmony_ci	readl(cp->regs + (reg));		\
37262306a36Sopenharmony_ci	} while (0)
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic void __cp_set_rx_mode (struct net_device *dev);
37662306a36Sopenharmony_cistatic void cp_tx (struct cp_private *cp);
37762306a36Sopenharmony_cistatic void cp_clean_rings (struct cp_private *cp);
37862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
37962306a36Sopenharmony_cistatic void cp_poll_controller(struct net_device *dev);
38062306a36Sopenharmony_ci#endif
38162306a36Sopenharmony_cistatic int cp_get_eeprom_len(struct net_device *dev);
38262306a36Sopenharmony_cistatic int cp_get_eeprom(struct net_device *dev,
38362306a36Sopenharmony_ci			 struct ethtool_eeprom *eeprom, u8 *data);
38462306a36Sopenharmony_cistatic int cp_set_eeprom(struct net_device *dev,
38562306a36Sopenharmony_ci			 struct ethtool_eeprom *eeprom, u8 *data);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic struct {
38862306a36Sopenharmony_ci	const char str[ETH_GSTRING_LEN];
38962306a36Sopenharmony_ci} ethtool_stats_keys[] = {
39062306a36Sopenharmony_ci	{ "tx_ok" },
39162306a36Sopenharmony_ci	{ "rx_ok" },
39262306a36Sopenharmony_ci	{ "tx_err" },
39362306a36Sopenharmony_ci	{ "rx_err" },
39462306a36Sopenharmony_ci	{ "rx_fifo" },
39562306a36Sopenharmony_ci	{ "frame_align" },
39662306a36Sopenharmony_ci	{ "tx_ok_1col" },
39762306a36Sopenharmony_ci	{ "tx_ok_mcol" },
39862306a36Sopenharmony_ci	{ "rx_ok_phys" },
39962306a36Sopenharmony_ci	{ "rx_ok_bcast" },
40062306a36Sopenharmony_ci	{ "rx_ok_mcast" },
40162306a36Sopenharmony_ci	{ "tx_abort" },
40262306a36Sopenharmony_ci	{ "tx_underrun" },
40362306a36Sopenharmony_ci	{ "rx_frags" },
40462306a36Sopenharmony_ci};
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic inline void cp_set_rxbufsize (struct cp_private *cp)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	unsigned int mtu = cp->dev->mtu;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (mtu > ETH_DATA_LEN)
41262306a36Sopenharmony_ci		/* MTU + ethernet header + FCS + optional VLAN tag */
41362306a36Sopenharmony_ci		cp->rx_buf_sz = mtu + ETH_HLEN + 8;
41462306a36Sopenharmony_ci	else
41562306a36Sopenharmony_ci		cp->rx_buf_sz = PKT_BUF_SZ;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
41962306a36Sopenharmony_ci			      struct cp_desc *desc)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	u32 opts2 = le32_to_cpu(desc->opts2);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	skb->protocol = eth_type_trans (skb, cp->dev);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	cp->dev->stats.rx_packets++;
42662306a36Sopenharmony_ci	cp->dev->stats.rx_bytes += skb->len;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (opts2 & RxVlanTagged)
42962306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	napi_gro_receive(&cp->napi, skb);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
43562306a36Sopenharmony_ci			    u32 status, u32 len)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	netif_dbg(cp, rx_err, cp->dev, "rx err, slot %d status 0x%x len %d\n",
43862306a36Sopenharmony_ci		  rx_tail, status, len);
43962306a36Sopenharmony_ci	cp->dev->stats.rx_errors++;
44062306a36Sopenharmony_ci	if (status & RxErrFrame)
44162306a36Sopenharmony_ci		cp->dev->stats.rx_frame_errors++;
44262306a36Sopenharmony_ci	if (status & RxErrCRC)
44362306a36Sopenharmony_ci		cp->dev->stats.rx_crc_errors++;
44462306a36Sopenharmony_ci	if ((status & RxErrRunt) || (status & RxErrLong))
44562306a36Sopenharmony_ci		cp->dev->stats.rx_length_errors++;
44662306a36Sopenharmony_ci	if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag))
44762306a36Sopenharmony_ci		cp->dev->stats.rx_length_errors++;
44862306a36Sopenharmony_ci	if (status & RxErrFIFO)
44962306a36Sopenharmony_ci		cp->dev->stats.rx_fifo_errors++;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic inline unsigned int cp_rx_csum_ok (u32 status)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	unsigned int protocol = (status >> 16) & 0x3;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (((protocol == RxProtoTCP) && !(status & TCPFail)) ||
45762306a36Sopenharmony_ci	    ((protocol == RxProtoUDP) && !(status & UDPFail)))
45862306a36Sopenharmony_ci		return 1;
45962306a36Sopenharmony_ci	else
46062306a36Sopenharmony_ci		return 0;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int cp_rx_poll(struct napi_struct *napi, int budget)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct cp_private *cp = container_of(napi, struct cp_private, napi);
46662306a36Sopenharmony_ci	struct net_device *dev = cp->dev;
46762306a36Sopenharmony_ci	unsigned int rx_tail = cp->rx_tail;
46862306a36Sopenharmony_ci	int rx = 0;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	cpw16(IntrStatus, cp_rx_intr_mask);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	while (rx < budget) {
47362306a36Sopenharmony_ci		u32 status, len;
47462306a36Sopenharmony_ci		dma_addr_t mapping, new_mapping;
47562306a36Sopenharmony_ci		struct sk_buff *skb, *new_skb;
47662306a36Sopenharmony_ci		struct cp_desc *desc;
47762306a36Sopenharmony_ci		const unsigned buflen = cp->rx_buf_sz;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		skb = cp->rx_skb[rx_tail];
48062306a36Sopenharmony_ci		BUG_ON(!skb);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		desc = &cp->rx_ring[rx_tail];
48362306a36Sopenharmony_ci		status = le32_to_cpu(desc->opts1);
48462306a36Sopenharmony_ci		if (status & DescOwn)
48562306a36Sopenharmony_ci			break;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		len = (status & 0x1fff) - 4;
48862306a36Sopenharmony_ci		mapping = le64_to_cpu(desc->addr);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
49162306a36Sopenharmony_ci			/* we don't support incoming fragmented frames.
49262306a36Sopenharmony_ci			 * instead, we attempt to ensure that the
49362306a36Sopenharmony_ci			 * pre-allocated RX skbs are properly sized such
49462306a36Sopenharmony_ci			 * that RX fragments are never encountered
49562306a36Sopenharmony_ci			 */
49662306a36Sopenharmony_ci			cp_rx_err_acct(cp, rx_tail, status, len);
49762306a36Sopenharmony_ci			dev->stats.rx_dropped++;
49862306a36Sopenharmony_ci			cp->cp_stats.rx_frags++;
49962306a36Sopenharmony_ci			goto rx_next;
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		if (status & (RxError | RxErrFIFO)) {
50362306a36Sopenharmony_ci			cp_rx_err_acct(cp, rx_tail, status, len);
50462306a36Sopenharmony_ci			goto rx_next;
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		netif_dbg(cp, rx_status, dev, "rx slot %d status 0x%x len %d\n",
50862306a36Sopenharmony_ci			  rx_tail, status, len);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		new_skb = napi_alloc_skb(napi, buflen);
51162306a36Sopenharmony_ci		if (!new_skb) {
51262306a36Sopenharmony_ci			dev->stats.rx_dropped++;
51362306a36Sopenharmony_ci			goto rx_next;
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
51762306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
51862306a36Sopenharmony_ci		if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
51962306a36Sopenharmony_ci			dev->stats.rx_dropped++;
52062306a36Sopenharmony_ci			kfree_skb(new_skb);
52162306a36Sopenharmony_ci			goto rx_next;
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		dma_unmap_single(&cp->pdev->dev, mapping,
52562306a36Sopenharmony_ci				 buflen, DMA_FROM_DEVICE);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		/* Handle checksum offloading for incoming packets. */
52862306a36Sopenharmony_ci		if (cp_rx_csum_ok(status))
52962306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
53062306a36Sopenharmony_ci		else
53162306a36Sopenharmony_ci			skb_checksum_none_assert(skb);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		skb_put(skb, len);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		cp->rx_skb[rx_tail] = new_skb;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		cp_rx_skb(cp, skb, desc);
53862306a36Sopenharmony_ci		rx++;
53962306a36Sopenharmony_ci		mapping = new_mapping;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cirx_next:
54262306a36Sopenharmony_ci		cp->rx_ring[rx_tail].opts2 = 0;
54362306a36Sopenharmony_ci		cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);
54462306a36Sopenharmony_ci		if (rx_tail == (CP_RX_RING_SIZE - 1))
54562306a36Sopenharmony_ci			desc->opts1 = cpu_to_le32(DescOwn | RingEnd |
54662306a36Sopenharmony_ci						  cp->rx_buf_sz);
54762306a36Sopenharmony_ci		else
54862306a36Sopenharmony_ci			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
54962306a36Sopenharmony_ci		rx_tail = NEXT_RX(rx_tail);
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	cp->rx_tail = rx_tail;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/* if we did not reach work limit, then we're done with
55562306a36Sopenharmony_ci	 * this round of polling
55662306a36Sopenharmony_ci	 */
55762306a36Sopenharmony_ci	if (rx < budget && napi_complete_done(napi, rx)) {
55862306a36Sopenharmony_ci		unsigned long flags;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		spin_lock_irqsave(&cp->lock, flags);
56162306a36Sopenharmony_ci		cpw16_f(IntrMask, cp_intr_mask);
56262306a36Sopenharmony_ci		spin_unlock_irqrestore(&cp->lock, flags);
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return rx;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic irqreturn_t cp_interrupt (int irq, void *dev_instance)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct net_device *dev = dev_instance;
57162306a36Sopenharmony_ci	struct cp_private *cp;
57262306a36Sopenharmony_ci	int handled = 0;
57362306a36Sopenharmony_ci	u16 status;
57462306a36Sopenharmony_ci	u16 mask;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (unlikely(dev == NULL))
57762306a36Sopenharmony_ci		return IRQ_NONE;
57862306a36Sopenharmony_ci	cp = netdev_priv(dev);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	spin_lock(&cp->lock);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	mask = cpr16(IntrMask);
58362306a36Sopenharmony_ci	if (!mask)
58462306a36Sopenharmony_ci		goto out_unlock;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	status = cpr16(IntrStatus);
58762306a36Sopenharmony_ci	if (!status || (status == 0xFFFF))
58862306a36Sopenharmony_ci		goto out_unlock;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	handled = 1;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
59362306a36Sopenharmony_ci		  status, cpr8(Cmd), cpr16(CpCmd));
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	cpw16(IntrStatus, status & ~cp_rx_intr_mask);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* close possible race's with dev_close */
59862306a36Sopenharmony_ci	if (unlikely(!netif_running(dev))) {
59962306a36Sopenharmony_ci		cpw16(IntrMask, 0);
60062306a36Sopenharmony_ci		goto out_unlock;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
60462306a36Sopenharmony_ci		if (napi_schedule_prep(&cp->napi)) {
60562306a36Sopenharmony_ci			cpw16_f(IntrMask, cp_norx_intr_mask);
60662306a36Sopenharmony_ci			__napi_schedule(&cp->napi);
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (status & (TxOK | TxErr | TxEmpty | SWInt))
61062306a36Sopenharmony_ci		cp_tx(cp);
61162306a36Sopenharmony_ci	if (status & LinkChg)
61262306a36Sopenharmony_ci		mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (status & PciErr) {
61662306a36Sopenharmony_ci		u16 pci_status;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
61962306a36Sopenharmony_ci		pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
62062306a36Sopenharmony_ci		netdev_err(dev, "PCI bus error, status=%04x, PCI status=%04x\n",
62162306a36Sopenharmony_ci			   status, pci_status);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		/* TODO: reset hardware */
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ciout_unlock:
62762306a36Sopenharmony_ci	spin_unlock(&cp->lock);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
63362306a36Sopenharmony_ci/*
63462306a36Sopenharmony_ci * Polling receive - used by netconsole and other diagnostic tools
63562306a36Sopenharmony_ci * to allow network i/o with interrupts disabled.
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_cistatic void cp_poll_controller(struct net_device *dev)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
64062306a36Sopenharmony_ci	const int irq = cp->pdev->irq;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	disable_irq(irq);
64362306a36Sopenharmony_ci	cp_interrupt(irq, dev);
64462306a36Sopenharmony_ci	enable_irq(irq);
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci#endif
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void cp_tx (struct cp_private *cp)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	unsigned tx_head = cp->tx_head;
65162306a36Sopenharmony_ci	unsigned tx_tail = cp->tx_tail;
65262306a36Sopenharmony_ci	unsigned bytes_compl = 0, pkts_compl = 0;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	while (tx_tail != tx_head) {
65562306a36Sopenharmony_ci		struct cp_desc *txd = cp->tx_ring + tx_tail;
65662306a36Sopenharmony_ci		struct sk_buff *skb;
65762306a36Sopenharmony_ci		u32 status;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		rmb();
66062306a36Sopenharmony_ci		status = le32_to_cpu(txd->opts1);
66162306a36Sopenharmony_ci		if (status & DescOwn)
66262306a36Sopenharmony_ci			break;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		skb = cp->tx_skb[tx_tail];
66562306a36Sopenharmony_ci		BUG_ON(!skb);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
66862306a36Sopenharmony_ci				 cp->tx_opts[tx_tail] & 0xffff,
66962306a36Sopenharmony_ci				 DMA_TO_DEVICE);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		if (status & LastFrag) {
67262306a36Sopenharmony_ci			if (status & (TxError | TxFIFOUnder)) {
67362306a36Sopenharmony_ci				netif_dbg(cp, tx_err, cp->dev,
67462306a36Sopenharmony_ci					  "tx err, status 0x%x\n", status);
67562306a36Sopenharmony_ci				cp->dev->stats.tx_errors++;
67662306a36Sopenharmony_ci				if (status & TxOWC)
67762306a36Sopenharmony_ci					cp->dev->stats.tx_window_errors++;
67862306a36Sopenharmony_ci				if (status & TxMaxCol)
67962306a36Sopenharmony_ci					cp->dev->stats.tx_aborted_errors++;
68062306a36Sopenharmony_ci				if (status & TxLinkFail)
68162306a36Sopenharmony_ci					cp->dev->stats.tx_carrier_errors++;
68262306a36Sopenharmony_ci				if (status & TxFIFOUnder)
68362306a36Sopenharmony_ci					cp->dev->stats.tx_fifo_errors++;
68462306a36Sopenharmony_ci			} else {
68562306a36Sopenharmony_ci				cp->dev->stats.collisions +=
68662306a36Sopenharmony_ci					((status >> TxColCntShift) & TxColCntMask);
68762306a36Sopenharmony_ci				cp->dev->stats.tx_packets++;
68862306a36Sopenharmony_ci				cp->dev->stats.tx_bytes += skb->len;
68962306a36Sopenharmony_ci				netif_dbg(cp, tx_done, cp->dev,
69062306a36Sopenharmony_ci					  "tx done, slot %d\n", tx_tail);
69162306a36Sopenharmony_ci			}
69262306a36Sopenharmony_ci			bytes_compl += skb->len;
69362306a36Sopenharmony_ci			pkts_compl++;
69462306a36Sopenharmony_ci			dev_consume_skb_irq(skb);
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		cp->tx_skb[tx_tail] = NULL;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		tx_tail = NEXT_TX(tx_tail);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	cp->tx_tail = tx_tail;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	netdev_completed_queue(cp->dev, pkts_compl, bytes_compl);
70562306a36Sopenharmony_ci	if (TX_BUFFS_AVAIL(cp) > (MAX_SKB_FRAGS + 1))
70662306a36Sopenharmony_ci		netif_wake_queue(cp->dev);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	return skb_vlan_tag_present(skb) ?
71262306a36Sopenharmony_ci		TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
71662306a36Sopenharmony_ci				   int first, int entry_last)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	int frag, index;
71962306a36Sopenharmony_ci	struct cp_desc *txd;
72062306a36Sopenharmony_ci	skb_frag_t *this_frag;
72162306a36Sopenharmony_ci	for (frag = 0; frag+first < entry_last; frag++) {
72262306a36Sopenharmony_ci		index = first+frag;
72362306a36Sopenharmony_ci		cp->tx_skb[index] = NULL;
72462306a36Sopenharmony_ci		txd = &cp->tx_ring[index];
72562306a36Sopenharmony_ci		this_frag = &skb_shinfo(skb)->frags[frag];
72662306a36Sopenharmony_ci		dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
72762306a36Sopenharmony_ci				 skb_frag_size(this_frag), DMA_TO_DEVICE);
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic netdev_tx_t cp_start_xmit (struct sk_buff *skb,
73262306a36Sopenharmony_ci					struct net_device *dev)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
73562306a36Sopenharmony_ci	unsigned entry;
73662306a36Sopenharmony_ci	u32 eor, opts1;
73762306a36Sopenharmony_ci	unsigned long intr_flags;
73862306a36Sopenharmony_ci	__le32 opts2;
73962306a36Sopenharmony_ci	int mss = 0;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, intr_flags);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* This is a hard error, log it. */
74462306a36Sopenharmony_ci	if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
74562306a36Sopenharmony_ci		netif_stop_queue(dev);
74662306a36Sopenharmony_ci		spin_unlock_irqrestore(&cp->lock, intr_flags);
74762306a36Sopenharmony_ci		netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
74862306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	entry = cp->tx_head;
75262306a36Sopenharmony_ci	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
75362306a36Sopenharmony_ci	mss = skb_shinfo(skb)->gso_size;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (mss > MSSMask) {
75662306a36Sopenharmony_ci		netdev_WARN_ONCE(dev, "Net bug: GSO size %d too large for 8139CP\n",
75762306a36Sopenharmony_ci				 mss);
75862306a36Sopenharmony_ci		goto out_dma_error;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	opts2 = cpu_to_le32(cp_tx_vlan_tag(skb));
76262306a36Sopenharmony_ci	opts1 = DescOwn;
76362306a36Sopenharmony_ci	if (mss)
76462306a36Sopenharmony_ci		opts1 |= LargeSend | (mss << MSSShift);
76562306a36Sopenharmony_ci	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
76662306a36Sopenharmony_ci		const struct iphdr *ip = ip_hdr(skb);
76762306a36Sopenharmony_ci		if (ip->protocol == IPPROTO_TCP)
76862306a36Sopenharmony_ci			opts1 |= IPCS | TCPCS;
76962306a36Sopenharmony_ci		else if (ip->protocol == IPPROTO_UDP)
77062306a36Sopenharmony_ci			opts1 |= IPCS | UDPCS;
77162306a36Sopenharmony_ci		else {
77262306a36Sopenharmony_ci			WARN_ONCE(1,
77362306a36Sopenharmony_ci				  "Net bug: asked to checksum invalid Legacy IP packet\n");
77462306a36Sopenharmony_ci			goto out_dma_error;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (skb_shinfo(skb)->nr_frags == 0) {
77962306a36Sopenharmony_ci		struct cp_desc *txd = &cp->tx_ring[entry];
78062306a36Sopenharmony_ci		u32 len;
78162306a36Sopenharmony_ci		dma_addr_t mapping;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		len = skb->len;
78462306a36Sopenharmony_ci		mapping = dma_map_single(&cp->pdev->dev, skb->data, len, DMA_TO_DEVICE);
78562306a36Sopenharmony_ci		if (dma_mapping_error(&cp->pdev->dev, mapping))
78662306a36Sopenharmony_ci			goto out_dma_error;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		txd->opts2 = opts2;
78962306a36Sopenharmony_ci		txd->addr = cpu_to_le64(mapping);
79062306a36Sopenharmony_ci		wmb();
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		opts1 |= eor | len | FirstFrag | LastFrag;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		txd->opts1 = cpu_to_le32(opts1);
79562306a36Sopenharmony_ci		wmb();
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		cp->tx_skb[entry] = skb;
79862306a36Sopenharmony_ci		cp->tx_opts[entry] = opts1;
79962306a36Sopenharmony_ci		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
80062306a36Sopenharmony_ci			  entry, skb->len);
80162306a36Sopenharmony_ci	} else {
80262306a36Sopenharmony_ci		struct cp_desc *txd;
80362306a36Sopenharmony_ci		u32 first_len, first_eor, ctrl;
80462306a36Sopenharmony_ci		dma_addr_t first_mapping;
80562306a36Sopenharmony_ci		int frag, first_entry = entry;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		/* We must give this initial chunk to the device last.
80862306a36Sopenharmony_ci		 * Otherwise we could race with the device.
80962306a36Sopenharmony_ci		 */
81062306a36Sopenharmony_ci		first_eor = eor;
81162306a36Sopenharmony_ci		first_len = skb_headlen(skb);
81262306a36Sopenharmony_ci		first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
81362306a36Sopenharmony_ci					       first_len, DMA_TO_DEVICE);
81462306a36Sopenharmony_ci		if (dma_mapping_error(&cp->pdev->dev, first_mapping))
81562306a36Sopenharmony_ci			goto out_dma_error;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		cp->tx_skb[entry] = skb;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
82062306a36Sopenharmony_ci			const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
82162306a36Sopenharmony_ci			u32 len;
82262306a36Sopenharmony_ci			dma_addr_t mapping;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci			entry = NEXT_TX(entry);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci			len = skb_frag_size(this_frag);
82762306a36Sopenharmony_ci			mapping = dma_map_single(&cp->pdev->dev,
82862306a36Sopenharmony_ci						 skb_frag_address(this_frag),
82962306a36Sopenharmony_ci						 len, DMA_TO_DEVICE);
83062306a36Sopenharmony_ci			if (dma_mapping_error(&cp->pdev->dev, mapping)) {
83162306a36Sopenharmony_ci				unwind_tx_frag_mapping(cp, skb, first_entry, entry);
83262306a36Sopenharmony_ci				goto out_dma_error;
83362306a36Sopenharmony_ci			}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci			ctrl = opts1 | eor | len;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci			if (frag == skb_shinfo(skb)->nr_frags - 1)
84062306a36Sopenharmony_ci				ctrl |= LastFrag;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci			txd = &cp->tx_ring[entry];
84362306a36Sopenharmony_ci			txd->opts2 = opts2;
84462306a36Sopenharmony_ci			txd->addr = cpu_to_le64(mapping);
84562306a36Sopenharmony_ci			wmb();
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci			txd->opts1 = cpu_to_le32(ctrl);
84862306a36Sopenharmony_ci			wmb();
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci			cp->tx_opts[entry] = ctrl;
85162306a36Sopenharmony_ci			cp->tx_skb[entry] = skb;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		txd = &cp->tx_ring[first_entry];
85562306a36Sopenharmony_ci		txd->opts2 = opts2;
85662306a36Sopenharmony_ci		txd->addr = cpu_to_le64(first_mapping);
85762306a36Sopenharmony_ci		wmb();
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		ctrl = opts1 | first_eor | first_len | FirstFrag;
86062306a36Sopenharmony_ci		txd->opts1 = cpu_to_le32(ctrl);
86162306a36Sopenharmony_ci		wmb();
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		cp->tx_opts[first_entry] = ctrl;
86462306a36Sopenharmony_ci		netif_dbg(cp, tx_queued, cp->dev, "tx queued, slots %d-%d, skblen %d\n",
86562306a36Sopenharmony_ci			  first_entry, entry, skb->len);
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci	cp->tx_head = NEXT_TX(entry);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	netdev_sent_queue(dev, skb->len);
87062306a36Sopenharmony_ci	if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
87162306a36Sopenharmony_ci		netif_stop_queue(dev);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ciout_unlock:
87462306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, intr_flags);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	cpw8(TxPoll, NormalTxPoll);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	return NETDEV_TX_OK;
87962306a36Sopenharmony_ciout_dma_error:
88062306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
88162306a36Sopenharmony_ci	cp->dev->stats.tx_dropped++;
88262306a36Sopenharmony_ci	goto out_unlock;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/* Set or clear the multicast filter for this adaptor.
88662306a36Sopenharmony_ci   This routine is not state sensitive and need not be SMP locked. */
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic void __cp_set_rx_mode (struct net_device *dev)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
89162306a36Sopenharmony_ci	u32 mc_filter[2];	/* Multicast hash filter */
89262306a36Sopenharmony_ci	int rx_mode;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/* Note: do not reorder, GCC is clever about common statements. */
89562306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
89662306a36Sopenharmony_ci		/* Unconditionally log net taps. */
89762306a36Sopenharmony_ci		rx_mode =
89862306a36Sopenharmony_ci		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
89962306a36Sopenharmony_ci		    AcceptAllPhys;
90062306a36Sopenharmony_ci		mc_filter[1] = mc_filter[0] = 0xffffffff;
90162306a36Sopenharmony_ci	} else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
90262306a36Sopenharmony_ci		   (dev->flags & IFF_ALLMULTI)) {
90362306a36Sopenharmony_ci		/* Too many to filter perfectly -- accept all multicasts. */
90462306a36Sopenharmony_ci		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
90562306a36Sopenharmony_ci		mc_filter[1] = mc_filter[0] = 0xffffffff;
90662306a36Sopenharmony_ci	} else {
90762306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
90862306a36Sopenharmony_ci		rx_mode = AcceptBroadcast | AcceptMyPhys;
90962306a36Sopenharmony_ci		mc_filter[1] = mc_filter[0] = 0;
91062306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
91162306a36Sopenharmony_ci			int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
91462306a36Sopenharmony_ci			rx_mode |= AcceptMulticast;
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	/* We can safely update without stopping the chip. */
91962306a36Sopenharmony_ci	cp->rx_config = cp_rx_config | rx_mode;
92062306a36Sopenharmony_ci	cpw32_f(RxConfig, cp->rx_config);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	cpw32_f (MAR0 + 0, mc_filter[0]);
92362306a36Sopenharmony_ci	cpw32_f (MAR0 + 4, mc_filter[1]);
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic void cp_set_rx_mode (struct net_device *dev)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	unsigned long flags;
92962306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	spin_lock_irqsave (&cp->lock, flags);
93262306a36Sopenharmony_ci	__cp_set_rx_mode(dev);
93362306a36Sopenharmony_ci	spin_unlock_irqrestore (&cp->lock, flags);
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic void __cp_get_stats(struct cp_private *cp)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	/* only lower 24 bits valid; write any value to clear */
93962306a36Sopenharmony_ci	cp->dev->stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff);
94062306a36Sopenharmony_ci	cpw32 (RxMissed, 0);
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic struct net_device_stats *cp_get_stats(struct net_device *dev)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
94662306a36Sopenharmony_ci	unsigned long flags;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	/* The chip only need report frame silently dropped. */
94962306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
95062306a36Sopenharmony_ci	if (netif_running(dev) && netif_device_present(dev))
95162306a36Sopenharmony_ci		__cp_get_stats(cp);
95262306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return &dev->stats;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void cp_stop_hw (struct cp_private *cp)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	cpw16(IntrStatus, ~(cpr16(IntrStatus)));
96062306a36Sopenharmony_ci	cpw16_f(IntrMask, 0);
96162306a36Sopenharmony_ci	cpw8(Cmd, 0);
96262306a36Sopenharmony_ci	cpw16_f(CpCmd, 0);
96362306a36Sopenharmony_ci	cpw16_f(IntrStatus, ~(cpr16(IntrStatus)));
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	cp->rx_tail = 0;
96662306a36Sopenharmony_ci	cp->tx_head = cp->tx_tail = 0;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	netdev_reset_queue(cp->dev);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic void cp_reset_hw (struct cp_private *cp)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	unsigned work = 1000;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	cpw8(Cmd, CmdReset);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	while (work--) {
97862306a36Sopenharmony_ci		if (!(cpr8(Cmd) & CmdReset))
97962306a36Sopenharmony_ci			return;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		schedule_timeout_uninterruptible(10);
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	netdev_err(cp->dev, "hardware reset timeout\n");
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic inline void cp_start_hw (struct cp_private *cp)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	dma_addr_t ring_dma;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	cpw16(CpCmd, cp->cpcmd);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/*
99462306a36Sopenharmony_ci	 * These (at least TxRingAddr) need to be configured after the
99562306a36Sopenharmony_ci	 * corresponding bits in CpCmd are enabled. Datasheet v1.6 §6.33
99662306a36Sopenharmony_ci	 * (C+ Command Register) recommends that these and more be configured
99762306a36Sopenharmony_ci	 * *after* the [RT]xEnable bits in CpCmd are set. And on some hardware
99862306a36Sopenharmony_ci	 * it's been observed that the TxRingAddr is actually reset to garbage
99962306a36Sopenharmony_ci	 * when C+ mode Tx is enabled in CpCmd.
100062306a36Sopenharmony_ci	 */
100162306a36Sopenharmony_ci	cpw32_f(HiTxRingAddr, 0);
100262306a36Sopenharmony_ci	cpw32_f(HiTxRingAddr + 4, 0);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	ring_dma = cp->ring_dma;
100562306a36Sopenharmony_ci	cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
100662306a36Sopenharmony_ci	cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
100962306a36Sopenharmony_ci	cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
101062306a36Sopenharmony_ci	cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/*
101362306a36Sopenharmony_ci	 * Strictly speaking, the datasheet says this should be enabled
101462306a36Sopenharmony_ci	 * *before* setting the descriptor addresses. But what, then, would
101562306a36Sopenharmony_ci	 * prevent it from doing DMA to random unconfigured addresses?
101662306a36Sopenharmony_ci	 * This variant appears to work fine.
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	cpw8(Cmd, RxOn | TxOn);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	netdev_reset_queue(cp->dev);
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic void cp_enable_irq(struct cp_private *cp)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	cpw16_f(IntrMask, cp_intr_mask);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic void cp_init_hw (struct cp_private *cp)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct net_device *dev = cp->dev;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	cp_reset_hw(cp);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	cpw8_f (Cfg9346, Cfg9346_Unlock);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	/* Restore our idea of the MAC address. */
103762306a36Sopenharmony_ci	cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
103862306a36Sopenharmony_ci	cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	cp_start_hw(cp);
104162306a36Sopenharmony_ci	cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	__cp_set_rx_mode(dev);
104462306a36Sopenharmony_ci	cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
104762306a36Sopenharmony_ci	/* Disable Wake-on-LAN. Can be turned on with ETHTOOL_SWOL */
104862306a36Sopenharmony_ci	cpw8(Config3, PARMEnable);
104962306a36Sopenharmony_ci	cp->wol_enabled = 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	cpw8(Config5, cpr8(Config5) & PMEStatus);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	cpw16(MultiIntr, 0);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	cpw8_f(Cfg9346, Cfg9346_Lock);
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic int cp_refill_rx(struct cp_private *cp)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct net_device *dev = cp->dev;
106162306a36Sopenharmony_ci	unsigned i;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	for (i = 0; i < CP_RX_RING_SIZE; i++) {
106462306a36Sopenharmony_ci		struct sk_buff *skb;
106562306a36Sopenharmony_ci		dma_addr_t mapping;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(dev, cp->rx_buf_sz);
106862306a36Sopenharmony_ci		if (!skb)
106962306a36Sopenharmony_ci			goto err_out;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci		mapping = dma_map_single(&cp->pdev->dev, skb->data,
107262306a36Sopenharmony_ci					 cp->rx_buf_sz, DMA_FROM_DEVICE);
107362306a36Sopenharmony_ci		if (dma_mapping_error(&cp->pdev->dev, mapping)) {
107462306a36Sopenharmony_ci			kfree_skb(skb);
107562306a36Sopenharmony_ci			goto err_out;
107662306a36Sopenharmony_ci		}
107762306a36Sopenharmony_ci		cp->rx_skb[i] = skb;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		cp->rx_ring[i].opts2 = 0;
108062306a36Sopenharmony_ci		cp->rx_ring[i].addr = cpu_to_le64(mapping);
108162306a36Sopenharmony_ci		if (i == (CP_RX_RING_SIZE - 1))
108262306a36Sopenharmony_ci			cp->rx_ring[i].opts1 =
108362306a36Sopenharmony_ci				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
108462306a36Sopenharmony_ci		else
108562306a36Sopenharmony_ci			cp->rx_ring[i].opts1 =
108662306a36Sopenharmony_ci				cpu_to_le32(DescOwn | cp->rx_buf_sz);
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return 0;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cierr_out:
109262306a36Sopenharmony_ci	cp_clean_rings(cp);
109362306a36Sopenharmony_ci	return -ENOMEM;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic void cp_init_rings_index (struct cp_private *cp)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	cp->rx_tail = 0;
109962306a36Sopenharmony_ci	cp->tx_head = cp->tx_tail = 0;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic int cp_init_rings (struct cp_private *cp)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
110562306a36Sopenharmony_ci	cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
110662306a36Sopenharmony_ci	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	cp_init_rings_index(cp);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	return cp_refill_rx (cp);
111162306a36Sopenharmony_ci}
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int cp_alloc_rings (struct cp_private *cp)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct device *d = &cp->pdev->dev;
111662306a36Sopenharmony_ci	void *mem;
111762306a36Sopenharmony_ci	int rc;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	mem = dma_alloc_coherent(d, CP_RING_BYTES, &cp->ring_dma, GFP_KERNEL);
112062306a36Sopenharmony_ci	if (!mem)
112162306a36Sopenharmony_ci		return -ENOMEM;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	cp->rx_ring = mem;
112462306a36Sopenharmony_ci	cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	rc = cp_init_rings(cp);
112762306a36Sopenharmony_ci	if (rc < 0)
112862306a36Sopenharmony_ci		dma_free_coherent(d, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return rc;
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic void cp_clean_rings (struct cp_private *cp)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct cp_desc *desc;
113662306a36Sopenharmony_ci	unsigned i;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	for (i = 0; i < CP_RX_RING_SIZE; i++) {
113962306a36Sopenharmony_ci		if (cp->rx_skb[i]) {
114062306a36Sopenharmony_ci			desc = cp->rx_ring + i;
114162306a36Sopenharmony_ci			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
114262306a36Sopenharmony_ci					 cp->rx_buf_sz, DMA_FROM_DEVICE);
114362306a36Sopenharmony_ci			dev_kfree_skb_any(cp->rx_skb[i]);
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	for (i = 0; i < CP_TX_RING_SIZE; i++) {
114862306a36Sopenharmony_ci		if (cp->tx_skb[i]) {
114962306a36Sopenharmony_ci			struct sk_buff *skb = cp->tx_skb[i];
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci			desc = cp->tx_ring + i;
115262306a36Sopenharmony_ci			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
115362306a36Sopenharmony_ci					 le32_to_cpu(desc->opts1) & 0xffff,
115462306a36Sopenharmony_ci					 DMA_TO_DEVICE);
115562306a36Sopenharmony_ci			if (le32_to_cpu(desc->opts1) & LastFrag)
115662306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
115762306a36Sopenharmony_ci			cp->dev->stats.tx_dropped++;
115862306a36Sopenharmony_ci		}
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci	netdev_reset_queue(cp->dev);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
116362306a36Sopenharmony_ci	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
116462306a36Sopenharmony_ci	memset(cp->tx_opts, 0, sizeof(cp->tx_opts));
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
116762306a36Sopenharmony_ci	memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistatic void cp_free_rings (struct cp_private *cp)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	cp_clean_rings(cp);
117362306a36Sopenharmony_ci	dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring,
117462306a36Sopenharmony_ci			  cp->ring_dma);
117562306a36Sopenharmony_ci	cp->rx_ring = NULL;
117662306a36Sopenharmony_ci	cp->tx_ring = NULL;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic int cp_open (struct net_device *dev)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
118262306a36Sopenharmony_ci	const int irq = cp->pdev->irq;
118362306a36Sopenharmony_ci	int rc;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	netif_dbg(cp, ifup, dev, "enabling interface\n");
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	rc = cp_alloc_rings(cp);
118862306a36Sopenharmony_ci	if (rc)
118962306a36Sopenharmony_ci		return rc;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	napi_enable(&cp->napi);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	cp_init_hw(cp);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	rc = request_irq(irq, cp_interrupt, IRQF_SHARED, dev->name, dev);
119662306a36Sopenharmony_ci	if (rc)
119762306a36Sopenharmony_ci		goto err_out_hw;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	cp_enable_irq(cp);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	netif_carrier_off(dev);
120262306a36Sopenharmony_ci	mii_check_media(&cp->mii_if, netif_msg_link(cp), true);
120362306a36Sopenharmony_ci	netif_start_queue(dev);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	return 0;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_cierr_out_hw:
120862306a36Sopenharmony_ci	napi_disable(&cp->napi);
120962306a36Sopenharmony_ci	cp_stop_hw(cp);
121062306a36Sopenharmony_ci	cp_free_rings(cp);
121162306a36Sopenharmony_ci	return rc;
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic int cp_close (struct net_device *dev)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
121762306a36Sopenharmony_ci	unsigned long flags;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	napi_disable(&cp->napi);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	netif_dbg(cp, ifdown, dev, "disabling interface\n");
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	netif_stop_queue(dev);
122662306a36Sopenharmony_ci	netif_carrier_off(dev);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	cp_stop_hw(cp);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	free_irq(cp->pdev->irq, dev);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	cp_free_rings(cp);
123562306a36Sopenharmony_ci	return 0;
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic void cp_tx_timeout(struct net_device *dev, unsigned int txqueue)
123962306a36Sopenharmony_ci{
124062306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
124162306a36Sopenharmony_ci	unsigned long flags;
124262306a36Sopenharmony_ci	int i;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
124562306a36Sopenharmony_ci		    cpr8(Cmd), cpr16(CpCmd),
124662306a36Sopenharmony_ci		    cpr16(IntrStatus), cpr16(IntrMask));
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	netif_dbg(cp, tx_err, cp->dev, "TX ring head %d tail %d desc %x\n",
125162306a36Sopenharmony_ci		  cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc));
125262306a36Sopenharmony_ci	for (i = 0; i < CP_TX_RING_SIZE; i++) {
125362306a36Sopenharmony_ci		netif_dbg(cp, tx_err, cp->dev,
125462306a36Sopenharmony_ci			  "TX slot %d @%p: %08x (%08x) %08x %llx %p\n",
125562306a36Sopenharmony_ci			  i, &cp->tx_ring[i], le32_to_cpu(cp->tx_ring[i].opts1),
125662306a36Sopenharmony_ci			  cp->tx_opts[i], le32_to_cpu(cp->tx_ring[i].opts2),
125762306a36Sopenharmony_ci			  le64_to_cpu(cp->tx_ring[i].addr),
125862306a36Sopenharmony_ci			  cp->tx_skb[i]);
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	cp_stop_hw(cp);
126262306a36Sopenharmony_ci	cp_clean_rings(cp);
126362306a36Sopenharmony_ci	cp_init_rings(cp);
126462306a36Sopenharmony_ci	cp_start_hw(cp);
126562306a36Sopenharmony_ci	__cp_set_rx_mode(dev);
126662306a36Sopenharmony_ci	cpw16_f(IntrMask, cp_norx_intr_mask);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	netif_wake_queue(dev);
126962306a36Sopenharmony_ci	napi_schedule_irqoff(&cp->napi);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic int cp_change_mtu(struct net_device *dev, int new_mtu)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	/* if network interface not up, no need for complexity */
127962306a36Sopenharmony_ci	if (!netif_running(dev)) {
128062306a36Sopenharmony_ci		dev->mtu = new_mtu;
128162306a36Sopenharmony_ci		cp_set_rxbufsize(cp);	/* set new rx buf size */
128262306a36Sopenharmony_ci		return 0;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/* network IS up, close it, reset MTU, and come up again. */
128662306a36Sopenharmony_ci	cp_close(dev);
128762306a36Sopenharmony_ci	dev->mtu = new_mtu;
128862306a36Sopenharmony_ci	cp_set_rxbufsize(cp);
128962306a36Sopenharmony_ci	return cp_open(dev);
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic const char mii_2_8139_map[8] = {
129362306a36Sopenharmony_ci	BasicModeCtrl,
129462306a36Sopenharmony_ci	BasicModeStatus,
129562306a36Sopenharmony_ci	0,
129662306a36Sopenharmony_ci	0,
129762306a36Sopenharmony_ci	NWayAdvert,
129862306a36Sopenharmony_ci	NWayLPAR,
129962306a36Sopenharmony_ci	NWayExpansion,
130062306a36Sopenharmony_ci	0
130162306a36Sopenharmony_ci};
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	return location < 8 && mii_2_8139_map[location] ?
130862306a36Sopenharmony_ci	       readw(cp->regs + mii_2_8139_map[location]) : 0;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location,
131362306a36Sopenharmony_ci		       int value)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (location == 0) {
131862306a36Sopenharmony_ci		cpw8(Cfg9346, Cfg9346_Unlock);
131962306a36Sopenharmony_ci		cpw16(BasicModeCtrl, value);
132062306a36Sopenharmony_ci		cpw8(Cfg9346, Cfg9346_Lock);
132162306a36Sopenharmony_ci	} else if (location < 8 && mii_2_8139_map[location])
132262306a36Sopenharmony_ci		cpw16(mii_2_8139_map[location], value);
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/* Set the ethtool Wake-on-LAN settings */
132662306a36Sopenharmony_cistatic int netdev_set_wol (struct cp_private *cp,
132762306a36Sopenharmony_ci			   const struct ethtool_wolinfo *wol)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	u8 options;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	options = cpr8 (Config3) & ~(LinkUp | MagicPacket);
133262306a36Sopenharmony_ci	/* If WOL is being disabled, no need for complexity */
133362306a36Sopenharmony_ci	if (wol->wolopts) {
133462306a36Sopenharmony_ci		if (wol->wolopts & WAKE_PHY)	options |= LinkUp;
133562306a36Sopenharmony_ci		if (wol->wolopts & WAKE_MAGIC)	options |= MagicPacket;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	cpw8 (Cfg9346, Cfg9346_Unlock);
133962306a36Sopenharmony_ci	cpw8 (Config3, options);
134062306a36Sopenharmony_ci	cpw8 (Cfg9346, Cfg9346_Lock);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	options = 0; /* Paranoia setting */
134362306a36Sopenharmony_ci	options = cpr8 (Config5) & ~(UWF | MWF | BWF);
134462306a36Sopenharmony_ci	/* If WOL is being disabled, no need for complexity */
134562306a36Sopenharmony_ci	if (wol->wolopts) {
134662306a36Sopenharmony_ci		if (wol->wolopts & WAKE_UCAST)  options |= UWF;
134762306a36Sopenharmony_ci		if (wol->wolopts & WAKE_BCAST)	options |= BWF;
134862306a36Sopenharmony_ci		if (wol->wolopts & WAKE_MCAST)	options |= MWF;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	cpw8 (Config5, options);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	cp->wol_enabled = (wol->wolopts) ? 1 : 0;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	return 0;
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci/* Get the ethtool Wake-on-LAN settings */
135962306a36Sopenharmony_cistatic void netdev_get_wol (struct cp_private *cp,
136062306a36Sopenharmony_ci	             struct ethtool_wolinfo *wol)
136162306a36Sopenharmony_ci{
136262306a36Sopenharmony_ci	u8 options;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	wol->wolopts   = 0; /* Start from scratch */
136562306a36Sopenharmony_ci	wol->supported = WAKE_PHY   | WAKE_BCAST | WAKE_MAGIC |
136662306a36Sopenharmony_ci		         WAKE_MCAST | WAKE_UCAST;
136762306a36Sopenharmony_ci	/* We don't need to go on if WOL is disabled */
136862306a36Sopenharmony_ci	if (!cp->wol_enabled) return;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	options        = cpr8 (Config3);
137162306a36Sopenharmony_ci	if (options & LinkUp)        wol->wolopts |= WAKE_PHY;
137262306a36Sopenharmony_ci	if (options & MagicPacket)   wol->wolopts |= WAKE_MAGIC;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	options        = 0; /* Paranoia setting */
137562306a36Sopenharmony_ci	options        = cpr8 (Config5);
137662306a36Sopenharmony_ci	if (options & UWF)           wol->wolopts |= WAKE_UCAST;
137762306a36Sopenharmony_ci	if (options & BWF)           wol->wolopts |= WAKE_BCAST;
137862306a36Sopenharmony_ci	if (options & MWF)           wol->wolopts |= WAKE_MCAST;
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
138662306a36Sopenharmony_ci	strscpy(info->version, DRV_VERSION, sizeof(info->version));
138762306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void cp_get_ringparam(struct net_device *dev,
139162306a36Sopenharmony_ci			     struct ethtool_ringparam *ring,
139262306a36Sopenharmony_ci			     struct kernel_ethtool_ringparam *kernel_ring,
139362306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	ring->rx_max_pending = CP_RX_RING_SIZE;
139662306a36Sopenharmony_ci	ring->tx_max_pending = CP_TX_RING_SIZE;
139762306a36Sopenharmony_ci	ring->rx_pending = CP_RX_RING_SIZE;
139862306a36Sopenharmony_ci	ring->tx_pending = CP_TX_RING_SIZE;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic int cp_get_regs_len(struct net_device *dev)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	return CP_REGS_SIZE;
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic int cp_get_sset_count (struct net_device *dev, int sset)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	switch (sset) {
140962306a36Sopenharmony_ci	case ETH_SS_STATS:
141062306a36Sopenharmony_ci		return CP_NUM_STATS;
141162306a36Sopenharmony_ci	default:
141262306a36Sopenharmony_ci		return -EOPNOTSUPP;
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic int cp_get_link_ksettings(struct net_device *dev,
141762306a36Sopenharmony_ci				 struct ethtool_link_ksettings *cmd)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
142062306a36Sopenharmony_ci	unsigned long flags;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
142362306a36Sopenharmony_ci	mii_ethtool_get_link_ksettings(&cp->mii_if, cmd);
142462306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	return 0;
142762306a36Sopenharmony_ci}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_cistatic int cp_set_link_ksettings(struct net_device *dev,
143062306a36Sopenharmony_ci				 const struct ethtool_link_ksettings *cmd)
143162306a36Sopenharmony_ci{
143262306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
143362306a36Sopenharmony_ci	int rc;
143462306a36Sopenharmony_ci	unsigned long flags;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
143762306a36Sopenharmony_ci	rc = mii_ethtool_set_link_ksettings(&cp->mii_if, cmd);
143862306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	return rc;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cistatic int cp_nway_reset(struct net_device *dev)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
144662306a36Sopenharmony_ci	return mii_nway_restart(&cp->mii_if);
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic u32 cp_get_msglevel(struct net_device *dev)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
145262306a36Sopenharmony_ci	return cp->msg_enable;
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_cistatic void cp_set_msglevel(struct net_device *dev, u32 value)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
145862306a36Sopenharmony_ci	cp->msg_enable = value;
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic int cp_set_features(struct net_device *dev, netdev_features_t features)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
146462306a36Sopenharmony_ci	unsigned long flags;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (!((dev->features ^ features) & NETIF_F_RXCSUM))
146762306a36Sopenharmony_ci		return 0;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	if (features & NETIF_F_RXCSUM)
147262306a36Sopenharmony_ci		cp->cpcmd |= RxChkSum;
147362306a36Sopenharmony_ci	else
147462306a36Sopenharmony_ci		cp->cpcmd &= ~RxChkSum;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	if (features & NETIF_F_HW_VLAN_CTAG_RX)
147762306a36Sopenharmony_ci		cp->cpcmd |= RxVlanOn;
147862306a36Sopenharmony_ci	else
147962306a36Sopenharmony_ci		cp->cpcmd &= ~RxVlanOn;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	cpw16_f(CpCmd, cp->cpcmd);
148262306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	return 0;
148562306a36Sopenharmony_ci}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_cistatic void cp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
148862306a36Sopenharmony_ci		        void *p)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
149162306a36Sopenharmony_ci	unsigned long flags;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	if (regs->len < CP_REGS_SIZE)
149462306a36Sopenharmony_ci		return /* -EINVAL */;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	regs->version = CP_REGS_VER;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
149962306a36Sopenharmony_ci	memcpy_fromio(p, cp->regs, CP_REGS_SIZE);
150062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_cistatic void cp_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
150662306a36Sopenharmony_ci	unsigned long flags;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	spin_lock_irqsave (&cp->lock, flags);
150962306a36Sopenharmony_ci	netdev_get_wol (cp, wol);
151062306a36Sopenharmony_ci	spin_unlock_irqrestore (&cp->lock, flags);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic int cp_set_wol (struct net_device *dev, struct ethtool_wolinfo *wol)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
151662306a36Sopenharmony_ci	unsigned long flags;
151762306a36Sopenharmony_ci	int rc;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	spin_lock_irqsave (&cp->lock, flags);
152062306a36Sopenharmony_ci	rc = netdev_set_wol (cp, wol);
152162306a36Sopenharmony_ci	spin_unlock_irqrestore (&cp->lock, flags);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	return rc;
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic void cp_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	switch (stringset) {
152962306a36Sopenharmony_ci	case ETH_SS_STATS:
153062306a36Sopenharmony_ci		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
153162306a36Sopenharmony_ci		break;
153262306a36Sopenharmony_ci	default:
153362306a36Sopenharmony_ci		BUG();
153462306a36Sopenharmony_ci		break;
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_cistatic void cp_get_ethtool_stats (struct net_device *dev,
153962306a36Sopenharmony_ci				  struct ethtool_stats *estats, u64 *tmp_stats)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
154262306a36Sopenharmony_ci	struct cp_dma_stats *nic_stats;
154362306a36Sopenharmony_ci	dma_addr_t dma;
154462306a36Sopenharmony_ci	int i;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats),
154762306a36Sopenharmony_ci				       &dma, GFP_KERNEL);
154862306a36Sopenharmony_ci	if (!nic_stats)
154962306a36Sopenharmony_ci		return;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	/* begin NIC statistics dump */
155262306a36Sopenharmony_ci	cpw32(StatsAddr + 4, (u64)dma >> 32);
155362306a36Sopenharmony_ci	cpw32(StatsAddr, ((u64)dma & DMA_BIT_MASK(32)) | DumpStats);
155462306a36Sopenharmony_ci	cpr32(StatsAddr);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	for (i = 0; i < 1000; i++) {
155762306a36Sopenharmony_ci		if ((cpr32(StatsAddr) & DumpStats) == 0)
155862306a36Sopenharmony_ci			break;
155962306a36Sopenharmony_ci		udelay(10);
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci	cpw32(StatsAddr, 0);
156262306a36Sopenharmony_ci	cpw32(StatsAddr + 4, 0);
156362306a36Sopenharmony_ci	cpr32(StatsAddr);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	i = 0;
156662306a36Sopenharmony_ci	tmp_stats[i++] = le64_to_cpu(nic_stats->tx_ok);
156762306a36Sopenharmony_ci	tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok);
156862306a36Sopenharmony_ci	tmp_stats[i++] = le64_to_cpu(nic_stats->tx_err);
156962306a36Sopenharmony_ci	tmp_stats[i++] = le32_to_cpu(nic_stats->rx_err);
157062306a36Sopenharmony_ci	tmp_stats[i++] = le16_to_cpu(nic_stats->rx_fifo);
157162306a36Sopenharmony_ci	tmp_stats[i++] = le16_to_cpu(nic_stats->frame_align);
157262306a36Sopenharmony_ci	tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_1col);
157362306a36Sopenharmony_ci	tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_mcol);
157462306a36Sopenharmony_ci	tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_phys);
157562306a36Sopenharmony_ci	tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_bcast);
157662306a36Sopenharmony_ci	tmp_stats[i++] = le32_to_cpu(nic_stats->rx_ok_mcast);
157762306a36Sopenharmony_ci	tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort);
157862306a36Sopenharmony_ci	tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun);
157962306a36Sopenharmony_ci	tmp_stats[i++] = cp->cp_stats.rx_frags;
158062306a36Sopenharmony_ci	BUG_ON(i != CP_NUM_STATS);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma);
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_cistatic const struct ethtool_ops cp_ethtool_ops = {
158662306a36Sopenharmony_ci	.get_drvinfo		= cp_get_drvinfo,
158762306a36Sopenharmony_ci	.get_regs_len		= cp_get_regs_len,
158862306a36Sopenharmony_ci	.get_sset_count		= cp_get_sset_count,
158962306a36Sopenharmony_ci	.nway_reset		= cp_nway_reset,
159062306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
159162306a36Sopenharmony_ci	.get_msglevel		= cp_get_msglevel,
159262306a36Sopenharmony_ci	.set_msglevel		= cp_set_msglevel,
159362306a36Sopenharmony_ci	.get_regs		= cp_get_regs,
159462306a36Sopenharmony_ci	.get_wol		= cp_get_wol,
159562306a36Sopenharmony_ci	.set_wol		= cp_set_wol,
159662306a36Sopenharmony_ci	.get_strings		= cp_get_strings,
159762306a36Sopenharmony_ci	.get_ethtool_stats	= cp_get_ethtool_stats,
159862306a36Sopenharmony_ci	.get_eeprom_len		= cp_get_eeprom_len,
159962306a36Sopenharmony_ci	.get_eeprom		= cp_get_eeprom,
160062306a36Sopenharmony_ci	.set_eeprom		= cp_set_eeprom,
160162306a36Sopenharmony_ci	.get_ringparam		= cp_get_ringparam,
160262306a36Sopenharmony_ci	.get_link_ksettings	= cp_get_link_ksettings,
160362306a36Sopenharmony_ci	.set_link_ksettings	= cp_set_link_ksettings,
160462306a36Sopenharmony_ci};
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
160962306a36Sopenharmony_ci	int rc;
161062306a36Sopenharmony_ci	unsigned long flags;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if (!netif_running(dev))
161362306a36Sopenharmony_ci		return -EINVAL;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	spin_lock_irqsave(&cp->lock, flags);
161662306a36Sopenharmony_ci	rc = generic_mii_ioctl(&cp->mii_if, if_mii(rq), cmd, NULL);
161762306a36Sopenharmony_ci	spin_unlock_irqrestore(&cp->lock, flags);
161862306a36Sopenharmony_ci	return rc;
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic int cp_set_mac_address(struct net_device *dev, void *p)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
162462306a36Sopenharmony_ci	struct sockaddr *addr = p;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
162762306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr->sa_data);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	spin_lock_irq(&cp->lock);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	cpw8_f(Cfg9346, Cfg9346_Unlock);
163462306a36Sopenharmony_ci	cpw32_f(MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
163562306a36Sopenharmony_ci	cpw32_f(MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
163662306a36Sopenharmony_ci	cpw8_f(Cfg9346, Cfg9346_Lock);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	spin_unlock_irq(&cp->lock);
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	return 0;
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/* Serial EEPROM section. */
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci/*  EEPROM_Ctrl bits. */
164662306a36Sopenharmony_ci#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
164762306a36Sopenharmony_ci#define EE_CS			0x08	/* EEPROM chip select. */
164862306a36Sopenharmony_ci#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
164962306a36Sopenharmony_ci#define EE_WRITE_0		0x00
165062306a36Sopenharmony_ci#define EE_WRITE_1		0x02
165162306a36Sopenharmony_ci#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
165262306a36Sopenharmony_ci#define EE_ENB			(0x80 | EE_CS)
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci/* Delay between EEPROM clock transitions.
165562306a36Sopenharmony_ci   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
165662306a36Sopenharmony_ci */
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci#define eeprom_delay()	readb(ee_addr)
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci/* The EEPROM commands include the alway-set leading bit. */
166162306a36Sopenharmony_ci#define EE_EXTEND_CMD	(4)
166262306a36Sopenharmony_ci#define EE_WRITE_CMD	(5)
166362306a36Sopenharmony_ci#define EE_READ_CMD		(6)
166462306a36Sopenharmony_ci#define EE_ERASE_CMD	(7)
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci#define EE_EWDS_ADDR	(0)
166762306a36Sopenharmony_ci#define EE_WRAL_ADDR	(1)
166862306a36Sopenharmony_ci#define EE_ERAL_ADDR	(2)
166962306a36Sopenharmony_ci#define EE_EWEN_ADDR	(3)
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci#define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic void eeprom_cmd_start(void __iomem *ee_addr)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	writeb (EE_ENB & ~EE_CS, ee_addr);
167662306a36Sopenharmony_ci	writeb (EE_ENB, ee_addr);
167762306a36Sopenharmony_ci	eeprom_delay ();
167862306a36Sopenharmony_ci}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_cistatic void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len)
168162306a36Sopenharmony_ci{
168262306a36Sopenharmony_ci	int i;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	/* Shift the command bits out. */
168562306a36Sopenharmony_ci	for (i = cmd_len - 1; i >= 0; i--) {
168662306a36Sopenharmony_ci		int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
168762306a36Sopenharmony_ci		writeb (EE_ENB | dataval, ee_addr);
168862306a36Sopenharmony_ci		eeprom_delay ();
168962306a36Sopenharmony_ci		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
169062306a36Sopenharmony_ci		eeprom_delay ();
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci	writeb (EE_ENB, ee_addr);
169362306a36Sopenharmony_ci	eeprom_delay ();
169462306a36Sopenharmony_ci}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_cistatic void eeprom_cmd_end(void __iomem *ee_addr)
169762306a36Sopenharmony_ci{
169862306a36Sopenharmony_ci	writeb(0, ee_addr);
169962306a36Sopenharmony_ci	eeprom_delay ();
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd,
170362306a36Sopenharmony_ci			      int addr_len)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2));
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	eeprom_cmd_start(ee_addr);
170862306a36Sopenharmony_ci	eeprom_cmd(ee_addr, cmd, 3 + addr_len);
170962306a36Sopenharmony_ci	eeprom_cmd_end(ee_addr);
171062306a36Sopenharmony_ci}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_cistatic u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	int i;
171562306a36Sopenharmony_ci	u16 retval = 0;
171662306a36Sopenharmony_ci	void __iomem *ee_addr = ioaddr + Cfg9346;
171762306a36Sopenharmony_ci	int read_cmd = location | (EE_READ_CMD << addr_len);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	eeprom_cmd_start(ee_addr);
172062306a36Sopenharmony_ci	eeprom_cmd(ee_addr, read_cmd, 3 + addr_len);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	for (i = 16; i > 0; i--) {
172362306a36Sopenharmony_ci		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
172462306a36Sopenharmony_ci		eeprom_delay ();
172562306a36Sopenharmony_ci		retval =
172662306a36Sopenharmony_ci		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
172762306a36Sopenharmony_ci				     0);
172862306a36Sopenharmony_ci		writeb (EE_ENB, ee_addr);
172962306a36Sopenharmony_ci		eeprom_delay ();
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	eeprom_cmd_end(ee_addr);
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	return retval;
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic void write_eeprom(void __iomem *ioaddr, int location, u16 val,
173862306a36Sopenharmony_ci			 int addr_len)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	int i;
174162306a36Sopenharmony_ci	void __iomem *ee_addr = ioaddr + Cfg9346;
174262306a36Sopenharmony_ci	int write_cmd = location | (EE_WRITE_CMD << addr_len);
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len);
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	eeprom_cmd_start(ee_addr);
174762306a36Sopenharmony_ci	eeprom_cmd(ee_addr, write_cmd, 3 + addr_len);
174862306a36Sopenharmony_ci	eeprom_cmd(ee_addr, val, 16);
174962306a36Sopenharmony_ci	eeprom_cmd_end(ee_addr);
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	eeprom_cmd_start(ee_addr);
175262306a36Sopenharmony_ci	for (i = 0; i < 20000; i++)
175362306a36Sopenharmony_ci		if (readb(ee_addr) & EE_DATA_READ)
175462306a36Sopenharmony_ci			break;
175562306a36Sopenharmony_ci	eeprom_cmd_end(ee_addr);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len);
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic int cp_get_eeprom_len(struct net_device *dev)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
176362306a36Sopenharmony_ci	int size;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	spin_lock_irq(&cp->lock);
176662306a36Sopenharmony_ci	size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128;
176762306a36Sopenharmony_ci	spin_unlock_irq(&cp->lock);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return size;
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistatic int cp_get_eeprom(struct net_device *dev,
177362306a36Sopenharmony_ci			 struct ethtool_eeprom *eeprom, u8 *data)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
177662306a36Sopenharmony_ci	unsigned int addr_len;
177762306a36Sopenharmony_ci	u16 val;
177862306a36Sopenharmony_ci	u32 offset = eeprom->offset >> 1;
177962306a36Sopenharmony_ci	u32 len = eeprom->len;
178062306a36Sopenharmony_ci	u32 i = 0;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	eeprom->magic = CP_EEPROM_MAGIC;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	spin_lock_irq(&cp->lock);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (eeprom->offset & 1) {
178962306a36Sopenharmony_ci		val = read_eeprom(cp->regs, offset, addr_len);
179062306a36Sopenharmony_ci		data[i++] = (u8)(val >> 8);
179162306a36Sopenharmony_ci		offset++;
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	while (i < len - 1) {
179562306a36Sopenharmony_ci		val = read_eeprom(cp->regs, offset, addr_len);
179662306a36Sopenharmony_ci		data[i++] = (u8)val;
179762306a36Sopenharmony_ci		data[i++] = (u8)(val >> 8);
179862306a36Sopenharmony_ci		offset++;
179962306a36Sopenharmony_ci	}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	if (i < len) {
180262306a36Sopenharmony_ci		val = read_eeprom(cp->regs, offset, addr_len);
180362306a36Sopenharmony_ci		data[i] = (u8)val;
180462306a36Sopenharmony_ci	}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	spin_unlock_irq(&cp->lock);
180762306a36Sopenharmony_ci	return 0;
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic int cp_set_eeprom(struct net_device *dev,
181162306a36Sopenharmony_ci			 struct ethtool_eeprom *eeprom, u8 *data)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
181462306a36Sopenharmony_ci	unsigned int addr_len;
181562306a36Sopenharmony_ci	u16 val;
181662306a36Sopenharmony_ci	u32 offset = eeprom->offset >> 1;
181762306a36Sopenharmony_ci	u32 len = eeprom->len;
181862306a36Sopenharmony_ci	u32 i = 0;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	if (eeprom->magic != CP_EEPROM_MAGIC)
182162306a36Sopenharmony_ci		return -EINVAL;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	spin_lock_irq(&cp->lock);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	if (eeprom->offset & 1) {
182862306a36Sopenharmony_ci		val = read_eeprom(cp->regs, offset, addr_len) & 0xff;
182962306a36Sopenharmony_ci		val |= (u16)data[i++] << 8;
183062306a36Sopenharmony_ci		write_eeprom(cp->regs, offset, val, addr_len);
183162306a36Sopenharmony_ci		offset++;
183262306a36Sopenharmony_ci	}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	while (i < len - 1) {
183562306a36Sopenharmony_ci		val = (u16)data[i++];
183662306a36Sopenharmony_ci		val |= (u16)data[i++] << 8;
183762306a36Sopenharmony_ci		write_eeprom(cp->regs, offset, val, addr_len);
183862306a36Sopenharmony_ci		offset++;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	if (i < len) {
184262306a36Sopenharmony_ci		val = read_eeprom(cp->regs, offset, addr_len) & 0xff00;
184362306a36Sopenharmony_ci		val |= (u16)data[i];
184462306a36Sopenharmony_ci		write_eeprom(cp->regs, offset, val, addr_len);
184562306a36Sopenharmony_ci	}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	spin_unlock_irq(&cp->lock);
184862306a36Sopenharmony_ci	return 0;
184962306a36Sopenharmony_ci}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci/* Put the board into D3cold state and wait for WakeUp signal */
185262306a36Sopenharmony_cistatic void cp_set_d3_state (struct cp_private *cp)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	pci_enable_wake(cp->pdev, PCI_D0, 1); /* Enable PME# generation */
185562306a36Sopenharmony_ci	pci_set_power_state (cp->pdev, PCI_D3hot);
185662306a36Sopenharmony_ci}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_cistatic netdev_features_t cp_features_check(struct sk_buff *skb,
185962306a36Sopenharmony_ci					   struct net_device *dev,
186062306a36Sopenharmony_ci					   netdev_features_t features)
186162306a36Sopenharmony_ci{
186262306a36Sopenharmony_ci	if (skb_shinfo(skb)->gso_size > MSSMask)
186362306a36Sopenharmony_ci		features &= ~NETIF_F_TSO;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	return vlan_features_check(skb, features);
186662306a36Sopenharmony_ci}
186762306a36Sopenharmony_cistatic const struct net_device_ops cp_netdev_ops = {
186862306a36Sopenharmony_ci	.ndo_open		= cp_open,
186962306a36Sopenharmony_ci	.ndo_stop		= cp_close,
187062306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
187162306a36Sopenharmony_ci	.ndo_set_mac_address 	= cp_set_mac_address,
187262306a36Sopenharmony_ci	.ndo_set_rx_mode	= cp_set_rx_mode,
187362306a36Sopenharmony_ci	.ndo_get_stats		= cp_get_stats,
187462306a36Sopenharmony_ci	.ndo_eth_ioctl		= cp_ioctl,
187562306a36Sopenharmony_ci	.ndo_start_xmit		= cp_start_xmit,
187662306a36Sopenharmony_ci	.ndo_tx_timeout		= cp_tx_timeout,
187762306a36Sopenharmony_ci	.ndo_set_features	= cp_set_features,
187862306a36Sopenharmony_ci	.ndo_change_mtu		= cp_change_mtu,
187962306a36Sopenharmony_ci	.ndo_features_check	= cp_features_check,
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
188262306a36Sopenharmony_ci	.ndo_poll_controller	= cp_poll_controller,
188362306a36Sopenharmony_ci#endif
188462306a36Sopenharmony_ci};
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_cistatic int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	struct net_device *dev;
188962306a36Sopenharmony_ci	struct cp_private *cp;
189062306a36Sopenharmony_ci	int rc;
189162306a36Sopenharmony_ci	void __iomem *regs;
189262306a36Sopenharmony_ci	resource_size_t pciaddr;
189362306a36Sopenharmony_ci	unsigned int addr_len, i, pci_using_dac;
189462306a36Sopenharmony_ci	__le16 addr[ETH_ALEN / 2];
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	pr_info_once("%s", version);
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
189962306a36Sopenharmony_ci	    pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision < 0x20) {
190062306a36Sopenharmony_ci		dev_info(&pdev->dev,
190162306a36Sopenharmony_ci			 "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip, use 8139too\n",
190262306a36Sopenharmony_ci			 pdev->vendor, pdev->device, pdev->revision);
190362306a36Sopenharmony_ci		return -ENODEV;
190462306a36Sopenharmony_ci	}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct cp_private));
190762306a36Sopenharmony_ci	if (!dev)
190862306a36Sopenharmony_ci		return -ENOMEM;
190962306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	cp = netdev_priv(dev);
191262306a36Sopenharmony_ci	cp->pdev = pdev;
191362306a36Sopenharmony_ci	cp->dev = dev;
191462306a36Sopenharmony_ci	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
191562306a36Sopenharmony_ci	spin_lock_init (&cp->lock);
191662306a36Sopenharmony_ci	cp->mii_if.dev = dev;
191762306a36Sopenharmony_ci	cp->mii_if.mdio_read = mdio_read;
191862306a36Sopenharmony_ci	cp->mii_if.mdio_write = mdio_write;
191962306a36Sopenharmony_ci	cp->mii_if.phy_id = CP_INTERNAL_PHY;
192062306a36Sopenharmony_ci	cp->mii_if.phy_id_mask = 0x1f;
192162306a36Sopenharmony_ci	cp->mii_if.reg_num_mask = 0x1f;
192262306a36Sopenharmony_ci	cp_set_rxbufsize(cp);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	rc = pci_enable_device(pdev);
192562306a36Sopenharmony_ci	if (rc)
192662306a36Sopenharmony_ci		goto err_out_free;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	rc = pci_set_mwi(pdev);
192962306a36Sopenharmony_ci	if (rc)
193062306a36Sopenharmony_ci		goto err_out_disable;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	rc = pci_request_regions(pdev, DRV_NAME);
193362306a36Sopenharmony_ci	if (rc)
193462306a36Sopenharmony_ci		goto err_out_mwi;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	pciaddr = pci_resource_start(pdev, 1);
193762306a36Sopenharmony_ci	if (!pciaddr) {
193862306a36Sopenharmony_ci		rc = -EIO;
193962306a36Sopenharmony_ci		dev_err(&pdev->dev, "no MMIO resource\n");
194062306a36Sopenharmony_ci		goto err_out_res;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci	if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
194362306a36Sopenharmony_ci		rc = -EIO;
194462306a36Sopenharmony_ci		dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
194562306a36Sopenharmony_ci		       (unsigned long long)pci_resource_len(pdev, 1));
194662306a36Sopenharmony_ci		goto err_out_res;
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	/* Configure DMA attributes. */
195062306a36Sopenharmony_ci	if ((sizeof(dma_addr_t) > 4) &&
195162306a36Sopenharmony_ci	    !dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
195262306a36Sopenharmony_ci		pci_using_dac = 1;
195362306a36Sopenharmony_ci	} else {
195462306a36Sopenharmony_ci		pci_using_dac = 0;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci		rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
195762306a36Sopenharmony_ci		if (rc) {
195862306a36Sopenharmony_ci			dev_err(&pdev->dev,
195962306a36Sopenharmony_ci				"No usable DMA configuration, aborting\n");
196062306a36Sopenharmony_ci			goto err_out_res;
196162306a36Sopenharmony_ci		}
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	cp->cpcmd = (pci_using_dac ? PCIDAC : 0) |
196562306a36Sopenharmony_ci		    PCIMulRW | RxChkSum | CpRxOn | CpTxOn;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	dev->features |= NETIF_F_RXCSUM;
196862306a36Sopenharmony_ci	dev->hw_features |= NETIF_F_RXCSUM;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	regs = ioremap(pciaddr, CP_REGS_SIZE);
197162306a36Sopenharmony_ci	if (!regs) {
197262306a36Sopenharmony_ci		rc = -EIO;
197362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot map PCI MMIO (%Lx@%Lx)\n",
197462306a36Sopenharmony_ci			(unsigned long long)pci_resource_len(pdev, 1),
197562306a36Sopenharmony_ci		       (unsigned long long)pciaddr);
197662306a36Sopenharmony_ci		goto err_out_res;
197762306a36Sopenharmony_ci	}
197862306a36Sopenharmony_ci	cp->regs = regs;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	cp_stop_hw(cp);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	/* read MAC address from EEPROM */
198362306a36Sopenharmony_ci	addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
198462306a36Sopenharmony_ci	for (i = 0; i < 3; i++)
198562306a36Sopenharmony_ci		addr[i] = cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
198662306a36Sopenharmony_ci	eth_hw_addr_set(dev, (u8 *)addr);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	dev->netdev_ops = &cp_netdev_ops;
198962306a36Sopenharmony_ci	netif_napi_add_weight(dev, &cp->napi, cp_rx_poll, 16);
199062306a36Sopenharmony_ci	dev->ethtool_ops = &cp_ethtool_ops;
199162306a36Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
199462306a36Sopenharmony_ci		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (pci_using_dac)
199762306a36Sopenharmony_ci		dev->features |= NETIF_F_HIGHDMA;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
200062306a36Sopenharmony_ci		NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
200162306a36Sopenharmony_ci	dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
200262306a36Sopenharmony_ci		NETIF_F_HIGHDMA;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	/* MTU range: 60 - 4096 */
200562306a36Sopenharmony_ci	dev->min_mtu = CP_MIN_MTU;
200662306a36Sopenharmony_ci	dev->max_mtu = CP_MAX_MTU;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	rc = register_netdev(dev);
200962306a36Sopenharmony_ci	if (rc)
201062306a36Sopenharmony_ci		goto err_out_iomap;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	netdev_info(dev, "RTL-8139C+ at 0x%p, %pM, IRQ %d\n",
201362306a36Sopenharmony_ci		    regs, dev->dev_addr, pdev->irq);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/* enable busmastering and memory-write-invalidate */
201862306a36Sopenharmony_ci	pci_set_master(pdev);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	if (cp->wol_enabled)
202162306a36Sopenharmony_ci		cp_set_d3_state (cp);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	return 0;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_cierr_out_iomap:
202662306a36Sopenharmony_ci	iounmap(regs);
202762306a36Sopenharmony_cierr_out_res:
202862306a36Sopenharmony_ci	pci_release_regions(pdev);
202962306a36Sopenharmony_cierr_out_mwi:
203062306a36Sopenharmony_ci	pci_clear_mwi(pdev);
203162306a36Sopenharmony_cierr_out_disable:
203262306a36Sopenharmony_ci	pci_disable_device(pdev);
203362306a36Sopenharmony_cierr_out_free:
203462306a36Sopenharmony_ci	free_netdev(dev);
203562306a36Sopenharmony_ci	return rc;
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_cistatic void cp_remove_one (struct pci_dev *pdev)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
204162306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	unregister_netdev(dev);
204462306a36Sopenharmony_ci	iounmap(cp->regs);
204562306a36Sopenharmony_ci	if (cp->wol_enabled)
204662306a36Sopenharmony_ci		pci_set_power_state (pdev, PCI_D0);
204762306a36Sopenharmony_ci	pci_release_regions(pdev);
204862306a36Sopenharmony_ci	pci_clear_mwi(pdev);
204962306a36Sopenharmony_ci	pci_disable_device(pdev);
205062306a36Sopenharmony_ci	free_netdev(dev);
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_cistatic int __maybe_unused cp_suspend(struct device *device)
205462306a36Sopenharmony_ci{
205562306a36Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(device);
205662306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
205762306a36Sopenharmony_ci	unsigned long flags;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	if (!netif_running(dev))
206062306a36Sopenharmony_ci		return 0;
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	netif_device_detach (dev);
206362306a36Sopenharmony_ci	netif_stop_queue (dev);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	spin_lock_irqsave (&cp->lock, flags);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	/* Disable Rx and Tx */
206862306a36Sopenharmony_ci	cpw16 (IntrMask, 0);
206962306a36Sopenharmony_ci	cpw8  (Cmd, cpr8 (Cmd) & (~RxOn | ~TxOn));
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	spin_unlock_irqrestore (&cp->lock, flags);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	device_set_wakeup_enable(device, cp->wol_enabled);
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	return 0;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic int __maybe_unused cp_resume(struct device *device)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(device);
208162306a36Sopenharmony_ci	struct cp_private *cp = netdev_priv(dev);
208262306a36Sopenharmony_ci	unsigned long flags;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	if (!netif_running(dev))
208562306a36Sopenharmony_ci		return 0;
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	netif_device_attach (dev);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	/* FIXME: sh*t may happen if the Rx ring buffer is depleted */
209062306a36Sopenharmony_ci	cp_init_rings_index (cp);
209162306a36Sopenharmony_ci	cp_init_hw (cp);
209262306a36Sopenharmony_ci	cp_enable_irq(cp);
209362306a36Sopenharmony_ci	netif_start_queue (dev);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	spin_lock_irqsave (&cp->lock, flags);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	spin_unlock_irqrestore (&cp->lock, flags);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	return 0;
210262306a36Sopenharmony_ci}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_cistatic const struct pci_device_id cp_pci_tbl[] = {
210562306a36Sopenharmony_ci        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     PCI_DEVICE_ID_REALTEK_8139), },
210662306a36Sopenharmony_ci        { PCI_DEVICE(PCI_VENDOR_ID_TTTECH,      PCI_DEVICE_ID_TTTECH_MC322), },
210762306a36Sopenharmony_ci        { },
210862306a36Sopenharmony_ci};
210962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cp_pci_tbl);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cp_pm_ops, cp_suspend, cp_resume);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cistatic struct pci_driver cp_driver = {
211462306a36Sopenharmony_ci	.name         = DRV_NAME,
211562306a36Sopenharmony_ci	.id_table     = cp_pci_tbl,
211662306a36Sopenharmony_ci	.probe        =	cp_init_one,
211762306a36Sopenharmony_ci	.remove       = cp_remove_one,
211862306a36Sopenharmony_ci	.driver.pm    = &cp_pm_ops,
211962306a36Sopenharmony_ci};
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_cimodule_pci_driver(cp_driver);
2122