162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Based on skelton.c by Donald Becker.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This driver is a replacement of older and less maintained version.
762306a36Sopenharmony_ci * This is a header of the older version:
862306a36Sopenharmony_ci *	-----<snip>-----
962306a36Sopenharmony_ci *	Copyright 2001 MontaVista Software Inc.
1062306a36Sopenharmony_ci *	Author: MontaVista Software, Inc.
1162306a36Sopenharmony_ci *		ahennessy@mvista.com
1262306a36Sopenharmony_ci *	Copyright (C) 2000-2001 Toshiba Corporation
1362306a36Sopenharmony_ci *	static const char *version =
1462306a36Sopenharmony_ci *		"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
1562306a36Sopenharmony_ci *	-----<snip>-----
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
1862306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
1962306a36Sopenharmony_ci * for more details.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * (C) Copyright TOSHIBA CORPORATION 2004-2005
2262306a36Sopenharmony_ci * All Rights Reserved.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DRV_VERSION	"1.39"
2662306a36Sopenharmony_cistatic const char version[] = "tc35815.c:v" DRV_VERSION "\n";
2762306a36Sopenharmony_ci#define MODNAME			"tc35815"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/module.h>
3062306a36Sopenharmony_ci#include <linux/kernel.h>
3162306a36Sopenharmony_ci#include <linux/types.h>
3262306a36Sopenharmony_ci#include <linux/fcntl.h>
3362306a36Sopenharmony_ci#include <linux/interrupt.h>
3462306a36Sopenharmony_ci#include <linux/ioport.h>
3562306a36Sopenharmony_ci#include <linux/in.h>
3662306a36Sopenharmony_ci#include <linux/if_vlan.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/string.h>
3962306a36Sopenharmony_ci#include <linux/spinlock.h>
4062306a36Sopenharmony_ci#include <linux/errno.h>
4162306a36Sopenharmony_ci#include <linux/netdevice.h>
4262306a36Sopenharmony_ci#include <linux/etherdevice.h>
4362306a36Sopenharmony_ci#include <linux/skbuff.h>
4462306a36Sopenharmony_ci#include <linux/delay.h>
4562306a36Sopenharmony_ci#include <linux/pci.h>
4662306a36Sopenharmony_ci#include <linux/phy.h>
4762306a36Sopenharmony_ci#include <linux/workqueue.h>
4862306a36Sopenharmony_ci#include <linux/platform_device.h>
4962306a36Sopenharmony_ci#include <linux/prefetch.h>
5062306a36Sopenharmony_ci#include <asm/io.h>
5162306a36Sopenharmony_ci#include <asm/byteorder.h>
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cienum tc35815_chiptype {
5462306a36Sopenharmony_ci	TC35815CF = 0,
5562306a36Sopenharmony_ci	TC35815_NWU,
5662306a36Sopenharmony_ci	TC35815_TX4939,
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* indexed by tc35815_chiptype, above */
6062306a36Sopenharmony_cistatic const struct {
6162306a36Sopenharmony_ci	const char *name;
6262306a36Sopenharmony_ci} chip_info[] = {
6362306a36Sopenharmony_ci	{ "TOSHIBA TC35815CF 10/100BaseTX" },
6462306a36Sopenharmony_ci	{ "TOSHIBA TC35815 with Wake on LAN" },
6562306a36Sopenharmony_ci	{ "TOSHIBA TC35815/TX4939" },
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const struct pci_device_id tc35815_pci_tbl[] = {
6962306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
7062306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
7162306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
7262306a36Sopenharmony_ci	{0,}
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, tc35815_pci_tbl);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* see MODULE_PARM_DESC */
7762306a36Sopenharmony_cistatic struct tc35815_options {
7862306a36Sopenharmony_ci	int speed;
7962306a36Sopenharmony_ci	int duplex;
8062306a36Sopenharmony_ci} options;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * Registers
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_cistruct tc35815_regs {
8662306a36Sopenharmony_ci	__u32 DMA_Ctl;		/* 0x00 */
8762306a36Sopenharmony_ci	__u32 TxFrmPtr;
8862306a36Sopenharmony_ci	__u32 TxThrsh;
8962306a36Sopenharmony_ci	__u32 TxPollCtr;
9062306a36Sopenharmony_ci	__u32 BLFrmPtr;
9162306a36Sopenharmony_ci	__u32 RxFragSize;
9262306a36Sopenharmony_ci	__u32 Int_En;
9362306a36Sopenharmony_ci	__u32 FDA_Bas;
9462306a36Sopenharmony_ci	__u32 FDA_Lim;		/* 0x20 */
9562306a36Sopenharmony_ci	__u32 Int_Src;
9662306a36Sopenharmony_ci	__u32 unused0[2];
9762306a36Sopenharmony_ci	__u32 PauseCnt;
9862306a36Sopenharmony_ci	__u32 RemPauCnt;
9962306a36Sopenharmony_ci	__u32 TxCtlFrmStat;
10062306a36Sopenharmony_ci	__u32 unused1;
10162306a36Sopenharmony_ci	__u32 MAC_Ctl;		/* 0x40 */
10262306a36Sopenharmony_ci	__u32 CAM_Ctl;
10362306a36Sopenharmony_ci	__u32 Tx_Ctl;
10462306a36Sopenharmony_ci	__u32 Tx_Stat;
10562306a36Sopenharmony_ci	__u32 Rx_Ctl;
10662306a36Sopenharmony_ci	__u32 Rx_Stat;
10762306a36Sopenharmony_ci	__u32 MD_Data;
10862306a36Sopenharmony_ci	__u32 MD_CA;
10962306a36Sopenharmony_ci	__u32 CAM_Adr;		/* 0x60 */
11062306a36Sopenharmony_ci	__u32 CAM_Data;
11162306a36Sopenharmony_ci	__u32 CAM_Ena;
11262306a36Sopenharmony_ci	__u32 PROM_Ctl;
11362306a36Sopenharmony_ci	__u32 PROM_Data;
11462306a36Sopenharmony_ci	__u32 Algn_Cnt;
11562306a36Sopenharmony_ci	__u32 CRC_Cnt;
11662306a36Sopenharmony_ci	__u32 Miss_Cnt;
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*
12062306a36Sopenharmony_ci * Bit assignments
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci/* DMA_Ctl bit assign ------------------------------------------------------- */
12362306a36Sopenharmony_ci#define DMA_RxAlign	       0x00c00000 /* 1:Reception Alignment	     */
12462306a36Sopenharmony_ci#define DMA_RxAlign_1	       0x00400000
12562306a36Sopenharmony_ci#define DMA_RxAlign_2	       0x00800000
12662306a36Sopenharmony_ci#define DMA_RxAlign_3	       0x00c00000
12762306a36Sopenharmony_ci#define DMA_M66EnStat	       0x00080000 /* 1:66MHz Enable State	     */
12862306a36Sopenharmony_ci#define DMA_IntMask	       0x00040000 /* 1:Interrupt mask		     */
12962306a36Sopenharmony_ci#define DMA_SWIntReq	       0x00020000 /* 1:Software Interrupt request    */
13062306a36Sopenharmony_ci#define DMA_TxWakeUp	       0x00010000 /* 1:Transmit Wake Up		     */
13162306a36Sopenharmony_ci#define DMA_RxBigE	       0x00008000 /* 1:Receive Big Endian	     */
13262306a36Sopenharmony_ci#define DMA_TxBigE	       0x00004000 /* 1:Transmit Big Endian	     */
13362306a36Sopenharmony_ci#define DMA_TestMode	       0x00002000 /* 1:Test Mode		     */
13462306a36Sopenharmony_ci#define DMA_PowrMgmnt	       0x00001000 /* 1:Power Management		     */
13562306a36Sopenharmony_ci#define DMA_DmBurst_Mask       0x000001fc /* DMA Burst size		     */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/* RxFragSize bit assign ---------------------------------------------------- */
13862306a36Sopenharmony_ci#define RxFrag_EnPack	       0x00008000 /* 1:Enable Packing		     */
13962306a36Sopenharmony_ci#define RxFrag_MinFragMask     0x00000ffc /* Minimum Fragment		     */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* MAC_Ctl bit assign ------------------------------------------------------- */
14262306a36Sopenharmony_ci#define MAC_Link10	       0x00008000 /* 1:Link Status 10Mbits	     */
14362306a36Sopenharmony_ci#define MAC_EnMissRoll	       0x00002000 /* 1:Enable Missed Roll	     */
14462306a36Sopenharmony_ci#define MAC_MissRoll	       0x00000400 /* 1:Missed Roll		     */
14562306a36Sopenharmony_ci#define MAC_Loop10	       0x00000080 /* 1:Loop 10 Mbps		     */
14662306a36Sopenharmony_ci#define MAC_Conn_Auto	       0x00000000 /*00:Connection mode (Automatic)   */
14762306a36Sopenharmony_ci#define MAC_Conn_10M	       0x00000020 /*01:		       (10Mbps endec)*/
14862306a36Sopenharmony_ci#define MAC_Conn_Mll	       0x00000040 /*10:		       (Mll clock)   */
14962306a36Sopenharmony_ci#define MAC_MacLoop	       0x00000010 /* 1:MAC Loopback		     */
15062306a36Sopenharmony_ci#define MAC_FullDup	       0x00000008 /* 1:Full Duplex 0:Half Duplex     */
15162306a36Sopenharmony_ci#define MAC_Reset	       0x00000004 /* 1:Software Reset		     */
15262306a36Sopenharmony_ci#define MAC_HaltImm	       0x00000002 /* 1:Halt Immediate		     */
15362306a36Sopenharmony_ci#define MAC_HaltReq	       0x00000001 /* 1:Halt request		     */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* PROM_Ctl bit assign ------------------------------------------------------ */
15662306a36Sopenharmony_ci#define PROM_Busy	       0x00008000 /* 1:Busy (Start Operation)	     */
15762306a36Sopenharmony_ci#define PROM_Read	       0x00004000 /*10:Read operation		     */
15862306a36Sopenharmony_ci#define PROM_Write	       0x00002000 /*01:Write operation		     */
15962306a36Sopenharmony_ci#define PROM_Erase	       0x00006000 /*11:Erase operation		     */
16062306a36Sopenharmony_ci					  /*00:Enable or Disable Writting,   */
16162306a36Sopenharmony_ci					  /*	  as specified in PROM_Addr. */
16262306a36Sopenharmony_ci#define PROM_Addr_Ena	       0x00000030 /*11xxxx:PROM Write enable	     */
16362306a36Sopenharmony_ci					  /*00xxxx:	      disable	     */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* CAM_Ctl bit assign ------------------------------------------------------- */
16662306a36Sopenharmony_ci#define CAM_CompEn	       0x00000010 /* 1:CAM Compare Enable	     */
16762306a36Sopenharmony_ci#define CAM_NegCAM	       0x00000008 /* 1:Reject packets CAM recognizes,*/
16862306a36Sopenharmony_ci					  /*			accept other */
16962306a36Sopenharmony_ci#define CAM_BroadAcc	       0x00000004 /* 1:Broadcast assept		     */
17062306a36Sopenharmony_ci#define CAM_GroupAcc	       0x00000002 /* 1:Multicast assept		     */
17162306a36Sopenharmony_ci#define CAM_StationAcc	       0x00000001 /* 1:unicast accept		     */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* CAM_Ena bit assign ------------------------------------------------------- */
17462306a36Sopenharmony_ci#define CAM_ENTRY_MAX		       21   /* CAM Data entry max count	     */
17562306a36Sopenharmony_ci#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits)  */
17662306a36Sopenharmony_ci#define CAM_Ena_Bit(index)	(1 << (index))
17762306a36Sopenharmony_ci#define CAM_ENTRY_DESTINATION	0
17862306a36Sopenharmony_ci#define CAM_ENTRY_SOURCE	1
17962306a36Sopenharmony_ci#define CAM_ENTRY_MACCTL	20
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/* Tx_Ctl bit assign -------------------------------------------------------- */
18262306a36Sopenharmony_ci#define Tx_En		       0x00000001 /* 1:Transmit enable		     */
18362306a36Sopenharmony_ci#define Tx_TxHalt	       0x00000002 /* 1:Transmit Halt Request	     */
18462306a36Sopenharmony_ci#define Tx_NoPad	       0x00000004 /* 1:Suppress Padding		     */
18562306a36Sopenharmony_ci#define Tx_NoCRC	       0x00000008 /* 1:Suppress Padding		     */
18662306a36Sopenharmony_ci#define Tx_FBack	       0x00000010 /* 1:Fast Back-off		     */
18762306a36Sopenharmony_ci#define Tx_EnUnder	       0x00000100 /* 1:Enable Underrun		     */
18862306a36Sopenharmony_ci#define Tx_EnExDefer	       0x00000200 /* 1:Enable Excessive Deferral     */
18962306a36Sopenharmony_ci#define Tx_EnLCarr	       0x00000400 /* 1:Enable Lost Carrier	     */
19062306a36Sopenharmony_ci#define Tx_EnExColl	       0x00000800 /* 1:Enable Excessive Collision    */
19162306a36Sopenharmony_ci#define Tx_EnLateColl	       0x00001000 /* 1:Enable Late Collision	     */
19262306a36Sopenharmony_ci#define Tx_EnTxPar	       0x00002000 /* 1:Enable Transmit Parity	     */
19362306a36Sopenharmony_ci#define Tx_EnComp	       0x00004000 /* 1:Enable Completion	     */
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/* Tx_Stat bit assign ------------------------------------------------------- */
19662306a36Sopenharmony_ci#define Tx_TxColl_MASK	       0x0000000F /* Tx Collision Count		     */
19762306a36Sopenharmony_ci#define Tx_ExColl	       0x00000010 /* Excessive Collision	     */
19862306a36Sopenharmony_ci#define Tx_TXDefer	       0x00000020 /* Transmit Defered		     */
19962306a36Sopenharmony_ci#define Tx_Paused	       0x00000040 /* Transmit Paused		     */
20062306a36Sopenharmony_ci#define Tx_IntTx	       0x00000080 /* Interrupt on Tx		     */
20162306a36Sopenharmony_ci#define Tx_Under	       0x00000100 /* Underrun			     */
20262306a36Sopenharmony_ci#define Tx_Defer	       0x00000200 /* Deferral			     */
20362306a36Sopenharmony_ci#define Tx_NCarr	       0x00000400 /* No Carrier			     */
20462306a36Sopenharmony_ci#define Tx_10Stat	       0x00000800 /* 10Mbps Status		     */
20562306a36Sopenharmony_ci#define Tx_LateColl	       0x00001000 /* Late Collision		     */
20662306a36Sopenharmony_ci#define Tx_TxPar	       0x00002000 /* Tx Parity Error		     */
20762306a36Sopenharmony_ci#define Tx_Comp		       0x00004000 /* Completion			     */
20862306a36Sopenharmony_ci#define Tx_Halted	       0x00008000 /* Tx Halted			     */
20962306a36Sopenharmony_ci#define Tx_SQErr	       0x00010000 /* Signal Quality Error(SQE)	     */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/* Rx_Ctl bit assign -------------------------------------------------------- */
21262306a36Sopenharmony_ci#define Rx_EnGood	       0x00004000 /* 1:Enable Good		     */
21362306a36Sopenharmony_ci#define Rx_EnRxPar	       0x00002000 /* 1:Enable Receive Parity	     */
21462306a36Sopenharmony_ci#define Rx_EnLongErr	       0x00000800 /* 1:Enable Long Error	     */
21562306a36Sopenharmony_ci#define Rx_EnOver	       0x00000400 /* 1:Enable OverFlow		     */
21662306a36Sopenharmony_ci#define Rx_EnCRCErr	       0x00000200 /* 1:Enable CRC Error		     */
21762306a36Sopenharmony_ci#define Rx_EnAlign	       0x00000100 /* 1:Enable Alignment		     */
21862306a36Sopenharmony_ci#define Rx_IgnoreCRC	       0x00000040 /* 1:Ignore CRC Value		     */
21962306a36Sopenharmony_ci#define Rx_StripCRC	       0x00000010 /* 1:Strip CRC Value		     */
22062306a36Sopenharmony_ci#define Rx_ShortEn	       0x00000008 /* 1:Short Enable		     */
22162306a36Sopenharmony_ci#define Rx_LongEn	       0x00000004 /* 1:Long Enable		     */
22262306a36Sopenharmony_ci#define Rx_RxHalt	       0x00000002 /* 1:Receive Halt Request	     */
22362306a36Sopenharmony_ci#define Rx_RxEn		       0x00000001 /* 1:Receive Intrrupt Enable	     */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Rx_Stat bit assign ------------------------------------------------------- */
22662306a36Sopenharmony_ci#define Rx_Halted	       0x00008000 /* Rx Halted			     */
22762306a36Sopenharmony_ci#define Rx_Good		       0x00004000 /* Rx Good			     */
22862306a36Sopenharmony_ci#define Rx_RxPar	       0x00002000 /* Rx Parity Error		     */
22962306a36Sopenharmony_ci#define Rx_TypePkt	       0x00001000 /* Rx Type Packet		     */
23062306a36Sopenharmony_ci#define Rx_LongErr	       0x00000800 /* Rx Long Error		     */
23162306a36Sopenharmony_ci#define Rx_Over		       0x00000400 /* Rx Overflow		     */
23262306a36Sopenharmony_ci#define Rx_CRCErr	       0x00000200 /* Rx CRC Error		     */
23362306a36Sopenharmony_ci#define Rx_Align	       0x00000100 /* Rx Alignment Error		     */
23462306a36Sopenharmony_ci#define Rx_10Stat	       0x00000080 /* Rx 10Mbps Status		     */
23562306a36Sopenharmony_ci#define Rx_IntRx	       0x00000040 /* Rx Interrupt		     */
23662306a36Sopenharmony_ci#define Rx_CtlRecd	       0x00000020 /* Rx Control Receive		     */
23762306a36Sopenharmony_ci#define Rx_InLenErr	       0x00000010 /* Rx In Range Frame Length Error  */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#define Rx_Stat_Mask	       0x0000FFF0 /* Rx All Status Mask		     */
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/* Int_En bit assign -------------------------------------------------------- */
24262306a36Sopenharmony_ci#define Int_NRAbtEn	       0x00000800 /* 1:Non-recoverable Abort Enable  */
24362306a36Sopenharmony_ci#define Int_TxCtlCmpEn	       0x00000400 /* 1:Transmit Ctl Complete Enable  */
24462306a36Sopenharmony_ci#define Int_DmParErrEn	       0x00000200 /* 1:DMA Parity Error Enable	     */
24562306a36Sopenharmony_ci#define Int_DParDEn	       0x00000100 /* 1:Data Parity Error Enable	     */
24662306a36Sopenharmony_ci#define Int_EarNotEn	       0x00000080 /* 1:Early Notify Enable	     */
24762306a36Sopenharmony_ci#define Int_DParErrEn	       0x00000040 /* 1:Detected Parity Error Enable  */
24862306a36Sopenharmony_ci#define Int_SSysErrEn	       0x00000020 /* 1:Signalled System Error Enable */
24962306a36Sopenharmony_ci#define Int_RMasAbtEn	       0x00000010 /* 1:Received Master Abort Enable  */
25062306a36Sopenharmony_ci#define Int_RTargAbtEn	       0x00000008 /* 1:Received Target Abort Enable  */
25162306a36Sopenharmony_ci#define Int_STargAbtEn	       0x00000004 /* 1:Signalled Target Abort Enable */
25262306a36Sopenharmony_ci#define Int_BLExEn	       0x00000002 /* 1:Buffer List Exhausted Enable  */
25362306a36Sopenharmony_ci#define Int_FDAExEn	       0x00000001 /* 1:Free Descriptor Area	     */
25462306a36Sopenharmony_ci					  /*		   Exhausted Enable  */
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/* Int_Src bit assign ------------------------------------------------------- */
25762306a36Sopenharmony_ci#define Int_NRabt	       0x00004000 /* 1:Non Recoverable error	     */
25862306a36Sopenharmony_ci#define Int_DmParErrStat       0x00002000 /* 1:DMA Parity Error & Clear	     */
25962306a36Sopenharmony_ci#define Int_BLEx	       0x00001000 /* 1:Buffer List Empty & Clear     */
26062306a36Sopenharmony_ci#define Int_FDAEx	       0x00000800 /* 1:FDA Empty & Clear	     */
26162306a36Sopenharmony_ci#define Int_IntNRAbt	       0x00000400 /* 1:Non Recoverable Abort	     */
26262306a36Sopenharmony_ci#define Int_IntCmp	       0x00000200 /* 1:MAC control packet complete   */
26362306a36Sopenharmony_ci#define Int_IntExBD	       0x00000100 /* 1:Interrupt Extra BD & Clear    */
26462306a36Sopenharmony_ci#define Int_DmParErr	       0x00000080 /* 1:DMA Parity Error & Clear	     */
26562306a36Sopenharmony_ci#define Int_IntEarNot	       0x00000040 /* 1:Receive Data write & Clear    */
26662306a36Sopenharmony_ci#define Int_SWInt	       0x00000020 /* 1:Software request & Clear	     */
26762306a36Sopenharmony_ci#define Int_IntBLEx	       0x00000010 /* 1:Buffer List Empty & Clear     */
26862306a36Sopenharmony_ci#define Int_IntFDAEx	       0x00000008 /* 1:FDA Empty & Clear	     */
26962306a36Sopenharmony_ci#define Int_IntPCI	       0x00000004 /* 1:PCI controller & Clear	     */
27062306a36Sopenharmony_ci#define Int_IntMacRx	       0x00000002 /* 1:Rx controller & Clear	     */
27162306a36Sopenharmony_ci#define Int_IntMacTx	       0x00000001 /* 1:Tx controller & Clear	     */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* MD_CA bit assign --------------------------------------------------------- */
27462306a36Sopenharmony_ci#define MD_CA_PreSup	       0x00001000 /* 1:Preamble Suppress		     */
27562306a36Sopenharmony_ci#define MD_CA_Busy	       0x00000800 /* 1:Busy (Start Operation)	     */
27662306a36Sopenharmony_ci#define MD_CA_Wr	       0x00000400 /* 1:Write 0:Read		     */
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/*
28062306a36Sopenharmony_ci * Descriptors
28162306a36Sopenharmony_ci */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/* Frame descriptor */
28462306a36Sopenharmony_cistruct FDesc {
28562306a36Sopenharmony_ci	volatile __u32 FDNext;
28662306a36Sopenharmony_ci	volatile __u32 FDSystem;
28762306a36Sopenharmony_ci	volatile __u32 FDStat;
28862306a36Sopenharmony_ci	volatile __u32 FDCtl;
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* Buffer descriptor */
29262306a36Sopenharmony_cistruct BDesc {
29362306a36Sopenharmony_ci	volatile __u32 BuffData;
29462306a36Sopenharmony_ci	volatile __u32 BDCtl;
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define FD_ALIGN	16
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/* Frame Descriptor bit assign ---------------------------------------------- */
30062306a36Sopenharmony_ci#define FD_FDLength_MASK       0x0000FFFF /* Length MASK		     */
30162306a36Sopenharmony_ci#define FD_BDCnt_MASK	       0x001F0000 /* BD count MASK in FD	     */
30262306a36Sopenharmony_ci#define FD_FrmOpt_MASK	       0x7C000000 /* Frame option MASK		     */
30362306a36Sopenharmony_ci#define FD_FrmOpt_BigEndian    0x40000000 /* Tx/Rx */
30462306a36Sopenharmony_ci#define FD_FrmOpt_IntTx	       0x20000000 /* Tx only */
30562306a36Sopenharmony_ci#define FD_FrmOpt_NoCRC	       0x10000000 /* Tx only */
30662306a36Sopenharmony_ci#define FD_FrmOpt_NoPadding    0x08000000 /* Tx only */
30762306a36Sopenharmony_ci#define FD_FrmOpt_Packing      0x04000000 /* Rx only */
30862306a36Sopenharmony_ci#define FD_CownsFD	       0x80000000 /* FD Controller owner bit	     */
30962306a36Sopenharmony_ci#define FD_Next_EOL	       0x00000001 /* FD EOL indicator		     */
31062306a36Sopenharmony_ci#define FD_BDCnt_SHIFT	       16
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/* Buffer Descriptor bit assign --------------------------------------------- */
31362306a36Sopenharmony_ci#define BD_BuffLength_MASK     0x0000FFFF /* Receive Data Size		     */
31462306a36Sopenharmony_ci#define BD_RxBDID_MASK	       0x00FF0000 /* BD ID Number MASK		     */
31562306a36Sopenharmony_ci#define BD_RxBDSeqN_MASK       0x7F000000 /* Rx BD Sequence Number	     */
31662306a36Sopenharmony_ci#define BD_CownsBD	       0x80000000 /* BD Controller owner bit	     */
31762306a36Sopenharmony_ci#define BD_RxBDID_SHIFT	       16
31862306a36Sopenharmony_ci#define BD_RxBDSeqN_SHIFT      24
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/* Some useful constants. */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci#define TX_CTL_CMD	(Tx_EnTxPar | Tx_EnLateColl | \
32462306a36Sopenharmony_ci	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
32562306a36Sopenharmony_ci	Tx_En)	/* maybe  0x7b01 */
32662306a36Sopenharmony_ci/* Do not use Rx_StripCRC -- it causes trouble on BLEx/FDAEx condition */
32762306a36Sopenharmony_ci#define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
32862306a36Sopenharmony_ci	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
32962306a36Sopenharmony_ci#define INT_EN_CMD  (Int_NRAbtEn | \
33062306a36Sopenharmony_ci	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
33162306a36Sopenharmony_ci	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
33262306a36Sopenharmony_ci	Int_STargAbtEn | \
33362306a36Sopenharmony_ci	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
33462306a36Sopenharmony_ci#define DMA_CTL_CMD	DMA_BURST_SIZE
33562306a36Sopenharmony_ci#define HAVE_DMA_RXALIGN(lp)	likely((lp)->chiptype != TC35815CF)
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/* Tuning parameters */
33862306a36Sopenharmony_ci#define DMA_BURST_SIZE	32
33962306a36Sopenharmony_ci#define TX_THRESHOLD	1024
34062306a36Sopenharmony_ci/* used threshold with packet max byte for low pci transfer ability.*/
34162306a36Sopenharmony_ci#define TX_THRESHOLD_MAX 1536
34262306a36Sopenharmony_ci/* setting threshold max value when overrun error occurred this count. */
34362306a36Sopenharmony_ci#define TX_THRESHOLD_KEEP_LIMIT 10
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
34662306a36Sopenharmony_ci#define FD_PAGE_NUM 4
34762306a36Sopenharmony_ci#define RX_BUF_NUM	128	/* < 256 */
34862306a36Sopenharmony_ci#define RX_FD_NUM	256	/* >= 32 */
34962306a36Sopenharmony_ci#define TX_FD_NUM	128
35062306a36Sopenharmony_ci#if RX_CTL_CMD & Rx_LongEn
35162306a36Sopenharmony_ci#define RX_BUF_SIZE	PAGE_SIZE
35262306a36Sopenharmony_ci#elif RX_CTL_CMD & Rx_StripCRC
35362306a36Sopenharmony_ci#define RX_BUF_SIZE	\
35462306a36Sopenharmony_ci	L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN)
35562306a36Sopenharmony_ci#else
35662306a36Sopenharmony_ci#define RX_BUF_SIZE	\
35762306a36Sopenharmony_ci	L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN)
35862306a36Sopenharmony_ci#endif
35962306a36Sopenharmony_ci#define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
36062306a36Sopenharmony_ci#define NAPI_WEIGHT	16
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistruct TxFD {
36362306a36Sopenharmony_ci	struct FDesc fd;
36462306a36Sopenharmony_ci	struct BDesc bd;
36562306a36Sopenharmony_ci	struct BDesc unused;
36662306a36Sopenharmony_ci};
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistruct RxFD {
36962306a36Sopenharmony_ci	struct FDesc fd;
37062306a36Sopenharmony_ci	struct BDesc bd[];	/* variable length */
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistruct FrFD {
37462306a36Sopenharmony_ci	struct FDesc fd;
37562306a36Sopenharmony_ci	struct BDesc bd[RX_BUF_NUM];
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci#define tc_readl(addr)	ioread32(addr)
38062306a36Sopenharmony_ci#define tc_writel(d, addr)	iowrite32(d, addr)
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/* Information that need to be kept for each controller. */
38562306a36Sopenharmony_cistruct tc35815_local {
38662306a36Sopenharmony_ci	struct pci_dev *pci_dev;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	struct net_device *dev;
38962306a36Sopenharmony_ci	struct napi_struct napi;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* statistics */
39262306a36Sopenharmony_ci	struct {
39362306a36Sopenharmony_ci		int max_tx_qlen;
39462306a36Sopenharmony_ci		int tx_ints;
39562306a36Sopenharmony_ci		int rx_ints;
39662306a36Sopenharmony_ci		int tx_underrun;
39762306a36Sopenharmony_ci	} lstats;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* Tx control lock.  This protects the transmit buffer ring
40062306a36Sopenharmony_ci	 * state along with the "tx full" state of the driver.  This
40162306a36Sopenharmony_ci	 * means all netif_queue flow control actions are protected
40262306a36Sopenharmony_ci	 * by this lock as well.
40362306a36Sopenharmony_ci	 */
40462306a36Sopenharmony_ci	spinlock_t lock;
40562306a36Sopenharmony_ci	spinlock_t rx_lock;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	struct mii_bus *mii_bus;
40862306a36Sopenharmony_ci	int duplex;
40962306a36Sopenharmony_ci	int speed;
41062306a36Sopenharmony_ci	int link;
41162306a36Sopenharmony_ci	struct work_struct restart_work;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/*
41462306a36Sopenharmony_ci	 * Transmitting: Batch Mode.
41562306a36Sopenharmony_ci	 *	1 BD in 1 TxFD.
41662306a36Sopenharmony_ci	 * Receiving: Non-Packing Mode.
41762306a36Sopenharmony_ci	 *	1 circular FD for Free Buffer List.
41862306a36Sopenharmony_ci	 *	RX_BUF_NUM BD in Free Buffer FD.
41962306a36Sopenharmony_ci	 *	One Free Buffer BD has ETH_FRAME_LEN data buffer.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	void *fd_buf;	/* for TxFD, RxFD, FrFD */
42262306a36Sopenharmony_ci	dma_addr_t fd_buf_dma;
42362306a36Sopenharmony_ci	struct TxFD *tfd_base;
42462306a36Sopenharmony_ci	unsigned int tfd_start;
42562306a36Sopenharmony_ci	unsigned int tfd_end;
42662306a36Sopenharmony_ci	struct RxFD *rfd_base;
42762306a36Sopenharmony_ci	struct RxFD *rfd_limit;
42862306a36Sopenharmony_ci	struct RxFD *rfd_cur;
42962306a36Sopenharmony_ci	struct FrFD *fbl_ptr;
43062306a36Sopenharmony_ci	unsigned int fbl_count;
43162306a36Sopenharmony_ci	struct {
43262306a36Sopenharmony_ci		struct sk_buff *skb;
43362306a36Sopenharmony_ci		dma_addr_t skb_dma;
43462306a36Sopenharmony_ci	} tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
43562306a36Sopenharmony_ci	u32 msg_enable;
43662306a36Sopenharmony_ci	enum tc35815_chiptype chiptype;
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci#ifdef DEBUG
44462306a36Sopenharmony_cistatic inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci#endif
44962306a36Sopenharmony_cistatic struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
45062306a36Sopenharmony_ci				       struct pci_dev *hwdev,
45162306a36Sopenharmony_ci				       dma_addr_t *dma_handle)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct sk_buff *skb;
45462306a36Sopenharmony_ci	skb = netdev_alloc_skb(dev, RX_BUF_SIZE);
45562306a36Sopenharmony_ci	if (!skb)
45662306a36Sopenharmony_ci		return NULL;
45762306a36Sopenharmony_ci	*dma_handle = dma_map_single(&hwdev->dev, skb->data, RX_BUF_SIZE,
45862306a36Sopenharmony_ci				     DMA_FROM_DEVICE);
45962306a36Sopenharmony_ci	if (dma_mapping_error(&hwdev->dev, *dma_handle)) {
46062306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
46162306a36Sopenharmony_ci		return NULL;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	skb_reserve(skb, 2);	/* make IP header 4byte aligned */
46462306a36Sopenharmony_ci	return skb;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	dma_unmap_single(&hwdev->dev, dma_handle, RX_BUF_SIZE,
47062306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
47162306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci/* Index to functions, as function prototypes. */
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int	tc35815_open(struct net_device *dev);
47762306a36Sopenharmony_cistatic netdev_tx_t	tc35815_send_packet(struct sk_buff *skb,
47862306a36Sopenharmony_ci					    struct net_device *dev);
47962306a36Sopenharmony_cistatic irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
48062306a36Sopenharmony_cistatic int	tc35815_rx(struct net_device *dev, int limit);
48162306a36Sopenharmony_cistatic int	tc35815_poll(struct napi_struct *napi, int budget);
48262306a36Sopenharmony_cistatic void	tc35815_txdone(struct net_device *dev);
48362306a36Sopenharmony_cistatic int	tc35815_close(struct net_device *dev);
48462306a36Sopenharmony_cistatic struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
48562306a36Sopenharmony_cistatic void	tc35815_set_multicast_list(struct net_device *dev);
48662306a36Sopenharmony_cistatic void	tc35815_tx_timeout(struct net_device *dev, unsigned int txqueue);
48762306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
48862306a36Sopenharmony_cistatic void	tc35815_poll_controller(struct net_device *dev);
48962306a36Sopenharmony_ci#endif
49062306a36Sopenharmony_cistatic const struct ethtool_ops tc35815_ethtool_ops;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/* Example routines you must write ;->. */
49362306a36Sopenharmony_cistatic void	tc35815_chip_reset(struct net_device *dev);
49462306a36Sopenharmony_cistatic void	tc35815_chip_init(struct net_device *dev);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci#ifdef DEBUG
49762306a36Sopenharmony_cistatic void	panic_queues(struct net_device *dev);
49862306a36Sopenharmony_ci#endif
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic void tc35815_restart_work(struct work_struct *work);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct net_device *dev = bus->priv;
50562306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
50662306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
50762306a36Sopenharmony_ci	unsigned long timeout = jiffies + HZ;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA);
51062306a36Sopenharmony_ci	udelay(12); /* it takes 32 x 400ns at least */
51162306a36Sopenharmony_ci	while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
51262306a36Sopenharmony_ci		if (time_after(jiffies, timeout))
51362306a36Sopenharmony_ci			return -EIO;
51462306a36Sopenharmony_ci		cpu_relax();
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci	return tc_readl(&tr->MD_Data) & 0xffff;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct net_device *dev = bus->priv;
52262306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
52362306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
52462306a36Sopenharmony_ci	unsigned long timeout = jiffies + HZ;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	tc_writel(val, &tr->MD_Data);
52762306a36Sopenharmony_ci	tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f),
52862306a36Sopenharmony_ci		  &tr->MD_CA);
52962306a36Sopenharmony_ci	udelay(12); /* it takes 32 x 400ns at least */
53062306a36Sopenharmony_ci	while (tc_readl(&tr->MD_CA) & MD_CA_Busy) {
53162306a36Sopenharmony_ci		if (time_after(jiffies, timeout))
53262306a36Sopenharmony_ci			return -EIO;
53362306a36Sopenharmony_ci		cpu_relax();
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci	return 0;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void tc_handle_link_change(struct net_device *dev)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
54162306a36Sopenharmony_ci	struct phy_device *phydev = dev->phydev;
54262306a36Sopenharmony_ci	unsigned long flags;
54362306a36Sopenharmony_ci	int status_change = 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
54662306a36Sopenharmony_ci	if (phydev->link &&
54762306a36Sopenharmony_ci	    (lp->speed != phydev->speed || lp->duplex != phydev->duplex)) {
54862306a36Sopenharmony_ci		struct tc35815_regs __iomem *tr =
54962306a36Sopenharmony_ci			(struct tc35815_regs __iomem *)dev->base_addr;
55062306a36Sopenharmony_ci		u32 reg;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		reg = tc_readl(&tr->MAC_Ctl);
55362306a36Sopenharmony_ci		reg |= MAC_HaltReq;
55462306a36Sopenharmony_ci		tc_writel(reg, &tr->MAC_Ctl);
55562306a36Sopenharmony_ci		if (phydev->duplex == DUPLEX_FULL)
55662306a36Sopenharmony_ci			reg |= MAC_FullDup;
55762306a36Sopenharmony_ci		else
55862306a36Sopenharmony_ci			reg &= ~MAC_FullDup;
55962306a36Sopenharmony_ci		tc_writel(reg, &tr->MAC_Ctl);
56062306a36Sopenharmony_ci		reg &= ~MAC_HaltReq;
56162306a36Sopenharmony_ci		tc_writel(reg, &tr->MAC_Ctl);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/*
56462306a36Sopenharmony_ci		 * TX4939 PCFG.SPEEDn bit will be changed on
56562306a36Sopenharmony_ci		 * NETDEV_CHANGE event.
56662306a36Sopenharmony_ci		 */
56762306a36Sopenharmony_ci		/*
56862306a36Sopenharmony_ci		 * WORKAROUND: enable LostCrS only if half duplex
56962306a36Sopenharmony_ci		 * operation.
57062306a36Sopenharmony_ci		 * (TX4939 does not have EnLCarr)
57162306a36Sopenharmony_ci		 */
57262306a36Sopenharmony_ci		if (phydev->duplex == DUPLEX_HALF &&
57362306a36Sopenharmony_ci		    lp->chiptype != TC35815_TX4939)
57462306a36Sopenharmony_ci			tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr,
57562306a36Sopenharmony_ci				  &tr->Tx_Ctl);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		lp->speed = phydev->speed;
57862306a36Sopenharmony_ci		lp->duplex = phydev->duplex;
57962306a36Sopenharmony_ci		status_change = 1;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if (phydev->link != lp->link) {
58362306a36Sopenharmony_ci		if (phydev->link) {
58462306a36Sopenharmony_ci			/* delayed promiscuous enabling */
58562306a36Sopenharmony_ci			if (dev->flags & IFF_PROMISC)
58662306a36Sopenharmony_ci				tc35815_set_multicast_list(dev);
58762306a36Sopenharmony_ci		} else {
58862306a36Sopenharmony_ci			lp->speed = 0;
58962306a36Sopenharmony_ci			lp->duplex = -1;
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci		lp->link = phydev->link;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		status_change = 1;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (status_change && netif_msg_link(lp)) {
59862306a36Sopenharmony_ci		phy_print_status(phydev);
59962306a36Sopenharmony_ci		pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n",
60062306a36Sopenharmony_ci			 dev->name,
60162306a36Sopenharmony_ci			 phy_read(phydev, MII_BMCR),
60262306a36Sopenharmony_ci			 phy_read(phydev, MII_BMSR),
60362306a36Sopenharmony_ci			 phy_read(phydev, MII_LPA));
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int tc_mii_probe(struct net_device *dev)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
61062306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
61162306a36Sopenharmony_ci	struct phy_device *phydev;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	phydev = phy_find_first(lp->mii_bus);
61462306a36Sopenharmony_ci	if (!phydev) {
61562306a36Sopenharmony_ci		printk(KERN_ERR "%s: no PHY found\n", dev->name);
61662306a36Sopenharmony_ci		return -ENODEV;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* attach the mac to the phy */
62062306a36Sopenharmony_ci	phydev = phy_connect(dev, phydev_name(phydev),
62162306a36Sopenharmony_ci			     &tc_handle_link_change,
62262306a36Sopenharmony_ci			     lp->chiptype == TC35815_TX4939 ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII);
62362306a36Sopenharmony_ci	if (IS_ERR(phydev)) {
62462306a36Sopenharmony_ci		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
62562306a36Sopenharmony_ci		return PTR_ERR(phydev);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	phy_attached_info(phydev);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* mask with MAC supported features */
63162306a36Sopenharmony_ci	phy_set_max_speed(phydev, SPEED_100);
63262306a36Sopenharmony_ci	if (options.speed == 10) {
63362306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mask);
63462306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mask);
63562306a36Sopenharmony_ci	} else if (options.speed == 100) {
63662306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, mask);
63762306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, mask);
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci	if (options.duplex == 1) {
64062306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, mask);
64162306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mask);
64262306a36Sopenharmony_ci	} else if (options.duplex == 2) {
64362306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, mask);
64462306a36Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mask);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	linkmode_andnot(phydev->supported, phydev->supported, mask);
64762306a36Sopenharmony_ci	linkmode_copy(phydev->advertising, phydev->supported);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	lp->link = 0;
65062306a36Sopenharmony_ci	lp->speed = 0;
65162306a36Sopenharmony_ci	lp->duplex = -1;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return 0;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic int tc_mii_init(struct net_device *dev)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
65962306a36Sopenharmony_ci	int err;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	lp->mii_bus = mdiobus_alloc();
66262306a36Sopenharmony_ci	if (lp->mii_bus == NULL) {
66362306a36Sopenharmony_ci		err = -ENOMEM;
66462306a36Sopenharmony_ci		goto err_out;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	lp->mii_bus->name = "tc35815_mii_bus";
66862306a36Sopenharmony_ci	lp->mii_bus->read = tc_mdio_read;
66962306a36Sopenharmony_ci	lp->mii_bus->write = tc_mdio_write;
67062306a36Sopenharmony_ci	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", pci_dev_id(lp->pci_dev));
67162306a36Sopenharmony_ci	lp->mii_bus->priv = dev;
67262306a36Sopenharmony_ci	lp->mii_bus->parent = &lp->pci_dev->dev;
67362306a36Sopenharmony_ci	err = mdiobus_register(lp->mii_bus);
67462306a36Sopenharmony_ci	if (err)
67562306a36Sopenharmony_ci		goto err_out_free_mii_bus;
67662306a36Sopenharmony_ci	err = tc_mii_probe(dev);
67762306a36Sopenharmony_ci	if (err)
67862306a36Sopenharmony_ci		goto err_out_unregister_bus;
67962306a36Sopenharmony_ci	return 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cierr_out_unregister_bus:
68262306a36Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
68362306a36Sopenharmony_cierr_out_free_mii_bus:
68462306a36Sopenharmony_ci	mdiobus_free(lp->mii_bus);
68562306a36Sopenharmony_cierr_out:
68662306a36Sopenharmony_ci	return err;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci#ifdef CONFIG_CPU_TX49XX
69062306a36Sopenharmony_ci/*
69162306a36Sopenharmony_ci * Find a platform_device providing a MAC address.  The platform code
69262306a36Sopenharmony_ci * should provide a "tc35815-mac" device with a MAC address in its
69362306a36Sopenharmony_ci * platform_data.
69462306a36Sopenharmony_ci */
69562306a36Sopenharmony_cistatic int tc35815_mac_match(struct device *dev, const void *data)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct platform_device *plat_dev = to_platform_device(dev);
69862306a36Sopenharmony_ci	const struct pci_dev *pci_dev = data;
69962306a36Sopenharmony_ci	unsigned int id = pci_dev->irq;
70062306a36Sopenharmony_ci	return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic int tc35815_read_plat_dev_addr(struct net_device *dev)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
70662306a36Sopenharmony_ci	struct device *pd = bus_find_device(&platform_bus_type, NULL,
70762306a36Sopenharmony_ci					    lp->pci_dev, tc35815_mac_match);
70862306a36Sopenharmony_ci	if (pd) {
70962306a36Sopenharmony_ci		if (pd->platform_data)
71062306a36Sopenharmony_ci			eth_hw_addr_set(dev, pd->platform_data);
71162306a36Sopenharmony_ci		put_device(pd);
71262306a36Sopenharmony_ci		return is_valid_ether_addr(dev->dev_addr) ? 0 : -ENODEV;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	return -ENODEV;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci#else
71762306a36Sopenharmony_cistatic int tc35815_read_plat_dev_addr(struct net_device *dev)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	return -ENODEV;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci#endif
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int tc35815_init_dev_addr(struct net_device *dev)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
72662306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
72762306a36Sopenharmony_ci	u8 addr[ETH_ALEN];
72862306a36Sopenharmony_ci	int i;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
73162306a36Sopenharmony_ci		;
73262306a36Sopenharmony_ci	for (i = 0; i < 6; i += 2) {
73362306a36Sopenharmony_ci		unsigned short data;
73462306a36Sopenharmony_ci		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
73562306a36Sopenharmony_ci		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
73662306a36Sopenharmony_ci			;
73762306a36Sopenharmony_ci		data = tc_readl(&tr->PROM_Data);
73862306a36Sopenharmony_ci		addr[i] = data & 0xff;
73962306a36Sopenharmony_ci		addr[i+1] = data >> 8;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr);
74262306a36Sopenharmony_ci	if (!is_valid_ether_addr(dev->dev_addr))
74362306a36Sopenharmony_ci		return tc35815_read_plat_dev_addr(dev);
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic const struct net_device_ops tc35815_netdev_ops = {
74862306a36Sopenharmony_ci	.ndo_open		= tc35815_open,
74962306a36Sopenharmony_ci	.ndo_stop		= tc35815_close,
75062306a36Sopenharmony_ci	.ndo_start_xmit		= tc35815_send_packet,
75162306a36Sopenharmony_ci	.ndo_get_stats		= tc35815_get_stats,
75262306a36Sopenharmony_ci	.ndo_set_rx_mode	= tc35815_set_multicast_list,
75362306a36Sopenharmony_ci	.ndo_tx_timeout		= tc35815_tx_timeout,
75462306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl_running,
75562306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
75662306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
75762306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
75862306a36Sopenharmony_ci	.ndo_poll_controller	= tc35815_poll_controller,
75962306a36Sopenharmony_ci#endif
76062306a36Sopenharmony_ci};
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic int tc35815_init_one(struct pci_dev *pdev,
76362306a36Sopenharmony_ci			    const struct pci_device_id *ent)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	void __iomem *ioaddr = NULL;
76662306a36Sopenharmony_ci	struct net_device *dev;
76762306a36Sopenharmony_ci	struct tc35815_local *lp;
76862306a36Sopenharmony_ci	int rc;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	static int printed_version;
77162306a36Sopenharmony_ci	if (!printed_version++) {
77262306a36Sopenharmony_ci		printk(version);
77362306a36Sopenharmony_ci		dev_printk(KERN_DEBUG, &pdev->dev,
77462306a36Sopenharmony_ci			   "speed:%d duplex:%d\n",
77562306a36Sopenharmony_ci			   options.speed, options.duplex);
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (!pdev->irq) {
77962306a36Sopenharmony_ci		dev_warn(&pdev->dev, "no IRQ assigned.\n");
78062306a36Sopenharmony_ci		return -ENODEV;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	/* dev zeroed in alloc_etherdev */
78462306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(*lp));
78562306a36Sopenharmony_ci	if (dev == NULL)
78662306a36Sopenharmony_ci		return -ENOMEM;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
78962306a36Sopenharmony_ci	lp = netdev_priv(dev);
79062306a36Sopenharmony_ci	lp->dev = dev;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* enable device (incl. PCI PM wakeup), and bus-mastering */
79362306a36Sopenharmony_ci	rc = pcim_enable_device(pdev);
79462306a36Sopenharmony_ci	if (rc)
79562306a36Sopenharmony_ci		goto err_out;
79662306a36Sopenharmony_ci	rc = pcim_iomap_regions(pdev, 1 << 1, MODNAME);
79762306a36Sopenharmony_ci	if (rc)
79862306a36Sopenharmony_ci		goto err_out;
79962306a36Sopenharmony_ci	pci_set_master(pdev);
80062306a36Sopenharmony_ci	ioaddr = pcim_iomap_table(pdev)[1];
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* Initialize the device structure. */
80362306a36Sopenharmony_ci	dev->netdev_ops = &tc35815_netdev_ops;
80462306a36Sopenharmony_ci	dev->ethtool_ops = &tc35815_ethtool_ops;
80562306a36Sopenharmony_ci	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
80662306a36Sopenharmony_ci	netif_napi_add_weight(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	dev->irq = pdev->irq;
80962306a36Sopenharmony_ci	dev->base_addr = (unsigned long)ioaddr;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	INIT_WORK(&lp->restart_work, tc35815_restart_work);
81262306a36Sopenharmony_ci	spin_lock_init(&lp->lock);
81362306a36Sopenharmony_ci	spin_lock_init(&lp->rx_lock);
81462306a36Sopenharmony_ci	lp->pci_dev = pdev;
81562306a36Sopenharmony_ci	lp->chiptype = ent->driver_data;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
81862306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Soft reset the chip. */
82162306a36Sopenharmony_ci	tc35815_chip_reset(dev);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* Retrieve the ethernet address. */
82462306a36Sopenharmony_ci	if (tc35815_init_dev_addr(dev)) {
82562306a36Sopenharmony_ci		dev_warn(&pdev->dev, "not valid ether addr\n");
82662306a36Sopenharmony_ci		eth_hw_addr_random(dev);
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	rc = register_netdev(dev);
83062306a36Sopenharmony_ci	if (rc)
83162306a36Sopenharmony_ci		goto err_out;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n",
83462306a36Sopenharmony_ci		dev->name,
83562306a36Sopenharmony_ci		chip_info[ent->driver_data].name,
83662306a36Sopenharmony_ci		dev->base_addr,
83762306a36Sopenharmony_ci		dev->dev_addr,
83862306a36Sopenharmony_ci		dev->irq);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	rc = tc_mii_init(dev);
84162306a36Sopenharmony_ci	if (rc)
84262306a36Sopenharmony_ci		goto err_out_unregister;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	return 0;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cierr_out_unregister:
84762306a36Sopenharmony_ci	unregister_netdev(dev);
84862306a36Sopenharmony_cierr_out:
84962306a36Sopenharmony_ci	free_netdev(dev);
85062306a36Sopenharmony_ci	return rc;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic void tc35815_remove_one(struct pci_dev *pdev)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
85762306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	phy_disconnect(dev->phydev);
86062306a36Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
86162306a36Sopenharmony_ci	mdiobus_free(lp->mii_bus);
86262306a36Sopenharmony_ci	unregister_netdev(dev);
86362306a36Sopenharmony_ci	free_netdev(dev);
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic int
86762306a36Sopenharmony_citc35815_init_queues(struct net_device *dev)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
87062306a36Sopenharmony_ci	int i;
87162306a36Sopenharmony_ci	unsigned long fd_addr;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (!lp->fd_buf) {
87462306a36Sopenharmony_ci		BUG_ON(sizeof(struct FDesc) +
87562306a36Sopenharmony_ci		       sizeof(struct BDesc) * RX_BUF_NUM +
87662306a36Sopenharmony_ci		       sizeof(struct FDesc) * RX_FD_NUM +
87762306a36Sopenharmony_ci		       sizeof(struct TxFD) * TX_FD_NUM >
87862306a36Sopenharmony_ci		       PAGE_SIZE * FD_PAGE_NUM);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		lp->fd_buf = dma_alloc_coherent(&lp->pci_dev->dev,
88162306a36Sopenharmony_ci						PAGE_SIZE * FD_PAGE_NUM,
88262306a36Sopenharmony_ci						&lp->fd_buf_dma, GFP_ATOMIC);
88362306a36Sopenharmony_ci		if (!lp->fd_buf)
88462306a36Sopenharmony_ci			return -ENOMEM;
88562306a36Sopenharmony_ci		for (i = 0; i < RX_BUF_NUM; i++) {
88662306a36Sopenharmony_ci			lp->rx_skbs[i].skb =
88762306a36Sopenharmony_ci				alloc_rxbuf_skb(dev, lp->pci_dev,
88862306a36Sopenharmony_ci						&lp->rx_skbs[i].skb_dma);
88962306a36Sopenharmony_ci			if (!lp->rx_skbs[i].skb) {
89062306a36Sopenharmony_ci				while (--i >= 0) {
89162306a36Sopenharmony_ci					free_rxbuf_skb(lp->pci_dev,
89262306a36Sopenharmony_ci						       lp->rx_skbs[i].skb,
89362306a36Sopenharmony_ci						       lp->rx_skbs[i].skb_dma);
89462306a36Sopenharmony_ci					lp->rx_skbs[i].skb = NULL;
89562306a36Sopenharmony_ci				}
89662306a36Sopenharmony_ci				dma_free_coherent(&lp->pci_dev->dev,
89762306a36Sopenharmony_ci						  PAGE_SIZE * FD_PAGE_NUM,
89862306a36Sopenharmony_ci						  lp->fd_buf, lp->fd_buf_dma);
89962306a36Sopenharmony_ci				lp->fd_buf = NULL;
90062306a36Sopenharmony_ci				return -ENOMEM;
90162306a36Sopenharmony_ci			}
90262306a36Sopenharmony_ci		}
90362306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: FD buf %p DataBuf",
90462306a36Sopenharmony_ci		       dev->name, lp->fd_buf);
90562306a36Sopenharmony_ci		printk("\n");
90662306a36Sopenharmony_ci	} else {
90762306a36Sopenharmony_ci		for (i = 0; i < FD_PAGE_NUM; i++)
90862306a36Sopenharmony_ci			clear_page((void *)((unsigned long)lp->fd_buf +
90962306a36Sopenharmony_ci					    i * PAGE_SIZE));
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci	fd_addr = (unsigned long)lp->fd_buf;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* Free Descriptors (for Receive) */
91462306a36Sopenharmony_ci	lp->rfd_base = (struct RxFD *)fd_addr;
91562306a36Sopenharmony_ci	fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
91662306a36Sopenharmony_ci	for (i = 0; i < RX_FD_NUM; i++)
91762306a36Sopenharmony_ci		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
91862306a36Sopenharmony_ci	lp->rfd_cur = lp->rfd_base;
91962306a36Sopenharmony_ci	lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/* Transmit Descriptors */
92262306a36Sopenharmony_ci	lp->tfd_base = (struct TxFD *)fd_addr;
92362306a36Sopenharmony_ci	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
92462306a36Sopenharmony_ci	for (i = 0; i < TX_FD_NUM; i++) {
92562306a36Sopenharmony_ci		lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
92662306a36Sopenharmony_ci		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
92762306a36Sopenharmony_ci		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
93062306a36Sopenharmony_ci	lp->tfd_start = 0;
93162306a36Sopenharmony_ci	lp->tfd_end = 0;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* Buffer List (for Receive) */
93462306a36Sopenharmony_ci	lp->fbl_ptr = (struct FrFD *)fd_addr;
93562306a36Sopenharmony_ci	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
93662306a36Sopenharmony_ci	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
93762306a36Sopenharmony_ci	/*
93862306a36Sopenharmony_ci	 * move all allocated skbs to head of rx_skbs[] array.
93962306a36Sopenharmony_ci	 * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
94062306a36Sopenharmony_ci	 * tc35815_rx() had failed.
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	lp->fbl_count = 0;
94362306a36Sopenharmony_ci	for (i = 0; i < RX_BUF_NUM; i++) {
94462306a36Sopenharmony_ci		if (lp->rx_skbs[i].skb) {
94562306a36Sopenharmony_ci			if (i != lp->fbl_count) {
94662306a36Sopenharmony_ci				lp->rx_skbs[lp->fbl_count].skb =
94762306a36Sopenharmony_ci					lp->rx_skbs[i].skb;
94862306a36Sopenharmony_ci				lp->rx_skbs[lp->fbl_count].skb_dma =
94962306a36Sopenharmony_ci					lp->rx_skbs[i].skb_dma;
95062306a36Sopenharmony_ci			}
95162306a36Sopenharmony_ci			lp->fbl_count++;
95262306a36Sopenharmony_ci		}
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci	for (i = 0; i < RX_BUF_NUM; i++) {
95562306a36Sopenharmony_ci		if (i >= lp->fbl_count) {
95662306a36Sopenharmony_ci			lp->fbl_ptr->bd[i].BuffData = 0;
95762306a36Sopenharmony_ci			lp->fbl_ptr->bd[i].BDCtl = 0;
95862306a36Sopenharmony_ci			continue;
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci		lp->fbl_ptr->bd[i].BuffData =
96162306a36Sopenharmony_ci			cpu_to_le32(lp->rx_skbs[i].skb_dma);
96262306a36Sopenharmony_ci		/* BDID is index of FrFD.bd[] */
96362306a36Sopenharmony_ci		lp->fbl_ptr->bd[i].BDCtl =
96462306a36Sopenharmony_ci			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
96562306a36Sopenharmony_ci				    RX_BUF_SIZE);
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
96962306a36Sopenharmony_ci	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
97062306a36Sopenharmony_ci	return 0;
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic void
97462306a36Sopenharmony_citc35815_clear_queues(struct net_device *dev)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
97762306a36Sopenharmony_ci	int i;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	for (i = 0; i < TX_FD_NUM; i++) {
98062306a36Sopenharmony_ci		u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
98162306a36Sopenharmony_ci		struct sk_buff *skb =
98262306a36Sopenharmony_ci			fdsystem != 0xffffffff ?
98362306a36Sopenharmony_ci			lp->tx_skbs[fdsystem].skb : NULL;
98462306a36Sopenharmony_ci#ifdef DEBUG
98562306a36Sopenharmony_ci		if (lp->tx_skbs[i].skb != skb) {
98662306a36Sopenharmony_ci			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
98762306a36Sopenharmony_ci			panic_queues(dev);
98862306a36Sopenharmony_ci		}
98962306a36Sopenharmony_ci#else
99062306a36Sopenharmony_ci		BUG_ON(lp->tx_skbs[i].skb != skb);
99162306a36Sopenharmony_ci#endif
99262306a36Sopenharmony_ci		if (skb) {
99362306a36Sopenharmony_ci			dma_unmap_single(&lp->pci_dev->dev,
99462306a36Sopenharmony_ci					 lp->tx_skbs[i].skb_dma, skb->len,
99562306a36Sopenharmony_ci					 DMA_TO_DEVICE);
99662306a36Sopenharmony_ci			lp->tx_skbs[i].skb = NULL;
99762306a36Sopenharmony_ci			lp->tx_skbs[i].skb_dma = 0;
99862306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
99962306a36Sopenharmony_ci		}
100062306a36Sopenharmony_ci		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	tc35815_init_queues(dev);
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic void
100762306a36Sopenharmony_citc35815_free_queues(struct net_device *dev)
100862306a36Sopenharmony_ci{
100962306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
101062306a36Sopenharmony_ci	int i;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (lp->tfd_base) {
101362306a36Sopenharmony_ci		for (i = 0; i < TX_FD_NUM; i++) {
101462306a36Sopenharmony_ci			u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
101562306a36Sopenharmony_ci			struct sk_buff *skb =
101662306a36Sopenharmony_ci				fdsystem != 0xffffffff ?
101762306a36Sopenharmony_ci				lp->tx_skbs[fdsystem].skb : NULL;
101862306a36Sopenharmony_ci#ifdef DEBUG
101962306a36Sopenharmony_ci			if (lp->tx_skbs[i].skb != skb) {
102062306a36Sopenharmony_ci				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
102162306a36Sopenharmony_ci				panic_queues(dev);
102262306a36Sopenharmony_ci			}
102362306a36Sopenharmony_ci#else
102462306a36Sopenharmony_ci			BUG_ON(lp->tx_skbs[i].skb != skb);
102562306a36Sopenharmony_ci#endif
102662306a36Sopenharmony_ci			if (skb) {
102762306a36Sopenharmony_ci				dma_unmap_single(&lp->pci_dev->dev,
102862306a36Sopenharmony_ci						 lp->tx_skbs[i].skb_dma,
102962306a36Sopenharmony_ci						 skb->len, DMA_TO_DEVICE);
103062306a36Sopenharmony_ci				dev_kfree_skb(skb);
103162306a36Sopenharmony_ci				lp->tx_skbs[i].skb = NULL;
103262306a36Sopenharmony_ci				lp->tx_skbs[i].skb_dma = 0;
103362306a36Sopenharmony_ci			}
103462306a36Sopenharmony_ci			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	lp->rfd_base = NULL;
103962306a36Sopenharmony_ci	lp->rfd_limit = NULL;
104062306a36Sopenharmony_ci	lp->rfd_cur = NULL;
104162306a36Sopenharmony_ci	lp->fbl_ptr = NULL;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	for (i = 0; i < RX_BUF_NUM; i++) {
104462306a36Sopenharmony_ci		if (lp->rx_skbs[i].skb) {
104562306a36Sopenharmony_ci			free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
104662306a36Sopenharmony_ci				       lp->rx_skbs[i].skb_dma);
104762306a36Sopenharmony_ci			lp->rx_skbs[i].skb = NULL;
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci	if (lp->fd_buf) {
105162306a36Sopenharmony_ci		dma_free_coherent(&lp->pci_dev->dev, PAGE_SIZE * FD_PAGE_NUM,
105262306a36Sopenharmony_ci				  lp->fd_buf, lp->fd_buf_dma);
105362306a36Sopenharmony_ci		lp->fd_buf = NULL;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic void
105862306a36Sopenharmony_cidump_txfd(struct TxFD *fd)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
106162306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDNext),
106262306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDSystem),
106362306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDStat),
106462306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDCtl));
106562306a36Sopenharmony_ci	printk("BD: ");
106662306a36Sopenharmony_ci	printk(" %08x %08x",
106762306a36Sopenharmony_ci	       le32_to_cpu(fd->bd.BuffData),
106862306a36Sopenharmony_ci	       le32_to_cpu(fd->bd.BDCtl));
106962306a36Sopenharmony_ci	printk("\n");
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic int
107362306a36Sopenharmony_cidump_rxfd(struct RxFD *fd)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
107662306a36Sopenharmony_ci	if (bd_count > 8)
107762306a36Sopenharmony_ci		bd_count = 8;
107862306a36Sopenharmony_ci	printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
107962306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDNext),
108062306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDSystem),
108162306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDStat),
108262306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDCtl));
108362306a36Sopenharmony_ci	if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
108462306a36Sopenharmony_ci		return 0;
108562306a36Sopenharmony_ci	printk("BD: ");
108662306a36Sopenharmony_ci	for (i = 0; i < bd_count; i++)
108762306a36Sopenharmony_ci		printk(" %08x %08x",
108862306a36Sopenharmony_ci		       le32_to_cpu(fd->bd[i].BuffData),
108962306a36Sopenharmony_ci		       le32_to_cpu(fd->bd[i].BDCtl));
109062306a36Sopenharmony_ci	printk("\n");
109162306a36Sopenharmony_ci	return bd_count;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci#ifdef DEBUG
109562306a36Sopenharmony_cistatic void
109662306a36Sopenharmony_cidump_frfd(struct FrFD *fd)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	int i;
109962306a36Sopenharmony_ci	printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
110062306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDNext),
110162306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDSystem),
110262306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDStat),
110362306a36Sopenharmony_ci	       le32_to_cpu(fd->fd.FDCtl));
110462306a36Sopenharmony_ci	printk("BD: ");
110562306a36Sopenharmony_ci	for (i = 0; i < RX_BUF_NUM; i++)
110662306a36Sopenharmony_ci		printk(" %08x %08x",
110762306a36Sopenharmony_ci		       le32_to_cpu(fd->bd[i].BuffData),
110862306a36Sopenharmony_ci		       le32_to_cpu(fd->bd[i].BDCtl));
110962306a36Sopenharmony_ci	printk("\n");
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic void
111362306a36Sopenharmony_cipanic_queues(struct net_device *dev)
111462306a36Sopenharmony_ci{
111562306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
111662306a36Sopenharmony_ci	int i;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	printk("TxFD base %p, start %u, end %u\n",
111962306a36Sopenharmony_ci	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
112062306a36Sopenharmony_ci	printk("RxFD base %p limit %p cur %p\n",
112162306a36Sopenharmony_ci	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
112262306a36Sopenharmony_ci	printk("FrFD %p\n", lp->fbl_ptr);
112362306a36Sopenharmony_ci	for (i = 0; i < TX_FD_NUM; i++)
112462306a36Sopenharmony_ci		dump_txfd(&lp->tfd_base[i]);
112562306a36Sopenharmony_ci	for (i = 0; i < RX_FD_NUM; i++) {
112662306a36Sopenharmony_ci		int bd_count = dump_rxfd(&lp->rfd_base[i]);
112762306a36Sopenharmony_ci		i += (bd_count + 1) / 2;	/* skip BDs */
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci	dump_frfd(lp->fbl_ptr);
113062306a36Sopenharmony_ci	panic("%s: Illegal queue state.", dev->name);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci#endif
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic void print_eth(const u8 *add)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	printk(KERN_DEBUG "print_eth(%p)\n", add);
113762306a36Sopenharmony_ci	printk(KERN_DEBUG " %pM => %pM : %02x%02x\n",
113862306a36Sopenharmony_ci		add + 6, add, add[12], add[13]);
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic int tc35815_tx_full(struct net_device *dev)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
114462306a36Sopenharmony_ci	return (lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic void tc35815_restart(struct net_device *dev)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
115062306a36Sopenharmony_ci	int ret;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	if (dev->phydev) {
115362306a36Sopenharmony_ci		ret = phy_init_hw(dev->phydev);
115462306a36Sopenharmony_ci		if (ret)
115562306a36Sopenharmony_ci			printk(KERN_ERR "%s: PHY init failed.\n", dev->name);
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	spin_lock_bh(&lp->rx_lock);
115962306a36Sopenharmony_ci	spin_lock_irq(&lp->lock);
116062306a36Sopenharmony_ci	tc35815_chip_reset(dev);
116162306a36Sopenharmony_ci	tc35815_clear_queues(dev);
116262306a36Sopenharmony_ci	tc35815_chip_init(dev);
116362306a36Sopenharmony_ci	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
116462306a36Sopenharmony_ci	tc35815_set_multicast_list(dev);
116562306a36Sopenharmony_ci	spin_unlock_irq(&lp->lock);
116662306a36Sopenharmony_ci	spin_unlock_bh(&lp->rx_lock);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	netif_wake_queue(dev);
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic void tc35815_restart_work(struct work_struct *work)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	struct tc35815_local *lp =
117462306a36Sopenharmony_ci		container_of(work, struct tc35815_local, restart_work);
117562306a36Sopenharmony_ci	struct net_device *dev = lp->dev;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	tc35815_restart(dev);
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic void tc35815_schedule_restart(struct net_device *dev)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
118362306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
118462306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
118562306a36Sopenharmony_ci	unsigned long flags;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	/* disable interrupts */
118862306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
118962306a36Sopenharmony_ci	tc_writel(0, &tr->Int_En);
119062306a36Sopenharmony_ci	tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl);
119162306a36Sopenharmony_ci	schedule_work(&lp->restart_work);
119262306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic void tc35815_tx_timeout(struct net_device *dev, unsigned int txqueue)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
119862306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
120162306a36Sopenharmony_ci	       dev->name, tc_readl(&tr->Tx_Stat));
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* Try to restart the adaptor. */
120462306a36Sopenharmony_ci	tc35815_schedule_restart(dev);
120562306a36Sopenharmony_ci	dev->stats.tx_errors++;
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci/*
120962306a36Sopenharmony_ci * Open/initialize the controller. This is called (in the current kernel)
121062306a36Sopenharmony_ci * sometime after booting when the 'ifconfig' program is run.
121162306a36Sopenharmony_ci *
121262306a36Sopenharmony_ci * This routine should set everything up anew at each open, even
121362306a36Sopenharmony_ci * registers that "should" only need to be set once at boot, so that
121462306a36Sopenharmony_ci * there is non-reboot way to recover if something goes wrong.
121562306a36Sopenharmony_ci */
121662306a36Sopenharmony_cistatic int
121762306a36Sopenharmony_citc35815_open(struct net_device *dev)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	/*
122262306a36Sopenharmony_ci	 * This is used if the interrupt line can turned off (shared).
122362306a36Sopenharmony_ci	 * See 3c503.c for an example of selecting the IRQ at config-time.
122462306a36Sopenharmony_ci	 */
122562306a36Sopenharmony_ci	if (request_irq(dev->irq, tc35815_interrupt, IRQF_SHARED,
122662306a36Sopenharmony_ci			dev->name, dev))
122762306a36Sopenharmony_ci		return -EAGAIN;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	tc35815_chip_reset(dev);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (tc35815_init_queues(dev) != 0) {
123262306a36Sopenharmony_ci		free_irq(dev->irq, dev);
123362306a36Sopenharmony_ci		return -EAGAIN;
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	napi_enable(&lp->napi);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	/* Reset the hardware here. Don't forget to set the station address. */
123962306a36Sopenharmony_ci	spin_lock_irq(&lp->lock);
124062306a36Sopenharmony_ci	tc35815_chip_init(dev);
124162306a36Sopenharmony_ci	spin_unlock_irq(&lp->lock);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	netif_carrier_off(dev);
124462306a36Sopenharmony_ci	/* schedule a link state check */
124562306a36Sopenharmony_ci	phy_start(dev->phydev);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* We are now ready to accept transmit requeusts from
124862306a36Sopenharmony_ci	 * the queueing layer of the networking.
124962306a36Sopenharmony_ci	 */
125062306a36Sopenharmony_ci	netif_start_queue(dev);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	return 0;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci/* This will only be invoked if your driver is _not_ in XOFF state.
125662306a36Sopenharmony_ci * What this means is that you need not check it, and that this
125762306a36Sopenharmony_ci * invariant will hold if you make sure that the netif_*_queue()
125862306a36Sopenharmony_ci * calls are done at the proper times.
125962306a36Sopenharmony_ci */
126062306a36Sopenharmony_cistatic netdev_tx_t
126162306a36Sopenharmony_citc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
126462306a36Sopenharmony_ci	struct TxFD *txfd;
126562306a36Sopenharmony_ci	unsigned long flags;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	/* If some error occurs while trying to transmit this
126862306a36Sopenharmony_ci	 * packet, you should return '1' from this function.
126962306a36Sopenharmony_ci	 * In such a case you _may not_ do anything to the
127062306a36Sopenharmony_ci	 * SKB, it is still owned by the network queueing
127162306a36Sopenharmony_ci	 * layer when an error is returned.  This means you
127262306a36Sopenharmony_ci	 * may not modify any SKB fields, you may not free
127362306a36Sopenharmony_ci	 * the SKB, etc.
127462306a36Sopenharmony_ci	 */
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* This is the most common case for modern hardware.
127762306a36Sopenharmony_ci	 * The spinlock protects this code from the TX complete
127862306a36Sopenharmony_ci	 * hardware interrupt handler.  Queue flow control is
127962306a36Sopenharmony_ci	 * thus managed under this lock as well.
128062306a36Sopenharmony_ci	 */
128162306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	/* failsafe... (handle txdone now if half of FDs are used) */
128462306a36Sopenharmony_ci	if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
128562306a36Sopenharmony_ci	    TX_FD_NUM / 2)
128662306a36Sopenharmony_ci		tc35815_txdone(dev);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (netif_msg_pktdata(lp))
128962306a36Sopenharmony_ci		print_eth(skb->data);
129062306a36Sopenharmony_ci#ifdef DEBUG
129162306a36Sopenharmony_ci	if (lp->tx_skbs[lp->tfd_start].skb) {
129262306a36Sopenharmony_ci		printk("%s: tx_skbs conflict.\n", dev->name);
129362306a36Sopenharmony_ci		panic_queues(dev);
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci#else
129662306a36Sopenharmony_ci	BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
129762306a36Sopenharmony_ci#endif
129862306a36Sopenharmony_ci	lp->tx_skbs[lp->tfd_start].skb = skb;
129962306a36Sopenharmony_ci	lp->tx_skbs[lp->tfd_start].skb_dma = dma_map_single(&lp->pci_dev->dev,
130062306a36Sopenharmony_ci							    skb->data,
130162306a36Sopenharmony_ci							    skb->len,
130262306a36Sopenharmony_ci							    DMA_TO_DEVICE);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/*add to ring */
130562306a36Sopenharmony_ci	txfd = &lp->tfd_base[lp->tfd_start];
130662306a36Sopenharmony_ci	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
130762306a36Sopenharmony_ci	txfd->bd.BDCtl = cpu_to_le32(skb->len);
130862306a36Sopenharmony_ci	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
130962306a36Sopenharmony_ci	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (lp->tfd_start == lp->tfd_end) {
131262306a36Sopenharmony_ci		struct tc35815_regs __iomem *tr =
131362306a36Sopenharmony_ci			(struct tc35815_regs __iomem *)dev->base_addr;
131462306a36Sopenharmony_ci		/* Start DMA Transmitter. */
131562306a36Sopenharmony_ci		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
131662306a36Sopenharmony_ci		txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
131762306a36Sopenharmony_ci		if (netif_msg_tx_queued(lp)) {
131862306a36Sopenharmony_ci			printk("%s: starting TxFD.\n", dev->name);
131962306a36Sopenharmony_ci			dump_txfd(txfd);
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci		tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
132262306a36Sopenharmony_ci	} else {
132362306a36Sopenharmony_ci		txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
132462306a36Sopenharmony_ci		if (netif_msg_tx_queued(lp)) {
132562306a36Sopenharmony_ci			printk("%s: queueing TxFD.\n", dev->name);
132662306a36Sopenharmony_ci			dump_txfd(txfd);
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci	lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	/* If we just used up the very last entry in the
133262306a36Sopenharmony_ci	 * TX ring on this device, tell the queueing
133362306a36Sopenharmony_ci	 * layer to send no more.
133462306a36Sopenharmony_ci	 */
133562306a36Sopenharmony_ci	if (tc35815_tx_full(dev)) {
133662306a36Sopenharmony_ci		if (netif_msg_tx_queued(lp))
133762306a36Sopenharmony_ci			printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
133862306a36Sopenharmony_ci		netif_stop_queue(dev);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/* When the TX completion hw interrupt arrives, this
134262306a36Sopenharmony_ci	 * is when the transmit statistics are updated.
134362306a36Sopenharmony_ci	 */
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
134662306a36Sopenharmony_ci	return NETDEV_TX_OK;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci#define FATAL_ERROR_INT \
135062306a36Sopenharmony_ci	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
135162306a36Sopenharmony_cistatic void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	static int count;
135462306a36Sopenharmony_ci	printk(KERN_WARNING "%s: Fatal Error Interrupt (%#x):",
135562306a36Sopenharmony_ci	       dev->name, status);
135662306a36Sopenharmony_ci	if (status & Int_IntPCI)
135762306a36Sopenharmony_ci		printk(" IntPCI");
135862306a36Sopenharmony_ci	if (status & Int_DmParErr)
135962306a36Sopenharmony_ci		printk(" DmParErr");
136062306a36Sopenharmony_ci	if (status & Int_IntNRAbt)
136162306a36Sopenharmony_ci		printk(" IntNRAbt");
136262306a36Sopenharmony_ci	printk("\n");
136362306a36Sopenharmony_ci	if (count++ > 100)
136462306a36Sopenharmony_ci		panic("%s: Too many fatal errors.", dev->name);
136562306a36Sopenharmony_ci	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
136662306a36Sopenharmony_ci	/* Try to restart the adaptor. */
136762306a36Sopenharmony_ci	tc35815_schedule_restart(dev);
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
137362306a36Sopenharmony_ci	int ret = -1;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	/* Fatal errors... */
137662306a36Sopenharmony_ci	if (status & FATAL_ERROR_INT) {
137762306a36Sopenharmony_ci		tc35815_fatal_error_interrupt(dev, status);
137862306a36Sopenharmony_ci		return 0;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci	/* recoverable errors */
138162306a36Sopenharmony_ci	if (status & Int_IntFDAEx) {
138262306a36Sopenharmony_ci		if (netif_msg_rx_err(lp))
138362306a36Sopenharmony_ci			dev_warn(&dev->dev,
138462306a36Sopenharmony_ci				 "Free Descriptor Area Exhausted (%#x).\n",
138562306a36Sopenharmony_ci				 status);
138662306a36Sopenharmony_ci		dev->stats.rx_dropped++;
138762306a36Sopenharmony_ci		ret = 0;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci	if (status & Int_IntBLEx) {
139062306a36Sopenharmony_ci		if (netif_msg_rx_err(lp))
139162306a36Sopenharmony_ci			dev_warn(&dev->dev,
139262306a36Sopenharmony_ci				 "Buffer List Exhausted (%#x).\n",
139362306a36Sopenharmony_ci				 status);
139462306a36Sopenharmony_ci		dev->stats.rx_dropped++;
139562306a36Sopenharmony_ci		ret = 0;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci	if (status & Int_IntExBD) {
139862306a36Sopenharmony_ci		if (netif_msg_rx_err(lp))
139962306a36Sopenharmony_ci			dev_warn(&dev->dev,
140062306a36Sopenharmony_ci				 "Excessive Buffer Descriptors (%#x).\n",
140162306a36Sopenharmony_ci				 status);
140262306a36Sopenharmony_ci		dev->stats.rx_length_errors++;
140362306a36Sopenharmony_ci		ret = 0;
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	/* normal notification */
140762306a36Sopenharmony_ci	if (status & Int_IntMacRx) {
140862306a36Sopenharmony_ci		/* Got a packet(s). */
140962306a36Sopenharmony_ci		ret = tc35815_rx(dev, limit);
141062306a36Sopenharmony_ci		lp->lstats.rx_ints++;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci	if (status & Int_IntMacTx) {
141362306a36Sopenharmony_ci		/* Transmit complete. */
141462306a36Sopenharmony_ci		lp->lstats.tx_ints++;
141562306a36Sopenharmony_ci		spin_lock_irq(&lp->lock);
141662306a36Sopenharmony_ci		tc35815_txdone(dev);
141762306a36Sopenharmony_ci		spin_unlock_irq(&lp->lock);
141862306a36Sopenharmony_ci		if (ret < 0)
141962306a36Sopenharmony_ci			ret = 0;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci	return ret;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci/*
142562306a36Sopenharmony_ci * The typical workload of the driver:
142662306a36Sopenharmony_ci * Handle the network interface interrupts.
142762306a36Sopenharmony_ci */
142862306a36Sopenharmony_cistatic irqreturn_t tc35815_interrupt(int irq, void *dev_id)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	struct net_device *dev = dev_id;
143162306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
143262306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
143362306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
143462306a36Sopenharmony_ci	u32 dmactl = tc_readl(&tr->DMA_Ctl);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (!(dmactl & DMA_IntMask)) {
143762306a36Sopenharmony_ci		/* disable interrupts */
143862306a36Sopenharmony_ci		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
143962306a36Sopenharmony_ci		if (napi_schedule_prep(&lp->napi))
144062306a36Sopenharmony_ci			__napi_schedule(&lp->napi);
144162306a36Sopenharmony_ci		else {
144262306a36Sopenharmony_ci			printk(KERN_ERR "%s: interrupt taken in poll\n",
144362306a36Sopenharmony_ci			       dev->name);
144462306a36Sopenharmony_ci			BUG();
144562306a36Sopenharmony_ci		}
144662306a36Sopenharmony_ci		(void)tc_readl(&tr->Int_Src);	/* flush */
144762306a36Sopenharmony_ci		return IRQ_HANDLED;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci	return IRQ_NONE;
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
145362306a36Sopenharmony_cistatic void tc35815_poll_controller(struct net_device *dev)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	disable_irq(dev->irq);
145662306a36Sopenharmony_ci	tc35815_interrupt(dev->irq, dev);
145762306a36Sopenharmony_ci	enable_irq(dev->irq);
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci#endif
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci/* We have a good packet(s), get it/them out of the buffers. */
146262306a36Sopenharmony_cistatic int
146362306a36Sopenharmony_citc35815_rx(struct net_device *dev, int limit)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
146662306a36Sopenharmony_ci	unsigned int fdctl;
146762306a36Sopenharmony_ci	int i;
146862306a36Sopenharmony_ci	int received = 0;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
147162306a36Sopenharmony_ci		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
147262306a36Sopenharmony_ci		int pkt_len = fdctl & FD_FDLength_MASK;
147362306a36Sopenharmony_ci		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
147462306a36Sopenharmony_ci#ifdef DEBUG
147562306a36Sopenharmony_ci		struct RxFD *next_rfd;
147662306a36Sopenharmony_ci#endif
147762306a36Sopenharmony_ci#if (RX_CTL_CMD & Rx_StripCRC) == 0
147862306a36Sopenharmony_ci		pkt_len -= ETH_FCS_LEN;
147962306a36Sopenharmony_ci#endif
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		if (netif_msg_rx_status(lp))
148262306a36Sopenharmony_ci			dump_rxfd(lp->rfd_cur);
148362306a36Sopenharmony_ci		if (status & Rx_Good) {
148462306a36Sopenharmony_ci			struct sk_buff *skb;
148562306a36Sopenharmony_ci			unsigned char *data;
148662306a36Sopenharmony_ci			int cur_bd;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci			if (--limit < 0)
148962306a36Sopenharmony_ci				break;
149062306a36Sopenharmony_ci			BUG_ON(bd_count > 1);
149162306a36Sopenharmony_ci			cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
149262306a36Sopenharmony_ci				  & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
149362306a36Sopenharmony_ci#ifdef DEBUG
149462306a36Sopenharmony_ci			if (cur_bd >= RX_BUF_NUM) {
149562306a36Sopenharmony_ci				printk("%s: invalid BDID.\n", dev->name);
149662306a36Sopenharmony_ci				panic_queues(dev);
149762306a36Sopenharmony_ci			}
149862306a36Sopenharmony_ci			BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
149962306a36Sopenharmony_ci			       (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
150062306a36Sopenharmony_ci			if (!lp->rx_skbs[cur_bd].skb) {
150162306a36Sopenharmony_ci				printk("%s: NULL skb.\n", dev->name);
150262306a36Sopenharmony_ci				panic_queues(dev);
150362306a36Sopenharmony_ci			}
150462306a36Sopenharmony_ci#else
150562306a36Sopenharmony_ci			BUG_ON(cur_bd >= RX_BUF_NUM);
150662306a36Sopenharmony_ci#endif
150762306a36Sopenharmony_ci			skb = lp->rx_skbs[cur_bd].skb;
150862306a36Sopenharmony_ci			prefetch(skb->data);
150962306a36Sopenharmony_ci			lp->rx_skbs[cur_bd].skb = NULL;
151062306a36Sopenharmony_ci			dma_unmap_single(&lp->pci_dev->dev,
151162306a36Sopenharmony_ci					 lp->rx_skbs[cur_bd].skb_dma,
151262306a36Sopenharmony_ci					 RX_BUF_SIZE, DMA_FROM_DEVICE);
151362306a36Sopenharmony_ci			if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN != 0)
151462306a36Sopenharmony_ci				memmove(skb->data, skb->data - NET_IP_ALIGN,
151562306a36Sopenharmony_ci					pkt_len);
151662306a36Sopenharmony_ci			data = skb_put(skb, pkt_len);
151762306a36Sopenharmony_ci			if (netif_msg_pktdata(lp))
151862306a36Sopenharmony_ci				print_eth(data);
151962306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
152062306a36Sopenharmony_ci			netif_receive_skb(skb);
152162306a36Sopenharmony_ci			received++;
152262306a36Sopenharmony_ci			dev->stats.rx_packets++;
152362306a36Sopenharmony_ci			dev->stats.rx_bytes += pkt_len;
152462306a36Sopenharmony_ci		} else {
152562306a36Sopenharmony_ci			dev->stats.rx_errors++;
152662306a36Sopenharmony_ci			if (netif_msg_rx_err(lp))
152762306a36Sopenharmony_ci				dev_info(&dev->dev, "Rx error (status %x)\n",
152862306a36Sopenharmony_ci					 status & Rx_Stat_Mask);
152962306a36Sopenharmony_ci			/* WORKAROUND: LongErr and CRCErr means Overflow. */
153062306a36Sopenharmony_ci			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
153162306a36Sopenharmony_ci				status &= ~(Rx_LongErr|Rx_CRCErr);
153262306a36Sopenharmony_ci				status |= Rx_Over;
153362306a36Sopenharmony_ci			}
153462306a36Sopenharmony_ci			if (status & Rx_LongErr)
153562306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
153662306a36Sopenharmony_ci			if (status & Rx_Over)
153762306a36Sopenharmony_ci				dev->stats.rx_fifo_errors++;
153862306a36Sopenharmony_ci			if (status & Rx_CRCErr)
153962306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
154062306a36Sopenharmony_ci			if (status & Rx_Align)
154162306a36Sopenharmony_ci				dev->stats.rx_frame_errors++;
154262306a36Sopenharmony_ci		}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		if (bd_count > 0) {
154562306a36Sopenharmony_ci			/* put Free Buffer back to controller */
154662306a36Sopenharmony_ci			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
154762306a36Sopenharmony_ci			unsigned char id =
154862306a36Sopenharmony_ci				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
154962306a36Sopenharmony_ci#ifdef DEBUG
155062306a36Sopenharmony_ci			if (id >= RX_BUF_NUM) {
155162306a36Sopenharmony_ci				printk("%s: invalid BDID.\n", dev->name);
155262306a36Sopenharmony_ci				panic_queues(dev);
155362306a36Sopenharmony_ci			}
155462306a36Sopenharmony_ci#else
155562306a36Sopenharmony_ci			BUG_ON(id >= RX_BUF_NUM);
155662306a36Sopenharmony_ci#endif
155762306a36Sopenharmony_ci			/* free old buffers */
155862306a36Sopenharmony_ci			lp->fbl_count--;
155962306a36Sopenharmony_ci			while (lp->fbl_count < RX_BUF_NUM)
156062306a36Sopenharmony_ci			{
156162306a36Sopenharmony_ci				unsigned char curid =
156262306a36Sopenharmony_ci					(id + 1 + lp->fbl_count) % RX_BUF_NUM;
156362306a36Sopenharmony_ci				struct BDesc *bd = &lp->fbl_ptr->bd[curid];
156462306a36Sopenharmony_ci#ifdef DEBUG
156562306a36Sopenharmony_ci				bdctl = le32_to_cpu(bd->BDCtl);
156662306a36Sopenharmony_ci				if (bdctl & BD_CownsBD) {
156762306a36Sopenharmony_ci					printk("%s: Freeing invalid BD.\n",
156862306a36Sopenharmony_ci					       dev->name);
156962306a36Sopenharmony_ci					panic_queues(dev);
157062306a36Sopenharmony_ci				}
157162306a36Sopenharmony_ci#endif
157262306a36Sopenharmony_ci				/* pass BD to controller */
157362306a36Sopenharmony_ci				if (!lp->rx_skbs[curid].skb) {
157462306a36Sopenharmony_ci					lp->rx_skbs[curid].skb =
157562306a36Sopenharmony_ci						alloc_rxbuf_skb(dev,
157662306a36Sopenharmony_ci								lp->pci_dev,
157762306a36Sopenharmony_ci								&lp->rx_skbs[curid].skb_dma);
157862306a36Sopenharmony_ci					if (!lp->rx_skbs[curid].skb)
157962306a36Sopenharmony_ci						break; /* try on next reception */
158062306a36Sopenharmony_ci					bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
158162306a36Sopenharmony_ci				}
158262306a36Sopenharmony_ci				/* Note: BDLength was modified by chip. */
158362306a36Sopenharmony_ci				bd->BDCtl = cpu_to_le32(BD_CownsBD |
158462306a36Sopenharmony_ci							(curid << BD_RxBDID_SHIFT) |
158562306a36Sopenharmony_ci							RX_BUF_SIZE);
158662306a36Sopenharmony_ci				lp->fbl_count++;
158762306a36Sopenharmony_ci			}
158862306a36Sopenharmony_ci		}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		/* put RxFD back to controller */
159162306a36Sopenharmony_ci#ifdef DEBUG
159262306a36Sopenharmony_ci		next_rfd = fd_bus_to_virt(lp,
159362306a36Sopenharmony_ci					  le32_to_cpu(lp->rfd_cur->fd.FDNext));
159462306a36Sopenharmony_ci		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
159562306a36Sopenharmony_ci			printk("%s: RxFD FDNext invalid.\n", dev->name);
159662306a36Sopenharmony_ci			panic_queues(dev);
159762306a36Sopenharmony_ci		}
159862306a36Sopenharmony_ci#endif
159962306a36Sopenharmony_ci		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
160062306a36Sopenharmony_ci			/* pass FD to controller */
160162306a36Sopenharmony_ci#ifdef DEBUG
160262306a36Sopenharmony_ci			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
160362306a36Sopenharmony_ci#else
160462306a36Sopenharmony_ci			lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
160562306a36Sopenharmony_ci#endif
160662306a36Sopenharmony_ci			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
160762306a36Sopenharmony_ci			lp->rfd_cur++;
160862306a36Sopenharmony_ci		}
160962306a36Sopenharmony_ci		if (lp->rfd_cur > lp->rfd_limit)
161062306a36Sopenharmony_ci			lp->rfd_cur = lp->rfd_base;
161162306a36Sopenharmony_ci#ifdef DEBUG
161262306a36Sopenharmony_ci		if (lp->rfd_cur != next_rfd)
161362306a36Sopenharmony_ci			printk("rfd_cur = %p, next_rfd %p\n",
161462306a36Sopenharmony_ci			       lp->rfd_cur, next_rfd);
161562306a36Sopenharmony_ci#endif
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	return received;
161962306a36Sopenharmony_ci}
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_cistatic int tc35815_poll(struct napi_struct *napi, int budget)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
162462306a36Sopenharmony_ci	struct net_device *dev = lp->dev;
162562306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
162662306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
162762306a36Sopenharmony_ci	int received = 0, handled;
162862306a36Sopenharmony_ci	u32 status;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	if (budget <= 0)
163162306a36Sopenharmony_ci		return received;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	spin_lock(&lp->rx_lock);
163462306a36Sopenharmony_ci	status = tc_readl(&tr->Int_Src);
163562306a36Sopenharmony_ci	do {
163662306a36Sopenharmony_ci		/* BLEx, FDAEx will be cleared later */
163762306a36Sopenharmony_ci		tc_writel(status & ~(Int_BLEx | Int_FDAEx),
163862306a36Sopenharmony_ci			  &tr->Int_Src);	/* write to clear */
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci		handled = tc35815_do_interrupt(dev, status, budget - received);
164162306a36Sopenharmony_ci		if (status & (Int_BLEx | Int_FDAEx))
164262306a36Sopenharmony_ci			tc_writel(status & (Int_BLEx | Int_FDAEx),
164362306a36Sopenharmony_ci				  &tr->Int_Src);
164462306a36Sopenharmony_ci		if (handled >= 0) {
164562306a36Sopenharmony_ci			received += handled;
164662306a36Sopenharmony_ci			if (received >= budget)
164762306a36Sopenharmony_ci				break;
164862306a36Sopenharmony_ci		}
164962306a36Sopenharmony_ci		status = tc_readl(&tr->Int_Src);
165062306a36Sopenharmony_ci	} while (status);
165162306a36Sopenharmony_ci	spin_unlock(&lp->rx_lock);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	if (received < budget) {
165462306a36Sopenharmony_ci		napi_complete_done(napi, received);
165562306a36Sopenharmony_ci		/* enable interrupts */
165662306a36Sopenharmony_ci		tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci	return received;
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cistatic void
166462306a36Sopenharmony_citc35815_check_tx_stat(struct net_device *dev, int status)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
166762306a36Sopenharmony_ci	const char *msg = NULL;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	/* count collisions */
167062306a36Sopenharmony_ci	if (status & Tx_ExColl)
167162306a36Sopenharmony_ci		dev->stats.collisions += 16;
167262306a36Sopenharmony_ci	if (status & Tx_TxColl_MASK)
167362306a36Sopenharmony_ci		dev->stats.collisions += status & Tx_TxColl_MASK;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	/* TX4939 does not have NCarr */
167662306a36Sopenharmony_ci	if (lp->chiptype == TC35815_TX4939)
167762306a36Sopenharmony_ci		status &= ~Tx_NCarr;
167862306a36Sopenharmony_ci	/* WORKAROUND: ignore LostCrS in full duplex operation */
167962306a36Sopenharmony_ci	if (!lp->link || lp->duplex == DUPLEX_FULL)
168062306a36Sopenharmony_ci		status &= ~Tx_NCarr;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	if (!(status & TX_STA_ERR)) {
168362306a36Sopenharmony_ci		/* no error. */
168462306a36Sopenharmony_ci		dev->stats.tx_packets++;
168562306a36Sopenharmony_ci		return;
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	dev->stats.tx_errors++;
168962306a36Sopenharmony_ci	if (status & Tx_ExColl) {
169062306a36Sopenharmony_ci		dev->stats.tx_aborted_errors++;
169162306a36Sopenharmony_ci		msg = "Excessive Collision.";
169262306a36Sopenharmony_ci	}
169362306a36Sopenharmony_ci	if (status & Tx_Under) {
169462306a36Sopenharmony_ci		dev->stats.tx_fifo_errors++;
169562306a36Sopenharmony_ci		msg = "Tx FIFO Underrun.";
169662306a36Sopenharmony_ci		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
169762306a36Sopenharmony_ci			lp->lstats.tx_underrun++;
169862306a36Sopenharmony_ci			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
169962306a36Sopenharmony_ci				struct tc35815_regs __iomem *tr =
170062306a36Sopenharmony_ci					(struct tc35815_regs __iomem *)dev->base_addr;
170162306a36Sopenharmony_ci				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
170262306a36Sopenharmony_ci				msg = "Tx FIFO Underrun.Change Tx threshold to max.";
170362306a36Sopenharmony_ci			}
170462306a36Sopenharmony_ci		}
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci	if (status & Tx_Defer) {
170762306a36Sopenharmony_ci		dev->stats.tx_fifo_errors++;
170862306a36Sopenharmony_ci		msg = "Excessive Deferral.";
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci	if (status & Tx_NCarr) {
171162306a36Sopenharmony_ci		dev->stats.tx_carrier_errors++;
171262306a36Sopenharmony_ci		msg = "Lost Carrier Sense.";
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci	if (status & Tx_LateColl) {
171562306a36Sopenharmony_ci		dev->stats.tx_aborted_errors++;
171662306a36Sopenharmony_ci		msg = "Late Collision.";
171762306a36Sopenharmony_ci	}
171862306a36Sopenharmony_ci	if (status & Tx_TxPar) {
171962306a36Sopenharmony_ci		dev->stats.tx_fifo_errors++;
172062306a36Sopenharmony_ci		msg = "Transmit Parity Error.";
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci	if (status & Tx_SQErr) {
172362306a36Sopenharmony_ci		dev->stats.tx_heartbeat_errors++;
172462306a36Sopenharmony_ci		msg = "Signal Quality Error.";
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci	if (msg && netif_msg_tx_err(lp))
172762306a36Sopenharmony_ci		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci/* This handles TX complete events posted by the device
173162306a36Sopenharmony_ci * via interrupts.
173262306a36Sopenharmony_ci */
173362306a36Sopenharmony_cistatic void
173462306a36Sopenharmony_citc35815_txdone(struct net_device *dev)
173562306a36Sopenharmony_ci{
173662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
173762306a36Sopenharmony_ci	struct TxFD *txfd;
173862306a36Sopenharmony_ci	unsigned int fdctl;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	txfd = &lp->tfd_base[lp->tfd_end];
174162306a36Sopenharmony_ci	while (lp->tfd_start != lp->tfd_end &&
174262306a36Sopenharmony_ci	       !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
174362306a36Sopenharmony_ci		int status = le32_to_cpu(txfd->fd.FDStat);
174462306a36Sopenharmony_ci		struct sk_buff *skb;
174562306a36Sopenharmony_ci		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
174662306a36Sopenharmony_ci		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci		if (netif_msg_tx_done(lp)) {
174962306a36Sopenharmony_ci			printk("%s: complete TxFD.\n", dev->name);
175062306a36Sopenharmony_ci			dump_txfd(txfd);
175162306a36Sopenharmony_ci		}
175262306a36Sopenharmony_ci		tc35815_check_tx_stat(dev, status);
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci		skb = fdsystem != 0xffffffff ?
175562306a36Sopenharmony_ci			lp->tx_skbs[fdsystem].skb : NULL;
175662306a36Sopenharmony_ci#ifdef DEBUG
175762306a36Sopenharmony_ci		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
175862306a36Sopenharmony_ci			printk("%s: tx_skbs mismatch.\n", dev->name);
175962306a36Sopenharmony_ci			panic_queues(dev);
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci#else
176262306a36Sopenharmony_ci		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
176362306a36Sopenharmony_ci#endif
176462306a36Sopenharmony_ci		if (skb) {
176562306a36Sopenharmony_ci			dev->stats.tx_bytes += skb->len;
176662306a36Sopenharmony_ci			dma_unmap_single(&lp->pci_dev->dev,
176762306a36Sopenharmony_ci					 lp->tx_skbs[lp->tfd_end].skb_dma,
176862306a36Sopenharmony_ci					 skb->len, DMA_TO_DEVICE);
176962306a36Sopenharmony_ci			lp->tx_skbs[lp->tfd_end].skb = NULL;
177062306a36Sopenharmony_ci			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
177162306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
177262306a36Sopenharmony_ci		}
177362306a36Sopenharmony_ci		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
177662306a36Sopenharmony_ci		txfd = &lp->tfd_base[lp->tfd_end];
177762306a36Sopenharmony_ci#ifdef DEBUG
177862306a36Sopenharmony_ci		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
177962306a36Sopenharmony_ci			printk("%s: TxFD FDNext invalid.\n", dev->name);
178062306a36Sopenharmony_ci			panic_queues(dev);
178162306a36Sopenharmony_ci		}
178262306a36Sopenharmony_ci#endif
178362306a36Sopenharmony_ci		if (fdnext & FD_Next_EOL) {
178462306a36Sopenharmony_ci			/* DMA Transmitter has been stopping... */
178562306a36Sopenharmony_ci			if (lp->tfd_end != lp->tfd_start) {
178662306a36Sopenharmony_ci				struct tc35815_regs __iomem *tr =
178762306a36Sopenharmony_ci					(struct tc35815_regs __iomem *)dev->base_addr;
178862306a36Sopenharmony_ci				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
178962306a36Sopenharmony_ci				struct TxFD *txhead = &lp->tfd_base[head];
179062306a36Sopenharmony_ci				int qlen = (lp->tfd_start + TX_FD_NUM
179162306a36Sopenharmony_ci					    - lp->tfd_end) % TX_FD_NUM;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci#ifdef DEBUG
179462306a36Sopenharmony_ci				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
179562306a36Sopenharmony_ci					printk("%s: TxFD FDCtl invalid.\n", dev->name);
179662306a36Sopenharmony_ci					panic_queues(dev);
179762306a36Sopenharmony_ci				}
179862306a36Sopenharmony_ci#endif
179962306a36Sopenharmony_ci				/* log max queue length */
180062306a36Sopenharmony_ci				if (lp->lstats.max_tx_qlen < qlen)
180162306a36Sopenharmony_ci					lp->lstats.max_tx_qlen = qlen;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci				/* start DMA Transmitter again */
180562306a36Sopenharmony_ci				txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
180662306a36Sopenharmony_ci				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
180762306a36Sopenharmony_ci				if (netif_msg_tx_queued(lp)) {
180862306a36Sopenharmony_ci					printk("%s: start TxFD on queue.\n",
180962306a36Sopenharmony_ci					       dev->name);
181062306a36Sopenharmony_ci					dump_txfd(txfd);
181162306a36Sopenharmony_ci				}
181262306a36Sopenharmony_ci				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
181362306a36Sopenharmony_ci			}
181462306a36Sopenharmony_ci			break;
181562306a36Sopenharmony_ci		}
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	/* If we had stopped the queue due to a "tx full"
181962306a36Sopenharmony_ci	 * condition, and space has now been made available,
182062306a36Sopenharmony_ci	 * wake up the queue.
182162306a36Sopenharmony_ci	 */
182262306a36Sopenharmony_ci	if (netif_queue_stopped(dev) && !tc35815_tx_full(dev))
182362306a36Sopenharmony_ci		netif_wake_queue(dev);
182462306a36Sopenharmony_ci}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci/* The inverse routine to tc35815_open(). */
182762306a36Sopenharmony_cistatic int
182862306a36Sopenharmony_citc35815_close(struct net_device *dev)
182962306a36Sopenharmony_ci{
183062306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	netif_stop_queue(dev);
183362306a36Sopenharmony_ci	napi_disable(&lp->napi);
183462306a36Sopenharmony_ci	if (dev->phydev)
183562306a36Sopenharmony_ci		phy_stop(dev->phydev);
183662306a36Sopenharmony_ci	cancel_work_sync(&lp->restart_work);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* Flush the Tx and disable Rx here. */
183962306a36Sopenharmony_ci	tc35815_chip_reset(dev);
184062306a36Sopenharmony_ci	free_irq(dev->irq, dev);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	tc35815_free_queues(dev);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	return 0;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci/*
184962306a36Sopenharmony_ci * Get the current statistics.
185062306a36Sopenharmony_ci * This may be called with the card open or closed.
185162306a36Sopenharmony_ci */
185262306a36Sopenharmony_cistatic struct net_device_stats *tc35815_get_stats(struct net_device *dev)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
185562306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
185662306a36Sopenharmony_ci	if (netif_running(dev))
185762306a36Sopenharmony_ci		/* Update the statistics from the device registers. */
185862306a36Sopenharmony_ci		dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return &dev->stats;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic void tc35815_set_cam_entry(struct net_device *dev, int index,
186462306a36Sopenharmony_ci				  const unsigned char *addr)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
186762306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
186862306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
186962306a36Sopenharmony_ci	int cam_index = index * 6;
187062306a36Sopenharmony_ci	u32 cam_data;
187162306a36Sopenharmony_ci	u32 saved_addr;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	saved_addr = tc_readl(&tr->CAM_Adr);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	if (netif_msg_hw(lp))
187662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: CAM %d: %pM\n",
187762306a36Sopenharmony_ci			dev->name, index, addr);
187862306a36Sopenharmony_ci	if (index & 1) {
187962306a36Sopenharmony_ci		/* read modify write */
188062306a36Sopenharmony_ci		tc_writel(cam_index - 2, &tr->CAM_Adr);
188162306a36Sopenharmony_ci		cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
188262306a36Sopenharmony_ci		cam_data |= addr[0] << 8 | addr[1];
188362306a36Sopenharmony_ci		tc_writel(cam_data, &tr->CAM_Data);
188462306a36Sopenharmony_ci		/* write whole word */
188562306a36Sopenharmony_ci		tc_writel(cam_index + 2, &tr->CAM_Adr);
188662306a36Sopenharmony_ci		cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
188762306a36Sopenharmony_ci		tc_writel(cam_data, &tr->CAM_Data);
188862306a36Sopenharmony_ci	} else {
188962306a36Sopenharmony_ci		/* write whole word */
189062306a36Sopenharmony_ci		tc_writel(cam_index, &tr->CAM_Adr);
189162306a36Sopenharmony_ci		cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
189262306a36Sopenharmony_ci		tc_writel(cam_data, &tr->CAM_Data);
189362306a36Sopenharmony_ci		/* read modify write */
189462306a36Sopenharmony_ci		tc_writel(cam_index + 4, &tr->CAM_Adr);
189562306a36Sopenharmony_ci		cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
189662306a36Sopenharmony_ci		cam_data |= addr[4] << 24 | (addr[5] << 16);
189762306a36Sopenharmony_ci		tc_writel(cam_data, &tr->CAM_Data);
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	tc_writel(saved_addr, &tr->CAM_Adr);
190162306a36Sopenharmony_ci}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci/*
190562306a36Sopenharmony_ci * Set or clear the multicast filter for this adaptor.
190662306a36Sopenharmony_ci * num_addrs == -1	Promiscuous mode, receive all packets
190762306a36Sopenharmony_ci * num_addrs == 0	Normal mode, clear multicast list
190862306a36Sopenharmony_ci * num_addrs > 0	Multicast mode, receive normal and MC packets,
190962306a36Sopenharmony_ci *			and do best-effort filtering.
191062306a36Sopenharmony_ci */
191162306a36Sopenharmony_cistatic void
191262306a36Sopenharmony_citc35815_set_multicast_list(struct net_device *dev)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
191562306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
191862306a36Sopenharmony_ci		/* With some (all?) 100MHalf HUB, controller will hang
191962306a36Sopenharmony_ci		 * if we enabled promiscuous mode before linkup...
192062306a36Sopenharmony_ci		 */
192162306a36Sopenharmony_ci		struct tc35815_local *lp = netdev_priv(dev);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci		if (!lp->link)
192462306a36Sopenharmony_ci			return;
192562306a36Sopenharmony_ci		/* Enable promiscuous mode */
192662306a36Sopenharmony_ci		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
192762306a36Sopenharmony_ci	} else if ((dev->flags & IFF_ALLMULTI) ||
192862306a36Sopenharmony_ci		  netdev_mc_count(dev) > CAM_ENTRY_MAX - 3) {
192962306a36Sopenharmony_ci		/* CAM 0, 1, 20 are reserved. */
193062306a36Sopenharmony_ci		/* Disable promiscuous mode, use normal mode. */
193162306a36Sopenharmony_ci		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
193262306a36Sopenharmony_ci	} else if (!netdev_mc_empty(dev)) {
193362306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
193462306a36Sopenharmony_ci		int i;
193562306a36Sopenharmony_ci		int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci		tc_writel(0, &tr->CAM_Ctl);
193862306a36Sopenharmony_ci		/* Walk the address list, and load the filter */
193962306a36Sopenharmony_ci		i = 0;
194062306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
194162306a36Sopenharmony_ci			/* entry 0,1 is reserved. */
194262306a36Sopenharmony_ci			tc35815_set_cam_entry(dev, i + 2, ha->addr);
194362306a36Sopenharmony_ci			ena_bits |= CAM_Ena_Bit(i + 2);
194462306a36Sopenharmony_ci			i++;
194562306a36Sopenharmony_ci		}
194662306a36Sopenharmony_ci		tc_writel(ena_bits, &tr->CAM_Ena);
194762306a36Sopenharmony_ci		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
194862306a36Sopenharmony_ci	} else {
194962306a36Sopenharmony_ci		tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
195062306a36Sopenharmony_ci		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
195162306a36Sopenharmony_ci	}
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
195562306a36Sopenharmony_ci{
195662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	strscpy(info->driver, MODNAME, sizeof(info->driver));
195962306a36Sopenharmony_ci	strscpy(info->version, DRV_VERSION, sizeof(info->version));
196062306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(lp->pci_dev), sizeof(info->bus_info));
196162306a36Sopenharmony_ci}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_cistatic u32 tc35815_get_msglevel(struct net_device *dev)
196462306a36Sopenharmony_ci{
196562306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
196662306a36Sopenharmony_ci	return lp->msg_enable;
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_cistatic void tc35815_set_msglevel(struct net_device *dev, u32 datum)
197062306a36Sopenharmony_ci{
197162306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
197262306a36Sopenharmony_ci	lp->msg_enable = datum;
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_cistatic int tc35815_get_sset_count(struct net_device *dev, int sset)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	switch (sset) {
198062306a36Sopenharmony_ci	case ETH_SS_STATS:
198162306a36Sopenharmony_ci		return sizeof(lp->lstats) / sizeof(int);
198262306a36Sopenharmony_ci	default:
198362306a36Sopenharmony_ci		return -EOPNOTSUPP;
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_cistatic void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
198862306a36Sopenharmony_ci{
198962306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
199062306a36Sopenharmony_ci	data[0] = lp->lstats.max_tx_qlen;
199162306a36Sopenharmony_ci	data[1] = lp->lstats.tx_ints;
199262306a36Sopenharmony_ci	data[2] = lp->lstats.rx_ints;
199362306a36Sopenharmony_ci	data[3] = lp->lstats.tx_underrun;
199462306a36Sopenharmony_ci}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cistatic struct {
199762306a36Sopenharmony_ci	const char str[ETH_GSTRING_LEN];
199862306a36Sopenharmony_ci} ethtool_stats_keys[] = {
199962306a36Sopenharmony_ci	{ "max_tx_qlen" },
200062306a36Sopenharmony_ci	{ "tx_ints" },
200162306a36Sopenharmony_ci	{ "rx_ints" },
200262306a36Sopenharmony_ci	{ "tx_underrun" },
200362306a36Sopenharmony_ci};
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_cistatic void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
200662306a36Sopenharmony_ci{
200762306a36Sopenharmony_ci	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_cistatic const struct ethtool_ops tc35815_ethtool_ops = {
201162306a36Sopenharmony_ci	.get_drvinfo		= tc35815_get_drvinfo,
201262306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
201362306a36Sopenharmony_ci	.get_msglevel		= tc35815_get_msglevel,
201462306a36Sopenharmony_ci	.set_msglevel		= tc35815_set_msglevel,
201562306a36Sopenharmony_ci	.get_strings		= tc35815_get_strings,
201662306a36Sopenharmony_ci	.get_sset_count		= tc35815_get_sset_count,
201762306a36Sopenharmony_ci	.get_ethtool_stats	= tc35815_get_ethtool_stats,
201862306a36Sopenharmony_ci	.get_link_ksettings = phy_ethtool_get_link_ksettings,
201962306a36Sopenharmony_ci	.set_link_ksettings = phy_ethtool_set_link_ksettings,
202062306a36Sopenharmony_ci};
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistatic void tc35815_chip_reset(struct net_device *dev)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
202562306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
202662306a36Sopenharmony_ci	int i;
202762306a36Sopenharmony_ci	/* reset the controller */
202862306a36Sopenharmony_ci	tc_writel(MAC_Reset, &tr->MAC_Ctl);
202962306a36Sopenharmony_ci	udelay(4); /* 3200ns */
203062306a36Sopenharmony_ci	i = 0;
203162306a36Sopenharmony_ci	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
203262306a36Sopenharmony_ci		if (i++ > 100) {
203362306a36Sopenharmony_ci			printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
203462306a36Sopenharmony_ci			break;
203562306a36Sopenharmony_ci		}
203662306a36Sopenharmony_ci		mdelay(1);
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci	tc_writel(0, &tr->MAC_Ctl);
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	/* initialize registers to default value */
204162306a36Sopenharmony_ci	tc_writel(0, &tr->DMA_Ctl);
204262306a36Sopenharmony_ci	tc_writel(0, &tr->TxThrsh);
204362306a36Sopenharmony_ci	tc_writel(0, &tr->TxPollCtr);
204462306a36Sopenharmony_ci	tc_writel(0, &tr->RxFragSize);
204562306a36Sopenharmony_ci	tc_writel(0, &tr->Int_En);
204662306a36Sopenharmony_ci	tc_writel(0, &tr->FDA_Bas);
204762306a36Sopenharmony_ci	tc_writel(0, &tr->FDA_Lim);
204862306a36Sopenharmony_ci	tc_writel(0xffffffff, &tr->Int_Src);	/* Write 1 to clear */
204962306a36Sopenharmony_ci	tc_writel(0, &tr->CAM_Ctl);
205062306a36Sopenharmony_ci	tc_writel(0, &tr->Tx_Ctl);
205162306a36Sopenharmony_ci	tc_writel(0, &tr->Rx_Ctl);
205262306a36Sopenharmony_ci	tc_writel(0, &tr->CAM_Ena);
205362306a36Sopenharmony_ci	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	/* initialize internal SRAM */
205662306a36Sopenharmony_ci	tc_writel(DMA_TestMode, &tr->DMA_Ctl);
205762306a36Sopenharmony_ci	for (i = 0; i < 0x1000; i += 4) {
205862306a36Sopenharmony_ci		tc_writel(i, &tr->CAM_Adr);
205962306a36Sopenharmony_ci		tc_writel(0, &tr->CAM_Data);
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci	tc_writel(0, &tr->DMA_Ctl);
206262306a36Sopenharmony_ci}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_cistatic void tc35815_chip_init(struct net_device *dev)
206562306a36Sopenharmony_ci{
206662306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
206762306a36Sopenharmony_ci	struct tc35815_regs __iomem *tr =
206862306a36Sopenharmony_ci		(struct tc35815_regs __iomem *)dev->base_addr;
206962306a36Sopenharmony_ci	unsigned long txctl = TX_CTL_CMD;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	/* load station address to CAM */
207262306a36Sopenharmony_ci	tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	/* Enable CAM (broadcast and unicast) */
207562306a36Sopenharmony_ci	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
207662306a36Sopenharmony_ci	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	/* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
207962306a36Sopenharmony_ci	if (HAVE_DMA_RXALIGN(lp))
208062306a36Sopenharmony_ci		tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
208162306a36Sopenharmony_ci	else
208262306a36Sopenharmony_ci		tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
208362306a36Sopenharmony_ci	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
208462306a36Sopenharmony_ci	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
208562306a36Sopenharmony_ci	tc_writel(INT_EN_CMD, &tr->Int_En);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	/* set queues */
208862306a36Sopenharmony_ci	tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
208962306a36Sopenharmony_ci	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
209062306a36Sopenharmony_ci		  &tr->FDA_Lim);
209162306a36Sopenharmony_ci	/*
209262306a36Sopenharmony_ci	 * Activation method:
209362306a36Sopenharmony_ci	 * First, enable the MAC Transmitter and the DMA Receive circuits.
209462306a36Sopenharmony_ci	 * Then enable the DMA Transmitter and the MAC Receive circuits.
209562306a36Sopenharmony_ci	 */
209662306a36Sopenharmony_ci	tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
209762306a36Sopenharmony_ci	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	/* start MAC transmitter */
210062306a36Sopenharmony_ci	/* TX4939 does not have EnLCarr */
210162306a36Sopenharmony_ci	if (lp->chiptype == TC35815_TX4939)
210262306a36Sopenharmony_ci		txctl &= ~Tx_EnLCarr;
210362306a36Sopenharmony_ci	/* WORKAROUND: ignore LostCrS in full duplex operation */
210462306a36Sopenharmony_ci	if (!dev->phydev || !lp->link || lp->duplex == DUPLEX_FULL)
210562306a36Sopenharmony_ci		txctl &= ~Tx_EnLCarr;
210662306a36Sopenharmony_ci	tc_writel(txctl, &tr->Tx_Ctl);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci#ifdef CONFIG_PM
211062306a36Sopenharmony_cistatic int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
211362306a36Sopenharmony_ci	struct tc35815_local *lp = netdev_priv(dev);
211462306a36Sopenharmony_ci	unsigned long flags;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	pci_save_state(pdev);
211762306a36Sopenharmony_ci	if (!netif_running(dev))
211862306a36Sopenharmony_ci		return 0;
211962306a36Sopenharmony_ci	netif_device_detach(dev);
212062306a36Sopenharmony_ci	if (dev->phydev)
212162306a36Sopenharmony_ci		phy_stop(dev->phydev);
212262306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
212362306a36Sopenharmony_ci	tc35815_chip_reset(dev);
212462306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
212562306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D3hot);
212662306a36Sopenharmony_ci	return 0;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic int tc35815_resume(struct pci_dev *pdev)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	pci_restore_state(pdev);
213462306a36Sopenharmony_ci	if (!netif_running(dev))
213562306a36Sopenharmony_ci		return 0;
213662306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
213762306a36Sopenharmony_ci	tc35815_restart(dev);
213862306a36Sopenharmony_ci	netif_carrier_off(dev);
213962306a36Sopenharmony_ci	if (dev->phydev)
214062306a36Sopenharmony_ci		phy_start(dev->phydev);
214162306a36Sopenharmony_ci	netif_device_attach(dev);
214262306a36Sopenharmony_ci	return 0;
214362306a36Sopenharmony_ci}
214462306a36Sopenharmony_ci#endif /* CONFIG_PM */
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_cistatic struct pci_driver tc35815_pci_driver = {
214762306a36Sopenharmony_ci	.name		= MODNAME,
214862306a36Sopenharmony_ci	.id_table	= tc35815_pci_tbl,
214962306a36Sopenharmony_ci	.probe		= tc35815_init_one,
215062306a36Sopenharmony_ci	.remove		= tc35815_remove_one,
215162306a36Sopenharmony_ci#ifdef CONFIG_PM
215262306a36Sopenharmony_ci	.suspend	= tc35815_suspend,
215362306a36Sopenharmony_ci	.resume		= tc35815_resume,
215462306a36Sopenharmony_ci#endif
215562306a36Sopenharmony_ci};
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cimodule_param_named(speed, options.speed, int, 0);
215862306a36Sopenharmony_ciMODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
215962306a36Sopenharmony_cimodule_param_named(duplex, options.duplex, int, 0);
216062306a36Sopenharmony_ciMODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_cimodule_pci_driver(tc35815_pci_driver);
216362306a36Sopenharmony_ciMODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
216462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2165