xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/tlan.c (revision 8044:b3af80bbf173)
1*8044SWilliam.Kucharski@Sun.COM #define EB51
2*8044SWilliam.Kucharski@Sun.COM 
3*8044SWilliam.Kucharski@Sun.COM #ifdef EB50
4*8044SWilliam.Kucharski@Sun.COM #define __unused __attribute__((unused))
5*8044SWilliam.Kucharski@Sun.COM #endif
6*8044SWilliam.Kucharski@Sun.COM 
7*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
8*8044SWilliam.Kucharski@Sun.COM *
9*8044SWilliam.Kucharski@Sun.COM *    tlan.c -- Etherboot device driver for the Texas Instruments ThunderLAN
10*8044SWilliam.Kucharski@Sun.COM *    Written 2003-2003 by Timothy Legge <tlegge@rogers.com>
11*8044SWilliam.Kucharski@Sun.COM *
12*8044SWilliam.Kucharski@Sun.COM *    This program is free software; you can redistribute it and/or modify
13*8044SWilliam.Kucharski@Sun.COM *    it under the terms of the GNU General Public License as published by
14*8044SWilliam.Kucharski@Sun.COM *    the Free Software Foundation; either version 2 of the License, or
15*8044SWilliam.Kucharski@Sun.COM *    (at your option) any later version.
16*8044SWilliam.Kucharski@Sun.COM *
17*8044SWilliam.Kucharski@Sun.COM *    This program is distributed in the hope that it will be useful,
18*8044SWilliam.Kucharski@Sun.COM *    but WITHOUT ANY WARRANTY; without even the implied warranty of
19*8044SWilliam.Kucharski@Sun.COM *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20*8044SWilliam.Kucharski@Sun.COM *    GNU General Public License for more details.
21*8044SWilliam.Kucharski@Sun.COM *
22*8044SWilliam.Kucharski@Sun.COM *    You should have received a copy of the GNU General Public License
23*8044SWilliam.Kucharski@Sun.COM *    along with this program; if not, write to the Free Software
24*8044SWilliam.Kucharski@Sun.COM *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*8044SWilliam.Kucharski@Sun.COM *
26*8044SWilliam.Kucharski@Sun.COM *    Portions of this code based on:
27*8044SWilliam.Kucharski@Sun.COM *	lan.c: Linux ThunderLan Driver:
28*8044SWilliam.Kucharski@Sun.COM *
29*8044SWilliam.Kucharski@Sun.COM *	by James Banks
30*8044SWilliam.Kucharski@Sun.COM *
31*8044SWilliam.Kucharski@Sun.COM *  	(C) 1997-1998 Caldera, Inc.
32*8044SWilliam.Kucharski@Sun.COM *	(C) 1998 James Banks
33*8044SWilliam.Kucharski@Sun.COM *	(C) 1999-2001 Torben Mathiasen
34*8044SWilliam.Kucharski@Sun.COM *	(C) 2002 Samuel Chessman
35*8044SWilliam.Kucharski@Sun.COM *
36*8044SWilliam.Kucharski@Sun.COM *    REVISION HISTORY:
37*8044SWilliam.Kucharski@Sun.COM *    ================
38*8044SWilliam.Kucharski@Sun.COM *    v1.0	07-08-2003	timlegge	Initial not quite working version
39*8044SWilliam.Kucharski@Sun.COM *    v1.1	07-27-2003	timlegge	Sync 5.0 and 5.1 versions
40*8044SWilliam.Kucharski@Sun.COM *    v1.2	08-19-2003	timlegge	Implement Multicast Support
41*8044SWilliam.Kucharski@Sun.COM *    v1.3	08-23-2003	timlegge	Fix the transmit Function
42*8044SWilliam.Kucharski@Sun.COM *    v1.4	01-17-2004	timlegge	Initial driver output cleanup
43*8044SWilliam.Kucharski@Sun.COM *
44*8044SWilliam.Kucharski@Sun.COM *    Indent Options: indent -kr -i8
45*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
46*8044SWilliam.Kucharski@Sun.COM 
47*8044SWilliam.Kucharski@Sun.COM /* to get some global routines like printf */
48*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
49*8044SWilliam.Kucharski@Sun.COM /* to get the interface to the body of the program */
50*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
51*8044SWilliam.Kucharski@Sun.COM /* to get the PCI support functions, if this is a PCI NIC */
52*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
53*8044SWilliam.Kucharski@Sun.COM #include "timer.h"
54*8044SWilliam.Kucharski@Sun.COM #include "tlan.h"
55*8044SWilliam.Kucharski@Sun.COM 
56*8044SWilliam.Kucharski@Sun.COM #define drv_version "v1.4"
57*8044SWilliam.Kucharski@Sun.COM #define drv_date "01-17-2004"
58*8044SWilliam.Kucharski@Sun.COM 
59*8044SWilliam.Kucharski@Sun.COM /* NIC specific static variables go here */
60*8044SWilliam.Kucharski@Sun.COM #define HZ 100
61*8044SWilliam.Kucharski@Sun.COM #define TX_TIME_OUT	  (6*HZ)
62*8044SWilliam.Kucharski@Sun.COM 
63*8044SWilliam.Kucharski@Sun.COM #ifdef EB50
64*8044SWilliam.Kucharski@Sun.COM #define	cpu_to_le32(val) (val)
65*8044SWilliam.Kucharski@Sun.COM #define	le32_to_cpu(val) (val)
66*8044SWilliam.Kucharski@Sun.COM #define	virt_to_bus(x) ((unsigned long) x)
67*8044SWilliam.Kucharski@Sun.COM #define	bus_to_virt(x) ((unsigned long) x)
68*8044SWilliam.Kucharski@Sun.COM #endif
69*8044SWilliam.Kucharski@Sun.COM 
70*8044SWilliam.Kucharski@Sun.COM /* Condensed operations for readability. */
71*8044SWilliam.Kucharski@Sun.COM #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
72*8044SWilliam.Kucharski@Sun.COM #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
73*8044SWilliam.Kucharski@Sun.COM 
74*8044SWilliam.Kucharski@Sun.COM 
75*8044SWilliam.Kucharski@Sun.COM static void TLan_ResetLists(struct nic *nic __unused);
76*8044SWilliam.Kucharski@Sun.COM static void TLan_ResetAdapter(struct nic *nic __unused);
77*8044SWilliam.Kucharski@Sun.COM static void TLan_FinishReset(struct nic *nic __unused);
78*8044SWilliam.Kucharski@Sun.COM 
79*8044SWilliam.Kucharski@Sun.COM static void TLan_EeSendStart(u16);
80*8044SWilliam.Kucharski@Sun.COM static int TLan_EeSendByte(u16, u8, int);
81*8044SWilliam.Kucharski@Sun.COM static void TLan_EeReceiveByte(u16, u8 *, int);
82*8044SWilliam.Kucharski@Sun.COM static int TLan_EeReadByte(u16 io_base, u8, u8 *);
83*8044SWilliam.Kucharski@Sun.COM 
84*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyDetect(struct nic *nic);
85*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyPowerDown(struct nic *nic);
86*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyPowerUp(struct nic *nic);
87*8044SWilliam.Kucharski@Sun.COM 
88*8044SWilliam.Kucharski@Sun.COM 
89*8044SWilliam.Kucharski@Sun.COM static void TLan_SetMac(struct nic *nic __unused, int areg, char *mac);
90*8044SWilliam.Kucharski@Sun.COM 
91*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyReset(struct nic *nic);
92*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyStartLink(struct nic *nic);
93*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyFinishAutoNeg(struct nic *nic);
94*8044SWilliam.Kucharski@Sun.COM 
95*8044SWilliam.Kucharski@Sun.COM #ifdef MONITOR
96*8044SWilliam.Kucharski@Sun.COM static void TLan_PhyMonitor(struct nic *nic);
97*8044SWilliam.Kucharski@Sun.COM #endif
98*8044SWilliam.Kucharski@Sun.COM 
99*8044SWilliam.Kucharski@Sun.COM 
100*8044SWilliam.Kucharski@Sun.COM static void refill_rx(struct nic *nic __unused);
101*8044SWilliam.Kucharski@Sun.COM 
102*8044SWilliam.Kucharski@Sun.COM static int TLan_MiiReadReg(struct nic *nic __unused, u16, u16, u16 *);
103*8044SWilliam.Kucharski@Sun.COM static void TLan_MiiSendData(u16, u32, unsigned);
104*8044SWilliam.Kucharski@Sun.COM static void TLan_MiiSync(u16);
105*8044SWilliam.Kucharski@Sun.COM static void TLan_MiiWriteReg(struct nic *nic __unused, u16, u16, u16);
106*8044SWilliam.Kucharski@Sun.COM 
107*8044SWilliam.Kucharski@Sun.COM 
108*8044SWilliam.Kucharski@Sun.COM const char *media[] = {
109*8044SWilliam.Kucharski@Sun.COM 	"10BaseT-HD ", "10BaseT-FD ", "100baseTx-HD ",
110*8044SWilliam.Kucharski@Sun.COM 	"100baseTx-FD", "100baseT4", 0
111*8044SWilliam.Kucharski@Sun.COM };
112*8044SWilliam.Kucharski@Sun.COM 
113*8044SWilliam.Kucharski@Sun.COM /* This much match tlan_pci_tbl[]!  */
114*8044SWilliam.Kucharski@Sun.COM enum tlan_nics {
115*8044SWilliam.Kucharski@Sun.COM 	NETEL10 = 0, NETEL100 = 1, NETFLEX3I = 2, THUNDER = 3, NETFLEX3B =
116*8044SWilliam.Kucharski@Sun.COM 	    4, NETEL100PI = 5,
117*8044SWilliam.Kucharski@Sun.COM 	NETEL100D = 6, NETEL100I = 7, OC2183 = 8, OC2325 = 9, OC2326 =
118*8044SWilliam.Kucharski@Sun.COM 	    10, NETELLIGENT_10_100_WS_5100 = 11,
119*8044SWilliam.Kucharski@Sun.COM 	NETELLIGENT_10_T2 = 12
120*8044SWilliam.Kucharski@Sun.COM };
121*8044SWilliam.Kucharski@Sun.COM 
122*8044SWilliam.Kucharski@Sun.COM struct pci_id_info {
123*8044SWilliam.Kucharski@Sun.COM 	const char *name;
124*8044SWilliam.Kucharski@Sun.COM 	int nic_id;
125*8044SWilliam.Kucharski@Sun.COM 	struct match_info {
126*8044SWilliam.Kucharski@Sun.COM 		u32 pci, pci_mask, subsystem, subsystem_mask;
127*8044SWilliam.Kucharski@Sun.COM 		u32 revision, revision_mask;	/* Only 8 bits. */
128*8044SWilliam.Kucharski@Sun.COM 	} id;
129*8044SWilliam.Kucharski@Sun.COM 	u32 flags;
130*8044SWilliam.Kucharski@Sun.COM 	u16 addrOfs;		/* Address Offset */
131*8044SWilliam.Kucharski@Sun.COM };
132*8044SWilliam.Kucharski@Sun.COM 
133*8044SWilliam.Kucharski@Sun.COM static struct pci_id_info tlan_pci_tbl[] = {
134*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent 10 T PCI UTP", NETEL10,
135*8044SWilliam.Kucharski@Sun.COM 	 {0xae340e11, 0xffffffff, 0, 0, 0, 0},
136*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
137*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent 10/100 TX PCI UTP", NETEL100,
138*8044SWilliam.Kucharski@Sun.COM 	 {0xae320e11, 0xffffffff, 0, 0, 0, 0},
139*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
140*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Integrated NetFlex-3/P", NETFLEX3I,
141*8044SWilliam.Kucharski@Sun.COM 	 {0xae350e11, 0xffffffff, 0, 0, 0, 0},
142*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_NONE, 0x83},
143*8044SWilliam.Kucharski@Sun.COM 	{"Compaq NetFlex-3/P", THUNDER,
144*8044SWilliam.Kucharski@Sun.COM 	 {0xf1300e11, 0xffffffff, 0, 0, 0, 0},
145*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
146*8044SWilliam.Kucharski@Sun.COM 	{"Compaq NetFlex-3/P", NETFLEX3B,
147*8044SWilliam.Kucharski@Sun.COM 	 {0xf1500e11, 0xffffffff, 0, 0, 0, 0},
148*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_NONE, 0x83},
149*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent Integrated 10/100 TX UTP", NETEL100PI,
150*8044SWilliam.Kucharski@Sun.COM 	 {0xae430e11, 0xffffffff, 0, 0, 0, 0},
151*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
152*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent Dual 10/100 TX PCI UTP", NETEL100D,
153*8044SWilliam.Kucharski@Sun.COM 	 {0xae400e11, 0xffffffff, 0, 0, 0, 0},
154*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_NONE, 0x83},
155*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent 10/100 TX Embedded UTP", NETEL100I,
156*8044SWilliam.Kucharski@Sun.COM 	 {0xb0110e11, 0xffffffff, 0, 0, 0, 0},
157*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_NONE, 0x83},
158*8044SWilliam.Kucharski@Sun.COM 	{"Olicom OC-2183/2185", OC2183,
159*8044SWilliam.Kucharski@Sun.COM 	 {0x0013108d, 0xffffffff, 0, 0, 0, 0},
160*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_USE_INTERN_10, 0x83},
161*8044SWilliam.Kucharski@Sun.COM 	{"Olicom OC-2325", OC2325,
162*8044SWilliam.Kucharski@Sun.COM 	 {0x0012108d, 0xffffffff, 0, 0, 0, 0},
163*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_UNMANAGED_PHY, 0xF8},
164*8044SWilliam.Kucharski@Sun.COM 	{"Olicom OC-2326", OC2326,
165*8044SWilliam.Kucharski@Sun.COM 	 {0x0014108d, 0xffffffff, 0, 0, 0, 0},
166*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_USE_INTERN_10, 0xF8},
167*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent 10/100 TX UTP", NETELLIGENT_10_100_WS_5100,
168*8044SWilliam.Kucharski@Sun.COM 	 {0xb0300e11, 0xffffffff, 0, 0, 0, 0},
169*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
170*8044SWilliam.Kucharski@Sun.COM 	{"Compaq Netelligent 10 T/2 PCI UTP/Coax", NETELLIGENT_10_T2,
171*8044SWilliam.Kucharski@Sun.COM 	 {0xb0120e11, 0xffffffff, 0, 0, 0, 0},
172*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_NONE, 0x83},
173*8044SWilliam.Kucharski@Sun.COM 	{"Compaq NetFlex-3/E", 0,	/* EISA card */
174*8044SWilliam.Kucharski@Sun.COM 	 {0, 0, 0, 0, 0, 0},
175*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED | TLAN_ADAPTER_UNMANAGED_PHY |
176*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_BIT_RATE_PHY, 0x83},
177*8044SWilliam.Kucharski@Sun.COM 	{"Compaq NetFlex-3/E", 0,	/* EISA card */
178*8044SWilliam.Kucharski@Sun.COM 	 {0, 0, 0, 0, 0, 0},
179*8044SWilliam.Kucharski@Sun.COM 	 TLAN_ADAPTER_ACTIVITY_LED, 0x83},
180*8044SWilliam.Kucharski@Sun.COM 	{0, 0,
181*8044SWilliam.Kucharski@Sun.COM 	 {0, 0, 0, 0, 0, 0},
182*8044SWilliam.Kucharski@Sun.COM 	 0, 0},
183*8044SWilliam.Kucharski@Sun.COM };
184*8044SWilliam.Kucharski@Sun.COM 
185*8044SWilliam.Kucharski@Sun.COM 
186*8044SWilliam.Kucharski@Sun.COM struct TLanList {
187*8044SWilliam.Kucharski@Sun.COM 	u32 forward;
188*8044SWilliam.Kucharski@Sun.COM 	u16 cStat;
189*8044SWilliam.Kucharski@Sun.COM 	u16 frameSize;
190*8044SWilliam.Kucharski@Sun.COM 	struct {
191*8044SWilliam.Kucharski@Sun.COM 		u32 count;
192*8044SWilliam.Kucharski@Sun.COM 		u32 address;
193*8044SWilliam.Kucharski@Sun.COM 	} buffer[TLAN_BUFFERS_PER_LIST];
194*8044SWilliam.Kucharski@Sun.COM };
195*8044SWilliam.Kucharski@Sun.COM 
196*8044SWilliam.Kucharski@Sun.COM 
197*8044SWilliam.Kucharski@Sun.COM 
198*8044SWilliam.Kucharski@Sun.COM struct TLanList tx_ring[TLAN_NUM_TX_LISTS];
199*8044SWilliam.Kucharski@Sun.COM static unsigned char txb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_TX_LISTS];
200*8044SWilliam.Kucharski@Sun.COM 
201*8044SWilliam.Kucharski@Sun.COM struct TLanList rx_ring[TLAN_NUM_RX_LISTS];
202*8044SWilliam.Kucharski@Sun.COM static unsigned char rxb[TLAN_MAX_FRAME_SIZE * TLAN_NUM_RX_LISTS];
203*8044SWilliam.Kucharski@Sun.COM 
204*8044SWilliam.Kucharski@Sun.COM typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
205*8044SWilliam.Kucharski@Sun.COM 
206*8044SWilliam.Kucharski@Sun.COM 
207*8044SWilliam.Kucharski@Sun.COM int chip_idx;
208*8044SWilliam.Kucharski@Sun.COM 
209*8044SWilliam.Kucharski@Sun.COM 
210*8044SWilliam.Kucharski@Sun.COM /*****************************************************************
211*8044SWilliam.Kucharski@Sun.COM * TLAN Private Information Structure
212*8044SWilliam.Kucharski@Sun.COM *
213*8044SWilliam.Kucharski@Sun.COM ****************************************************************/
214*8044SWilliam.Kucharski@Sun.COM struct tlan_private {
215*8044SWilliam.Kucharski@Sun.COM 	unsigned short vendor_id;	/* PCI Vendor code */
216*8044SWilliam.Kucharski@Sun.COM 	unsigned short dev_id;	/* PCI Device code */
217*8044SWilliam.Kucharski@Sun.COM 	const char *nic_name;
218*8044SWilliam.Kucharski@Sun.COM 	u8 *padBuffer;
219*8044SWilliam.Kucharski@Sun.COM 	u8 *rxBuffer;
220*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *rx_head_desc;
221*8044SWilliam.Kucharski@Sun.COM 	u32 rxHead;
222*8044SWilliam.Kucharski@Sun.COM 	u32 rxTail;
223*8044SWilliam.Kucharski@Sun.COM 	u32 rxEocCount;
224*8044SWilliam.Kucharski@Sun.COM 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indicies */
225*8044SWilliam.Kucharski@Sun.COM 	unsigned int cur_tx, dirty_tx;
226*8044SWilliam.Kucharski@Sun.COM 	unsigned rx_buf_sz;	/* Based on mtu + Slack */
227*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *txList;
228*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *rxList;
229*8044SWilliam.Kucharski@Sun.COM 	u8 *txBuffer;
230*8044SWilliam.Kucharski@Sun.COM 	u32 txHead;
231*8044SWilliam.Kucharski@Sun.COM 	u32 txInProgress;
232*8044SWilliam.Kucharski@Sun.COM 	u32 txTail;
233*8044SWilliam.Kucharski@Sun.COM 	int eoc;
234*8044SWilliam.Kucharski@Sun.COM 	u32 txBusyCount;
235*8044SWilliam.Kucharski@Sun.COM 	u32 phyOnline;
236*8044SWilliam.Kucharski@Sun.COM 	u32 timerSetAt;
237*8044SWilliam.Kucharski@Sun.COM 	u32 timerType;
238*8044SWilliam.Kucharski@Sun.COM 	u32 adapterRev;
239*8044SWilliam.Kucharski@Sun.COM 	u32 aui;
240*8044SWilliam.Kucharski@Sun.COM 	u32 debug;
241*8044SWilliam.Kucharski@Sun.COM 	u32 duplex;
242*8044SWilliam.Kucharski@Sun.COM 	u32 phy[2];
243*8044SWilliam.Kucharski@Sun.COM 	u32 phyNum;
244*8044SWilliam.Kucharski@Sun.COM 	u32 speed;
245*8044SWilliam.Kucharski@Sun.COM 	u8 tlanRev;
246*8044SWilliam.Kucharski@Sun.COM 	u8 tlanFullDuplex;
247*8044SWilliam.Kucharski@Sun.COM 	char devName[8];
248*8044SWilliam.Kucharski@Sun.COM 	u8 link;
249*8044SWilliam.Kucharski@Sun.COM 	u8 is_eisa;
250*8044SWilliam.Kucharski@Sun.COM 	u8 neg_be_verbose;
251*8044SWilliam.Kucharski@Sun.COM } TLanPrivateInfo;
252*8044SWilliam.Kucharski@Sun.COM 
253*8044SWilliam.Kucharski@Sun.COM static struct tlan_private *priv;
254*8044SWilliam.Kucharski@Sun.COM 
255*8044SWilliam.Kucharski@Sun.COM u32 BASE;
256*8044SWilliam.Kucharski@Sun.COM 
257*8044SWilliam.Kucharski@Sun.COM 
258*8044SWilliam.Kucharski@Sun.COM 
259*8044SWilliam.Kucharski@Sun.COM /***************************************************************
260*8044SWilliam.Kucharski@Sun.COM *	TLan_ResetLists
261*8044SWilliam.Kucharski@Sun.COM *
262*8044SWilliam.Kucharski@Sun.COM *	Returns:
263*8044SWilliam.Kucharski@Sun.COM *		Nothing
264*8044SWilliam.Kucharski@Sun.COM *	Parms:
265*8044SWilliam.Kucharski@Sun.COM *		dev	The device structure with the list
266*8044SWilliam.Kucharski@Sun.COM *			stuctures to be reset.
267*8044SWilliam.Kucharski@Sun.COM *
268*8044SWilliam.Kucharski@Sun.COM *	This routine sets the variables associated with managing
269*8044SWilliam.Kucharski@Sun.COM *	the TLAN lists to their initial values.
270*8044SWilliam.Kucharski@Sun.COM *
271*8044SWilliam.Kucharski@Sun.COM **************************************************************/
272*8044SWilliam.Kucharski@Sun.COM 
TLan_ResetLists(struct nic * nic __unused)273*8044SWilliam.Kucharski@Sun.COM void TLan_ResetLists(struct nic *nic __unused)
274*8044SWilliam.Kucharski@Sun.COM {
275*8044SWilliam.Kucharski@Sun.COM 
276*8044SWilliam.Kucharski@Sun.COM 	int i;
277*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *list;
278*8044SWilliam.Kucharski@Sun.COM 	priv->txHead = 0;
279*8044SWilliam.Kucharski@Sun.COM 	priv->txTail = 0;
280*8044SWilliam.Kucharski@Sun.COM 
281*8044SWilliam.Kucharski@Sun.COM 	for (i = 0; i < TLAN_NUM_TX_LISTS; i++) {
282*8044SWilliam.Kucharski@Sun.COM 		list = &tx_ring[i];
283*8044SWilliam.Kucharski@Sun.COM 		list->cStat = TLAN_CSTAT_UNUSED;
284*8044SWilliam.Kucharski@Sun.COM /*		list->buffer[0].address = 0; */
285*8044SWilliam.Kucharski@Sun.COM 		list->buffer[0].address = virt_to_bus(txb +
286*8044SWilliam.Kucharski@Sun.COM 				(i * TLAN_MAX_FRAME_SIZE));
287*8044SWilliam.Kucharski@Sun.COM 		list->buffer[2].count = 0;
288*8044SWilliam.Kucharski@Sun.COM 		list->buffer[2].address = 0;
289*8044SWilliam.Kucharski@Sun.COM 		list->buffer[9].address = 0;
290*8044SWilliam.Kucharski@Sun.COM /*		list->forward = 0; */
291*8044SWilliam.Kucharski@Sun.COM 	}
292*8044SWilliam.Kucharski@Sun.COM 
293*8044SWilliam.Kucharski@Sun.COM 	priv->cur_rx = 0;
294*8044SWilliam.Kucharski@Sun.COM 	priv->rx_buf_sz = (TLAN_MAX_FRAME_SIZE);
295*8044SWilliam.Kucharski@Sun.COM 	priv->rx_head_desc = &rx_ring[0];
296*8044SWilliam.Kucharski@Sun.COM 
297*8044SWilliam.Kucharski@Sun.COM 	/* Initialize all the Rx descriptors */
298*8044SWilliam.Kucharski@Sun.COM 	for (i = 0; i < TLAN_NUM_RX_LISTS; i++) {
299*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].forward = virt_to_le32desc(&rx_ring[i + 1]);
300*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].cStat = TLAN_CSTAT_READY;
301*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].frameSize = TLAN_MAX_FRAME_SIZE;
302*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].buffer[0].count =
303*8044SWilliam.Kucharski@Sun.COM 		    TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
304*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].buffer[0].address =
305*8044SWilliam.Kucharski@Sun.COM 		    virt_to_le32desc(&rxb[i * TLAN_MAX_FRAME_SIZE]);
306*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].buffer[1].count = 0;
307*8044SWilliam.Kucharski@Sun.COM 		rx_ring[i].buffer[1].address = 0;
308*8044SWilliam.Kucharski@Sun.COM 	}
309*8044SWilliam.Kucharski@Sun.COM 
310*8044SWilliam.Kucharski@Sun.COM 	/* Mark the last entry as wrapping the ring */
311*8044SWilliam.Kucharski@Sun.COM 	rx_ring[i - 1].forward = virt_to_le32desc(&rx_ring[0]);
312*8044SWilliam.Kucharski@Sun.COM 	priv->dirty_rx = (unsigned int) (i - TLAN_NUM_RX_LISTS);
313*8044SWilliam.Kucharski@Sun.COM 
314*8044SWilliam.Kucharski@Sun.COM } /* TLan_ResetLists */
315*8044SWilliam.Kucharski@Sun.COM 
316*8044SWilliam.Kucharski@Sun.COM /***************************************************************
317*8044SWilliam.Kucharski@Sun.COM *	TLan_Reset
318*8044SWilliam.Kucharski@Sun.COM *
319*8044SWilliam.Kucharski@Sun.COM *	Returns:
320*8044SWilliam.Kucharski@Sun.COM *		0
321*8044SWilliam.Kucharski@Sun.COM *	Parms:
322*8044SWilliam.Kucharski@Sun.COM *		dev	Pointer to device structure of adapter
323*8044SWilliam.Kucharski@Sun.COM *			to be reset.
324*8044SWilliam.Kucharski@Sun.COM *
325*8044SWilliam.Kucharski@Sun.COM *	This function resets the adapter and it's physical
326*8044SWilliam.Kucharski@Sun.COM *	device.  See Chap. 3, pp. 9-10 of the "ThunderLAN
327*8044SWilliam.Kucharski@Sun.COM *	Programmer's Guide" for details.  The routine tries to
328*8044SWilliam.Kucharski@Sun.COM *	implement what is detailed there, though adjustments
329*8044SWilliam.Kucharski@Sun.COM *	have been made.
330*8044SWilliam.Kucharski@Sun.COM *
331*8044SWilliam.Kucharski@Sun.COM **************************************************************/
332*8044SWilliam.Kucharski@Sun.COM 
TLan_ResetAdapter(struct nic * nic __unused)333*8044SWilliam.Kucharski@Sun.COM void TLan_ResetAdapter(struct nic *nic __unused)
334*8044SWilliam.Kucharski@Sun.COM {
335*8044SWilliam.Kucharski@Sun.COM 	int i;
336*8044SWilliam.Kucharski@Sun.COM 	u32 addr;
337*8044SWilliam.Kucharski@Sun.COM 	u32 data;
338*8044SWilliam.Kucharski@Sun.COM 	u8 data8;
339*8044SWilliam.Kucharski@Sun.COM 
340*8044SWilliam.Kucharski@Sun.COM 	priv->tlanFullDuplex = FALSE;
341*8044SWilliam.Kucharski@Sun.COM 	priv->phyOnline = 0;
342*8044SWilliam.Kucharski@Sun.COM /*  1.	Assert reset bit. */
343*8044SWilliam.Kucharski@Sun.COM 
344*8044SWilliam.Kucharski@Sun.COM 	data = inl(BASE + TLAN_HOST_CMD);
345*8044SWilliam.Kucharski@Sun.COM 	data |= TLAN_HC_AD_RST;
346*8044SWilliam.Kucharski@Sun.COM 	outl(data, BASE + TLAN_HOST_CMD);
347*8044SWilliam.Kucharski@Sun.COM 
348*8044SWilliam.Kucharski@Sun.COM 	udelay(1000);
349*8044SWilliam.Kucharski@Sun.COM 
350*8044SWilliam.Kucharski@Sun.COM /*  2.	Turn off interrupts. ( Probably isn't necessary ) */
351*8044SWilliam.Kucharski@Sun.COM 
352*8044SWilliam.Kucharski@Sun.COM 	data = inl(BASE + TLAN_HOST_CMD);
353*8044SWilliam.Kucharski@Sun.COM 	data |= TLAN_HC_INT_OFF;
354*8044SWilliam.Kucharski@Sun.COM 	outl(data, BASE + TLAN_HOST_CMD);
355*8044SWilliam.Kucharski@Sun.COM /*  3.	Clear AREGs and HASHs. */
356*8044SWilliam.Kucharski@Sun.COM 
357*8044SWilliam.Kucharski@Sun.COM 	for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) {
358*8044SWilliam.Kucharski@Sun.COM 		TLan_DioWrite32(BASE, (u16) i, 0);
359*8044SWilliam.Kucharski@Sun.COM 	}
360*8044SWilliam.Kucharski@Sun.COM 
361*8044SWilliam.Kucharski@Sun.COM /*  4.	Setup NetConfig register. */
362*8044SWilliam.Kucharski@Sun.COM 
363*8044SWilliam.Kucharski@Sun.COM 	data =
364*8044SWilliam.Kucharski@Sun.COM 	    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
365*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
366*8044SWilliam.Kucharski@Sun.COM 
367*8044SWilliam.Kucharski@Sun.COM /*  5.	Load Ld_Tmr and Ld_Thr in HOST_CMD. */
368*8044SWilliam.Kucharski@Sun.COM 
369*8044SWilliam.Kucharski@Sun.COM 	outl(TLAN_HC_LD_TMR | 0x3f, BASE + TLAN_HOST_CMD);
370*8044SWilliam.Kucharski@Sun.COM 	outl(TLAN_HC_LD_THR | 0x0, BASE + TLAN_HOST_CMD);
371*8044SWilliam.Kucharski@Sun.COM 
372*8044SWilliam.Kucharski@Sun.COM /*  6.	Unreset the MII by setting NMRST (in NetSio) to 1. */
373*8044SWilliam.Kucharski@Sun.COM 
374*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
375*8044SWilliam.Kucharski@Sun.COM 	addr = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
376*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_NMRST, addr);
377*8044SWilliam.Kucharski@Sun.COM 
378*8044SWilliam.Kucharski@Sun.COM /*  7.	Setup the remaining registers. */
379*8044SWilliam.Kucharski@Sun.COM 
380*8044SWilliam.Kucharski@Sun.COM 	if (priv->tlanRev >= 0x30) {
381*8044SWilliam.Kucharski@Sun.COM 		data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC;
382*8044SWilliam.Kucharski@Sun.COM 		TLan_DioWrite8(BASE, TLAN_INT_DIS, data8);
383*8044SWilliam.Kucharski@Sun.COM 	}
384*8044SWilliam.Kucharski@Sun.COM 	TLan_PhyDetect(nic);
385*8044SWilliam.Kucharski@Sun.COM 	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
386*8044SWilliam.Kucharski@Sun.COM 
387*8044SWilliam.Kucharski@Sun.COM 	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_BIT_RATE_PHY) {
388*8044SWilliam.Kucharski@Sun.COM 		data |= TLAN_NET_CFG_BIT;
389*8044SWilliam.Kucharski@Sun.COM 		if (priv->aui == 1) {
390*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x0a);
391*8044SWilliam.Kucharski@Sun.COM 		} else if (priv->duplex == TLAN_DUPLEX_FULL) {
392*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x00);
393*8044SWilliam.Kucharski@Sun.COM 			priv->tlanFullDuplex = TRUE;
394*8044SWilliam.Kucharski@Sun.COM 		} else {
395*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_ACOMMIT, 0x08);
396*8044SWilliam.Kucharski@Sun.COM 		}
397*8044SWilliam.Kucharski@Sun.COM 	}
398*8044SWilliam.Kucharski@Sun.COM 
399*8044SWilliam.Kucharski@Sun.COM 	if (priv->phyNum == 0) {
400*8044SWilliam.Kucharski@Sun.COM 		data |= TLAN_NET_CFG_PHY_EN;
401*8044SWilliam.Kucharski@Sun.COM 	}
402*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite16(BASE, TLAN_NET_CONFIG, (u16) data);
403*8044SWilliam.Kucharski@Sun.COM 
404*8044SWilliam.Kucharski@Sun.COM 	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
405*8044SWilliam.Kucharski@Sun.COM 		TLan_FinishReset(nic);
406*8044SWilliam.Kucharski@Sun.COM 	} else {
407*8044SWilliam.Kucharski@Sun.COM 		TLan_PhyPowerDown(nic);
408*8044SWilliam.Kucharski@Sun.COM 	}
409*8044SWilliam.Kucharski@Sun.COM 
410*8044SWilliam.Kucharski@Sun.COM }	/* TLan_ResetAdapter */
411*8044SWilliam.Kucharski@Sun.COM 
TLan_FinishReset(struct nic * nic)412*8044SWilliam.Kucharski@Sun.COM void TLan_FinishReset(struct nic *nic)
413*8044SWilliam.Kucharski@Sun.COM {
414*8044SWilliam.Kucharski@Sun.COM 
415*8044SWilliam.Kucharski@Sun.COM 	u8 data;
416*8044SWilliam.Kucharski@Sun.COM 	u32 phy;
417*8044SWilliam.Kucharski@Sun.COM 	u8 sio;
418*8044SWilliam.Kucharski@Sun.COM 	u16 status;
419*8044SWilliam.Kucharski@Sun.COM 	u16 partner;
420*8044SWilliam.Kucharski@Sun.COM 	u16 tlphy_ctl;
421*8044SWilliam.Kucharski@Sun.COM 	u16 tlphy_par;
422*8044SWilliam.Kucharski@Sun.COM 	u16 tlphy_id1, tlphy_id2;
423*8044SWilliam.Kucharski@Sun.COM 	int i;
424*8044SWilliam.Kucharski@Sun.COM 
425*8044SWilliam.Kucharski@Sun.COM 	phy = priv->phy[priv->phyNum];
426*8044SWilliam.Kucharski@Sun.COM 
427*8044SWilliam.Kucharski@Sun.COM 	data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP;
428*8044SWilliam.Kucharski@Sun.COM 	if (priv->tlanFullDuplex) {
429*8044SWilliam.Kucharski@Sun.COM 		data |= TLAN_NET_CMD_DUPLEX;
430*8044SWilliam.Kucharski@Sun.COM 	}
431*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite8(BASE, TLAN_NET_CMD, data);
432*8044SWilliam.Kucharski@Sun.COM 	data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
433*8044SWilliam.Kucharski@Sun.COM 	if (priv->phyNum == 0) {
434*8044SWilliam.Kucharski@Sun.COM 		data |= TLAN_NET_MASK_MASK7;
435*8044SWilliam.Kucharski@Sun.COM 	}
436*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite8(BASE, TLAN_NET_MASK, data);
437*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite16(BASE, TLAN_MAX_RX, ((1536) + 7) & ~7);
438*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_ID_HI, &tlphy_id1);
439*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_ID_LO, &tlphy_id2);
440*8044SWilliam.Kucharski@Sun.COM 
441*8044SWilliam.Kucharski@Sun.COM 	if ((tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY)
442*8044SWilliam.Kucharski@Sun.COM 	    || (priv->aui)) {
443*8044SWilliam.Kucharski@Sun.COM 		status = MII_GS_LINK;
444*8044SWilliam.Kucharski@Sun.COM 		printf("TLAN:  %s: Link forced.\n", priv->nic_name);
445*8044SWilliam.Kucharski@Sun.COM 	} else {
446*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
447*8044SWilliam.Kucharski@Sun.COM 		udelay(1000);
448*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
449*8044SWilliam.Kucharski@Sun.COM 		if ((status & MII_GS_LINK) &&	/* We only support link info on Nat.Sem. PHY's */
450*8044SWilliam.Kucharski@Sun.COM 		    (tlphy_id1 == NAT_SEM_ID1)
451*8044SWilliam.Kucharski@Sun.COM 		    && (tlphy_id2 == NAT_SEM_ID2)) {
452*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiReadReg(nic, phy, MII_AN_LPA, &partner);
453*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiReadReg(nic, phy, TLAN_TLPHY_PAR,
454*8044SWilliam.Kucharski@Sun.COM 					&tlphy_par);
455*8044SWilliam.Kucharski@Sun.COM 
456*8044SWilliam.Kucharski@Sun.COM 			printf("TLAN: %s: Link active with ",
457*8044SWilliam.Kucharski@Sun.COM 			       priv->nic_name);
458*8044SWilliam.Kucharski@Sun.COM 			if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
459*8044SWilliam.Kucharski@Sun.COM 				printf("forced 10%sMbps %s-Duplex\n",
460*8044SWilliam.Kucharski@Sun.COM 				       tlphy_par & TLAN_PHY_SPEED_100 ? ""
461*8044SWilliam.Kucharski@Sun.COM 				       : "0",
462*8044SWilliam.Kucharski@Sun.COM 				       tlphy_par & TLAN_PHY_DUPLEX_FULL ?
463*8044SWilliam.Kucharski@Sun.COM 				       "Full" : "Half");
464*8044SWilliam.Kucharski@Sun.COM 			} else {
465*8044SWilliam.Kucharski@Sun.COM 				printf
466*8044SWilliam.Kucharski@Sun.COM 				    ("AutoNegotiation enabled, at 10%sMbps %s-Duplex\n",
467*8044SWilliam.Kucharski@Sun.COM 				     tlphy_par & TLAN_PHY_SPEED_100 ? "" :
468*8044SWilliam.Kucharski@Sun.COM 				     "0",
469*8044SWilliam.Kucharski@Sun.COM 				     tlphy_par & TLAN_PHY_DUPLEX_FULL ?
470*8044SWilliam.Kucharski@Sun.COM 				     "Full" : "Half");
471*8044SWilliam.Kucharski@Sun.COM 				printf("TLAN: Partner capability: ");
472*8044SWilliam.Kucharski@Sun.COM 				for (i = 5; i <= 10; i++)
473*8044SWilliam.Kucharski@Sun.COM 					if (partner & (1 << i))
474*8044SWilliam.Kucharski@Sun.COM 						printf("%s", media[i - 5]);
475*8044SWilliam.Kucharski@Sun.COM 				printf("\n");
476*8044SWilliam.Kucharski@Sun.COM 			}
477*8044SWilliam.Kucharski@Sun.COM 
478*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
479*8044SWilliam.Kucharski@Sun.COM #ifdef MONITOR
480*8044SWilliam.Kucharski@Sun.COM 			/* We have link beat..for now anyway */
481*8044SWilliam.Kucharski@Sun.COM 			priv->link = 1;
482*8044SWilliam.Kucharski@Sun.COM 			/*Enabling link beat monitoring */
483*8044SWilliam.Kucharski@Sun.COM 			/* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_LINK_BEAT ); */
484*8044SWilliam.Kucharski@Sun.COM 			mdelay(10000);
485*8044SWilliam.Kucharski@Sun.COM 			TLan_PhyMonitor(nic);
486*8044SWilliam.Kucharski@Sun.COM #endif
487*8044SWilliam.Kucharski@Sun.COM 		} else if (status & MII_GS_LINK) {
488*8044SWilliam.Kucharski@Sun.COM 			printf("TLAN: %s: Link active\n", priv->nic_name);
489*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_LED_REG, TLAN_LED_LINK);
490*8044SWilliam.Kucharski@Sun.COM 		}
491*8044SWilliam.Kucharski@Sun.COM 	}
492*8044SWilliam.Kucharski@Sun.COM 
493*8044SWilliam.Kucharski@Sun.COM 	if (priv->phyNum == 0) {
494*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tlphy_ctl);
495*8044SWilliam.Kucharski@Sun.COM 		tlphy_ctl |= TLAN_TC_INTEN;
496*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tlphy_ctl);
497*8044SWilliam.Kucharski@Sun.COM 		sio = TLan_DioRead8(BASE, TLAN_NET_SIO);
498*8044SWilliam.Kucharski@Sun.COM 		sio |= TLAN_NET_SIO_MINTEN;
499*8044SWilliam.Kucharski@Sun.COM 		TLan_DioWrite8(BASE, TLAN_NET_SIO, sio);
500*8044SWilliam.Kucharski@Sun.COM 	}
501*8044SWilliam.Kucharski@Sun.COM 
502*8044SWilliam.Kucharski@Sun.COM 	if (status & MII_GS_LINK) {
503*8044SWilliam.Kucharski@Sun.COM 		TLan_SetMac(nic, 0, nic->node_addr);
504*8044SWilliam.Kucharski@Sun.COM 		priv->phyOnline = 1;
505*8044SWilliam.Kucharski@Sun.COM 		outb((TLAN_HC_INT_ON >> 8), BASE + TLAN_HOST_CMD + 1);
506*8044SWilliam.Kucharski@Sun.COM /*		if ( debug >= 1 && debug != TLAN_DEBUG_PROBE ) {
507*8044SWilliam.Kucharski@Sun.COM 			outb( ( TLAN_HC_REQ_INT >> 8 ), BASE + TLAN_HOST_CMD + 1 );
508*8044SWilliam.Kucharski@Sun.COM 		}
509*8044SWilliam.Kucharski@Sun.COM 
510*8044SWilliam.Kucharski@Sun.COM 		*/
511*8044SWilliam.Kucharski@Sun.COM 		outl(virt_to_bus(&rx_ring), BASE + TLAN_CH_PARM);
512*8044SWilliam.Kucharski@Sun.COM 		outl(TLAN_HC_GO | TLAN_HC_RT, BASE + TLAN_HOST_CMD);
513*8044SWilliam.Kucharski@Sun.COM 	} else {
514*8044SWilliam.Kucharski@Sun.COM 		printf
515*8044SWilliam.Kucharski@Sun.COM 		    ("TLAN: %s: Link inactive, will retry in 10 secs...\n",
516*8044SWilliam.Kucharski@Sun.COM 		     priv->nic_name);
517*8044SWilliam.Kucharski@Sun.COM 		/* TLan_SetTimer( nic, (10*HZ), TLAN_TIMER_FINISH_RESET ); */
518*8044SWilliam.Kucharski@Sun.COM 		mdelay(10000);
519*8044SWilliam.Kucharski@Sun.COM 		TLan_FinishReset(nic);
520*8044SWilliam.Kucharski@Sun.COM 		return;
521*8044SWilliam.Kucharski@Sun.COM 
522*8044SWilliam.Kucharski@Sun.COM 	}
523*8044SWilliam.Kucharski@Sun.COM 
524*8044SWilliam.Kucharski@Sun.COM }	/* TLan_FinishReset */
525*8044SWilliam.Kucharski@Sun.COM 
526*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
527*8044SWilliam.Kucharski@Sun.COM POLL - Wait for a frame
528*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tlan_poll(struct nic * nic,int retrieve)529*8044SWilliam.Kucharski@Sun.COM static int tlan_poll(struct nic *nic, int retrieve)
530*8044SWilliam.Kucharski@Sun.COM {
531*8044SWilliam.Kucharski@Sun.COM 	/* return true if there's an ethernet packet ready to read */
532*8044SWilliam.Kucharski@Sun.COM 	/* nic->packet should contain data on return */
533*8044SWilliam.Kucharski@Sun.COM 	/* nic->packetlen should contain length of data */
534*8044SWilliam.Kucharski@Sun.COM 	u32 framesize;
535*8044SWilliam.Kucharski@Sun.COM 	u32 host_cmd = 0;
536*8044SWilliam.Kucharski@Sun.COM 	u32 ack = 1;
537*8044SWilliam.Kucharski@Sun.COM 	int eoc = 0;
538*8044SWilliam.Kucharski@Sun.COM 	int entry = priv->cur_rx % TLAN_NUM_RX_LISTS;
539*8044SWilliam.Kucharski@Sun.COM 	u16 tmpCStat = le32_to_cpu(rx_ring[entry].cStat);
540*8044SWilliam.Kucharski@Sun.COM 	u16 host_int = inw(BASE + TLAN_HOST_INT);
541*8044SWilliam.Kucharski@Sun.COM 
542*8044SWilliam.Kucharski@Sun.COM 	if ((tmpCStat & TLAN_CSTAT_FRM_CMP) && !retrieve)
543*8044SWilliam.Kucharski@Sun.COM 	  return 1;
544*8044SWilliam.Kucharski@Sun.COM 
545*8044SWilliam.Kucharski@Sun.COM 	outw(host_int, BASE + TLAN_HOST_INT);
546*8044SWilliam.Kucharski@Sun.COM 
547*8044SWilliam.Kucharski@Sun.COM 	if (!(tmpCStat & TLAN_CSTAT_FRM_CMP))
548*8044SWilliam.Kucharski@Sun.COM 		return 0;
549*8044SWilliam.Kucharski@Sun.COM 
550*8044SWilliam.Kucharski@Sun.COM 	/* printf("PI-1: 0x%hX\n", host_int); */
551*8044SWilliam.Kucharski@Sun.COM 	if (tmpCStat & TLAN_CSTAT_EOC)
552*8044SWilliam.Kucharski@Sun.COM 		eoc = 1;
553*8044SWilliam.Kucharski@Sun.COM 
554*8044SWilliam.Kucharski@Sun.COM 	framesize = rx_ring[entry].frameSize;
555*8044SWilliam.Kucharski@Sun.COM 
556*8044SWilliam.Kucharski@Sun.COM 	nic->packetlen = framesize;
557*8044SWilliam.Kucharski@Sun.COM 
558*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
559*8044SWilliam.Kucharski@Sun.COM      printf(".%d.", framesize);
560*8044SWilliam.Kucharski@Sun.COM #endif
561*8044SWilliam.Kucharski@Sun.COM 
562*8044SWilliam.Kucharski@Sun.COM 	memcpy(nic->packet, rxb +
563*8044SWilliam.Kucharski@Sun.COM 	       (priv->cur_rx * TLAN_MAX_FRAME_SIZE), nic->packetlen);
564*8044SWilliam.Kucharski@Sun.COM 
565*8044SWilliam.Kucharski@Sun.COM 	rx_ring[entry].cStat = 0;
566*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
567*8044SWilliam.Kucharski@Sun.COM 	hex_dump(nic->packet, nic->packetlen);
568*8044SWilliam.Kucharski@Sun.COM 	printf("%d", entry);
569*8044SWilliam.Kucharski@Sun.COM #endif
570*8044SWilliam.Kucharski@Sun.COM 	entry = (entry + 1) % TLAN_NUM_RX_LISTS;
571*8044SWilliam.Kucharski@Sun.COM 	priv->cur_rx = entry;
572*8044SWilliam.Kucharski@Sun.COM 	if (eoc) {
573*8044SWilliam.Kucharski@Sun.COM 		if ((rx_ring[entry].cStat & TLAN_CSTAT_READY) ==
574*8044SWilliam.Kucharski@Sun.COM 		    TLAN_CSTAT_READY) {
575*8044SWilliam.Kucharski@Sun.COM 			ack |= TLAN_HC_GO | TLAN_HC_RT;
576*8044SWilliam.Kucharski@Sun.COM 			host_cmd = TLAN_HC_ACK | ack | 0x001C0000;
577*8044SWilliam.Kucharski@Sun.COM 			outl(host_cmd, BASE + TLAN_HOST_CMD);
578*8044SWilliam.Kucharski@Sun.COM 		}
579*8044SWilliam.Kucharski@Sun.COM 	} else {
580*8044SWilliam.Kucharski@Sun.COM 		host_cmd = TLAN_HC_ACK | ack | (0x000C0000);
581*8044SWilliam.Kucharski@Sun.COM 		outl(host_cmd, BASE + TLAN_HOST_CMD);
582*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
583*8044SWilliam.Kucharski@Sun.COM 		printf("AC: 0x%hX\n", inw(BASE + TLAN_CH_PARM));
584*8044SWilliam.Kucharski@Sun.COM 		host_int = inw(BASE + TLAN_HOST_INT);
585*8044SWilliam.Kucharski@Sun.COM 		printf("PI-2: 0x%hX\n", host_int);
586*8044SWilliam.Kucharski@Sun.COM #endif
587*8044SWilliam.Kucharski@Sun.COM 	}
588*8044SWilliam.Kucharski@Sun.COM 	refill_rx(nic);
589*8044SWilliam.Kucharski@Sun.COM 	return (1);		/* initially as this is called to flush the input */
590*8044SWilliam.Kucharski@Sun.COM }
591*8044SWilliam.Kucharski@Sun.COM 
refill_rx(struct nic * nic __unused)592*8044SWilliam.Kucharski@Sun.COM static void refill_rx(struct nic *nic __unused)
593*8044SWilliam.Kucharski@Sun.COM {
594*8044SWilliam.Kucharski@Sun.COM 	int entry = 0;
595*8044SWilliam.Kucharski@Sun.COM 
596*8044SWilliam.Kucharski@Sun.COM 	for (;
597*8044SWilliam.Kucharski@Sun.COM 	     (priv->cur_rx - priv->dirty_rx +
598*8044SWilliam.Kucharski@Sun.COM 	      TLAN_NUM_RX_LISTS) % TLAN_NUM_RX_LISTS > 0;
599*8044SWilliam.Kucharski@Sun.COM 	     priv->dirty_rx = (priv->dirty_rx + 1) % TLAN_NUM_RX_LISTS) {
600*8044SWilliam.Kucharski@Sun.COM 		entry = priv->dirty_rx % TLAN_NUM_TX_LISTS;
601*8044SWilliam.Kucharski@Sun.COM 		rx_ring[entry].frameSize = TLAN_MAX_FRAME_SIZE;
602*8044SWilliam.Kucharski@Sun.COM 		rx_ring[entry].cStat = TLAN_CSTAT_READY;
603*8044SWilliam.Kucharski@Sun.COM 	}
604*8044SWilliam.Kucharski@Sun.COM 
605*8044SWilliam.Kucharski@Sun.COM }
606*8044SWilliam.Kucharski@Sun.COM 
607*8044SWilliam.Kucharski@Sun.COM /* #define EBDEBUG */
608*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
609*8044SWilliam.Kucharski@Sun.COM TRANSMIT - Transmit a frame
610*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tlan_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)611*8044SWilliam.Kucharski@Sun.COM static void tlan_transmit(struct nic *nic, const char *d,	/* Destination */
612*8044SWilliam.Kucharski@Sun.COM 			  unsigned int t,	/* Type */
613*8044SWilliam.Kucharski@Sun.COM 			  unsigned int s,	/* size */
614*8044SWilliam.Kucharski@Sun.COM 			  const char *p)
615*8044SWilliam.Kucharski@Sun.COM {				/* Packet */
616*8044SWilliam.Kucharski@Sun.COM 	u16 nstype;
617*8044SWilliam.Kucharski@Sun.COM 	u32 to;
618*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *tail_list;
619*8044SWilliam.Kucharski@Sun.COM 	struct TLanList *head_list;
620*8044SWilliam.Kucharski@Sun.COM 	u8 *tail_buffer;
621*8044SWilliam.Kucharski@Sun.COM 	u32 ack = 0;
622*8044SWilliam.Kucharski@Sun.COM 	u32 host_cmd;
623*8044SWilliam.Kucharski@Sun.COM 	int eoc = 0;
624*8044SWilliam.Kucharski@Sun.COM 	u16 tmpCStat;
625*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
626*8044SWilliam.Kucharski@Sun.COM 	u16 host_int = inw(BASE + TLAN_HOST_INT);
627*8044SWilliam.Kucharski@Sun.COM #endif
628*8044SWilliam.Kucharski@Sun.COM 	int entry = 0;
629*8044SWilliam.Kucharski@Sun.COM 
630*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
631*8044SWilliam.Kucharski@Sun.COM 	printf("INT0-0x%hX\n", host_int);
632*8044SWilliam.Kucharski@Sun.COM #endif
633*8044SWilliam.Kucharski@Sun.COM 
634*8044SWilliam.Kucharski@Sun.COM 	if (!priv->phyOnline) {
635*8044SWilliam.Kucharski@Sun.COM 		printf("TRANSMIT:  %s PHY is not ready\n", priv->nic_name);
636*8044SWilliam.Kucharski@Sun.COM 		return;
637*8044SWilliam.Kucharski@Sun.COM 	}
638*8044SWilliam.Kucharski@Sun.COM 
639*8044SWilliam.Kucharski@Sun.COM 	tail_list = priv->txList + priv->txTail;
640*8044SWilliam.Kucharski@Sun.COM 
641*8044SWilliam.Kucharski@Sun.COM 	if (tail_list->cStat != TLAN_CSTAT_UNUSED) {
642*8044SWilliam.Kucharski@Sun.COM 		printf("TRANSMIT: %s is busy (Head=%d Tail=%d)\n",
643*8044SWilliam.Kucharski@Sun.COM 		       priv->nic_name, priv->txList, priv->txTail);
644*8044SWilliam.Kucharski@Sun.COM 		tx_ring[entry].cStat = TLAN_CSTAT_UNUSED;
645*8044SWilliam.Kucharski@Sun.COM 		priv->txBusyCount++;
646*8044SWilliam.Kucharski@Sun.COM 		return;
647*8044SWilliam.Kucharski@Sun.COM 	}
648*8044SWilliam.Kucharski@Sun.COM 
649*8044SWilliam.Kucharski@Sun.COM 	tail_list->forward = 0;
650*8044SWilliam.Kucharski@Sun.COM 
651*8044SWilliam.Kucharski@Sun.COM 	tail_buffer = txb + (priv->txTail * TLAN_MAX_FRAME_SIZE);
652*8044SWilliam.Kucharski@Sun.COM 
653*8044SWilliam.Kucharski@Sun.COM 	/* send the packet to destination */
654*8044SWilliam.Kucharski@Sun.COM 	memcpy(tail_buffer, d, ETH_ALEN);
655*8044SWilliam.Kucharski@Sun.COM 	memcpy(tail_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN);
656*8044SWilliam.Kucharski@Sun.COM 	nstype = htons((u16) t);
657*8044SWilliam.Kucharski@Sun.COM 	memcpy(tail_buffer + 2 * ETH_ALEN, (u8 *) & nstype, 2);
658*8044SWilliam.Kucharski@Sun.COM 	memcpy(tail_buffer + ETH_HLEN, p, s);
659*8044SWilliam.Kucharski@Sun.COM 
660*8044SWilliam.Kucharski@Sun.COM 	s += ETH_HLEN;
661*8044SWilliam.Kucharski@Sun.COM 	s &= 0x0FFF;
662*8044SWilliam.Kucharski@Sun.COM 	while (s < ETH_ZLEN)
663*8044SWilliam.Kucharski@Sun.COM 		tail_buffer[s++] = '\0';
664*8044SWilliam.Kucharski@Sun.COM 
665*8044SWilliam.Kucharski@Sun.COM 	/*=====================================================*/
666*8044SWilliam.Kucharski@Sun.COM 	/* Receive
667*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0001 1100
668*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 1100
669*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0011 = 0x0003
670*8044SWilliam.Kucharski@Sun.COM 	 *
671*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0000 0000 0000 0000 0011
672*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 1100 0000 0000 0000 0000 = 0x000C0000
673*8044SWilliam.Kucharski@Sun.COM 	 *
674*8044SWilliam.Kucharski@Sun.COM 	 * Transmit
675*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0001 1100
676*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0100
677*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0001 = 0x0001
678*8044SWilliam.Kucharski@Sun.COM 	 *
679*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0000 0000 0000 0000 0001
680*8044SWilliam.Kucharski@Sun.COM 	 * 0000 0000 0000 0100 0000 0000 0000 0000 = 0x00040000
681*8044SWilliam.Kucharski@Sun.COM 	 * */
682*8044SWilliam.Kucharski@Sun.COM 
683*8044SWilliam.Kucharski@Sun.COM 	/* Setup the transmit descriptor */
684*8044SWilliam.Kucharski@Sun.COM 	tail_list->frameSize = (u16) s;
685*8044SWilliam.Kucharski@Sun.COM 	tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) s;
686*8044SWilliam.Kucharski@Sun.COM 	tail_list->buffer[1].count = 0;
687*8044SWilliam.Kucharski@Sun.COM 	tail_list->buffer[1].address = 0;
688*8044SWilliam.Kucharski@Sun.COM 
689*8044SWilliam.Kucharski@Sun.COM 	tail_list->cStat = TLAN_CSTAT_READY;
690*8044SWilliam.Kucharski@Sun.COM 
691*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
692*8044SWilliam.Kucharski@Sun.COM 	host_int = inw(BASE + TLAN_HOST_INT);
693*8044SWilliam.Kucharski@Sun.COM 	printf("INT1-0x%hX\n", host_int);
694*8044SWilliam.Kucharski@Sun.COM #endif
695*8044SWilliam.Kucharski@Sun.COM 
696*8044SWilliam.Kucharski@Sun.COM 	if (!priv->txInProgress) {
697*8044SWilliam.Kucharski@Sun.COM 		priv->txInProgress = 1;
698*8044SWilliam.Kucharski@Sun.COM 		outl(virt_to_le32desc(tail_list), BASE + TLAN_CH_PARM);
699*8044SWilliam.Kucharski@Sun.COM 		outl(TLAN_HC_GO, BASE + TLAN_HOST_CMD);
700*8044SWilliam.Kucharski@Sun.COM 	} else {
701*8044SWilliam.Kucharski@Sun.COM 		if (priv->txTail == 0) {
702*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
703*8044SWilliam.Kucharski@Sun.COM 			printf("Out buffer\n");
704*8044SWilliam.Kucharski@Sun.COM #endif
705*8044SWilliam.Kucharski@Sun.COM 			(priv->txList + (TLAN_NUM_TX_LISTS - 1))->forward =
706*8044SWilliam.Kucharski@Sun.COM 			    virt_to_le32desc(tail_list);
707*8044SWilliam.Kucharski@Sun.COM 		} else {
708*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
709*8044SWilliam.Kucharski@Sun.COM 			printf("Fix this \n");
710*8044SWilliam.Kucharski@Sun.COM #endif
711*8044SWilliam.Kucharski@Sun.COM 			(priv->txList + (priv->txTail - 1))->forward =
712*8044SWilliam.Kucharski@Sun.COM 			    virt_to_le32desc(tail_list);
713*8044SWilliam.Kucharski@Sun.COM 		}
714*8044SWilliam.Kucharski@Sun.COM 	}
715*8044SWilliam.Kucharski@Sun.COM 
716*8044SWilliam.Kucharski@Sun.COM 	CIRC_INC(priv->txTail, TLAN_NUM_TX_LISTS);
717*8044SWilliam.Kucharski@Sun.COM 
718*8044SWilliam.Kucharski@Sun.COM #ifdef EBDEBUG
719*8044SWilliam.Kucharski@Sun.COM 	host_int = inw(BASE + TLAN_HOST_INT);
720*8044SWilliam.Kucharski@Sun.COM 	printf("INT2-0x%hX\n", host_int);
721*8044SWilliam.Kucharski@Sun.COM #endif
722*8044SWilliam.Kucharski@Sun.COM 
723*8044SWilliam.Kucharski@Sun.COM 	to = currticks() + TX_TIME_OUT;
724*8044SWilliam.Kucharski@Sun.COM 	while ((tail_list->cStat == TLAN_CSTAT_READY) && currticks() < to);
725*8044SWilliam.Kucharski@Sun.COM 
726*8044SWilliam.Kucharski@Sun.COM 	head_list = priv->txList + priv->txHead;
727*8044SWilliam.Kucharski@Sun.COM 	while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP)
728*8044SWilliam.Kucharski@Sun.COM 			&& (ack < 255)) {
729*8044SWilliam.Kucharski@Sun.COM 		ack++;
730*8044SWilliam.Kucharski@Sun.COM 		if(tmpCStat & TLAN_CSTAT_EOC)
731*8044SWilliam.Kucharski@Sun.COM 			eoc =1;
732*8044SWilliam.Kucharski@Sun.COM 		head_list->cStat = TLAN_CSTAT_UNUSED;
733*8044SWilliam.Kucharski@Sun.COM 		CIRC_INC(priv->txHead, TLAN_NUM_TX_LISTS);
734*8044SWilliam.Kucharski@Sun.COM 		head_list = priv->txList + priv->txHead;
735*8044SWilliam.Kucharski@Sun.COM 
736*8044SWilliam.Kucharski@Sun.COM 	}
737*8044SWilliam.Kucharski@Sun.COM 	if(!ack)
738*8044SWilliam.Kucharski@Sun.COM 		printf("Incomplete TX Frame\n");
739*8044SWilliam.Kucharski@Sun.COM 
740*8044SWilliam.Kucharski@Sun.COM 	if(eoc) {
741*8044SWilliam.Kucharski@Sun.COM 		head_list = priv->txList + priv->txHead;
742*8044SWilliam.Kucharski@Sun.COM 		if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
743*8044SWilliam.Kucharski@Sun.COM 			outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
744*8044SWilliam.Kucharski@Sun.COM 			ack |= TLAN_HC_GO;
745*8044SWilliam.Kucharski@Sun.COM 		} else {
746*8044SWilliam.Kucharski@Sun.COM 			priv->txInProgress = 0;
747*8044SWilliam.Kucharski@Sun.COM 		}
748*8044SWilliam.Kucharski@Sun.COM 	}
749*8044SWilliam.Kucharski@Sun.COM 	if(ack) {
750*8044SWilliam.Kucharski@Sun.COM 		host_cmd = TLAN_HC_ACK | ack;
751*8044SWilliam.Kucharski@Sun.COM 		outl(host_cmd, BASE + TLAN_HOST_CMD);
752*8044SWilliam.Kucharski@Sun.COM 	}
753*8044SWilliam.Kucharski@Sun.COM 
754*8044SWilliam.Kucharski@Sun.COM 	if(priv->tlanRev < 0x30 ) {
755*8044SWilliam.Kucharski@Sun.COM 		ack = 1;
756*8044SWilliam.Kucharski@Sun.COM 		head_list = priv->txList + priv->txHead;
757*8044SWilliam.Kucharski@Sun.COM 		if ((head_list->cStat & TLAN_CSTAT_READY) == TLAN_CSTAT_READY) {
758*8044SWilliam.Kucharski@Sun.COM 			outl(virt_to_le32desc(head_list), BASE + TLAN_CH_PARM);
759*8044SWilliam.Kucharski@Sun.COM 			ack |= TLAN_HC_GO;
760*8044SWilliam.Kucharski@Sun.COM 		} else {
761*8044SWilliam.Kucharski@Sun.COM 			priv->txInProgress = 0;
762*8044SWilliam.Kucharski@Sun.COM 		}
763*8044SWilliam.Kucharski@Sun.COM 		host_cmd = TLAN_HC_ACK | ack | 0x00140000;
764*8044SWilliam.Kucharski@Sun.COM 		outl(host_cmd, BASE + TLAN_HOST_CMD);
765*8044SWilliam.Kucharski@Sun.COM 
766*8044SWilliam.Kucharski@Sun.COM 	}
767*8044SWilliam.Kucharski@Sun.COM 
768*8044SWilliam.Kucharski@Sun.COM 	if (currticks() >= to) {
769*8044SWilliam.Kucharski@Sun.COM 		printf("TX Time Out");
770*8044SWilliam.Kucharski@Sun.COM 	}
771*8044SWilliam.Kucharski@Sun.COM }
772*8044SWilliam.Kucharski@Sun.COM 
773*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
774*8044SWilliam.Kucharski@Sun.COM DISABLE - Turn off ethernet interface
775*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
776*8044SWilliam.Kucharski@Sun.COM #ifdef EB51
tlan_disable(struct dev * dev __unused)777*8044SWilliam.Kucharski@Sun.COM static void tlan_disable(struct dev *dev __unused)
778*8044SWilliam.Kucharski@Sun.COM #else
779*8044SWilliam.Kucharski@Sun.COM static void tlan_disable(struct nic *nic __unused)
780*8044SWilliam.Kucharski@Sun.COM #endif
781*8044SWilliam.Kucharski@Sun.COM {
782*8044SWilliam.Kucharski@Sun.COM 	/* put the card in its initial state */
783*8044SWilliam.Kucharski@Sun.COM 	/* This function serves 3 purposes.
784*8044SWilliam.Kucharski@Sun.COM 	 * This disables DMA and interrupts so we don't receive
785*8044SWilliam.Kucharski@Sun.COM 	 *  unexpected packets or interrupts from the card after
786*8044SWilliam.Kucharski@Sun.COM 	 *  etherboot has finished.
787*8044SWilliam.Kucharski@Sun.COM 	 * This frees resources so etherboot may use
788*8044SWilliam.Kucharski@Sun.COM 	 *  this driver on another interface
789*8044SWilliam.Kucharski@Sun.COM 	 * This allows etherboot to reinitialize the interface
790*8044SWilliam.Kucharski@Sun.COM 	 *  if something is something goes wrong.
791*8044SWilliam.Kucharski@Sun.COM 	 *
792*8044SWilliam.Kucharski@Sun.COM 	 */
793*8044SWilliam.Kucharski@Sun.COM 	outl(TLAN_HC_AD_RST, BASE + TLAN_HOST_CMD);
794*8044SWilliam.Kucharski@Sun.COM }
795*8044SWilliam.Kucharski@Sun.COM 
796*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
797*8044SWilliam.Kucharski@Sun.COM IRQ - Enable, Disable, or Force interrupts
798*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
tlan_irq(struct nic * nic __unused,irq_action_t action __unused)799*8044SWilliam.Kucharski@Sun.COM static void tlan_irq(struct nic *nic __unused, irq_action_t action __unused)
800*8044SWilliam.Kucharski@Sun.COM {
801*8044SWilliam.Kucharski@Sun.COM   switch ( action ) {
802*8044SWilliam.Kucharski@Sun.COM   case DISABLE :
803*8044SWilliam.Kucharski@Sun.COM     break;
804*8044SWilliam.Kucharski@Sun.COM   case ENABLE :
805*8044SWilliam.Kucharski@Sun.COM     break;
806*8044SWilliam.Kucharski@Sun.COM   case FORCE :
807*8044SWilliam.Kucharski@Sun.COM     break;
808*8044SWilliam.Kucharski@Sun.COM   }
809*8044SWilliam.Kucharski@Sun.COM }
810*8044SWilliam.Kucharski@Sun.COM 
TLan_SetMulticastList(struct nic * nic)811*8044SWilliam.Kucharski@Sun.COM static void TLan_SetMulticastList(struct nic *nic) {
812*8044SWilliam.Kucharski@Sun.COM 	int i;
813*8044SWilliam.Kucharski@Sun.COM 	u8 tmp;
814*8044SWilliam.Kucharski@Sun.COM 
815*8044SWilliam.Kucharski@Sun.COM 	/* !IFF_PROMISC */
816*8044SWilliam.Kucharski@Sun.COM 	tmp = TLan_DioRead8(BASE, TLAN_NET_CMD);
817*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite8(BASE, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF);
818*8044SWilliam.Kucharski@Sun.COM 
819*8044SWilliam.Kucharski@Sun.COM 	/* IFF_ALLMULTI */
820*8044SWilliam.Kucharski@Sun.COM 	for(i = 0; i< 3; i++)
821*8044SWilliam.Kucharski@Sun.COM 		TLan_SetMac(nic, i + 1, NULL);
822*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite32(BASE, TLAN_HASH_1, 0xFFFFFFFF);
823*8044SWilliam.Kucharski@Sun.COM 	TLan_DioWrite32(BASE, TLAN_HASH_2, 0xFFFFFFFF);
824*8044SWilliam.Kucharski@Sun.COM 
825*8044SWilliam.Kucharski@Sun.COM 
826*8044SWilliam.Kucharski@Sun.COM }
827*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
828*8044SWilliam.Kucharski@Sun.COM PROBE - Look for an adapter, this routine's visible to the outside
829*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
830*8044SWilliam.Kucharski@Sun.COM 
831*8044SWilliam.Kucharski@Sun.COM #define board_found 1
832*8044SWilliam.Kucharski@Sun.COM #define valid_link 0
833*8044SWilliam.Kucharski@Sun.COM #ifdef EB51
tlan_probe(struct dev * dev,struct pci_device * pci)834*8044SWilliam.Kucharski@Sun.COM static int tlan_probe(struct dev *dev, struct pci_device *pci)
835*8044SWilliam.Kucharski@Sun.COM {
836*8044SWilliam.Kucharski@Sun.COM 	struct nic *nic = (struct nic *) dev;
837*8044SWilliam.Kucharski@Sun.COM #else
838*8044SWilliam.Kucharski@Sun.COM struct nic *tlan_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
839*8044SWilliam.Kucharski@Sun.COM {
840*8044SWilliam.Kucharski@Sun.COM #endif
841*8044SWilliam.Kucharski@Sun.COM 		u16 data = 0;
842*8044SWilliam.Kucharski@Sun.COM 	int err;
843*8044SWilliam.Kucharski@Sun.COM 	int i;
844*8044SWilliam.Kucharski@Sun.COM 
845*8044SWilliam.Kucharski@Sun.COM 	if (pci->ioaddr == 0)
846*8044SWilliam.Kucharski@Sun.COM 		return 0;
847*8044SWilliam.Kucharski@Sun.COM 
848*8044SWilliam.Kucharski@Sun.COM 	nic->irqno  = 0;
849*8044SWilliam.Kucharski@Sun.COM 	nic->ioaddr = pci->ioaddr & ~3;
850*8044SWilliam.Kucharski@Sun.COM 
851*8044SWilliam.Kucharski@Sun.COM 	BASE = pci->ioaddr;
852*8044SWilliam.Kucharski@Sun.COM 	printf("\n");
853*8044SWilliam.Kucharski@Sun.COM 	printf("tlan.c: %s, %s\n", drv_version, drv_date);
854*8044SWilliam.Kucharski@Sun.COM 	printf("%s: Probing for Vendor 0x%hX, Device 0x%hX",
855*8044SWilliam.Kucharski@Sun.COM 	       pci->name, pci->vendor, pci->dev_id);
856*8044SWilliam.Kucharski@Sun.COM 
857*8044SWilliam.Kucharski@Sun.COM 
858*8044SWilliam.Kucharski@Sun.COM 	/* I really must find out what this does */
859*8044SWilliam.Kucharski@Sun.COM 	adjust_pci_device(pci);
860*8044SWilliam.Kucharski@Sun.COM 
861*8044SWilliam.Kucharski@Sun.COM 	/* Point to private storage */
862*8044SWilliam.Kucharski@Sun.COM 	priv = &TLanPrivateInfo;
863*8044SWilliam.Kucharski@Sun.COM 	/* Figure out which chip we're dealing with */
864*8044SWilliam.Kucharski@Sun.COM 	i = 0;
865*8044SWilliam.Kucharski@Sun.COM 	chip_idx = -1;
866*8044SWilliam.Kucharski@Sun.COM 
867*8044SWilliam.Kucharski@Sun.COM 	while (tlan_pci_tbl[i].name) {
868*8044SWilliam.Kucharski@Sun.COM 		if ((((u32) pci->dev_id << 16) | pci->vendor) ==
869*8044SWilliam.Kucharski@Sun.COM 		    (tlan_pci_tbl[i].id.pci & 0xffffffff)) {
870*8044SWilliam.Kucharski@Sun.COM 			chip_idx = i;
871*8044SWilliam.Kucharski@Sun.COM 			break;
872*8044SWilliam.Kucharski@Sun.COM 		}
873*8044SWilliam.Kucharski@Sun.COM 		i++;
874*8044SWilliam.Kucharski@Sun.COM 	}
875*8044SWilliam.Kucharski@Sun.COM 
876*8044SWilliam.Kucharski@Sun.COM 	priv->vendor_id = pci->vendor;
877*8044SWilliam.Kucharski@Sun.COM 	priv->dev_id = pci->dev_id;
878*8044SWilliam.Kucharski@Sun.COM 	priv->nic_name = pci->name;
879*8044SWilliam.Kucharski@Sun.COM 	priv->eoc = 0;
880*8044SWilliam.Kucharski@Sun.COM 
881*8044SWilliam.Kucharski@Sun.COM 	err = 0;
882*8044SWilliam.Kucharski@Sun.COM 	for (i = 0; i < 6; i++)
883*8044SWilliam.Kucharski@Sun.COM 		err |= TLan_EeReadByte(BASE,
884*8044SWilliam.Kucharski@Sun.COM 				       (u8) tlan_pci_tbl[chip_idx].
885*8044SWilliam.Kucharski@Sun.COM 				       addrOfs + i,
886*8044SWilliam.Kucharski@Sun.COM 				       (u8 *) & nic->node_addr[i]);
887*8044SWilliam.Kucharski@Sun.COM 	if (err) {
888*8044SWilliam.Kucharski@Sun.COM 		printf("TLAN: %s: Error reading MAC from eeprom: %d\n",
889*8044SWilliam.Kucharski@Sun.COM 		       pci->name, err);
890*8044SWilliam.Kucharski@Sun.COM 	} else
891*8044SWilliam.Kucharski@Sun.COM 		printf("\nAddress: %!\n", nic->node_addr);
892*8044SWilliam.Kucharski@Sun.COM 
893*8044SWilliam.Kucharski@Sun.COM 	priv->tlanRev = TLan_DioRead8(BASE, TLAN_DEF_REVISION);
894*8044SWilliam.Kucharski@Sun.COM 	printf("\nRevision = 0x%hX\n", priv->tlanRev);
895*8044SWilliam.Kucharski@Sun.COM 
896*8044SWilliam.Kucharski@Sun.COM 	TLan_ResetLists(nic);
897*8044SWilliam.Kucharski@Sun.COM 	TLan_ResetAdapter(nic);
898*8044SWilliam.Kucharski@Sun.COM /*
899*8044SWilliam.Kucharski@Sun.COM 	data = inl(BASE + TLAN_HOST_CMD);
900*8044SWilliam.Kucharski@Sun.COM 	data |= TLAN_HC_EOC;
901*8044SWilliam.Kucharski@Sun.COM 	outw(data, BASE + TLAN_HOST_CMD);
902*8044SWilliam.Kucharski@Sun.COM */
903*8044SWilliam.Kucharski@Sun.COM 
904*8044SWilliam.Kucharski@Sun.COM 	data = inl(BASE + TLAN_HOST_CMD);
905*8044SWilliam.Kucharski@Sun.COM 	data |= TLAN_HC_INT_OFF;
906*8044SWilliam.Kucharski@Sun.COM 	outw(data, BASE + TLAN_HOST_CMD);
907*8044SWilliam.Kucharski@Sun.COM 
908*8044SWilliam.Kucharski@Sun.COM 	TLan_SetMulticastList(nic);
909*8044SWilliam.Kucharski@Sun.COM 	udelay(100);
910*8044SWilliam.Kucharski@Sun.COM 	priv->txList = tx_ring;
911*8044SWilliam.Kucharski@Sun.COM 	priv->rxList = rx_ring;
912*8044SWilliam.Kucharski@Sun.COM /*	if (board_found && valid_link)
913*8044SWilliam.Kucharski@Sun.COM 	{*/
914*8044SWilliam.Kucharski@Sun.COM 	/* point to NIC specific routines */
915*8044SWilliam.Kucharski@Sun.COM #ifdef EB51
916*8044SWilliam.Kucharski@Sun.COM 	dev->disable = tlan_disable;
917*8044SWilliam.Kucharski@Sun.COM 	nic->poll = tlan_poll;
918*8044SWilliam.Kucharski@Sun.COM 	nic->transmit = tlan_transmit;
919*8044SWilliam.Kucharski@Sun.COM 	nic->irq    = tlan_irq;
920*8044SWilliam.Kucharski@Sun.COM 	return 1;
921*8044SWilliam.Kucharski@Sun.COM #else
922*8044SWilliam.Kucharski@Sun.COM 	nic->disable = tlan_disable;
923*8044SWilliam.Kucharski@Sun.COM 	nic->poll = tlan_poll;
924*8044SWilliam.Kucharski@Sun.COM 	nic->transmit = tlan_transmit;
925*8044SWilliam.Kucharski@Sun.COM 	nic->irq    = tlan_irq;
926*8044SWilliam.Kucharski@Sun.COM 	return nic;
927*8044SWilliam.Kucharski@Sun.COM #endif
928*8044SWilliam.Kucharski@Sun.COM }
929*8044SWilliam.Kucharski@Sun.COM 
930*8044SWilliam.Kucharski@Sun.COM 
931*8044SWilliam.Kucharski@Sun.COM /*****************************************************************************
932*8044SWilliam.Kucharski@Sun.COM ******************************************************************************
933*8044SWilliam.Kucharski@Sun.COM 
934*8044SWilliam.Kucharski@Sun.COM 	ThunderLAN Driver Eeprom routines
935*8044SWilliam.Kucharski@Sun.COM 
936*8044SWilliam.Kucharski@Sun.COM 	The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A
937*8044SWilliam.Kucharski@Sun.COM 	EEPROM.  These functions are based on information in Microchip's
938*8044SWilliam.Kucharski@Sun.COM 	data sheet.  I don't know how well this functions will work with
939*8044SWilliam.Kucharski@Sun.COM 	other EEPROMs.
940*8044SWilliam.Kucharski@Sun.COM 
941*8044SWilliam.Kucharski@Sun.COM ******************************************************************************
942*8044SWilliam.Kucharski@Sun.COM *****************************************************************************/
943*8044SWilliam.Kucharski@Sun.COM 
944*8044SWilliam.Kucharski@Sun.COM 
945*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
946*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_EeSendStart
947*8044SWilliam.Kucharski@Sun.COM 	 *
948*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
949*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
950*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
951*8044SWilliam.Kucharski@Sun.COM 	 *		io_base		The IO port base address for the
952*8044SWilliam.Kucharski@Sun.COM 	 *				TLAN device with the EEPROM to
953*8044SWilliam.Kucharski@Sun.COM 	 *				use.
954*8044SWilliam.Kucharski@Sun.COM 	 *
955*8044SWilliam.Kucharski@Sun.COM 	 *	This function sends a start cycle to an EEPROM attached
956*8044SWilliam.Kucharski@Sun.COM 	 *	to a TLAN chip.
957*8044SWilliam.Kucharski@Sun.COM 	 *
958*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
959*8044SWilliam.Kucharski@Sun.COM 
960*8044SWilliam.Kucharski@Sun.COM void TLan_EeSendStart(u16 io_base)
961*8044SWilliam.Kucharski@Sun.COM {
962*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
963*8044SWilliam.Kucharski@Sun.COM 
964*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
965*8044SWilliam.Kucharski@Sun.COM 	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
966*8044SWilliam.Kucharski@Sun.COM 
967*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
968*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
969*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
970*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
971*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
972*8044SWilliam.Kucharski@Sun.COM 
973*8044SWilliam.Kucharski@Sun.COM }				/* TLan_EeSendStart */
974*8044SWilliam.Kucharski@Sun.COM 
975*8044SWilliam.Kucharski@Sun.COM 
976*8044SWilliam.Kucharski@Sun.COM 
977*8044SWilliam.Kucharski@Sun.COM 
978*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
979*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_EeSendByte
980*8044SWilliam.Kucharski@Sun.COM 	 *
981*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
982*8044SWilliam.Kucharski@Sun.COM 	 *		If the correct ack was received, 0, otherwise 1
983*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:	io_base		The IO port base address for the
984*8044SWilliam.Kucharski@Sun.COM 	 *				TLAN device with the EEPROM to
985*8044SWilliam.Kucharski@Sun.COM 	 *				use.
986*8044SWilliam.Kucharski@Sun.COM 	 *		data		The 8 bits of information to
987*8044SWilliam.Kucharski@Sun.COM 	 *				send to the EEPROM.
988*8044SWilliam.Kucharski@Sun.COM 	 *		stop		If TLAN_EEPROM_STOP is passed, a
989*8044SWilliam.Kucharski@Sun.COM 	 *				stop cycle is sent after the
990*8044SWilliam.Kucharski@Sun.COM 	 *				byte is sent after the ack is
991*8044SWilliam.Kucharski@Sun.COM 	 *				read.
992*8044SWilliam.Kucharski@Sun.COM 	 *
993*8044SWilliam.Kucharski@Sun.COM 	 *	This function sends a byte on the serial EEPROM line,
994*8044SWilliam.Kucharski@Sun.COM 	 *	driving the clock to send each bit. The function then
995*8044SWilliam.Kucharski@Sun.COM 	 *	reverses transmission direction and reads an acknowledge
996*8044SWilliam.Kucharski@Sun.COM 	 *	bit.
997*8044SWilliam.Kucharski@Sun.COM 	 *
998*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
999*8044SWilliam.Kucharski@Sun.COM 
1000*8044SWilliam.Kucharski@Sun.COM int TLan_EeSendByte(u16 io_base, u8 data, int stop)
1001*8044SWilliam.Kucharski@Sun.COM {
1002*8044SWilliam.Kucharski@Sun.COM 	int err;
1003*8044SWilliam.Kucharski@Sun.COM 	u8 place;
1004*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
1005*8044SWilliam.Kucharski@Sun.COM 
1006*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
1007*8044SWilliam.Kucharski@Sun.COM 	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
1008*8044SWilliam.Kucharski@Sun.COM 
1009*8044SWilliam.Kucharski@Sun.COM 	/* Assume clock is low, tx is enabled; */
1010*8044SWilliam.Kucharski@Sun.COM 	for (place = 0x80; place != 0; place >>= 1) {
1011*8044SWilliam.Kucharski@Sun.COM 		if (place & data)
1012*8044SWilliam.Kucharski@Sun.COM 			TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
1013*8044SWilliam.Kucharski@Sun.COM 		else
1014*8044SWilliam.Kucharski@Sun.COM 			TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);
1015*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1016*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
1017*8044SWilliam.Kucharski@Sun.COM 	}
1018*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
1019*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1020*8044SWilliam.Kucharski@Sun.COM 	err = TLan_GetBit(TLAN_NET_SIO_EDATA, sio);
1021*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
1022*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
1023*8044SWilliam.Kucharski@Sun.COM 
1024*8044SWilliam.Kucharski@Sun.COM 	if ((!err) && stop) {
1025*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* STOP, raise data while clock is high */
1026*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1027*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
1028*8044SWilliam.Kucharski@Sun.COM 	}
1029*8044SWilliam.Kucharski@Sun.COM 
1030*8044SWilliam.Kucharski@Sun.COM 	return (err);
1031*8044SWilliam.Kucharski@Sun.COM 
1032*8044SWilliam.Kucharski@Sun.COM }				/* TLan_EeSendByte */
1033*8044SWilliam.Kucharski@Sun.COM 
1034*8044SWilliam.Kucharski@Sun.COM 
1035*8044SWilliam.Kucharski@Sun.COM 
1036*8044SWilliam.Kucharski@Sun.COM 
1037*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1038*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_EeReceiveByte
1039*8044SWilliam.Kucharski@Sun.COM 	 *
1040*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1041*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1042*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1043*8044SWilliam.Kucharski@Sun.COM 	 *		io_base		The IO port base address for the
1044*8044SWilliam.Kucharski@Sun.COM 	 *				TLAN device with the EEPROM to
1045*8044SWilliam.Kucharski@Sun.COM 	 *				use.
1046*8044SWilliam.Kucharski@Sun.COM 	 *		data		An address to a char to hold the
1047*8044SWilliam.Kucharski@Sun.COM 	 *				data sent from the EEPROM.
1048*8044SWilliam.Kucharski@Sun.COM 	 *		stop		If TLAN_EEPROM_STOP is passed, a
1049*8044SWilliam.Kucharski@Sun.COM 	 *				stop cycle is sent after the
1050*8044SWilliam.Kucharski@Sun.COM 	 *				byte is received, and no ack is
1051*8044SWilliam.Kucharski@Sun.COM 	 *				sent.
1052*8044SWilliam.Kucharski@Sun.COM 	 *
1053*8044SWilliam.Kucharski@Sun.COM 	 *	This function receives 8 bits of data from the EEPROM
1054*8044SWilliam.Kucharski@Sun.COM 	 *	over the serial link.  It then sends and ack bit, or no
1055*8044SWilliam.Kucharski@Sun.COM 	 *	ack and a stop bit.  This function is used to retrieve
1056*8044SWilliam.Kucharski@Sun.COM 	 *	data after the address of a byte in the EEPROM has been
1057*8044SWilliam.Kucharski@Sun.COM 	 *	sent.
1058*8044SWilliam.Kucharski@Sun.COM 	 *
1059*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1060*8044SWilliam.Kucharski@Sun.COM 
1061*8044SWilliam.Kucharski@Sun.COM void TLan_EeReceiveByte(u16 io_base, u8 * data, int stop)
1062*8044SWilliam.Kucharski@Sun.COM {
1063*8044SWilliam.Kucharski@Sun.COM 	u8 place;
1064*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
1065*8044SWilliam.Kucharski@Sun.COM 
1066*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR);
1067*8044SWilliam.Kucharski@Sun.COM 	sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
1068*8044SWilliam.Kucharski@Sun.COM 	*data = 0;
1069*8044SWilliam.Kucharski@Sun.COM 
1070*8044SWilliam.Kucharski@Sun.COM 	/* Assume clock is low, tx is enabled; */
1071*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_ETXEN, sio);
1072*8044SWilliam.Kucharski@Sun.COM 	for (place = 0x80; place; place >>= 1) {
1073*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1074*8044SWilliam.Kucharski@Sun.COM 		if (TLan_GetBit(TLAN_NET_SIO_EDATA, sio))
1075*8044SWilliam.Kucharski@Sun.COM 			*data |= place;
1076*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
1077*8044SWilliam.Kucharski@Sun.COM 	}
1078*8044SWilliam.Kucharski@Sun.COM 
1079*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_ETXEN, sio);
1080*8044SWilliam.Kucharski@Sun.COM 	if (!stop) {
1081*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* Ack = 0 */
1082*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1083*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
1084*8044SWilliam.Kucharski@Sun.COM 	} else {
1085*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);	/* No ack = 1 (?) */
1086*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1087*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_ECLOK, sio);
1088*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_EDATA, sio);	/* STOP, raise data while clock is high */
1089*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_ECLOK, sio);
1090*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_EDATA, sio);
1091*8044SWilliam.Kucharski@Sun.COM 	}
1092*8044SWilliam.Kucharski@Sun.COM 
1093*8044SWilliam.Kucharski@Sun.COM }				/* TLan_EeReceiveByte */
1094*8044SWilliam.Kucharski@Sun.COM 
1095*8044SWilliam.Kucharski@Sun.COM 
1096*8044SWilliam.Kucharski@Sun.COM 
1097*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1098*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_EeReadByte
1099*8044SWilliam.Kucharski@Sun.COM 	 *
1100*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1101*8044SWilliam.Kucharski@Sun.COM 	 *		No error = 0, else, the stage at which the error
1102*8044SWilliam.Kucharski@Sun.COM 	 *		occurred.
1103*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1104*8044SWilliam.Kucharski@Sun.COM 	 *		io_base		The IO port base address for the
1105*8044SWilliam.Kucharski@Sun.COM 	 *				TLAN device with the EEPROM to
1106*8044SWilliam.Kucharski@Sun.COM 	 *				use.
1107*8044SWilliam.Kucharski@Sun.COM 	 *		ee_addr		The address of the byte in the
1108*8044SWilliam.Kucharski@Sun.COM 	 *				EEPROM whose contents are to be
1109*8044SWilliam.Kucharski@Sun.COM 	 *				retrieved.
1110*8044SWilliam.Kucharski@Sun.COM 	 *		data		An address to a char to hold the
1111*8044SWilliam.Kucharski@Sun.COM 	 *				data obtained from the EEPROM.
1112*8044SWilliam.Kucharski@Sun.COM 	 *
1113*8044SWilliam.Kucharski@Sun.COM 	 *	This function reads a byte of information from an byte
1114*8044SWilliam.Kucharski@Sun.COM 	 *	cell in the EEPROM.
1115*8044SWilliam.Kucharski@Sun.COM 	 *
1116*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1117*8044SWilliam.Kucharski@Sun.COM 
1118*8044SWilliam.Kucharski@Sun.COM int TLan_EeReadByte(u16 io_base, u8 ee_addr, u8 * data)
1119*8044SWilliam.Kucharski@Sun.COM {
1120*8044SWilliam.Kucharski@Sun.COM 	int err;
1121*8044SWilliam.Kucharski@Sun.COM 	int ret = 0;
1122*8044SWilliam.Kucharski@Sun.COM 
1123*8044SWilliam.Kucharski@Sun.COM 
1124*8044SWilliam.Kucharski@Sun.COM 	TLan_EeSendStart(io_base);
1125*8044SWilliam.Kucharski@Sun.COM 	err = TLan_EeSendByte(io_base, 0xA0, TLAN_EEPROM_ACK);
1126*8044SWilliam.Kucharski@Sun.COM 	if (err) {
1127*8044SWilliam.Kucharski@Sun.COM 		ret = 1;
1128*8044SWilliam.Kucharski@Sun.COM 		goto fail;
1129*8044SWilliam.Kucharski@Sun.COM 	}
1130*8044SWilliam.Kucharski@Sun.COM 	err = TLan_EeSendByte(io_base, ee_addr, TLAN_EEPROM_ACK);
1131*8044SWilliam.Kucharski@Sun.COM 	if (err) {
1132*8044SWilliam.Kucharski@Sun.COM 		ret = 2;
1133*8044SWilliam.Kucharski@Sun.COM 		goto fail;
1134*8044SWilliam.Kucharski@Sun.COM 	}
1135*8044SWilliam.Kucharski@Sun.COM 	TLan_EeSendStart(io_base);
1136*8044SWilliam.Kucharski@Sun.COM 	err = TLan_EeSendByte(io_base, 0xA1, TLAN_EEPROM_ACK);
1137*8044SWilliam.Kucharski@Sun.COM 	if (err) {
1138*8044SWilliam.Kucharski@Sun.COM 		ret = 3;
1139*8044SWilliam.Kucharski@Sun.COM 		goto fail;
1140*8044SWilliam.Kucharski@Sun.COM 	}
1141*8044SWilliam.Kucharski@Sun.COM 	TLan_EeReceiveByte(io_base, data, TLAN_EEPROM_STOP);
1142*8044SWilliam.Kucharski@Sun.COM       fail:
1143*8044SWilliam.Kucharski@Sun.COM 
1144*8044SWilliam.Kucharski@Sun.COM 	return ret;
1145*8044SWilliam.Kucharski@Sun.COM 
1146*8044SWilliam.Kucharski@Sun.COM }				/* TLan_EeReadByte */
1147*8044SWilliam.Kucharski@Sun.COM 
1148*8044SWilliam.Kucharski@Sun.COM 
1149*8044SWilliam.Kucharski@Sun.COM /*****************************************************************************
1150*8044SWilliam.Kucharski@Sun.COM ******************************************************************************
1151*8044SWilliam.Kucharski@Sun.COM 
1152*8044SWilliam.Kucharski@Sun.COM 	ThunderLAN Driver MII Routines
1153*8044SWilliam.Kucharski@Sun.COM 
1154*8044SWilliam.Kucharski@Sun.COM 	These routines are based on the information in Chap. 2 of the
1155*8044SWilliam.Kucharski@Sun.COM 	"ThunderLAN Programmer's Guide", pp. 15-24.
1156*8044SWilliam.Kucharski@Sun.COM 
1157*8044SWilliam.Kucharski@Sun.COM ******************************************************************************
1158*8044SWilliam.Kucharski@Sun.COM *****************************************************************************/
1159*8044SWilliam.Kucharski@Sun.COM 
1160*8044SWilliam.Kucharski@Sun.COM 
1161*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1162*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_MiiReadReg
1163*8044SWilliam.Kucharski@Sun.COM 	 *
1164*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1165*8044SWilliam.Kucharski@Sun.COM 	 *		0	if ack received ok
1166*8044SWilliam.Kucharski@Sun.COM 	 *		1	otherwise.
1167*8044SWilliam.Kucharski@Sun.COM 	 *
1168*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1169*8044SWilliam.Kucharski@Sun.COM 	 *		dev		The device structure containing
1170*8044SWilliam.Kucharski@Sun.COM 	 *				The io address and interrupt count
1171*8044SWilliam.Kucharski@Sun.COM 	 *				for this device.
1172*8044SWilliam.Kucharski@Sun.COM 	 *		phy		The address of the PHY to be queried.
1173*8044SWilliam.Kucharski@Sun.COM 	 *		reg		The register whose contents are to be
1174*8044SWilliam.Kucharski@Sun.COM 	 *				retreived.
1175*8044SWilliam.Kucharski@Sun.COM 	 *		val		A pointer to a variable to store the
1176*8044SWilliam.Kucharski@Sun.COM 	 *				retrieved value.
1177*8044SWilliam.Kucharski@Sun.COM 	 *
1178*8044SWilliam.Kucharski@Sun.COM 	 *	This function uses the TLAN's MII bus to retreive the contents
1179*8044SWilliam.Kucharski@Sun.COM 	 *	of a given register on a PHY.  It sends the appropriate info
1180*8044SWilliam.Kucharski@Sun.COM 	 *	and then reads the 16-bit register value from the MII bus via
1181*8044SWilliam.Kucharski@Sun.COM 	 *	the TLAN SIO register.
1182*8044SWilliam.Kucharski@Sun.COM 	 *
1183*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1184*8044SWilliam.Kucharski@Sun.COM 
1185*8044SWilliam.Kucharski@Sun.COM int TLan_MiiReadReg(struct nic *nic __unused, u16 phy, u16 reg, u16 * val)
1186*8044SWilliam.Kucharski@Sun.COM {
1187*8044SWilliam.Kucharski@Sun.COM 	u8 nack;
1188*8044SWilliam.Kucharski@Sun.COM 	u16 sio, tmp;
1189*8044SWilliam.Kucharski@Sun.COM 	u32 i;
1190*8044SWilliam.Kucharski@Sun.COM 	int err;
1191*8044SWilliam.Kucharski@Sun.COM 	int minten;
1192*8044SWilliam.Kucharski@Sun.COM 
1193*8044SWilliam.Kucharski@Sun.COM 	err = FALSE;
1194*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
1195*8044SWilliam.Kucharski@Sun.COM 	sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
1196*8044SWilliam.Kucharski@Sun.COM 
1197*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1198*8044SWilliam.Kucharski@Sun.COM 
1199*8044SWilliam.Kucharski@Sun.COM 	minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
1200*8044SWilliam.Kucharski@Sun.COM 	if (minten)
1201*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
1202*8044SWilliam.Kucharski@Sun.COM 
1203*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, 0x1, 2);	/* Start ( 01b ) */
1204*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, 0x2, 2);	/* Read  ( 10b ) */
1205*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, phy, 5);	/* Device #      */
1206*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, reg, 5);	/* Register #    */
1207*8044SWilliam.Kucharski@Sun.COM 
1208*8044SWilliam.Kucharski@Sun.COM 
1209*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);	/* Change direction */
1210*8044SWilliam.Kucharski@Sun.COM 
1211*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Clock Idle bit */
1212*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1213*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Wait 300ns */
1214*8044SWilliam.Kucharski@Sun.COM 
1215*8044SWilliam.Kucharski@Sun.COM 	nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio);	/* Check for ACK */
1216*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);	/* Finish ACK */
1217*8044SWilliam.Kucharski@Sun.COM 	if (nack) {		/* No ACK, so fake it */
1218*8044SWilliam.Kucharski@Sun.COM 		for (i = 0; i < 16; i++) {
1219*8044SWilliam.Kucharski@Sun.COM 			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
1220*8044SWilliam.Kucharski@Sun.COM 			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1221*8044SWilliam.Kucharski@Sun.COM 		}
1222*8044SWilliam.Kucharski@Sun.COM 		tmp = 0xffff;
1223*8044SWilliam.Kucharski@Sun.COM 		err = TRUE;
1224*8044SWilliam.Kucharski@Sun.COM 	} else {		/* ACK, so read data */
1225*8044SWilliam.Kucharski@Sun.COM 		for (tmp = 0, i = 0x8000; i; i >>= 1) {
1226*8044SWilliam.Kucharski@Sun.COM 			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
1227*8044SWilliam.Kucharski@Sun.COM 			if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio))
1228*8044SWilliam.Kucharski@Sun.COM 				tmp |= i;
1229*8044SWilliam.Kucharski@Sun.COM 			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1230*8044SWilliam.Kucharski@Sun.COM 		}
1231*8044SWilliam.Kucharski@Sun.COM 	}
1232*8044SWilliam.Kucharski@Sun.COM 
1233*8044SWilliam.Kucharski@Sun.COM 
1234*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Idle cycle */
1235*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1236*8044SWilliam.Kucharski@Sun.COM 
1237*8044SWilliam.Kucharski@Sun.COM 	if (minten)
1238*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
1239*8044SWilliam.Kucharski@Sun.COM 
1240*8044SWilliam.Kucharski@Sun.COM 	*val = tmp;
1241*8044SWilliam.Kucharski@Sun.COM 
1242*8044SWilliam.Kucharski@Sun.COM 	return err;
1243*8044SWilliam.Kucharski@Sun.COM 
1244*8044SWilliam.Kucharski@Sun.COM }				/* TLan_MiiReadReg */
1245*8044SWilliam.Kucharski@Sun.COM 
1246*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1247*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_MiiSendData
1248*8044SWilliam.Kucharski@Sun.COM 	 *
1249*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1250*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1251*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1252*8044SWilliam.Kucharski@Sun.COM 	 *		base_port	The base IO port of the adapter	in
1253*8044SWilliam.Kucharski@Sun.COM 	 *				question.
1254*8044SWilliam.Kucharski@Sun.COM 	 *		dev		The address of the PHY to be queried.
1255*8044SWilliam.Kucharski@Sun.COM 	 *		data		The value to be placed on the MII bus.
1256*8044SWilliam.Kucharski@Sun.COM 	 *		num_bits	The number of bits in data that are to
1257*8044SWilliam.Kucharski@Sun.COM 	 *				be placed on the MII bus.
1258*8044SWilliam.Kucharski@Sun.COM 	 *
1259*8044SWilliam.Kucharski@Sun.COM 	 *	This function sends on sequence of bits on the MII
1260*8044SWilliam.Kucharski@Sun.COM 	 *	configuration bus.
1261*8044SWilliam.Kucharski@Sun.COM 	 *
1262*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1263*8044SWilliam.Kucharski@Sun.COM 
1264*8044SWilliam.Kucharski@Sun.COM void TLan_MiiSendData(u16 base_port, u32 data, unsigned num_bits)
1265*8044SWilliam.Kucharski@Sun.COM {
1266*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
1267*8044SWilliam.Kucharski@Sun.COM 	u32 i;
1268*8044SWilliam.Kucharski@Sun.COM 
1269*8044SWilliam.Kucharski@Sun.COM 	if (num_bits == 0)
1270*8044SWilliam.Kucharski@Sun.COM 		return;
1271*8044SWilliam.Kucharski@Sun.COM 
1272*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
1273*8044SWilliam.Kucharski@Sun.COM 	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
1274*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_MTXEN, sio);
1275*8044SWilliam.Kucharski@Sun.COM 
1276*8044SWilliam.Kucharski@Sun.COM 	for (i = (0x1 << (num_bits - 1)); i; i >>= 1) {
1277*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
1278*8044SWilliam.Kucharski@Sun.COM 		(void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
1279*8044SWilliam.Kucharski@Sun.COM 		if (data & i)
1280*8044SWilliam.Kucharski@Sun.COM 			TLan_SetBit(TLAN_NET_SIO_MDATA, sio);
1281*8044SWilliam.Kucharski@Sun.COM 		else
1282*8044SWilliam.Kucharski@Sun.COM 			TLan_ClearBit(TLAN_NET_SIO_MDATA, sio);
1283*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1284*8044SWilliam.Kucharski@Sun.COM 		(void) TLan_GetBit(TLAN_NET_SIO_MCLK, sio);
1285*8044SWilliam.Kucharski@Sun.COM 	}
1286*8044SWilliam.Kucharski@Sun.COM 
1287*8044SWilliam.Kucharski@Sun.COM }				/* TLan_MiiSendData */
1288*8044SWilliam.Kucharski@Sun.COM 
1289*8044SWilliam.Kucharski@Sun.COM 
1290*8044SWilliam.Kucharski@Sun.COM 
1291*8044SWilliam.Kucharski@Sun.COM 
1292*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1293*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_MiiSync
1294*8044SWilliam.Kucharski@Sun.COM 	 *
1295*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1296*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1297*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1298*8044SWilliam.Kucharski@Sun.COM 	 *		base_port	The base IO port of the adapter in
1299*8044SWilliam.Kucharski@Sun.COM 	 *				question.
1300*8044SWilliam.Kucharski@Sun.COM 	 *
1301*8044SWilliam.Kucharski@Sun.COM 	 *	This functions syncs all PHYs in terms of the MII configuration
1302*8044SWilliam.Kucharski@Sun.COM 	 *	bus.
1303*8044SWilliam.Kucharski@Sun.COM 	 *
1304*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1305*8044SWilliam.Kucharski@Sun.COM 
1306*8044SWilliam.Kucharski@Sun.COM void TLan_MiiSync(u16 base_port)
1307*8044SWilliam.Kucharski@Sun.COM {
1308*8044SWilliam.Kucharski@Sun.COM 	int i;
1309*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
1310*8044SWilliam.Kucharski@Sun.COM 
1311*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
1312*8044SWilliam.Kucharski@Sun.COM 	sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
1313*8044SWilliam.Kucharski@Sun.COM 
1314*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);
1315*8044SWilliam.Kucharski@Sun.COM 	for (i = 0; i < 32; i++) {
1316*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
1317*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1318*8044SWilliam.Kucharski@Sun.COM 	}
1319*8044SWilliam.Kucharski@Sun.COM 
1320*8044SWilliam.Kucharski@Sun.COM }				/* TLan_MiiSync */
1321*8044SWilliam.Kucharski@Sun.COM 
1322*8044SWilliam.Kucharski@Sun.COM 
1323*8044SWilliam.Kucharski@Sun.COM 
1324*8044SWilliam.Kucharski@Sun.COM 
1325*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1326*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_MiiWriteReg
1327*8044SWilliam.Kucharski@Sun.COM 	 *
1328*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1329*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1330*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1331*8044SWilliam.Kucharski@Sun.COM 	 *		dev		The device structure for the device
1332*8044SWilliam.Kucharski@Sun.COM 	 *				to write to.
1333*8044SWilliam.Kucharski@Sun.COM 	 *		phy		The address of the PHY to be written to.
1334*8044SWilliam.Kucharski@Sun.COM 	 *		reg		The register whose contents are to be
1335*8044SWilliam.Kucharski@Sun.COM 	 *				written.
1336*8044SWilliam.Kucharski@Sun.COM 	 *		val		The value to be written to the register.
1337*8044SWilliam.Kucharski@Sun.COM 	 *
1338*8044SWilliam.Kucharski@Sun.COM 	 *	This function uses the TLAN's MII bus to write the contents of a
1339*8044SWilliam.Kucharski@Sun.COM 	 *	given register on a PHY.  It sends the appropriate info and then
1340*8044SWilliam.Kucharski@Sun.COM 	 *	writes the 16-bit register value from the MII configuration bus
1341*8044SWilliam.Kucharski@Sun.COM 	 *	via the TLAN SIO register.
1342*8044SWilliam.Kucharski@Sun.COM 	 *
1343*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1344*8044SWilliam.Kucharski@Sun.COM 
1345*8044SWilliam.Kucharski@Sun.COM void TLan_MiiWriteReg(struct nic *nic __unused, u16 phy, u16 reg, u16 val)
1346*8044SWilliam.Kucharski@Sun.COM {
1347*8044SWilliam.Kucharski@Sun.COM 	u16 sio;
1348*8044SWilliam.Kucharski@Sun.COM 	int minten;
1349*8044SWilliam.Kucharski@Sun.COM 
1350*8044SWilliam.Kucharski@Sun.COM 	outw(TLAN_NET_SIO, BASE + TLAN_DIO_ADR);
1351*8044SWilliam.Kucharski@Sun.COM 	sio = BASE + TLAN_DIO_DATA + TLAN_NET_SIO;
1352*8044SWilliam.Kucharski@Sun.COM 
1353*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1354*8044SWilliam.Kucharski@Sun.COM 
1355*8044SWilliam.Kucharski@Sun.COM 	minten = TLan_GetBit(TLAN_NET_SIO_MINTEN, sio);
1356*8044SWilliam.Kucharski@Sun.COM 	if (minten)
1357*8044SWilliam.Kucharski@Sun.COM 		TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);
1358*8044SWilliam.Kucharski@Sun.COM 
1359*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, 0x1, 2);	/* Start ( 01b ) */
1360*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, 0x1, 2);	/* Write ( 01b ) */
1361*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, phy, 5);	/* Device #      */
1362*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, reg, 5);	/* Register #    */
1363*8044SWilliam.Kucharski@Sun.COM 
1364*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, 0x2, 2);	/* Send ACK */
1365*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSendData(BASE, val, 16);	/* Send Data */
1366*8044SWilliam.Kucharski@Sun.COM 
1367*8044SWilliam.Kucharski@Sun.COM 	TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);	/* Idle cycle */
1368*8044SWilliam.Kucharski@Sun.COM 	TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
1369*8044SWilliam.Kucharski@Sun.COM 
1370*8044SWilliam.Kucharski@Sun.COM 	if (minten)
1371*8044SWilliam.Kucharski@Sun.COM 		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
1372*8044SWilliam.Kucharski@Sun.COM 
1373*8044SWilliam.Kucharski@Sun.COM 
1374*8044SWilliam.Kucharski@Sun.COM }				/* TLan_MiiWriteReg */
1375*8044SWilliam.Kucharski@Sun.COM 
1376*8044SWilliam.Kucharski@Sun.COM 	/***************************************************************
1377*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_SetMac
1378*8044SWilliam.Kucharski@Sun.COM 	 *
1379*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1380*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1381*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1382*8044SWilliam.Kucharski@Sun.COM 	 *		dev	Pointer to device structure of adapter
1383*8044SWilliam.Kucharski@Sun.COM 	 *			on which to change the AREG.
1384*8044SWilliam.Kucharski@Sun.COM 	 *		areg	The AREG to set the address in (0 - 3).
1385*8044SWilliam.Kucharski@Sun.COM 	 *		mac	A pointer to an array of chars.  Each
1386*8044SWilliam.Kucharski@Sun.COM 	 *			element stores one byte of the address.
1387*8044SWilliam.Kucharski@Sun.COM 	 *			IE, it isn't in ascii.
1388*8044SWilliam.Kucharski@Sun.COM 	 *
1389*8044SWilliam.Kucharski@Sun.COM 	 *	This function transfers a MAC address to one of the
1390*8044SWilliam.Kucharski@Sun.COM 	 *	TLAN AREGs (address registers).  The TLAN chip locks
1391*8044SWilliam.Kucharski@Sun.COM 	 *	the register on writing to offset 0 and unlocks the
1392*8044SWilliam.Kucharski@Sun.COM 	 *	register after writing to offset 5.  If NULL is passed
1393*8044SWilliam.Kucharski@Sun.COM 	 *	in mac, then the AREG is filled with 0's.
1394*8044SWilliam.Kucharski@Sun.COM 	 *
1395*8044SWilliam.Kucharski@Sun.COM 	 **************************************************************/
1396*8044SWilliam.Kucharski@Sun.COM 
1397*8044SWilliam.Kucharski@Sun.COM void TLan_SetMac(struct nic *nic __unused, int areg, char *mac)
1398*8044SWilliam.Kucharski@Sun.COM {
1399*8044SWilliam.Kucharski@Sun.COM 	int i;
1400*8044SWilliam.Kucharski@Sun.COM 
1401*8044SWilliam.Kucharski@Sun.COM 	areg *= 6;
1402*8044SWilliam.Kucharski@Sun.COM 
1403*8044SWilliam.Kucharski@Sun.COM 	if (mac != NULL) {
1404*8044SWilliam.Kucharski@Sun.COM 		for (i = 0; i < 6; i++)
1405*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i,
1406*8044SWilliam.Kucharski@Sun.COM 				       mac[i]);
1407*8044SWilliam.Kucharski@Sun.COM 	} else {
1408*8044SWilliam.Kucharski@Sun.COM 		for (i = 0; i < 6; i++)
1409*8044SWilliam.Kucharski@Sun.COM 			TLan_DioWrite8(BASE, TLAN_AREG_0 + areg + i, 0);
1410*8044SWilliam.Kucharski@Sun.COM 	}
1411*8044SWilliam.Kucharski@Sun.COM 
1412*8044SWilliam.Kucharski@Sun.COM }				/* TLan_SetMac */
1413*8044SWilliam.Kucharski@Sun.COM 
1414*8044SWilliam.Kucharski@Sun.COM 	/*********************************************************************
1415*8044SWilliam.Kucharski@Sun.COM 	 *	TLan_PhyDetect
1416*8044SWilliam.Kucharski@Sun.COM 	 *
1417*8044SWilliam.Kucharski@Sun.COM 	 *	Returns:
1418*8044SWilliam.Kucharski@Sun.COM 	 *		Nothing
1419*8044SWilliam.Kucharski@Sun.COM 	 *	Parms:
1420*8044SWilliam.Kucharski@Sun.COM 	 *		dev	A pointer to the device structure of the adapter
1421*8044SWilliam.Kucharski@Sun.COM 	 *			for which the PHY needs determined.
1422*8044SWilliam.Kucharski@Sun.COM 	 *
1423*8044SWilliam.Kucharski@Sun.COM 	 *	So far I've found that adapters which have external PHYs
1424*8044SWilliam.Kucharski@Sun.COM 	 *	may also use the internal PHY for part of the functionality.
1425*8044SWilliam.Kucharski@Sun.COM 	 *	(eg, AUI/Thinnet).  This function finds out if this TLAN
1426*8044SWilliam.Kucharski@Sun.COM 	 *	chip has an internal PHY, and then finds the first external
1427*8044SWilliam.Kucharski@Sun.COM 	 *	PHY (starting from address 0) if it exists).
1428*8044SWilliam.Kucharski@Sun.COM 	 *
1429*8044SWilliam.Kucharski@Sun.COM 	 ********************************************************************/
1430*8044SWilliam.Kucharski@Sun.COM 
1431*8044SWilliam.Kucharski@Sun.COM void TLan_PhyDetect(struct nic *nic)
1432*8044SWilliam.Kucharski@Sun.COM {
1433*8044SWilliam.Kucharski@Sun.COM 	u16 control;
1434*8044SWilliam.Kucharski@Sun.COM 	u16 hi;
1435*8044SWilliam.Kucharski@Sun.COM 	u16 lo;
1436*8044SWilliam.Kucharski@Sun.COM 	u32 phy;
1437*8044SWilliam.Kucharski@Sun.COM 
1438*8044SWilliam.Kucharski@Sun.COM 	if (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_UNMANAGED_PHY) {
1439*8044SWilliam.Kucharski@Sun.COM 		priv->phyNum = 0xFFFF;
1440*8044SWilliam.Kucharski@Sun.COM 		return;
1441*8044SWilliam.Kucharski@Sun.COM 	}
1442*8044SWilliam.Kucharski@Sun.COM 
1443*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi);
1444*8044SWilliam.Kucharski@Sun.COM 
1445*8044SWilliam.Kucharski@Sun.COM 	if (hi != 0xFFFF) {
1446*8044SWilliam.Kucharski@Sun.COM 		priv->phy[0] = TLAN_PHY_MAX_ADDR;
1447*8044SWilliam.Kucharski@Sun.COM 	} else {
1448*8044SWilliam.Kucharski@Sun.COM 		priv->phy[0] = TLAN_PHY_NONE;
1449*8044SWilliam.Kucharski@Sun.COM 	}
1450*8044SWilliam.Kucharski@Sun.COM 
1451*8044SWilliam.Kucharski@Sun.COM 	priv->phy[1] = TLAN_PHY_NONE;
1452*8044SWilliam.Kucharski@Sun.COM 	for (phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++) {
1453*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &control);
1454*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_ID_HI, &hi);
1455*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_ID_LO, &lo);
1456*8044SWilliam.Kucharski@Sun.COM 		if ((control != 0xFFFF) || (hi != 0xFFFF)
1457*8044SWilliam.Kucharski@Sun.COM 		    || (lo != 0xFFFF)) {
1458*8044SWilliam.Kucharski@Sun.COM 			printf("PHY found at %hX %hX %hX %hX\n", phy,
1459*8044SWilliam.Kucharski@Sun.COM 			       control, hi, lo);
1460*8044SWilliam.Kucharski@Sun.COM 			if ((priv->phy[1] == TLAN_PHY_NONE)
1461*8044SWilliam.Kucharski@Sun.COM 			    && (phy != TLAN_PHY_MAX_ADDR)) {
1462*8044SWilliam.Kucharski@Sun.COM 				priv->phy[1] = phy;
1463*8044SWilliam.Kucharski@Sun.COM 			}
1464*8044SWilliam.Kucharski@Sun.COM 		}
1465*8044SWilliam.Kucharski@Sun.COM 	}
1466*8044SWilliam.Kucharski@Sun.COM 
1467*8044SWilliam.Kucharski@Sun.COM 	if (priv->phy[1] != TLAN_PHY_NONE) {
1468*8044SWilliam.Kucharski@Sun.COM 		priv->phyNum = 1;
1469*8044SWilliam.Kucharski@Sun.COM 	} else if (priv->phy[0] != TLAN_PHY_NONE) {
1470*8044SWilliam.Kucharski@Sun.COM 		priv->phyNum = 0;
1471*8044SWilliam.Kucharski@Sun.COM 	} else {
1472*8044SWilliam.Kucharski@Sun.COM 		printf
1473*8044SWilliam.Kucharski@Sun.COM 		    ("TLAN:  Cannot initialize device, no PHY was found!\n");
1474*8044SWilliam.Kucharski@Sun.COM 	}
1475*8044SWilliam.Kucharski@Sun.COM 
1476*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyDetect */
1477*8044SWilliam.Kucharski@Sun.COM 
1478*8044SWilliam.Kucharski@Sun.COM void TLan_PhyPowerDown(struct nic *nic)
1479*8044SWilliam.Kucharski@Sun.COM {
1480*8044SWilliam.Kucharski@Sun.COM 
1481*8044SWilliam.Kucharski@Sun.COM 	u16 value;
1482*8044SWilliam.Kucharski@Sun.COM 	printf("%s: Powering down PHY(s).\n", priv->nic_name);
1483*8044SWilliam.Kucharski@Sun.COM 	value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
1484*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1485*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_GEN_CTL, value);
1486*8044SWilliam.Kucharski@Sun.COM 	if ((priv->phyNum == 0) && (priv->phy[1] != TLAN_PHY_NONE)
1487*8044SWilliam.Kucharski@Sun.COM 	    &&
1488*8044SWilliam.Kucharski@Sun.COM 	    (!(tlan_pci_tbl[chip_idx].
1489*8044SWilliam.Kucharski@Sun.COM 	       flags & TLAN_ADAPTER_USE_INTERN_10))) {
1490*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiSync(BASE);
1491*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiWriteReg(nic, priv->phy[1], MII_GEN_CTL, value);
1492*8044SWilliam.Kucharski@Sun.COM 	}
1493*8044SWilliam.Kucharski@Sun.COM 
1494*8044SWilliam.Kucharski@Sun.COM 	/* Wait for 50 ms and powerup
1495*8044SWilliam.Kucharski@Sun.COM 	 * This is abitrary.  It is intended to make sure the
1496*8044SWilliam.Kucharski@Sun.COM 	 * tranceiver settles.
1497*8044SWilliam.Kucharski@Sun.COM 	 */
1498*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); */
1499*8044SWilliam.Kucharski@Sun.COM 	mdelay(50);
1500*8044SWilliam.Kucharski@Sun.COM 	TLan_PhyPowerUp(nic);
1501*8044SWilliam.Kucharski@Sun.COM 
1502*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyPowerDown */
1503*8044SWilliam.Kucharski@Sun.COM 
1504*8044SWilliam.Kucharski@Sun.COM 
1505*8044SWilliam.Kucharski@Sun.COM void TLan_PhyPowerUp(struct nic *nic)
1506*8044SWilliam.Kucharski@Sun.COM {
1507*8044SWilliam.Kucharski@Sun.COM 	u16 value;
1508*8044SWilliam.Kucharski@Sun.COM 
1509*8044SWilliam.Kucharski@Sun.COM 	printf("%s: Powering up PHY.\n", priv->nic_name);
1510*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1511*8044SWilliam.Kucharski@Sun.COM 	value = MII_GC_LOOPBK;
1512*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiWriteReg(nic, priv->phy[priv->phyNum], MII_GEN_CTL, value);
1513*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1514*8044SWilliam.Kucharski@Sun.COM 	/* Wait for 500 ms and reset the
1515*8044SWilliam.Kucharski@Sun.COM 	 * tranceiver.  The TLAN docs say both 50 ms and
1516*8044SWilliam.Kucharski@Sun.COM 	 * 500 ms, so do the longer, just in case.
1517*8044SWilliam.Kucharski@Sun.COM 	 */
1518*8044SWilliam.Kucharski@Sun.COM 	mdelay(500);
1519*8044SWilliam.Kucharski@Sun.COM 	TLan_PhyReset(nic);
1520*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET ); */
1521*8044SWilliam.Kucharski@Sun.COM 
1522*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyPowerUp */
1523*8044SWilliam.Kucharski@Sun.COM 
1524*8044SWilliam.Kucharski@Sun.COM void TLan_PhyReset(struct nic *nic)
1525*8044SWilliam.Kucharski@Sun.COM {
1526*8044SWilliam.Kucharski@Sun.COM 	u16 phy;
1527*8044SWilliam.Kucharski@Sun.COM 	u16 value;
1528*8044SWilliam.Kucharski@Sun.COM 
1529*8044SWilliam.Kucharski@Sun.COM 	phy = priv->phy[priv->phyNum];
1530*8044SWilliam.Kucharski@Sun.COM 
1531*8044SWilliam.Kucharski@Sun.COM 	printf("%s: Reseting PHY.\n", priv->nic_name);
1532*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiSync(BASE);
1533*8044SWilliam.Kucharski@Sun.COM 	value = MII_GC_LOOPBK | MII_GC_RESET;
1534*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, value);
1535*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &value);
1536*8044SWilliam.Kucharski@Sun.COM 	while (value & MII_GC_RESET) {
1537*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, MII_GEN_CTL, &value);
1538*8044SWilliam.Kucharski@Sun.COM 	}
1539*8044SWilliam.Kucharski@Sun.COM 
1540*8044SWilliam.Kucharski@Sun.COM 	/* Wait for 500 ms and initialize.
1541*8044SWilliam.Kucharski@Sun.COM 	 * I don't remember why I wait this long.
1542*8044SWilliam.Kucharski@Sun.COM 	 * I've changed this to 50ms, as it seems long enough.
1543*8044SWilliam.Kucharski@Sun.COM 	 */
1544*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK ); */
1545*8044SWilliam.Kucharski@Sun.COM 	mdelay(50);
1546*8044SWilliam.Kucharski@Sun.COM 	TLan_PhyStartLink(nic);
1547*8044SWilliam.Kucharski@Sun.COM 
1548*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyReset */
1549*8044SWilliam.Kucharski@Sun.COM 
1550*8044SWilliam.Kucharski@Sun.COM 
1551*8044SWilliam.Kucharski@Sun.COM void TLan_PhyStartLink(struct nic *nic)
1552*8044SWilliam.Kucharski@Sun.COM {
1553*8044SWilliam.Kucharski@Sun.COM 
1554*8044SWilliam.Kucharski@Sun.COM 	u16 ability;
1555*8044SWilliam.Kucharski@Sun.COM 	u16 control;
1556*8044SWilliam.Kucharski@Sun.COM 	u16 data;
1557*8044SWilliam.Kucharski@Sun.COM 	u16 phy;
1558*8044SWilliam.Kucharski@Sun.COM 	u16 status;
1559*8044SWilliam.Kucharski@Sun.COM 	u16 tctl;
1560*8044SWilliam.Kucharski@Sun.COM 
1561*8044SWilliam.Kucharski@Sun.COM 	phy = priv->phy[priv->phyNum];
1562*8044SWilliam.Kucharski@Sun.COM 	printf("%s: Trying to activate link.\n", priv->nic_name);
1563*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
1564*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_STS, &ability);
1565*8044SWilliam.Kucharski@Sun.COM 
1566*8044SWilliam.Kucharski@Sun.COM 	if ((status & MII_GS_AUTONEG) && (!priv->aui)) {
1567*8044SWilliam.Kucharski@Sun.COM 		ability = status >> 11;
1568*8044SWilliam.Kucharski@Sun.COM 		if (priv->speed == TLAN_SPEED_10 &&
1569*8044SWilliam.Kucharski@Sun.COM 		    priv->duplex == TLAN_DUPLEX_HALF) {
1570*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x0000);
1571*8044SWilliam.Kucharski@Sun.COM 		} else if (priv->speed == TLAN_SPEED_10 &&
1572*8044SWilliam.Kucharski@Sun.COM 			   priv->duplex == TLAN_DUPLEX_FULL) {
1573*8044SWilliam.Kucharski@Sun.COM 			priv->tlanFullDuplex = TRUE;
1574*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x0100);
1575*8044SWilliam.Kucharski@Sun.COM 		} else if (priv->speed == TLAN_SPEED_100 &&
1576*8044SWilliam.Kucharski@Sun.COM 			   priv->duplex == TLAN_DUPLEX_HALF) {
1577*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x2000);
1578*8044SWilliam.Kucharski@Sun.COM 		} else if (priv->speed == TLAN_SPEED_100 &&
1579*8044SWilliam.Kucharski@Sun.COM 			   priv->duplex == TLAN_DUPLEX_FULL) {
1580*8044SWilliam.Kucharski@Sun.COM 			priv->tlanFullDuplex = TRUE;
1581*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x2100);
1582*8044SWilliam.Kucharski@Sun.COM 		} else {
1583*8044SWilliam.Kucharski@Sun.COM 
1584*8044SWilliam.Kucharski@Sun.COM 			/* Set Auto-Neg advertisement */
1585*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_AN_ADV,
1586*8044SWilliam.Kucharski@Sun.COM 					 (ability << 5) | 1);
1587*8044SWilliam.Kucharski@Sun.COM 			/* Enablee Auto-Neg */
1588*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x1000);
1589*8044SWilliam.Kucharski@Sun.COM 			/* Restart Auto-Neg */
1590*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, 0x1200);
1591*8044SWilliam.Kucharski@Sun.COM 			/* Wait for 4 sec for autonegotiation
1592*8044SWilliam.Kucharski@Sun.COM 			 * to complete.  The max spec time is less than this
1593*8044SWilliam.Kucharski@Sun.COM 			 * but the card need additional time to start AN.
1594*8044SWilliam.Kucharski@Sun.COM 			 * .5 sec should be plenty extra.
1595*8044SWilliam.Kucharski@Sun.COM 			 */
1596*8044SWilliam.Kucharski@Sun.COM 			printf("TLAN: %s: Starting autonegotiation.\n",
1597*8044SWilliam.Kucharski@Sun.COM 			       priv->nic_name);
1598*8044SWilliam.Kucharski@Sun.COM 			mdelay(4000);
1599*8044SWilliam.Kucharski@Sun.COM 			TLan_PhyFinishAutoNeg(nic);
1600*8044SWilliam.Kucharski@Sun.COM 			/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
1601*8044SWilliam.Kucharski@Sun.COM 			return;
1602*8044SWilliam.Kucharski@Sun.COM 		}
1603*8044SWilliam.Kucharski@Sun.COM 
1604*8044SWilliam.Kucharski@Sun.COM 	}
1605*8044SWilliam.Kucharski@Sun.COM 
1606*8044SWilliam.Kucharski@Sun.COM 	if ((priv->aui) && (priv->phyNum != 0)) {
1607*8044SWilliam.Kucharski@Sun.COM 		priv->phyNum = 0;
1608*8044SWilliam.Kucharski@Sun.COM 		data =
1609*8044SWilliam.Kucharski@Sun.COM 		    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
1610*8044SWilliam.Kucharski@Sun.COM 		    TLAN_NET_CFG_PHY_EN;
1611*8044SWilliam.Kucharski@Sun.COM 		TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
1612*8044SWilliam.Kucharski@Sun.COM 		mdelay(50);
1613*8044SWilliam.Kucharski@Sun.COM 		/* TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
1614*8044SWilliam.Kucharski@Sun.COM 		TLan_PhyPowerDown(nic);
1615*8044SWilliam.Kucharski@Sun.COM 		return;
1616*8044SWilliam.Kucharski@Sun.COM 	} else if (priv->phyNum == 0) {
1617*8044SWilliam.Kucharski@Sun.COM 		control = 0;
1618*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiReadReg(nic, phy, TLAN_TLPHY_CTL, &tctl);
1619*8044SWilliam.Kucharski@Sun.COM 		if (priv->aui) {
1620*8044SWilliam.Kucharski@Sun.COM 			tctl |= TLAN_TC_AUISEL;
1621*8044SWilliam.Kucharski@Sun.COM 		} else {
1622*8044SWilliam.Kucharski@Sun.COM 			tctl &= ~TLAN_TC_AUISEL;
1623*8044SWilliam.Kucharski@Sun.COM 			if (priv->duplex == TLAN_DUPLEX_FULL) {
1624*8044SWilliam.Kucharski@Sun.COM 				control |= MII_GC_DUPLEX;
1625*8044SWilliam.Kucharski@Sun.COM 				priv->tlanFullDuplex = TRUE;
1626*8044SWilliam.Kucharski@Sun.COM 			}
1627*8044SWilliam.Kucharski@Sun.COM 			if (priv->speed == TLAN_SPEED_100) {
1628*8044SWilliam.Kucharski@Sun.COM 				control |= MII_GC_SPEEDSEL;
1629*8044SWilliam.Kucharski@Sun.COM 			}
1630*8044SWilliam.Kucharski@Sun.COM 		}
1631*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiWriteReg(nic, phy, MII_GEN_CTL, control);
1632*8044SWilliam.Kucharski@Sun.COM 		TLan_MiiWriteReg(nic, phy, TLAN_TLPHY_CTL, tctl);
1633*8044SWilliam.Kucharski@Sun.COM 	}
1634*8044SWilliam.Kucharski@Sun.COM 
1635*8044SWilliam.Kucharski@Sun.COM 	/* Wait for 2 sec to give the tranceiver time
1636*8044SWilliam.Kucharski@Sun.COM 	 * to establish link.
1637*8044SWilliam.Kucharski@Sun.COM 	 */
1638*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET ); */
1639*8044SWilliam.Kucharski@Sun.COM 	mdelay(2000);
1640*8044SWilliam.Kucharski@Sun.COM 	TLan_FinishReset(nic);
1641*8044SWilliam.Kucharski@Sun.COM 
1642*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyStartLink */
1643*8044SWilliam.Kucharski@Sun.COM 
1644*8044SWilliam.Kucharski@Sun.COM void TLan_PhyFinishAutoNeg(struct nic *nic)
1645*8044SWilliam.Kucharski@Sun.COM {
1646*8044SWilliam.Kucharski@Sun.COM 
1647*8044SWilliam.Kucharski@Sun.COM 	u16 an_adv;
1648*8044SWilliam.Kucharski@Sun.COM 	u16 an_lpa;
1649*8044SWilliam.Kucharski@Sun.COM 	u16 data;
1650*8044SWilliam.Kucharski@Sun.COM 	u16 mode;
1651*8044SWilliam.Kucharski@Sun.COM 	u16 phy;
1652*8044SWilliam.Kucharski@Sun.COM 	u16 status;
1653*8044SWilliam.Kucharski@Sun.COM 
1654*8044SWilliam.Kucharski@Sun.COM 	phy = priv->phy[priv->phyNum];
1655*8044SWilliam.Kucharski@Sun.COM 
1656*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
1657*8044SWilliam.Kucharski@Sun.COM 	udelay(1000);
1658*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_STS, &status);
1659*8044SWilliam.Kucharski@Sun.COM 
1660*8044SWilliam.Kucharski@Sun.COM 	if (!(status & MII_GS_AUTOCMPLT)) {
1661*8044SWilliam.Kucharski@Sun.COM 		/* Wait for 8 sec to give the process
1662*8044SWilliam.Kucharski@Sun.COM 		 * more time.  Perhaps we should fail after a while.
1663*8044SWilliam.Kucharski@Sun.COM 		 */
1664*8044SWilliam.Kucharski@Sun.COM 		if (!priv->neg_be_verbose++) {
1665*8044SWilliam.Kucharski@Sun.COM 			printf
1666*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  Giving autonegotiation more time.\n");
1667*8044SWilliam.Kucharski@Sun.COM 			printf
1668*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  Please check that your adapter has\n");
1669*8044SWilliam.Kucharski@Sun.COM 			printf
1670*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  been properly connected to a HUB or Switch.\n");
1671*8044SWilliam.Kucharski@Sun.COM 			printf
1672*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  Trying to establish link in the background...\n");
1673*8044SWilliam.Kucharski@Sun.COM 		}
1674*8044SWilliam.Kucharski@Sun.COM 		mdelay(8000);
1675*8044SWilliam.Kucharski@Sun.COM 		TLan_PhyFinishAutoNeg(nic);
1676*8044SWilliam.Kucharski@Sun.COM 		/* TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); */
1677*8044SWilliam.Kucharski@Sun.COM 		return;
1678*8044SWilliam.Kucharski@Sun.COM 	}
1679*8044SWilliam.Kucharski@Sun.COM 
1680*8044SWilliam.Kucharski@Sun.COM 	printf("TLAN: %s: Autonegotiation complete.\n", priv->nic_name);
1681*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_AN_ADV, &an_adv);
1682*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_AN_LPA, &an_lpa);
1683*8044SWilliam.Kucharski@Sun.COM 	mode = an_adv & an_lpa & 0x03E0;
1684*8044SWilliam.Kucharski@Sun.COM 	if (mode & 0x0100) {
1685*8044SWilliam.Kucharski@Sun.COM 		printf("Full Duplex\n");
1686*8044SWilliam.Kucharski@Sun.COM 		priv->tlanFullDuplex = TRUE;
1687*8044SWilliam.Kucharski@Sun.COM 	} else if (!(mode & 0x0080) && (mode & 0x0040)) {
1688*8044SWilliam.Kucharski@Sun.COM 		priv->tlanFullDuplex = TRUE;
1689*8044SWilliam.Kucharski@Sun.COM 		printf("Full Duplex\n");
1690*8044SWilliam.Kucharski@Sun.COM 	}
1691*8044SWilliam.Kucharski@Sun.COM 
1692*8044SWilliam.Kucharski@Sun.COM 	if ((!(mode & 0x0180))
1693*8044SWilliam.Kucharski@Sun.COM 	    && (tlan_pci_tbl[chip_idx].flags & TLAN_ADAPTER_USE_INTERN_10)
1694*8044SWilliam.Kucharski@Sun.COM 	    && (priv->phyNum != 0)) {
1695*8044SWilliam.Kucharski@Sun.COM 		priv->phyNum = 0;
1696*8044SWilliam.Kucharski@Sun.COM 		data =
1697*8044SWilliam.Kucharski@Sun.COM 		    TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN |
1698*8044SWilliam.Kucharski@Sun.COM 		    TLAN_NET_CFG_PHY_EN;
1699*8044SWilliam.Kucharski@Sun.COM 		TLan_DioWrite16(BASE, TLAN_NET_CONFIG, data);
1700*8044SWilliam.Kucharski@Sun.COM 		/* TLan_SetTimer( nic, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); */
1701*8044SWilliam.Kucharski@Sun.COM 		mdelay(400);
1702*8044SWilliam.Kucharski@Sun.COM 		TLan_PhyPowerDown(nic);
1703*8044SWilliam.Kucharski@Sun.COM 		return;
1704*8044SWilliam.Kucharski@Sun.COM 	}
1705*8044SWilliam.Kucharski@Sun.COM 
1706*8044SWilliam.Kucharski@Sun.COM 	if (priv->phyNum == 0) {
1707*8044SWilliam.Kucharski@Sun.COM 		if ((priv->duplex == TLAN_DUPLEX_FULL)
1708*8044SWilliam.Kucharski@Sun.COM 		    || (an_adv & an_lpa & 0x0040)) {
1709*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL,
1710*8044SWilliam.Kucharski@Sun.COM 					 MII_GC_AUTOENB | MII_GC_DUPLEX);
1711*8044SWilliam.Kucharski@Sun.COM 			printf
1712*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  Starting internal PHY with FULL-DUPLEX\n");
1713*8044SWilliam.Kucharski@Sun.COM 		} else {
1714*8044SWilliam.Kucharski@Sun.COM 			TLan_MiiWriteReg(nic, phy, MII_GEN_CTL,
1715*8044SWilliam.Kucharski@Sun.COM 					 MII_GC_AUTOENB);
1716*8044SWilliam.Kucharski@Sun.COM 			printf
1717*8044SWilliam.Kucharski@Sun.COM 			    ("TLAN:  Starting internal PHY with HALF-DUPLEX\n");
1718*8044SWilliam.Kucharski@Sun.COM 		}
1719*8044SWilliam.Kucharski@Sun.COM 	}
1720*8044SWilliam.Kucharski@Sun.COM 
1721*8044SWilliam.Kucharski@Sun.COM 	/* Wait for 100 ms.  No reason in partiticular.
1722*8044SWilliam.Kucharski@Sun.COM 	 */
1723*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); */
1724*8044SWilliam.Kucharski@Sun.COM 	mdelay(100);
1725*8044SWilliam.Kucharski@Sun.COM 	TLan_FinishReset(nic);
1726*8044SWilliam.Kucharski@Sun.COM 
1727*8044SWilliam.Kucharski@Sun.COM }				/* TLan_PhyFinishAutoNeg */
1728*8044SWilliam.Kucharski@Sun.COM 
1729*8044SWilliam.Kucharski@Sun.COM #ifdef MONITOR
1730*8044SWilliam.Kucharski@Sun.COM 
1731*8044SWilliam.Kucharski@Sun.COM 	/*********************************************************************
1732*8044SWilliam.Kucharski@Sun.COM         *
1733*8044SWilliam.Kucharski@Sun.COM         *      TLan_phyMonitor
1734*8044SWilliam.Kucharski@Sun.COM         *
1735*8044SWilliam.Kucharski@Sun.COM         *      Returns:
1736*8044SWilliam.Kucharski@Sun.COM         *              None
1737*8044SWilliam.Kucharski@Sun.COM         *
1738*8044SWilliam.Kucharski@Sun.COM         *      Params:
1739*8044SWilliam.Kucharski@Sun.COM         *              dev             The device structure of this device.
1740*8044SWilliam.Kucharski@Sun.COM         *
1741*8044SWilliam.Kucharski@Sun.COM         *
1742*8044SWilliam.Kucharski@Sun.COM         *      This function monitors PHY condition by reading the status
1743*8044SWilliam.Kucharski@Sun.COM         *      register via the MII bus. This can be used to give info
1744*8044SWilliam.Kucharski@Sun.COM         *      about link changes (up/down), and possible switch to alternate
1745*8044SWilliam.Kucharski@Sun.COM         *      media.
1746*8044SWilliam.Kucharski@Sun.COM         *
1747*8044SWilliam.Kucharski@Sun.COM         * ******************************************************************/
1748*8044SWilliam.Kucharski@Sun.COM 
1749*8044SWilliam.Kucharski@Sun.COM void TLan_PhyMonitor(struct net_device *dev)
1750*8044SWilliam.Kucharski@Sun.COM {
1751*8044SWilliam.Kucharski@Sun.COM 	TLanPrivateInfo *priv = dev->priv;
1752*8044SWilliam.Kucharski@Sun.COM 	u16 phy;
1753*8044SWilliam.Kucharski@Sun.COM 	u16 phy_status;
1754*8044SWilliam.Kucharski@Sun.COM 
1755*8044SWilliam.Kucharski@Sun.COM 	phy = priv->phy[priv->phyNum];
1756*8044SWilliam.Kucharski@Sun.COM 
1757*8044SWilliam.Kucharski@Sun.COM 	/* Get PHY status register */
1758*8044SWilliam.Kucharski@Sun.COM 	TLan_MiiReadReg(nic, phy, MII_GEN_STS, &phy_status);
1759*8044SWilliam.Kucharski@Sun.COM 
1760*8044SWilliam.Kucharski@Sun.COM 	/* Check if link has been lost */
1761*8044SWilliam.Kucharski@Sun.COM 	if (!(phy_status & MII_GS_LINK)) {
1762*8044SWilliam.Kucharski@Sun.COM 		if (priv->link) {
1763*8044SWilliam.Kucharski@Sun.COM 			priv->link = 0;
1764*8044SWilliam.Kucharski@Sun.COM 			printf("TLAN: %s has lost link\n", priv->nic_name);
1765*8044SWilliam.Kucharski@Sun.COM 			priv->flags &= ~IFF_RUNNING;
1766*8044SWilliam.Kucharski@Sun.COM 			mdelay(2000);
1767*8044SWilliam.Kucharski@Sun.COM 			TLan_PhyMonitor(nic);
1768*8044SWilliam.Kucharski@Sun.COM 			/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
1769*8044SWilliam.Kucharski@Sun.COM 			return;
1770*8044SWilliam.Kucharski@Sun.COM 		}
1771*8044SWilliam.Kucharski@Sun.COM 	}
1772*8044SWilliam.Kucharski@Sun.COM 
1773*8044SWilliam.Kucharski@Sun.COM 	/* Link restablished? */
1774*8044SWilliam.Kucharski@Sun.COM 	if ((phy_status & MII_GS_LINK) && !priv->link) {
1775*8044SWilliam.Kucharski@Sun.COM 		priv->link = 1;
1776*8044SWilliam.Kucharski@Sun.COM 		printf("TLAN: %s has reestablished link\n",
1777*8044SWilliam.Kucharski@Sun.COM 		       priv->nic_name);
1778*8044SWilliam.Kucharski@Sun.COM 		priv->flags |= IFF_RUNNING;
1779*8044SWilliam.Kucharski@Sun.COM 	}
1780*8044SWilliam.Kucharski@Sun.COM 
1781*8044SWilliam.Kucharski@Sun.COM 	/* Setup a new monitor */
1782*8044SWilliam.Kucharski@Sun.COM 	/* TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); */
1783*8044SWilliam.Kucharski@Sun.COM 	mdelay(2000);
1784*8044SWilliam.Kucharski@Sun.COM 	TLan_PhyMonitor(nic);
1785*8044SWilliam.Kucharski@Sun.COM }
1786*8044SWilliam.Kucharski@Sun.COM 
1787*8044SWilliam.Kucharski@Sun.COM #endif				/* MONITOR */
1788*8044SWilliam.Kucharski@Sun.COM 
1789*8044SWilliam.Kucharski@Sun.COM #ifdef EB51
1790*8044SWilliam.Kucharski@Sun.COM static struct pci_id tlan_nics[] = {
1791*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xae34, "netel10", "Compaq Netelligent 10 T PCI UTP"),
1792*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xae32, "netel100","Compaq Netelligent 10/100 TX PCI UTP"),
1793*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xae35, "netflex3i", "Compaq Integrated NetFlex-3/P"),
1794*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xf130, "thunder", "Compaq NetFlex-3/P"),
1795*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xf150, "netflex3b", "Compaq NetFlex-3/P"),
1796*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xae43, "netel100pi", "Compaq Netelligent Integrated 10/100 TX UTP"),
1797*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xae40, "netel100d", "Compaq Netelligent Dual 10/100 TX PCI UTP"),
1798*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xb011, "netel100i", "Compaq Netelligent 10/100 TX Embedded UTP"),
1799*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x108d, 0x0013, "oc2183", "Olicom OC-2183/2185"),
1800*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x108d, 0x0012, "oc2325", "Olicom OC-2325"),
1801*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x108d, 0x0014, "oc2326", "Olicom OC-2326"),
1802*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xb030, "netelligent_10_100_ws_5100", "Compaq Netelligent 10/100 TX UTP"),
1803*8044SWilliam.Kucharski@Sun.COM 	PCI_ROM(0x0e11, 0xb012, "netelligent_10_t2", "Compaq Netelligent 10 T/2 PCI UTP/Coax"),
1804*8044SWilliam.Kucharski@Sun.COM };
1805*8044SWilliam.Kucharski@Sun.COM 
1806*8044SWilliam.Kucharski@Sun.COM struct pci_driver tlan_driver = {
1807*8044SWilliam.Kucharski@Sun.COM 	.type = NIC_DRIVER,
1808*8044SWilliam.Kucharski@Sun.COM 	.name = "TLAN/PCI",
1809*8044SWilliam.Kucharski@Sun.COM 	.probe = tlan_probe,
1810*8044SWilliam.Kucharski@Sun.COM 	.ids = tlan_nics,
1811*8044SWilliam.Kucharski@Sun.COM 	.id_count = sizeof(tlan_nics) / sizeof(tlan_nics[0]),
1812*8044SWilliam.Kucharski@Sun.COM 	.class = 0,
1813*8044SWilliam.Kucharski@Sun.COM };
1814*8044SWilliam.Kucharski@Sun.COM #endif
1815