17c478bd9Sstevel@tonic-gate /**************************************************************************
27c478bd9Sstevel@tonic-gate *    r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
37c478bd9Sstevel@tonic-gate *    Written 2003 by Timothy Legge <tlegge@rogers.com>
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate *    This program is free software; you can redistribute it and/or modify
67c478bd9Sstevel@tonic-gate *    it under the terms of the GNU General Public License as published by
77c478bd9Sstevel@tonic-gate *    the Free Software Foundation; either version 2 of the License, or
87c478bd9Sstevel@tonic-gate *    (at your option) any later version.
97c478bd9Sstevel@tonic-gate *
107c478bd9Sstevel@tonic-gate *    This program is distributed in the hope that it will be useful,
117c478bd9Sstevel@tonic-gate *    but WITHOUT ANY WARRANTY; without even the implied warranty of
127c478bd9Sstevel@tonic-gate *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137c478bd9Sstevel@tonic-gate *    GNU General Public License for more details.
147c478bd9Sstevel@tonic-gate *
157c478bd9Sstevel@tonic-gate *    You should have received a copy of the GNU General Public License
167c478bd9Sstevel@tonic-gate *    along with this program; if not, write to the Free Software
177c478bd9Sstevel@tonic-gate *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate *    Portions of this code based on:
207c478bd9Sstevel@tonic-gate *	r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
217c478bd9Sstevel@tonic-gate * 		for Linux kernel 2.4.x.
227c478bd9Sstevel@tonic-gate *
237c478bd9Sstevel@tonic-gate *    Written 2002 ShuChen <shuchen@realtek.com.tw>
247c478bd9Sstevel@tonic-gate *	  See Linux Driver for full information
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate *    Linux Driver Version 1.27a, 10.02.2002
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate *    Thanks to:
297c478bd9Sstevel@tonic-gate *    	Jean Chen of RealTek Semiconductor Corp. for
307c478bd9Sstevel@tonic-gate *    	providing the evaluation NIC used to develop
317c478bd9Sstevel@tonic-gate *    	this driver.  RealTek's support for Etherboot
327c478bd9Sstevel@tonic-gate *    	is appreciated.
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate *    REVISION HISTORY:
357c478bd9Sstevel@tonic-gate *    ================
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate *    v1.0	11-26-2003	timlegge	Initial port of Linux driver
387c478bd9Sstevel@tonic-gate *    v1.5	01-17-2004	timlegge	Initial driver output cleanup
397c478bd9Sstevel@tonic-gate *    v1.6	03-27-2004	timlegge	Additional Cleanup
407c478bd9Sstevel@tonic-gate *
417c478bd9Sstevel@tonic-gate *    Indent Options: indent -kr -i8
427c478bd9Sstevel@tonic-gate ***************************************************************************/
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /* to get some global routines like printf */
457c478bd9Sstevel@tonic-gate #include "etherboot.h"
467c478bd9Sstevel@tonic-gate /* to get the interface to the body of the program */
477c478bd9Sstevel@tonic-gate #include "nic.h"
487c478bd9Sstevel@tonic-gate /* to get the PCI support functions, if this is a PCI NIC */
497c478bd9Sstevel@tonic-gate #include "pci.h"
507c478bd9Sstevel@tonic-gate #include "timer.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define drv_version "v1.6"
537c478bd9Sstevel@tonic-gate #define drv_date "03-27-2004"
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate typedef unsigned char u8;
567c478bd9Sstevel@tonic-gate typedef signed char s8;
577c478bd9Sstevel@tonic-gate typedef unsigned short u16;
587c478bd9Sstevel@tonic-gate typedef signed short s16;
597c478bd9Sstevel@tonic-gate typedef unsigned int u32;
607c478bd9Sstevel@tonic-gate typedef signed int s32;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define HZ 1000
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static u32 ioaddr;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #ifdef EDEBUG
677c478bd9Sstevel@tonic-gate #define dprintf(x) printf x
687c478bd9Sstevel@tonic-gate #else
697c478bd9Sstevel@tonic-gate #define dprintf(x)
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /* Condensed operations for readability. */
737c478bd9Sstevel@tonic-gate #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
747c478bd9Sstevel@tonic-gate #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /* media options
797c478bd9Sstevel@tonic-gate         _10_Half = 0x01,
807c478bd9Sstevel@tonic-gate         _10_Full = 0x02,
817c478bd9Sstevel@tonic-gate         _100_Half = 0x04,
827c478bd9Sstevel@tonic-gate         _100_Full = 0x08,
837c478bd9Sstevel@tonic-gate         _1000_Full = 0x10,
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate static int media = -1;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #if 0
887c478bd9Sstevel@tonic-gate /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
897c478bd9Sstevel@tonic-gate static int max_interrupt_work = 20;
907c478bd9Sstevel@tonic-gate #endif
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #if 0
937c478bd9Sstevel@tonic-gate /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
947c478bd9Sstevel@tonic-gate    The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
957c478bd9Sstevel@tonic-gate static int multicast_filter_limit = 32;
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* MAC address length*/
997c478bd9Sstevel@tonic-gate #define MAC_ADDR_LEN	6
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
1027c478bd9Sstevel@tonic-gate #define MAX_ETH_FRAME_SIZE	1536
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #define TX_FIFO_THRESH 256	/* In bytes */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer.  */
1077c478bd9Sstevel@tonic-gate #define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
1087c478bd9Sstevel@tonic-gate #define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
1097c478bd9Sstevel@tonic-gate #define EarlyTxThld 	0x3F	/* 0x3F means NO early transmit */
1107c478bd9Sstevel@tonic-gate #define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
1117c478bd9Sstevel@tonic-gate #define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #define NUM_TX_DESC	1	/* Number of Tx descriptor registers */
1147c478bd9Sstevel@tonic-gate #define NUM_RX_DESC	4	/* Number of Rx descriptor registers */
1157c478bd9Sstevel@tonic-gate #define RX_BUF_SIZE	1536	/* Rx Buffer size */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate #define RTL_MIN_IO_SIZE 0x80
1187c478bd9Sstevel@tonic-gate #define TX_TIMEOUT  (6*HZ)
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /* write/read MMIO register */
1217c478bd9Sstevel@tonic-gate #define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
1227c478bd9Sstevel@tonic-gate #define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
1237c478bd9Sstevel@tonic-gate #define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
1247c478bd9Sstevel@tonic-gate #define RTL_R8(reg)		readb (ioaddr + (reg))
1257c478bd9Sstevel@tonic-gate #define RTL_R16(reg)		readw (ioaddr + (reg))
1267c478bd9Sstevel@tonic-gate #define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate enum RTL8169_registers {
1297c478bd9Sstevel@tonic-gate 	MAC0 = 0,		/* Ethernet hardware address. */
1307c478bd9Sstevel@tonic-gate 	MAR0 = 8,		/* Multicast filter. */
1317c478bd9Sstevel@tonic-gate 	TxDescStartAddr = 0x20,
1327c478bd9Sstevel@tonic-gate 	TxHDescStartAddr = 0x28,
1337c478bd9Sstevel@tonic-gate 	FLASH = 0x30,
1347c478bd9Sstevel@tonic-gate 	ERSR = 0x36,
1357c478bd9Sstevel@tonic-gate 	ChipCmd = 0x37,
1367c478bd9Sstevel@tonic-gate 	TxPoll = 0x38,
1377c478bd9Sstevel@tonic-gate 	IntrMask = 0x3C,
1387c478bd9Sstevel@tonic-gate 	IntrStatus = 0x3E,
1397c478bd9Sstevel@tonic-gate 	TxConfig = 0x40,
1407c478bd9Sstevel@tonic-gate 	RxConfig = 0x44,
1417c478bd9Sstevel@tonic-gate 	RxMissed = 0x4C,
1427c478bd9Sstevel@tonic-gate 	Cfg9346 = 0x50,
1437c478bd9Sstevel@tonic-gate 	Config0 = 0x51,
1447c478bd9Sstevel@tonic-gate 	Config1 = 0x52,
1457c478bd9Sstevel@tonic-gate 	Config2 = 0x53,
1467c478bd9Sstevel@tonic-gate 	Config3 = 0x54,
1477c478bd9Sstevel@tonic-gate 	Config4 = 0x55,
1487c478bd9Sstevel@tonic-gate 	Config5 = 0x56,
1497c478bd9Sstevel@tonic-gate 	MultiIntr = 0x5C,
1507c478bd9Sstevel@tonic-gate 	PHYAR = 0x60,
1517c478bd9Sstevel@tonic-gate 	TBICSR = 0x64,
1527c478bd9Sstevel@tonic-gate 	TBI_ANAR = 0x68,
1537c478bd9Sstevel@tonic-gate 	TBI_LPAR = 0x6A,
1547c478bd9Sstevel@tonic-gate 	PHYstatus = 0x6C,
1557c478bd9Sstevel@tonic-gate 	RxMaxSize = 0xDA,
1567c478bd9Sstevel@tonic-gate 	CPlusCmd = 0xE0,
1577c478bd9Sstevel@tonic-gate 	RxDescStartAddr = 0xE4,
1587c478bd9Sstevel@tonic-gate 	EarlyTxThres = 0xEC,
1597c478bd9Sstevel@tonic-gate 	FuncEvent = 0xF0,
1607c478bd9Sstevel@tonic-gate 	FuncEventMask = 0xF4,
1617c478bd9Sstevel@tonic-gate 	FuncPresetState = 0xF8,
1627c478bd9Sstevel@tonic-gate 	FuncForceEvent = 0xFC,
1637c478bd9Sstevel@tonic-gate };
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate enum RTL8169_register_content {
1667c478bd9Sstevel@tonic-gate 	/*InterruptStatusBits */
1677c478bd9Sstevel@tonic-gate 	SYSErr = 0x8000,
1687c478bd9Sstevel@tonic-gate 	PCSTimeout = 0x4000,
1697c478bd9Sstevel@tonic-gate 	SWInt = 0x0100,
1707c478bd9Sstevel@tonic-gate 	TxDescUnavail = 0x80,
1717c478bd9Sstevel@tonic-gate 	RxFIFOOver = 0x40,
1727c478bd9Sstevel@tonic-gate 	RxUnderrun = 0x20,
1737c478bd9Sstevel@tonic-gate 	RxOverflow = 0x10,
1747c478bd9Sstevel@tonic-gate 	TxErr = 0x08,
1757c478bd9Sstevel@tonic-gate 	TxOK = 0x04,
1767c478bd9Sstevel@tonic-gate 	RxErr = 0x02,
1777c478bd9Sstevel@tonic-gate 	RxOK = 0x01,
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/*RxStatusDesc */
1807c478bd9Sstevel@tonic-gate 	RxRES = 0x00200000,
1817c478bd9Sstevel@tonic-gate 	RxCRC = 0x00080000,
1827c478bd9Sstevel@tonic-gate 	RxRUNT = 0x00100000,
1837c478bd9Sstevel@tonic-gate 	RxRWT = 0x00400000,
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/*ChipCmdBits */
1867c478bd9Sstevel@tonic-gate 	CmdReset = 0x10,
1877c478bd9Sstevel@tonic-gate 	CmdRxEnb = 0x08,
1887c478bd9Sstevel@tonic-gate 	CmdTxEnb = 0x04,
1897c478bd9Sstevel@tonic-gate 	RxBufEmpty = 0x01,
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/*Cfg9346Bits */
1927c478bd9Sstevel@tonic-gate 	Cfg9346_Lock = 0x00,
1937c478bd9Sstevel@tonic-gate 	Cfg9346_Unlock = 0xC0,
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/*rx_mode_bits */
1967c478bd9Sstevel@tonic-gate 	AcceptErr = 0x20,
1977c478bd9Sstevel@tonic-gate 	AcceptRunt = 0x10,
1987c478bd9Sstevel@tonic-gate 	AcceptBroadcast = 0x08,
1997c478bd9Sstevel@tonic-gate 	AcceptMulticast = 0x04,
2007c478bd9Sstevel@tonic-gate 	AcceptMyPhys = 0x02,
2017c478bd9Sstevel@tonic-gate 	AcceptAllPhys = 0x01,
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/*RxConfigBits */
2047c478bd9Sstevel@tonic-gate 	RxCfgFIFOShift = 13,
2057c478bd9Sstevel@tonic-gate 	RxCfgDMAShift = 8,
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	/*TxConfigBits */
2087c478bd9Sstevel@tonic-gate 	TxInterFrameGapShift = 24,
2097c478bd9Sstevel@tonic-gate 	TxDMAShift = 8,		/* DMA burst value (0-7) is shift this many bits */
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/*rtl8169_PHYstatus */
2127c478bd9Sstevel@tonic-gate 	TBI_Enable = 0x80,
2137c478bd9Sstevel@tonic-gate 	TxFlowCtrl = 0x40,
2147c478bd9Sstevel@tonic-gate 	RxFlowCtrl = 0x20,
2157c478bd9Sstevel@tonic-gate 	_1000bpsF = 0x10,
2167c478bd9Sstevel@tonic-gate 	_100bps = 0x08,
2177c478bd9Sstevel@tonic-gate 	_10bps = 0x04,
2187c478bd9Sstevel@tonic-gate 	LinkStatus = 0x02,
2197c478bd9Sstevel@tonic-gate 	FullDup = 0x01,
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*GIGABIT_PHY_registers */
2227c478bd9Sstevel@tonic-gate 	PHY_CTRL_REG = 0,
2237c478bd9Sstevel@tonic-gate 	PHY_STAT_REG = 1,
2247c478bd9Sstevel@tonic-gate 	PHY_AUTO_NEGO_REG = 4,
2257c478bd9Sstevel@tonic-gate 	PHY_1000_CTRL_REG = 9,
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*GIGABIT_PHY_REG_BIT */
2287c478bd9Sstevel@tonic-gate 	PHY_Restart_Auto_Nego = 0x0200,
2297c478bd9Sstevel@tonic-gate 	PHY_Enable_Auto_Nego = 0x1000,
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/* PHY_STAT_REG = 1; */
2327c478bd9Sstevel@tonic-gate 	PHY_Auto_Neco_Comp = 0x0020,
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/* PHY_AUTO_NEGO_REG = 4; */
2357c478bd9Sstevel@tonic-gate 	PHY_Cap_10_Half = 0x0020,
2367c478bd9Sstevel@tonic-gate 	PHY_Cap_10_Full = 0x0040,
2377c478bd9Sstevel@tonic-gate 	PHY_Cap_100_Half = 0x0080,
2387c478bd9Sstevel@tonic-gate 	PHY_Cap_100_Full = 0x0100,
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/* PHY_1000_CTRL_REG = 9; */
2417c478bd9Sstevel@tonic-gate 	PHY_Cap_1000_Full = 0x0200,
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	PHY_Cap_Null = 0x0,
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*_MediaType*/
2467c478bd9Sstevel@tonic-gate 	_10_Half = 0x01,
2477c478bd9Sstevel@tonic-gate 	_10_Full = 0x02,
2487c478bd9Sstevel@tonic-gate 	_100_Half = 0x04,
2497c478bd9Sstevel@tonic-gate 	_100_Full = 0x08,
2507c478bd9Sstevel@tonic-gate 	_1000_Full = 0x10,
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/*_TBICSRBit*/
2537c478bd9Sstevel@tonic-gate 	TBILinkOK = 0x02000000,
2547c478bd9Sstevel@tonic-gate };
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate static struct {
2577c478bd9Sstevel@tonic-gate 	const char *name;
2587c478bd9Sstevel@tonic-gate 	u8 version;		/* depend on RTL8169 docs */
2597c478bd9Sstevel@tonic-gate 	u32 RxConfigMask;	/* should clear the bits supported by this chip */
2607c478bd9Sstevel@tonic-gate } rtl_chip_info[] = {
2617c478bd9Sstevel@tonic-gate 	{
2627c478bd9Sstevel@tonic-gate "RTL-8169", 0x00, 0xff7e1880,},};
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate enum _DescStatusBit {
2657c478bd9Sstevel@tonic-gate 	OWNbit = 0x80000000,
2667c478bd9Sstevel@tonic-gate 	EORbit = 0x40000000,
2677c478bd9Sstevel@tonic-gate 	FSbit = 0x20000000,
2687c478bd9Sstevel@tonic-gate 	LSbit = 0x10000000,
2697c478bd9Sstevel@tonic-gate };
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate struct TxDesc {
2727c478bd9Sstevel@tonic-gate 	u32 status;
2737c478bd9Sstevel@tonic-gate 	u32 vlan_tag;
2747c478bd9Sstevel@tonic-gate 	u32 buf_addr;
2757c478bd9Sstevel@tonic-gate 	u32 buf_Haddr;
2767c478bd9Sstevel@tonic-gate };
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate struct RxDesc {
2797c478bd9Sstevel@tonic-gate 	u32 status;
2807c478bd9Sstevel@tonic-gate 	u32 vlan_tag;
2817c478bd9Sstevel@tonic-gate 	u32 buf_addr;
2827c478bd9Sstevel@tonic-gate 	u32 buf_Haddr;
2837c478bd9Sstevel@tonic-gate };
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /* The descriptors for this card are required to be aligned on
2867c478bd9Sstevel@tonic-gate 256 byte boundaries.  As the align attribute does not do more than
2877c478bd9Sstevel@tonic-gate 16 bytes of alignment it requires some extra steps.  Add 256 to the
2887c478bd9Sstevel@tonic-gate size of the array and the init_ring adjusts the alignment */
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /* Define the TX Descriptor */
2917c478bd9Sstevel@tonic-gate static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /* Create a static buffer of size RX_BUF_SZ for each
2947c478bd9Sstevel@tonic-gate TX Descriptor.  All descriptors point to a
2957c478bd9Sstevel@tonic-gate part of this buffer */
2967c478bd9Sstevel@tonic-gate static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /* Define the RX Descriptor */
2997c478bd9Sstevel@tonic-gate static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate /* Create a static buffer of size RX_BUF_SZ for each
3027c478bd9Sstevel@tonic-gate RX Descriptor   All descriptors point to a
3037c478bd9Sstevel@tonic-gate part of this buffer */
3047c478bd9Sstevel@tonic-gate static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate struct rtl8169_private {
3077c478bd9Sstevel@tonic-gate 	void *mmio_addr;	/* memory map physical address */
3087c478bd9Sstevel@tonic-gate 	int chipset;
3097c478bd9Sstevel@tonic-gate 	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
3107c478bd9Sstevel@tonic-gate 	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
3117c478bd9Sstevel@tonic-gate 	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
3127c478bd9Sstevel@tonic-gate 	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
3137c478bd9Sstevel@tonic-gate 	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
3147c478bd9Sstevel@tonic-gate 	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
3157c478bd9Sstevel@tonic-gate 	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
3167c478bd9Sstevel@tonic-gate 	unsigned char *Tx_skbuff[NUM_TX_DESC];
3177c478bd9Sstevel@tonic-gate } tpx;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static struct rtl8169_private *tpc;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static const u16 rtl8169_intr_mask =
3227c478bd9Sstevel@tonic-gate     SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr |
3237c478bd9Sstevel@tonic-gate     TxOK | RxErr | RxOK;
3247c478bd9Sstevel@tonic-gate static const unsigned int rtl8169_rx_config =
3257c478bd9Sstevel@tonic-gate     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
3267c478bd9Sstevel@tonic-gate 
mdio_write(int RegAddr,int value)3277c478bd9Sstevel@tonic-gate void mdio_write(int RegAddr, int value)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	int i;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
3327c478bd9Sstevel@tonic-gate 	udelay(1000);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	for (i = 2000; i > 0; i--) {
3357c478bd9Sstevel@tonic-gate 		/* Check if the RTL8169 has completed writing to the specified MII register */
3367c478bd9Sstevel@tonic-gate 		if (!(RTL_R32(PHYAR) & 0x80000000)) {
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 		} else {
3397c478bd9Sstevel@tonic-gate 			udelay(100);
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
mdio_read(int RegAddr)3447c478bd9Sstevel@tonic-gate int mdio_read(int RegAddr)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	int i, value = -1;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
3497c478bd9Sstevel@tonic-gate 	udelay(1000);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	for (i = 2000; i > 0; i--) {
3527c478bd9Sstevel@tonic-gate 		/* Check if the RTL8169 has completed retrieving data from the specified MII register */
3537c478bd9Sstevel@tonic-gate 		if (RTL_R32(PHYAR) & 0x80000000) {
3547c478bd9Sstevel@tonic-gate 			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		} else {
3577c478bd9Sstevel@tonic-gate 			udelay(100);
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	return value;
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
rtl8169_init_board(struct pci_device * pdev)3637c478bd9Sstevel@tonic-gate static int rtl8169_init_board(struct pci_device *pdev)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	int i;
3667c478bd9Sstevel@tonic-gate 	unsigned long rtreg_base, rtreg_len;
3677c478bd9Sstevel@tonic-gate 	u32 tmp;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	rtreg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
3707c478bd9Sstevel@tonic-gate 	rtreg_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/* check for weird/broken PCI region reporting */
3737c478bd9Sstevel@tonic-gate 	if (rtreg_len < RTL_MIN_IO_SIZE) {
3747c478bd9Sstevel@tonic-gate 		printf("Invalid PCI region size(s), aborting\n");
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	adjust_pci_device(pdev);
3787c478bd9Sstevel@tonic-gate /*      pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); */
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/* ioremap MMIO region */
3817c478bd9Sstevel@tonic-gate 	ioaddr = (unsigned long) ioremap(rtreg_base, rtreg_len);
3827c478bd9Sstevel@tonic-gate 	if (ioaddr == 0)
3837c478bd9Sstevel@tonic-gate 		return 0;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	tpc->mmio_addr = &ioaddr;
3867c478bd9Sstevel@tonic-gate 	/* Soft reset the chip. */
3877c478bd9Sstevel@tonic-gate 	RTL_W8(ChipCmd, CmdReset);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/* Check that the chip has finished the reset. */
3907c478bd9Sstevel@tonic-gate 	for (i = 1000; i > 0; i--)
3917c478bd9Sstevel@tonic-gate 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
3927c478bd9Sstevel@tonic-gate 			break;
3937c478bd9Sstevel@tonic-gate 		else
3947c478bd9Sstevel@tonic-gate 			udelay(10);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	/* identify chip attached to board */
3977c478bd9Sstevel@tonic-gate 	tmp = RTL_R32(TxConfig);
3987c478bd9Sstevel@tonic-gate 	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
4017c478bd9Sstevel@tonic-gate 		if (tmp == rtl_chip_info[i].version) {
4027c478bd9Sstevel@tonic-gate 			tpc->chipset = i;
4037c478bd9Sstevel@tonic-gate 			goto match;
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 	/* if unknown chip, assume array element #0, original RTL-8169 in this case */
4067c478bd9Sstevel@tonic-gate 	dprintf(("PCI device: unknown chip version, assuming RTL-8169\n"));
4077c478bd9Sstevel@tonic-gate 	dprintf(("PCI device: TxConfig = 0x%hX\n",
4087c478bd9Sstevel@tonic-gate 		 (unsigned long) RTL_R32(TxConfig)));
4097c478bd9Sstevel@tonic-gate 	tpc->chipset = 0;
4107c478bd9Sstevel@tonic-gate 	return 1;
4117c478bd9Sstevel@tonic-gate       match:
4127c478bd9Sstevel@tonic-gate 	return 0;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /**************************************************************************
4177c478bd9Sstevel@tonic-gate IRQ - Wait for a frame
4187c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_irq(struct nic * nic __unused,irq_action_t action)4197c478bd9Sstevel@tonic-gate void r8169_irq ( struct nic *nic __unused, irq_action_t action ) {
4207c478bd9Sstevel@tonic-gate 	int intr_status = 0;
4217c478bd9Sstevel@tonic-gate 	int interested = RxUnderrun | RxOverflow | RxFIFOOver | RxErr | RxOK;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	switch ( action ) {
4247c478bd9Sstevel@tonic-gate 		case DISABLE:
4257c478bd9Sstevel@tonic-gate 		case ENABLE:
4267c478bd9Sstevel@tonic-gate 			intr_status = RTL_R16(IntrStatus);
4277c478bd9Sstevel@tonic-gate 			/* h/w no longer present (hotplug?) or major error,
4287c478bd9Sstevel@tonic-gate 				bail */
4297c478bd9Sstevel@tonic-gate 			if (intr_status == 0xFFFF)
4307c478bd9Sstevel@tonic-gate 				break;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 			intr_status = intr_status & ~interested;
4337c478bd9Sstevel@tonic-gate 			if ( action == ENABLE )
4347c478bd9Sstevel@tonic-gate 				intr_status = intr_status | interested;
4357c478bd9Sstevel@tonic-gate 			RTL_W16(IntrMask, intr_status);
4367c478bd9Sstevel@tonic-gate 			break;
4377c478bd9Sstevel@tonic-gate 		case FORCE :
4387c478bd9Sstevel@tonic-gate 			RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01));
4397c478bd9Sstevel@tonic-gate 			break;
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate /**************************************************************************
4447c478bd9Sstevel@tonic-gate POLL - Wait for a frame
4457c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_poll(struct nic * nic,int retreive)4467c478bd9Sstevel@tonic-gate static int r8169_poll(struct nic *nic, int retreive)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	/* return true if there's an ethernet packet ready to read */
4497c478bd9Sstevel@tonic-gate 	/* nic->packet should contain data on return */
4507c478bd9Sstevel@tonic-gate 	/* nic->packetlen should contain length of data */
4517c478bd9Sstevel@tonic-gate 	int cur_rx;
4527c478bd9Sstevel@tonic-gate 	unsigned int intr_status = 0;
4537c478bd9Sstevel@tonic-gate 	cur_rx = tpc->cur_rx;
4547c478bd9Sstevel@tonic-gate 	if ((tpc->RxDescArray[cur_rx].status & OWNbit) == 0) {
4557c478bd9Sstevel@tonic-gate 	         /* There is a packet ready */
4567c478bd9Sstevel@tonic-gate   	         if(!retreive)
4577c478bd9Sstevel@tonic-gate   	                 return 1;
4587c478bd9Sstevel@tonic-gate 		intr_status = RTL_R16(IntrStatus);
4597c478bd9Sstevel@tonic-gate 		/* h/w no longer present (hotplug?) or major error,
4607c478bd9Sstevel@tonic-gate 			bail */
4617c478bd9Sstevel@tonic-gate 		if (intr_status == 0xFFFF)
4627c478bd9Sstevel@tonic-gate 			return 0;
4637c478bd9Sstevel@tonic-gate 		RTL_W16(IntrStatus, intr_status &
4647c478bd9Sstevel@tonic-gate 			~(RxFIFOOver | RxOverflow | RxOK));
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		if (!(tpc->RxDescArray[cur_rx].status & RxRES)) {
4677c478bd9Sstevel@tonic-gate 			nic->packetlen = (int) (tpc->RxDescArray[cur_rx].
4687c478bd9Sstevel@tonic-gate 						status & 0x00001FFF) - 4;
4697c478bd9Sstevel@tonic-gate 			memcpy(nic->packet, tpc->RxBufferRing[cur_rx],
4707c478bd9Sstevel@tonic-gate 			       nic->packetlen);
4717c478bd9Sstevel@tonic-gate 			if (cur_rx == NUM_RX_DESC - 1)
4727c478bd9Sstevel@tonic-gate 				tpc->RxDescArray[cur_rx].status =
4737c478bd9Sstevel@tonic-gate 				    (OWNbit | EORbit) + RX_BUF_SIZE;
4747c478bd9Sstevel@tonic-gate 			else
4757c478bd9Sstevel@tonic-gate 				tpc->RxDescArray[cur_rx].status =
4767c478bd9Sstevel@tonic-gate 				    OWNbit + RX_BUF_SIZE;
4777c478bd9Sstevel@tonic-gate 			tpc->RxDescArray[cur_rx].buf_addr =
4787c478bd9Sstevel@tonic-gate 			    virt_to_bus(tpc->RxBufferRing[cur_rx]);
4797c478bd9Sstevel@tonic-gate 		} else
4807c478bd9Sstevel@tonic-gate 			printf("Error Rx");
4817c478bd9Sstevel@tonic-gate 		/* FIXME: shouldn't I reset the status on an error */
4827c478bd9Sstevel@tonic-gate 		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
4837c478bd9Sstevel@tonic-gate 		tpc->cur_rx = cur_rx;
4847c478bd9Sstevel@tonic-gate 		RTL_W16(IntrStatus, intr_status &
4857c478bd9Sstevel@tonic-gate 			(RxFIFOOver | RxOverflow | RxOK));
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		return 1;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	tpc->cur_rx = cur_rx;
4917c478bd9Sstevel@tonic-gate 	/* FIXME: There is no reason to do this as cur_rx did not change */
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (0);		/* initially as this is called to flush the input */
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate /**************************************************************************
4987c478bd9Sstevel@tonic-gate TRANSMIT - Transmit a frame
4997c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)5007c478bd9Sstevel@tonic-gate static void r8169_transmit(struct nic *nic, const char *d,	/* Destination */
5017c478bd9Sstevel@tonic-gate 			   unsigned int t,	/* Type */
5027c478bd9Sstevel@tonic-gate 			   unsigned int s,	/* size */
5037c478bd9Sstevel@tonic-gate 			   const char *p)
5047c478bd9Sstevel@tonic-gate {				/* Packet */
5057c478bd9Sstevel@tonic-gate 	/* send the packet to destination */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	u16 nstype;
5087c478bd9Sstevel@tonic-gate 	u32 to;
5097c478bd9Sstevel@tonic-gate 	u8 *ptxb;
5107c478bd9Sstevel@tonic-gate 	int entry = tpc->cur_tx % NUM_TX_DESC;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* point to the current txb incase multiple tx_rings are used */
5137c478bd9Sstevel@tonic-gate 	ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
5147c478bd9Sstevel@tonic-gate 	memcpy(ptxb, d, ETH_ALEN);
5157c478bd9Sstevel@tonic-gate 	memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
5167c478bd9Sstevel@tonic-gate 	nstype = htons((u16) t);
5177c478bd9Sstevel@tonic-gate 	memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
5187c478bd9Sstevel@tonic-gate 	memcpy(ptxb + ETH_HLEN, p, s);
5197c478bd9Sstevel@tonic-gate 	s += ETH_HLEN;
5207c478bd9Sstevel@tonic-gate 	s &= 0x0FFF;
5217c478bd9Sstevel@tonic-gate 	while (s < ETH_ZLEN)
5227c478bd9Sstevel@tonic-gate 		ptxb[s++] = '\0';
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	tpc->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
5257c478bd9Sstevel@tonic-gate 	if (entry != (NUM_TX_DESC - 1))
5267c478bd9Sstevel@tonic-gate 		tpc->TxDescArray[entry].status =
5277c478bd9Sstevel@tonic-gate 		    (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s :
5287c478bd9Sstevel@tonic-gate 						ETH_ZLEN);
5297c478bd9Sstevel@tonic-gate 	else
5307c478bd9Sstevel@tonic-gate 		tpc->TxDescArray[entry].status =
5317c478bd9Sstevel@tonic-gate 		    (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s
5327c478bd9Sstevel@tonic-gate 							 : ETH_ZLEN);
5337c478bd9Sstevel@tonic-gate 	RTL_W8(TxPoll, 0x40);	/* set polling bit */
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	tpc->cur_tx++;
5367c478bd9Sstevel@tonic-gate 	to = currticks() + TX_TIMEOUT;
5377c478bd9Sstevel@tonic-gate 	while ((tpc->TxDescArray[entry].status & OWNbit) && (currticks() < to));	/* wait */
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (currticks() >= to) {
5407c478bd9Sstevel@tonic-gate 		printf("TX Time Out");
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
rtl8169_set_rx_mode(struct nic * nic __unused)5447c478bd9Sstevel@tonic-gate static void rtl8169_set_rx_mode(struct nic *nic __unused)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	u32 mc_filter[2];	/* Multicast hash filter */
5477c478bd9Sstevel@tonic-gate 	int rx_mode;
5487c478bd9Sstevel@tonic-gate 	u32 tmp = 0;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/* IFF_ALLMULTI */
5517c478bd9Sstevel@tonic-gate 	/* Too many to filter perfectly -- accept all multicasts. */
5527c478bd9Sstevel@tonic-gate 	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
5537c478bd9Sstevel@tonic-gate 	mc_filter[1] = mc_filter[0] = 0xffffffff;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	tmp =
5567c478bd9Sstevel@tonic-gate 	    rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
5577c478bd9Sstevel@tonic-gate 					   rtl_chip_info[tpc->chipset].
5587c478bd9Sstevel@tonic-gate 					   RxConfigMask);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	RTL_W32(RxConfig, tmp);
5617c478bd9Sstevel@tonic-gate 	RTL_W32(MAR0 + 0, mc_filter[0]);
5627c478bd9Sstevel@tonic-gate 	RTL_W32(MAR0 + 4, mc_filter[1]);
5637c478bd9Sstevel@tonic-gate }
rtl8169_hw_start(struct nic * nic)5647c478bd9Sstevel@tonic-gate static void rtl8169_hw_start(struct nic *nic)
5657c478bd9Sstevel@tonic-gate {
5667c478bd9Sstevel@tonic-gate 	u32 i;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* Soft reset the chip. */
5697c478bd9Sstevel@tonic-gate 	RTL_W8(ChipCmd, CmdReset);
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	/* Check that the chip has finished the reset. */
5727c478bd9Sstevel@tonic-gate 	for (i = 1000; i > 0; i--) {
5737c478bd9Sstevel@tonic-gate 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
5747c478bd9Sstevel@tonic-gate 			break;
5757c478bd9Sstevel@tonic-gate 		else
5767c478bd9Sstevel@tonic-gate 			udelay(10);
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	RTL_W8(Cfg9346, Cfg9346_Unlock);
5807c478bd9Sstevel@tonic-gate 	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5817c478bd9Sstevel@tonic-gate 	RTL_W8(EarlyTxThres, EarlyTxThld);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	/* For gigabit rtl8169 */
5847c478bd9Sstevel@tonic-gate 	RTL_W16(RxMaxSize, RxPacketMaxSize);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/* Set Rx Config register */
5877c478bd9Sstevel@tonic-gate 	i = rtl8169_rx_config | (RTL_R32(RxConfig) &
5887c478bd9Sstevel@tonic-gate 				 rtl_chip_info[tpc->chipset].RxConfigMask);
5897c478bd9Sstevel@tonic-gate 	RTL_W32(RxConfig, i);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/* Set DMA burst size and Interframe Gap Time */
5927c478bd9Sstevel@tonic-gate 	RTL_W32(TxConfig,
5937c478bd9Sstevel@tonic-gate 		(TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
5947c478bd9Sstevel@tonic-gate 						TxInterFrameGapShift));
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	tpc->cur_rx = 0;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	RTL_W32(TxDescStartAddr, virt_to_le32desc(tpc->TxDescArray));
6007c478bd9Sstevel@tonic-gate 	RTL_W32(RxDescStartAddr, virt_to_le32desc(tpc->RxDescArray));
6017c478bd9Sstevel@tonic-gate 	RTL_W8(Cfg9346, Cfg9346_Lock);
6027c478bd9Sstevel@tonic-gate 	udelay(10);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	RTL_W32(RxMissed, 0);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	rtl8169_set_rx_mode(nic);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/* no early-rx interrupts */
6097c478bd9Sstevel@tonic-gate 	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
rtl8169_init_ring(struct nic * nic __unused)6127c478bd9Sstevel@tonic-gate static void rtl8169_init_ring(struct nic *nic __unused)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	int i;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	tpc->cur_rx = 0;
6177c478bd9Sstevel@tonic-gate 	tpc->cur_tx = 0;
6187c478bd9Sstevel@tonic-gate 	memset(tpc->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
6197c478bd9Sstevel@tonic-gate 	memset(tpc->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUM_TX_DESC; i++) {
6227c478bd9Sstevel@tonic-gate 		tpc->Tx_skbuff[i] = &txb[i];
6237c478bd9Sstevel@tonic-gate 	}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUM_RX_DESC; i++) {
6267c478bd9Sstevel@tonic-gate 		if (i == (NUM_RX_DESC - 1))
6277c478bd9Sstevel@tonic-gate 			tpc->RxDescArray[i].status =
6287c478bd9Sstevel@tonic-gate 			    (OWNbit | EORbit) + RX_BUF_SIZE;
6297c478bd9Sstevel@tonic-gate 		else
6307c478bd9Sstevel@tonic-gate 			tpc->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 		tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
6337c478bd9Sstevel@tonic-gate 		tpc->RxDescArray[i].buf_addr =
6347c478bd9Sstevel@tonic-gate 		    virt_to_bus(tpc->RxBufferRing[i]);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /**************************************************************************
6397c478bd9Sstevel@tonic-gate RESET - Finish setting up the ethernet interface
6407c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_reset(struct nic * nic)6417c478bd9Sstevel@tonic-gate static void r8169_reset(struct nic *nic)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	int i;
6447c478bd9Sstevel@tonic-gate 	u8 diff;
6457c478bd9Sstevel@tonic-gate 	u32 TxPhyAddr, RxPhyAddr;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	tpc->TxDescArrays = tx_ring;
6487c478bd9Sstevel@tonic-gate 	if (tpc->TxDescArrays == 0)
6497c478bd9Sstevel@tonic-gate 		printf("Allot Error");
6507c478bd9Sstevel@tonic-gate 	/* Tx Desscriptor needs 256 bytes alignment; */
6517c478bd9Sstevel@tonic-gate 	TxPhyAddr = virt_to_bus(tpc->TxDescArrays);
6527c478bd9Sstevel@tonic-gate 	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
6537c478bd9Sstevel@tonic-gate 	TxPhyAddr += diff;
6547c478bd9Sstevel@tonic-gate 	tpc->TxDescArray = (struct TxDesc *) (tpc->TxDescArrays + diff);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	tpc->RxDescArrays = rx_ring;
6577c478bd9Sstevel@tonic-gate 	/* Rx Desscriptor needs 256 bytes alignment; */
6587c478bd9Sstevel@tonic-gate 	RxPhyAddr = virt_to_bus(tpc->RxDescArrays);
6597c478bd9Sstevel@tonic-gate 	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
6607c478bd9Sstevel@tonic-gate 	RxPhyAddr += diff;
6617c478bd9Sstevel@tonic-gate 	tpc->RxDescArray = (struct RxDesc *) (tpc->RxDescArrays + diff);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (tpc->TxDescArrays == NULL || tpc->RxDescArrays == NULL) {
6647c478bd9Sstevel@tonic-gate 		printf("Allocate RxDescArray or TxDescArray failed\n");
6657c478bd9Sstevel@tonic-gate 		return;
6667c478bd9Sstevel@tonic-gate 	}
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	rtl8169_init_ring(nic);
6697c478bd9Sstevel@tonic-gate 	rtl8169_hw_start(nic);
6707c478bd9Sstevel@tonic-gate 	/* Construct a perfect filter frame with the mac address as first match
6717c478bd9Sstevel@tonic-gate 	 * and broadcast for all others */
6727c478bd9Sstevel@tonic-gate 	for (i = 0; i < 192; i++)
6737c478bd9Sstevel@tonic-gate 		txb[i] = 0xFF;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	txb[0] = nic->node_addr[0];
6767c478bd9Sstevel@tonic-gate 	txb[1] = nic->node_addr[1];
6777c478bd9Sstevel@tonic-gate 	txb[2] = nic->node_addr[2];
6787c478bd9Sstevel@tonic-gate 	txb[3] = nic->node_addr[3];
6797c478bd9Sstevel@tonic-gate 	txb[4] = nic->node_addr[4];
6807c478bd9Sstevel@tonic-gate 	txb[5] = nic->node_addr[5];
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate /**************************************************************************
6847c478bd9Sstevel@tonic-gate DISABLE - Turn off ethernet interface
6857c478bd9Sstevel@tonic-gate ***************************************************************************/
r8169_disable(struct dev * dev __unused)6867c478bd9Sstevel@tonic-gate static void r8169_disable(struct dev *dev __unused)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	int i;
6897c478bd9Sstevel@tonic-gate 	/* Stop the chip's Tx and Rx DMA processes. */
6907c478bd9Sstevel@tonic-gate 	RTL_W8(ChipCmd, 0x00);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	/* Disable interrupts by clearing the interrupt mask. */
6937c478bd9Sstevel@tonic-gate 	RTL_W16(IntrMask, 0x0000);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	RTL_W32(RxMissed, 0);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	tpc->TxDescArrays = NULL;
6987c478bd9Sstevel@tonic-gate 	tpc->RxDescArrays = NULL;
6997c478bd9Sstevel@tonic-gate 	tpc->TxDescArray = NULL;
7007c478bd9Sstevel@tonic-gate 	tpc->RxDescArray = NULL;
7017c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUM_RX_DESC; i++) {
7027c478bd9Sstevel@tonic-gate 		tpc->RxBufferRing[i] = NULL;
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate /**************************************************************************
7077c478bd9Sstevel@tonic-gate PROBE - Look for an adapter, this routine's visible to the outside
7087c478bd9Sstevel@tonic-gate ***************************************************************************/
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate #define board_found 1
7117c478bd9Sstevel@tonic-gate #define valid_link 0
r8169_probe(struct dev * dev,struct pci_device * pci)7127c478bd9Sstevel@tonic-gate static int r8169_probe(struct dev *dev, struct pci_device *pci)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	struct nic *nic = (struct nic *) dev;
7157c478bd9Sstevel@tonic-gate 	static int board_idx = -1;
7167c478bd9Sstevel@tonic-gate 	static int printed_version = 0;
7177c478bd9Sstevel@tonic-gate 	int i, rc;
7187c478bd9Sstevel@tonic-gate 	int option = -1, Cap10_100 = 0, Cap1000 = 0;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	printf("r8169.c: Found %s, Vendor=%hX Device=%hX\n",
7217c478bd9Sstevel@tonic-gate 	       pci->name, pci->vendor, pci->dev_id);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	board_idx++;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	printed_version = 1;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	/* point to private storage */
7287c478bd9Sstevel@tonic-gate 	tpc = &tpx;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	rc = rtl8169_init_board(pci);	/* Return code is meaningless */
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	/* Get MAC address.  FIXME: read EEPROM */
7337c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAC_ADDR_LEN; i++)
7347c478bd9Sstevel@tonic-gate 		nic->node_addr[i] = RTL_R8(MAC0 + i);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	dprintf(("%s: Identified chip type is '%s'.\n", pci->name,
7377c478bd9Sstevel@tonic-gate 		 rtl_chip_info[tpc->chipset].name));
7387c478bd9Sstevel@tonic-gate 	/* Print out some hardware info */
7397c478bd9Sstevel@tonic-gate 	printf("%s: %! at ioaddr %hX, ", pci->name, nic->node_addr,
7407c478bd9Sstevel@tonic-gate 	       ioaddr);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	/* if TBI is not endbled */
7437c478bd9Sstevel@tonic-gate 	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
7447c478bd9Sstevel@tonic-gate 		int val = mdio_read(PHY_AUTO_NEGO_REG);
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 		option = media;
7477c478bd9Sstevel@tonic-gate 		/* Force RTL8169 in 10/100/1000 Full/Half mode. */
7487c478bd9Sstevel@tonic-gate 		if (option > 0) {
7497c478bd9Sstevel@tonic-gate 			printf(" Force-mode Enabled.\n");
7507c478bd9Sstevel@tonic-gate 			Cap10_100 = 0, Cap1000 = 0;
7517c478bd9Sstevel@tonic-gate 			switch (option) {
7527c478bd9Sstevel@tonic-gate 			case _10_Half:
7537c478bd9Sstevel@tonic-gate 				Cap10_100 = PHY_Cap_10_Half;
7547c478bd9Sstevel@tonic-gate 				Cap1000 = PHY_Cap_Null;
7557c478bd9Sstevel@tonic-gate 				break;
7567c478bd9Sstevel@tonic-gate 			case _10_Full:
7577c478bd9Sstevel@tonic-gate 				Cap10_100 = PHY_Cap_10_Full;
7587c478bd9Sstevel@tonic-gate 				Cap1000 = PHY_Cap_Null;
7597c478bd9Sstevel@tonic-gate 				break;
7607c478bd9Sstevel@tonic-gate 			case _100_Half:
7617c478bd9Sstevel@tonic-gate 				Cap10_100 = PHY_Cap_100_Half;
7627c478bd9Sstevel@tonic-gate 				Cap1000 = PHY_Cap_Null;
7637c478bd9Sstevel@tonic-gate 				break;
7647c478bd9Sstevel@tonic-gate 			case _100_Full:
7657c478bd9Sstevel@tonic-gate 				Cap10_100 = PHY_Cap_100_Full;
7667c478bd9Sstevel@tonic-gate 				Cap1000 = PHY_Cap_Null;
7677c478bd9Sstevel@tonic-gate 				break;
7687c478bd9Sstevel@tonic-gate 			case _1000_Full:
7697c478bd9Sstevel@tonic-gate 				Cap10_100 = PHY_Cap_Null;
7707c478bd9Sstevel@tonic-gate 				Cap1000 = PHY_Cap_1000_Full;
7717c478bd9Sstevel@tonic-gate 				break;
7727c478bd9Sstevel@tonic-gate 			default:
7737c478bd9Sstevel@tonic-gate 				break;
7747c478bd9Sstevel@tonic-gate 			}
7757c478bd9Sstevel@tonic-gate 			/* leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
7767c478bd9Sstevel@tonic-gate 			mdio_write(PHY_AUTO_NEGO_REG,
7777c478bd9Sstevel@tonic-gate 				   Cap10_100 | (val & 0x1F));
7787c478bd9Sstevel@tonic-gate 			mdio_write(PHY_1000_CTRL_REG, Cap1000);
7797c478bd9Sstevel@tonic-gate 		} else {
7807c478bd9Sstevel@tonic-gate 			dprintf(("Auto-negotiation Enabled.\n",
7817c478bd9Sstevel@tonic-gate 				 pci->name));
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 			/* enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged */
7847c478bd9Sstevel@tonic-gate 			mdio_write(PHY_AUTO_NEGO_REG,
7857c478bd9Sstevel@tonic-gate 				   PHY_Cap_10_Half | PHY_Cap_10_Full |
7867c478bd9Sstevel@tonic-gate 				   PHY_Cap_100_Half | PHY_Cap_100_Full |
7877c478bd9Sstevel@tonic-gate 				   (val & 0x1F));
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 			/* enable 1000 Full Mode */
7907c478bd9Sstevel@tonic-gate 			mdio_write(PHY_1000_CTRL_REG, PHY_Cap_1000_Full);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		/* Enable auto-negotiation and restart auto-nigotiation */
7957c478bd9Sstevel@tonic-gate 		mdio_write(PHY_CTRL_REG,
7967c478bd9Sstevel@tonic-gate 			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
7977c478bd9Sstevel@tonic-gate 		udelay(100);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		/* wait for auto-negotiation process */
8007c478bd9Sstevel@tonic-gate 		for (i = 10000; i > 0; i--) {
8017c478bd9Sstevel@tonic-gate 			/* Check if auto-negotiation complete */
8027c478bd9Sstevel@tonic-gate 			if (mdio_read(PHY_STAT_REG) & PHY_Auto_Neco_Comp) {
8037c478bd9Sstevel@tonic-gate 				udelay(100);
8047c478bd9Sstevel@tonic-gate 				option = RTL_R8(PHYstatus);
8057c478bd9Sstevel@tonic-gate 				if (option & _1000bpsF) {
8067c478bd9Sstevel@tonic-gate 					printf
8077c478bd9Sstevel@tonic-gate 					    ("1000Mbps Full-duplex operation.\n");
8087c478bd9Sstevel@tonic-gate 				} else {
8097c478bd9Sstevel@tonic-gate 					printf
8107c478bd9Sstevel@tonic-gate 					    ("%sMbps %s-duplex operation.\n",
8117c478bd9Sstevel@tonic-gate 					     (option & _100bps) ? "100" :
8127c478bd9Sstevel@tonic-gate 					     "10",
8137c478bd9Sstevel@tonic-gate 					     (option & FullDup) ? "Full" :
8147c478bd9Sstevel@tonic-gate 					     "Half");
8157c478bd9Sstevel@tonic-gate 				}
8167c478bd9Sstevel@tonic-gate 				break;
8177c478bd9Sstevel@tonic-gate 			} else {
8187c478bd9Sstevel@tonic-gate 				udelay(100);
8197c478bd9Sstevel@tonic-gate 			}
8207c478bd9Sstevel@tonic-gate 		}		/* end for-loop to wait for auto-negotiation process */
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	} else {
8237c478bd9Sstevel@tonic-gate 		udelay(100);
8247c478bd9Sstevel@tonic-gate 		printf
8257c478bd9Sstevel@tonic-gate 		    ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
8267c478bd9Sstevel@tonic-gate 		     pci->name,
8277c478bd9Sstevel@tonic-gate 		     (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	r8169_reset(nic);
8327c478bd9Sstevel@tonic-gate 	/* point to NIC specific routines */
8337c478bd9Sstevel@tonic-gate 	dev->disable = r8169_disable;
8347c478bd9Sstevel@tonic-gate 	nic->poll = r8169_poll;
8357c478bd9Sstevel@tonic-gate 	nic->transmit = r8169_transmit;
8367c478bd9Sstevel@tonic-gate 	nic->irqno = pci->irq;
8377c478bd9Sstevel@tonic-gate 	nic->irq = r8169_irq;
8387c478bd9Sstevel@tonic-gate 	nic->ioaddr = ioaddr;
8397c478bd9Sstevel@tonic-gate 	return 1;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate static struct pci_id r8169_nics[] = {
8447c478bd9Sstevel@tonic-gate 	PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"),
8457c478bd9Sstevel@tonic-gate };
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate struct pci_driver r8169_driver = {
8487c478bd9Sstevel@tonic-gate 	.type = NIC_DRIVER,
8497c478bd9Sstevel@tonic-gate 	.name = "r8169/PCI",
8507c478bd9Sstevel@tonic-gate 	.probe = r8169_probe,
8517c478bd9Sstevel@tonic-gate 	.ids = r8169_nics,
8527c478bd9Sstevel@tonic-gate 	.id_count = sizeof(r8169_nics) / sizeof(r8169_nics[0]),
8537c478bd9Sstevel@tonic-gate 	.class = 0,
8547c478bd9Sstevel@tonic-gate };
855