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