1 |
|
/* -*- Mode:C; c-basic-offset:4; -*- */ |
2 |
|
|
3 |
/* |
/* |
4 |
Tulip and clone Etherboot Driver |
Tulip and clone Etherboot Driver |
5 |
By Marty Connor (mdc@thinguin.org) |
|
6 |
This software may be used and distributed according to the terms |
By Marty Connor (mdc@thinguin.org) |
7 |
of the GNU Public License, incorporated herein by reference. |
Copyright (C) 2001 Entity Cyber, Inc. |
8 |
|
|
9 |
Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's |
This software may be used and distributed according to the terms |
10 |
Linux Tulip Driver. Supports N-Way speed auto-configuration on |
of the GNU Public License, incorporated herein by reference. |
11 |
MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards |
|
12 |
based on the Macronix MX987x5 chip, such as the SOHOware Fast |
As of April 2001 this driver should support most tulip cards that |
13 |
model SFA110A, and the LinkSYS model LNE100TX. The NetGear |
the Linux tulip driver supports because Donald Becker's Linux media |
14 |
model FA310X, based on the LC82C168 chip is supported. |
detection code is now included. |
15 |
The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD |
|
16 |
chipset is supported. |
Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's |
17 |
Also, Davicom DM9102's. |
Linux Tulip Driver. Supports N-Way speed auto-configuration on |
18 |
|
MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards |
19 |
Documentation and source code used: |
based on the Macronix MX987x5 chip, such as the SOHOware Fast |
20 |
Source for Etherboot driver at |
model SFA110A, and the LinkSYS model LNE100TX. The NetGear |
21 |
http://etherboot.sourceforge.net/ |
model FA310X, based on the LC82C168 chip is supported. |
22 |
MX98715A Data Sheet and MX98715A Application Note |
The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD |
23 |
on http://www.macronix.com/ (PDF format files) |
chipset is supported. Also, Davicom DM9102's. |
24 |
Source for Linux tulip driver at |
|
25 |
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html |
Documentation and source code used: |
26 |
|
Source for Etherboot driver at |
27 |
Adapted by Ken Yap from |
http://etherboot.sourceforge.net/ |
28 |
FreeBSD netboot DEC 21143 driver |
MX98715A Data Sheet and MX98715A Application Note |
29 |
Author: David Sharp |
on http://www.macronix.com/ (PDF format files) |
30 |
date: Nov/98 |
Source for Linux tulip driver at |
31 |
|
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html |
32 |
Some code fragments were taken from verious places, Ken Yap's |
|
33 |
etherboot, FreeBSD's if_de.c, and various Linux related files. |
Adapted by Ken Yap from |
34 |
DEC's manuals for the 21143 and SROM format were very helpful. |
FreeBSD netboot DEC 21143 driver |
35 |
The Linux de driver development page has a number of links to |
Author: David Sharp |
36 |
useful related information. Have a look at: |
date: Nov/98 |
37 |
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html |
|
38 |
|
Some code fragments were taken from verious places, Ken Yap's |
39 |
|
etherboot, FreeBSD's if_de.c, and various Linux related files. |
40 |
|
DEC's manuals for the 21143 and SROM format were very helpful. |
41 |
|
The Linux de driver development page has a number of links to |
42 |
|
useful related information. Have a look at: |
43 |
|
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html |
44 |
*/ |
*/ |
45 |
|
|
46 |
/*********************************************************************/ |
/*********************************************************************/ |
48 |
/*********************************************************************/ |
/*********************************************************************/ |
49 |
|
|
50 |
/* |
/* |
51 |
|
11 Apr 2001 mdc [patch to etherboot 4.7.24] |
52 |
|
Major rewrite to include Linux tulip driver media detection |
53 |
|
code. This driver should support a lot more cards now. |
54 |
16 Jul 2000 mdc 0.75b11 |
16 Jul 2000 mdc 0.75b11 |
55 |
Added support for ADMtek 0985 Centaur-P, a "Comet" tulip clone |
Added support for ADMtek 0985 Centaur-P, a "Comet" tulip clone |
56 |
which is used on the LinkSYS LNE100TX v4.x cards. We already |
which is used on the LinkSYS LNE100TX v4.x cards. We already |
57 |
support LNE100TX v2.0 cards, which use a different controller. |
support LNE100TX v2.0 cards, which use a different controller. |
58 |
04 Jul 2000 jam ? |
04 Jul 2000 jam ? |
59 |
Added test of status after receiving a packet from the card. |
Added test of status after receiving a packet from the card. |
60 |
Also uncommented the tulip_disable routine. Stray packets |
Also uncommented the tulip_disable routine. Stray packets |
61 |
seemed to be causing problems. |
seemed to be causing problems. |
62 |
27 Apr 2000 njl ? |
27 Apr 2000 njl ? |
63 |
29 Feb 2000 mdc 0.75b7 |
29 Feb 2000 mdc 0.75b7 |
64 |
Increased reset delay to 3 seconds because Macronix cards seem to |
Increased reset delay to 3 seconds because Macronix cards seem to |
65 |
need more reset time before card comes back to a usable state. |
need more reset time before card comes back to a usable state. |
108 |
#include "pci.h" |
#include "pci.h" |
109 |
#include "cards.h" |
#include "cards.h" |
110 |
|
|
111 |
#undef TULIP_DEBUG |
/* User settable parameters */ |
112 |
#undef TULIP_DEBUG_WHERE |
|
113 |
|
#undef TULIP_DEBUG |
114 |
|
#undef TULIP_DEBUG_WHERE |
115 |
|
static int tulip_debug = 2; /* 1 normal messages, 0 quiet .. 7 verbose. */ |
116 |
|
|
117 |
#define TX_TIME_OUT 2*TICKS_PER_SEC |
#define TX_TIME_OUT 2*TICKS_PER_SEC |
118 |
|
|
123 |
typedef unsigned int u32; |
typedef unsigned int u32; |
124 |
typedef signed int s32; |
typedef signed int s32; |
125 |
|
|
126 |
/* Register offsets for tulip device */ |
/* helpful macros if on a big_endian machine for changing byte order. |
127 |
|
not strictly needed on Intel */ |
128 |
|
#define le16_to_cpu(val) (val) |
129 |
|
#define cpu_to_le32(val) (val) |
130 |
|
#define get_unaligned(ptr) (*(ptr)) |
131 |
|
#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) |
132 |
|
#define get_u16(ptr) (*(u16 *)(ptr)) |
133 |
|
#define virt_to_bus(x) ((unsigned long)x) |
134 |
|
#define virt_to_le32desc(addr) virt_to_bus(addr) |
135 |
|
|
136 |
|
#define TULIP_IOTYPE PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0 |
137 |
|
#define TULIP_SIZE 0x80 |
138 |
|
|
139 |
|
/* This is a mysterious value that can be written to CSR11 in the 21040 (only) |
140 |
|
to support a pre-NWay full-duplex signaling mechanism using short frames. |
141 |
|
No one knows what it should be, but if left at its default value some |
142 |
|
10base2(!) packets trigger a full-duplex-request interrupt. */ |
143 |
|
#define FULL_DUPLEX_MAGIC 0x6969 |
144 |
|
|
145 |
|
static const int csr0 = 0x01A00000 | 0x8000; |
146 |
|
|
147 |
|
/* The possible media types that can be set in options[] are: */ |
148 |
|
#define MEDIA_MASK 31 |
149 |
|
static const char * const medianame[32] = { |
150 |
|
"10baseT", "10base2", "AUI", "100baseTx", |
151 |
|
"10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx", |
152 |
|
"100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII", |
153 |
|
"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4", |
154 |
|
"MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19", |
155 |
|
}; |
156 |
|
|
157 |
|
/* This much match tulip_tbl[]! Note 21142 == 21143. */ |
158 |
|
enum tulip_chips { |
159 |
|
DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, |
160 |
|
LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET, |
161 |
|
COMPEX9881, I21145, XIRCOM |
162 |
|
}; |
163 |
|
|
164 |
|
enum pci_id_flags_bits { |
165 |
|
/* Set PCI command register bits before calling probe1(). */ |
166 |
|
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, |
167 |
|
/* Read and map the single following PCI BAR. */ |
168 |
|
PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, |
169 |
|
PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, |
170 |
|
PCI_UNUSED_IRQ=0x800, |
171 |
|
}; |
172 |
|
|
173 |
|
struct pci_id_info { |
174 |
|
char *name; |
175 |
|
struct match_info { |
176 |
|
u32 pci, pci_mask, subsystem, subsystem_mask; |
177 |
|
u32 revision, revision_mask; /* Only 8 bits. */ |
178 |
|
} id; |
179 |
|
enum pci_id_flags_bits pci_flags; |
180 |
|
int io_size; /* Needed for I/O region check or ioremap(). */ |
181 |
|
int drv_flags; /* Driver use, intended as capability flags. */ |
182 |
|
}; |
183 |
|
|
184 |
|
static struct pci_id_info pci_id_tbl[] = { |
185 |
|
{ "Digital DC21040 Tulip", { 0x00021011, 0xffffffff, 0, 0, 0, 0 }, |
186 |
|
TULIP_IOTYPE, 0x80, DC21040 }, |
187 |
|
{ "Digital DC21041 Tulip", { 0x00141011, 0xffffffff, 0, 0, 0, 0 }, |
188 |
|
TULIP_IOTYPE, 0x80, DC21041 }, |
189 |
|
{ "Digital DS21140A Tulip", { 0x00091011, 0xffffffff, 0,0, 0x20,0xf0 }, |
190 |
|
TULIP_IOTYPE, 0x80, DC21140 }, |
191 |
|
{ "Digital DS21140 Tulip", { 0x00091011, 0xffffffff, 0, 0, 0, 0 }, |
192 |
|
TULIP_IOTYPE, 0x80, DC21140 }, |
193 |
|
{ "Digital DS21143 Tulip", { 0x00191011, 0xffffffff, 0,0, 65,0xff }, |
194 |
|
TULIP_IOTYPE, TULIP_SIZE, DC21142 }, |
195 |
|
{ "Digital DS21142 Tulip", { 0x00191011, 0xffffffff, 0, 0, 0, 0 }, |
196 |
|
TULIP_IOTYPE, TULIP_SIZE, DC21142 }, |
197 |
|
{ "Kingston KNE110tx (PNIC)", { 0x000211AD, 0xffffffff, 0xf0022646, 0xffffffff, 0, 0 }, |
198 |
|
TULIP_IOTYPE, 256, LC82C168 }, |
199 |
|
{ "Lite-On 82c168 PNIC", { 0x000211AD, 0xffffffff, 0, 0, 0, 0 }, |
200 |
|
TULIP_IOTYPE, 256, LC82C168 }, |
201 |
|
{ "Macronix 98713 PMAC", { 0x051210d9, 0xffffffff, 0, 0, 0, 0 }, |
202 |
|
TULIP_IOTYPE, 256, MX98713 }, |
203 |
|
{ "Macronix 98715 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 }, |
204 |
|
TULIP_IOTYPE, 256, MX98715 }, |
205 |
|
{ "Macronix 98725 PMAC", { 0x053110d9, 0xffffffff, 0, 0, 0, 0 }, |
206 |
|
TULIP_IOTYPE, 256, MX98725 }, |
207 |
|
{ "ASIX AX88141", { 0x1400125B, 0xffffffff, 0,0, 0x10, 0xf0 }, |
208 |
|
TULIP_IOTYPE, 128, AX88141 }, |
209 |
|
{ "ASIX AX88140", { 0x1400125B, 0xffffffff, 0, 0, 0, 0 }, |
210 |
|
TULIP_IOTYPE, 128, AX88140 }, |
211 |
|
{ "Lite-On LC82C115 PNIC-II", { 0xc11511AD, 0xffffffff, 0, 0, 0, 0 }, |
212 |
|
TULIP_IOTYPE, 256, PNIC2 }, |
213 |
|
{ "ADMtek AN981 Comet", { 0x09811317, 0xffffffff, 0, 0, 0, 0 }, |
214 |
|
TULIP_IOTYPE, 256, COMET }, |
215 |
|
{ "ADMtek Centaur-P", { 0x09851317, 0xffffffff, 0, 0, 0, 0 }, |
216 |
|
TULIP_IOTYPE, 256, COMET }, |
217 |
|
{ "ADMtek Centaur-C", { 0x19851317, 0xffffffff, 0, 0, 0, 0 }, |
218 |
|
TULIP_IOTYPE, 256, COMET }, |
219 |
|
{ "Compex RL100-TX", { 0x988111F6, 0xffffffff, 0, 0, 0, 0 }, |
220 |
|
TULIP_IOTYPE, 128, COMPEX9881 }, |
221 |
|
{ "Intel 21145 Tulip", { 0x00398086, 0xffffffff, 0, 0, 0, 0 }, |
222 |
|
TULIP_IOTYPE, 128, I21145 }, |
223 |
|
{ "Xircom Tulip clone", { 0x0003115d, 0xffffffff, 0, 0, 0, 0 }, |
224 |
|
TULIP_IOTYPE, 128, XIRCOM }, |
225 |
|
{ "Davicom DM9102", { 0x91021282, 0xffffffff, 0, 0, 0, 0 }, |
226 |
|
TULIP_IOTYPE, 0x80, DC21140 }, |
227 |
|
{ "Davicom DM9100", { 0x91001282, 0xffffffff, 0, 0, 0, 0 }, |
228 |
|
TULIP_IOTYPE, 0x80, DC21140 }, |
229 |
|
{ "Macronix mxic-98715 (EN1217)", { 0x12171113, 0xffffffff, 0, 0, 0, 0 }, |
230 |
|
TULIP_IOTYPE, 256, MX98715 }, |
231 |
|
{ 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 }, |
232 |
|
}; |
233 |
|
|
234 |
|
enum tbl_flag { |
235 |
|
HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, |
236 |
|
HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ |
237 |
|
HAS_PNICNWAY=0x80, HAS_NWAY=0x40, /* Uses internal NWay xcvr. */ |
238 |
|
HAS_INTR_MITIGATION=0x100, IS_ASIX=0x200, HAS_8023X=0x400, |
239 |
|
}; |
240 |
|
|
241 |
|
/* Note: this table must match enum tulip_chips above. */ |
242 |
|
static struct tulip_chip_table { |
243 |
|
char *chip_name; |
244 |
|
int flags; |
245 |
|
} tulip_tbl[] = { |
246 |
|
{ "Digital DC21040 Tulip", 0}, |
247 |
|
{ "Digital DC21041 Tulip", HAS_MEDIA_TABLE | HAS_NWAY }, |
248 |
|
{ "Digital DS21140 Tulip", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, |
249 |
|
{ "Digital DS21143 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII |
250 |
|
| HAS_PWRDWN | HAS_NWAY | HAS_INTR_MITIGATION }, |
251 |
|
{ "Lite-On 82c168 PNIC", HAS_MII | HAS_PNICNWAY }, |
252 |
|
{ "Macronix 98713 PMAC", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, |
253 |
|
{ "Macronix 98715 PMAC", HAS_MEDIA_TABLE }, |
254 |
|
{ "Macronix 98725 PMAC", HAS_MEDIA_TABLE }, |
255 |
|
{ "ASIX AX88140", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM |
256 |
|
| MC_HASH_ONLY | IS_ASIX }, |
257 |
|
{ "ASIX AX88141", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY |
258 |
|
| IS_ASIX }, |
259 |
|
{ "Lite-On PNIC-II", HAS_MII | HAS_NWAY | HAS_8023X }, |
260 |
|
{ "ADMtek Comet", MC_HASH_ONLY }, |
261 |
|
{ "Compex 9881 PMAC", HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM }, |
262 |
|
{ "Intel DS21145 Tulip", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII |
263 |
|
| HAS_PWRDWN | HAS_NWAY }, |
264 |
|
{ "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII |
265 |
|
| HAS_PWRDWN | HAS_NWAY }, |
266 |
|
{ 0, 0 }, |
267 |
|
}; |
268 |
|
|
269 |
|
/* A full-duplex map for media types. */ |
270 |
|
enum MediaIs { |
271 |
|
MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, |
272 |
|
MediaIs100=16}; |
273 |
|
|
274 |
|
static const char media_cap[32] = |
275 |
|
{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20, 20,31,0,0, }; |
276 |
|
static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; |
277 |
|
|
278 |
|
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD */ |
279 |
|
static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; |
280 |
|
static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; |
281 |
|
static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; |
282 |
|
|
283 |
|
static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; |
284 |
|
static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; |
285 |
|
static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; |
286 |
|
|
287 |
|
/* Offsets to the Command and Status Registers, "CSRs". All accesses |
288 |
|
must be longword instructions and quadword aligned. */ |
289 |
enum tulip_offsets { |
enum tulip_offsets { |
290 |
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, |
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, |
291 |
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, |
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, |
292 |
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0 |
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0 |
293 |
|
}; |
294 |
|
|
295 |
|
/* The bits in the CSR5 status registers, mostly interrupt sources. */ |
296 |
|
enum status_bits { |
297 |
|
TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, |
298 |
|
NormalIntr=0x10000, AbnormalIntr=0x8000, |
299 |
|
RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, |
300 |
|
TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, |
301 |
|
}; |
302 |
|
|
303 |
|
enum desc_status_bits { |
304 |
|
DescOwnded=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, |
305 |
|
}; |
306 |
|
|
307 |
|
struct medialeaf { |
308 |
|
u8 type; |
309 |
|
u8 media; |
310 |
|
unsigned char *leafdata; |
311 |
|
}; |
312 |
|
|
313 |
|
struct mediatable { |
314 |
|
u16 defaultmedia; |
315 |
|
u8 leafcount, csr12dir; /* General purpose pin directions. */ |
316 |
|
unsigned has_mii:1, has_nonmii:1, has_reset:6; |
317 |
|
u32 csr15dir, csr15val; /* 21143 NWay setting. */ |
318 |
|
struct medialeaf mleaf[0]; |
319 |
}; |
}; |
320 |
|
|
321 |
#define DEC_21142_CSR6_TTM 0x00400000 /* Transmit Threshold Mode */ |
struct mediainfo { |
322 |
#define DEC_21142_CSR6_HBD 0x00080000 /* Heartbeat Disable */ |
struct mediainfo *next; |
323 |
#define DEC_21142_CSR6_PS 0x00040000 /* Port Select */ |
int info_type; |
324 |
|
int index; |
325 |
|
unsigned char *info; |
326 |
|
}; |
327 |
|
|
328 |
/* EEPROM Address width definitions */ |
/* EEPROM Address width definitions */ |
329 |
#define EEPROM_ADDRLEN 6 |
#define EEPROM_ADDRLEN 6 |
330 |
#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ |
#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ |
331 |
|
|
|
/* Data Read from the EEPROM */ |
|
|
static unsigned char ee_data[EEPROM_SIZE]; |
|
|
|
|
332 |
/* The EEPROM commands include the alway-set leading bit. */ |
/* The EEPROM commands include the alway-set leading bit. */ |
333 |
#define EE_WRITE_CMD (5 << addr_len) |
#define EE_WRITE_CMD (5 << addr_len) |
334 |
#define EE_READ_CMD (6 << addr_len) |
#define EE_READ_CMD (6 << addr_len) |
348 |
turn-around to insure that this remains true. */ |
turn-around to insure that this remains true. */ |
349 |
#define eeprom_delay() inl(ee_addr) |
#define eeprom_delay() inl(ee_addr) |
350 |
|
|
351 |
/* helpful macro if on a big_endian machine for changing byte order. |
/* Size of transmit and receive buffers */ |
352 |
not strictly needed on Intel */ |
#define BUFLEN 1536 |
353 |
#define le16_to_cpu(val) (val) |
|
354 |
|
/* Ring-wrap flag in length field, use for last ring entry. |
355 |
|
0x01000000 means chain on buffer2 address, |
356 |
|
0x02000000 means use the ring start address in CSR2/3. |
357 |
|
Note: Some work-alike chips do not function correctly in chained mode. |
358 |
|
The ASIX chip works only in chained mode. |
359 |
|
Thus we indicate ring mode, but always write the 'next' field for |
360 |
|
chained mode as well. */ |
361 |
|
#define DESC_RING_WRAP 0x02000000 |
362 |
|
|
363 |
/* transmit and receive descriptor format */ |
/* transmit and receive descriptor format */ |
364 |
struct txdesc { |
struct tulip_rx_desc { |
365 |
volatile unsigned long status; /* owner, status */ |
volatile u32 status; |
366 |
unsigned long buf1sz:11, /* size of buffer 1 */ |
u32 length; |
367 |
buf2sz:11, /* size of buffer 2 */ |
u32 buffer1, buffer2; |
|
control:10; /* control bits */ |
|
|
const unsigned char *buf1addr; /* buffer 1 address */ |
|
|
const unsigned char *buf2addr; /* buffer 2 address */ |
|
|
}; |
|
|
|
|
|
struct rxdesc { |
|
|
volatile unsigned long status; /* owner, status */ |
|
|
unsigned long buf1sz:11, /* size of buffer 1 */ |
|
|
buf2sz:11, /* size of buffer 2 */ |
|
|
control:10; /* control bits */ |
|
|
unsigned char *buf1addr; /* buffer 1 address */ |
|
|
unsigned char *buf2addr; /* buffer 2 address */ |
|
368 |
}; |
}; |
369 |
|
|
370 |
/* Size of transmit and receive buffers */ |
struct tulip_tx_desc { |
371 |
#define BUFLEN 1536 |
volatile u32 status; |
372 |
|
u32 length; |
373 |
|
u32 buffer1, buffer2; |
374 |
|
}; |
375 |
|
|
376 |
/*********************************************************************/ |
/*********************************************************************/ |
377 |
/* Global Storage */ |
/* Global Storage */ |
378 |
/*********************************************************************/ |
/*********************************************************************/ |
379 |
|
|
380 |
/* PCI Bus parameters */ |
static u32 ioaddr; |
|
static unsigned short vendor, dev_id; |
|
|
static unsigned long ioaddr; |
|
381 |
|
|
382 |
/* Note: transmit and receive buffers must be longword aligned and |
/* Note: transmit and receive buffers must be longword aligned and |
383 |
longword divisable */ |
longword divisable */ |
384 |
|
|
385 |
/* transmit descriptor and buffer */ |
#define TX_RING_SIZE 2 |
386 |
static struct txdesc txd __attribute__ ((aligned(4))); |
static struct tulip_tx_desc tx_ring[TX_RING_SIZE] __attribute__ ((aligned(4))); |
387 |
#ifndef USE_INTERNAL_BUFFER |
|
388 |
|
#ifdef USE_LOWMEM_BUFFER |
389 |
#define txb ((char *)0x10000 - BUFLEN) |
#define txb ((char *)0x10000 - BUFLEN) |
390 |
#else |
#else |
391 |
static unsigned char txb[BUFLEN] __attribute__ ((aligned(4))); |
static unsigned char txb[BUFLEN] __attribute__ ((aligned(4))); |
392 |
#endif |
#endif |
393 |
|
|
394 |
/* receive descriptor(s) and buffer(s) */ |
#define RX_RING_SIZE 4 |
395 |
#define NRXD 4 |
static struct tulip_rx_desc rx_ring[RX_RING_SIZE] __attribute__ ((aligned(4))); |
396 |
static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4))); |
|
397 |
#ifndef USE_INTERNAL_BUFFER |
#ifdef USE_LOWMEM_BUFFER |
398 |
#define rxb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN) |
#define rxb ((char *)0x10000 - RX_RING_SIZE * BUFLEN - BUFLEN) |
399 |
#else |
#else |
400 |
static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4))); |
static unsigned char rxb[RX_RING_SIZE * BUFLEN] __attribute__ ((aligned(4))); |
401 |
#endif |
#endif |
|
static int rxd_tail; |
|
402 |
|
|
403 |
/* buffer for ethernet header */ |
static struct tulip_private { |
404 |
static unsigned char ehdr[ETHER_HDR_SIZE]; |
int cur_rx; |
405 |
|
int chip_id; /* index into tulip_tbl[] */ |
406 |
|
int pci_id_idx; /* index into pci_id_tbl[] */ |
407 |
|
int revision; |
408 |
|
int flags; |
409 |
|
unsigned short vendor_id; /* PCI card vendor code */ |
410 |
|
unsigned short dev_id; /* PCI card device code */ |
411 |
|
unsigned char ehdr[ETH_HLEN]; /* buffer for ethernet header */ |
412 |
|
const char *nic_name; |
413 |
|
unsigned int csr0, csr6; /* Current CSR0, CSR6 settings. */ |
414 |
|
unsigned int if_port; |
415 |
|
unsigned int full_duplex; /* Full-duplex operation requested. */ |
416 |
|
unsigned int full_duplex_lock; |
417 |
|
unsigned int medialock; /* Do not sense media type. */ |
418 |
|
unsigned int mediasense; /* Media sensing in progress. */ |
419 |
|
unsigned int nway, nwayset; /* 21143 internal NWay. */ |
420 |
|
unsigned int default_port; |
421 |
|
unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ |
422 |
|
u8 media_table_storage[(sizeof(struct mediatable) + 32*sizeof(struct medialeaf))]; |
423 |
|
u16 sym_advertise, mii_advertise; /* NWay to-advertise. */ |
424 |
|
struct mediatable *mtable; |
425 |
|
u16 lpar; /* 21143 Link partner ability. */ |
426 |
|
u16 advertising[4]; /* MII advertise, from SROM table. */ |
427 |
|
signed char phys[4], mii_cnt; /* MII device addresses. */ |
428 |
|
int cur_index; /* Current media index. */ |
429 |
|
int saved_if_port; |
430 |
|
} tpx; |
431 |
|
|
432 |
|
static struct tulip_private *tp; |
433 |
|
|
434 |
|
/* Known cards that have old-style EEPROMs. |
435 |
|
Writing this table is described at |
436 |
|
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip-drivers/tulip-media.html */ |
437 |
|
static struct fixups { |
438 |
|
char *name; |
439 |
|
unsigned char addr0, addr1, addr2; |
440 |
|
u16 newtable[32]; /* Max length below. */ |
441 |
|
} eeprom_fixups[] = { |
442 |
|
{"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, |
443 |
|
0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, |
444 |
|
{"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, |
445 |
|
0x0000, 0x009E, /* 10baseT */ |
446 |
|
0x0004, 0x009E, /* 10baseT-FD */ |
447 |
|
0x0903, 0x006D, /* 100baseTx */ |
448 |
|
0x0905, 0x006D, /* 100baseTx-FD */ }}, |
449 |
|
{"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, |
450 |
|
0x0107, 0x8021, /* 100baseFx */ |
451 |
|
0x0108, 0x8021, /* 100baseFx-FD */ |
452 |
|
0x0100, 0x009E, /* 10baseT */ |
453 |
|
0x0104, 0x009E, /* 10baseT-FD */ |
454 |
|
0x0103, 0x006D, /* 100baseTx */ |
455 |
|
0x0105, 0x006D, /* 100baseTx-FD */ }}, |
456 |
|
{"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, |
457 |
|
0x1001, 0x009E, /* 10base2, CSR12 0x10*/ |
458 |
|
0x0000, 0x009E, /* 10baseT */ |
459 |
|
0x0004, 0x009E, /* 10baseT-FD */ |
460 |
|
0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ |
461 |
|
0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, |
462 |
|
{"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, |
463 |
|
0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ |
464 |
|
0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ |
465 |
|
0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ |
466 |
|
0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ |
467 |
|
0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ |
468 |
|
}}, |
469 |
|
{0, 0, 0, 0, {}}}; |
470 |
|
|
471 |
|
static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", |
472 |
|
"21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; |
473 |
|
|
474 |
|
|
475 |
/*********************************************************************/ |
/*********************************************************************/ |
476 |
/* Function Prototypes */ |
/* Function Prototypes */ |
477 |
/*********************************************************************/ |
/*********************************************************************/ |
478 |
static void whereami(const char *str); |
static int mdio_read(struct nic *nic, int phy_id, int location); |
479 |
static int lc82c168_mdio_read(int phy_id, int location); |
static void mdio_write(struct nic *nic, int phy_id, int location, int value); |
|
static void lc82c168_mdio_write(int phy_id, int location, int value); |
|
|
static void lc82c168_do_mii(); |
|
480 |
static int read_eeprom(unsigned long ioaddr, int location, int addr_len); |
static int read_eeprom(unsigned long ioaddr, int location, int addr_len); |
481 |
|
static void parse_eeprom(struct nic *nic); |
482 |
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, |
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, |
483 |
struct pci_device *pci); |
struct pci_device *pci); |
484 |
static void tulip_init_ring(struct nic *nic); |
static void tulip_init_ring(struct nic *nic); |
485 |
static void tulip_reset(struct nic *nic); |
static void tulip_reset(struct nic *nic); |
486 |
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, |
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, |
487 |
unsigned int s, const char *p); |
unsigned int s, const char *p); |
488 |
static int tulip_poll(struct nic *nic); |
static int tulip_poll(struct nic *nic); |
489 |
static void tulip_disable(struct nic *nic); |
static void tulip_disable(struct nic *nic); |
490 |
static void whereami (const char *str); |
static void nway_start(struct nic *nic); |
491 |
#ifdef TULIP_DEBUG |
static void pnic_do_nway(struct nic *nic); |
492 |
static void tulip_more(void); |
static void select_media(struct nic *nic, int startup); |
493 |
#endif /* TULIP_DEBUG */ |
static void init_media(struct nic *nic); |
494 |
|
static void start_link(struct nic *nic); |
495 |
|
static int tulip_check_duplex(struct nic *nic); |
496 |
|
|
497 |
static void tulip_wait(unsigned int nticks); |
static void tulip_wait(unsigned int nticks); |
498 |
|
|
499 |
|
#ifdef TULIP_DEBUG_WHERE |
500 |
|
static void whereami(const char *str); |
501 |
|
#endif |
502 |
|
|
503 |
|
#ifdef TULIP_DEBUG |
504 |
|
static void tulip_more(void); |
505 |
|
#endif |
506 |
|
|
507 |
|
|
508 |
/*********************************************************************/ |
/*********************************************************************/ |
509 |
/* Utility Routines */ |
/* Utility Routines */ |
510 |
/*********************************************************************/ |
/*********************************************************************/ |
511 |
|
|
512 |
static inline void whereami (const char *str) |
#ifdef TULIP_DEBUG_WHERE |
513 |
|
static void whereami (const char *str) |
514 |
{ |
{ |
515 |
#ifdef TULIP_DEBUG_WHERE |
printf("%s: %s\n", tp->nic_name, str); |
516 |
printf("%s\n", str); |
/* sleep(2); */ |
|
/* sleep(2); */ |
|
|
#endif |
|
517 |
} |
} |
518 |
|
#endif |
519 |
|
|
520 |
#ifdef TULIP_DEBUG |
#ifdef TULIP_DEBUG |
521 |
static void tulip_more() |
static void tulip_more(void) |
522 |
{ |
{ |
523 |
printf("\n\n-- more --"); |
printf("\n\n-- more --"); |
524 |
while (!iskey()) |
while (!iskey()) |
525 |
/* wait */; |
/* wait */; |
526 |
getchar(); |
getchar(); |
527 |
printf("\n\n"); |
printf("\n\n"); |
528 |
} |
} |
529 |
#endif /* TULIP_DEBUG */ |
#endif /* TULIP_DEBUG */ |
530 |
|
|
531 |
static void tulip_wait(unsigned int nticks) |
static void tulip_wait(unsigned int nticks) |
532 |
{ |
{ |
533 |
unsigned int to = currticks() + nticks; |
unsigned int to = currticks() + nticks; |
534 |
while (currticks() < to) |
while (currticks() < to) |
535 |
/* wait */ ; |
/* wait */ ; |
536 |
} |
} |
537 |
|
|
538 |
|
|
539 |
/*********************************************************************/ |
/*********************************************************************/ |
540 |
/* Media Descriptor Code */ |
/* Media Descriptor Code */ |
541 |
/*********************************************************************/ |
/*********************************************************************/ |
|
static int lc82c168_mdio_read(int phy_id, int location) |
|
|
{ |
|
|
int i = 1000; |
|
|
int retval = 0; |
|
542 |
|
|
543 |
whereami("mdio_read\n"); |
/* MII transceiver control section. |
544 |
|
Read and write the MII registers using software-generated serial |
545 |
|
MDIO protocol. See the MII specifications or DP83840A data sheet |
546 |
|
for details. */ |
547 |
|
|
548 |
|
/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually |
549 |
|
met by back-to-back PCI I/O cycles, but we insert a delay to avoid |
550 |
|
"overclocking" issues or future 66Mhz PCI. */ |
551 |
|
#define mdio_delay() inl(mdio_addr) |
552 |
|
|
553 |
|
/* Read and write the MII registers using software-generated serial |
554 |
|
MDIO protocol. It is just different enough from the EEPROM protocol |
555 |
|
to not share code. The maxium data clock rate is 2.5 Mhz. */ |
556 |
|
#define MDIO_SHIFT_CLK 0x10000 |
557 |
|
#define MDIO_DATA_WRITE0 0x00000 |
558 |
|
#define MDIO_DATA_WRITE1 0x20000 |
559 |
|
#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ |
560 |
|
#define MDIO_ENB_IN 0x40000 |
561 |
|
#define MDIO_DATA_READ 0x80000 |
562 |
|
|
563 |
|
/* MII transceiver control section. |
564 |
|
Read and write the MII registers using software-generated serial |
565 |
|
MDIO protocol. See the MII specifications or DP83840A data sheet |
566 |
|
for details. */ |
567 |
|
|
568 |
outl(0x60020000 | (phy_id<<23) | (location<<18), ioaddr + 0xA0); |
int mdio_read(struct nic *nic, int phy_id, int location) |
|
inl(ioaddr + 0xA0); |
|
|
inl(ioaddr + 0xA0); |
|
|
while (--i > 0) |
|
|
if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) |
|
|
return retval & 0xFFFF; |
|
|
if (i == 0) printf("mdio read timeout!\n"); |
|
|
return 0xFFFF; |
|
|
} |
|
|
|
|
|
static void lc82c168_mdio_write(int phy_id, int location, int value) |
|
569 |
{ |
{ |
570 |
int i = 1000; |
int i; |
571 |
int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; |
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; |
572 |
|
int retval = 0; |
573 |
whereami("mdio_write\n"); |
long mdio_addr = ioaddr + CSR9; |
|
|
|
|
outl(cmd, ioaddr + 0xA0); |
|
|
do |
|
|
if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) |
|
|
break; |
|
|
while (--i > 0); |
|
|
if (i == 0) printf("mdio write timeout!\n"); |
|
|
return; |
|
|
} |
|
574 |
|
|
575 |
static void lc82c168_do_mii(void) |
#ifdef TULIP_DEBUG_WHERE |
576 |
{ |
whereami("mdio_read\n"); |
577 |
int phy, phy_idx; |
#endif |
578 |
|
|
579 |
whereami("do_mii\n"); |
if (tp->chip_id == LC82C168) { |
580 |
|
int i = 1000; |
581 |
|
outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); |
582 |
|
inl(ioaddr + 0xA0); |
583 |
|
inl(ioaddr + 0xA0); |
584 |
|
while (--i > 0) |
585 |
|
if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) |
586 |
|
return retval & 0xffff; |
587 |
|
return 0xffff; |
588 |
|
} |
589 |
|
|
590 |
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < 4; phy++) { |
if (tp->chip_id == COMET) { |
591 |
|
if (phy_id == 1) { |
592 |
|
if (location < 7) |
593 |
|
return inl(ioaddr + 0xB4 + (location<<2)); |
594 |
|
else if (location == 17) |
595 |
|
return inl(ioaddr + 0xD0); |
596 |
|
else if (location >= 29 && location <= 31) |
597 |
|
return inl(ioaddr + 0xD4 + ((location-29)<<2)); |
598 |
|
} |
599 |
|
return 0xffff; |
600 |
|
} |
601 |
|
|
602 |
int mii_status = lc82c168_mdio_read(phy, 1); |
/* Establish sync by sending at least 32 logic ones. */ |
603 |
|
for (i = 32; i >= 0; i--) { |
604 |
|
outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); |
605 |
|
mdio_delay(); |
606 |
|
outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); |
607 |
|
mdio_delay(); |
608 |
|
} |
609 |
|
/* Shift the read command bits out. */ |
610 |
|
for (i = 15; i >= 0; i--) { |
611 |
|
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; |
612 |
|
|
613 |
|
outl(MDIO_ENB | dataval, mdio_addr); |
614 |
|
mdio_delay(); |
615 |
|
outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); |
616 |
|
mdio_delay(); |
617 |
|
} |
618 |
|
/* Read the two transition, 16 data, and wire-idle bits. */ |
619 |
|
for (i = 19; i > 0; i--) { |
620 |
|
outl(MDIO_ENB_IN, mdio_addr); |
621 |
|
mdio_delay(); |
622 |
|
retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); |
623 |
|
outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); |
624 |
|
mdio_delay(); |
625 |
|
} |
626 |
|
return (retval>>1) & 0xffff; |
627 |
|
} |
628 |
|
|
629 |
if ((mii_status & 0x8301) == 0x8001 || |
void mdio_write(struct nic *nic, int phy_id, int location, int value) |
630 |
((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { |
{ |
631 |
|
int i; |
632 |
|
int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; |
633 |
|
long mdio_addr = ioaddr + CSR9; |
634 |
|
|
635 |
int mii_reg0 = lc82c168_mdio_read(phy, 0); |
#ifdef TULIP_DEBUG_WHERE |
636 |
int mii_advert = lc82c168_mdio_read(phy, 4); |
whereami("mdio_write\n"); |
637 |
int mii_reg4 = ((mii_status >> 6) & 0x01E1) | 1; |
#endif |
638 |
|
|
639 |
phy_idx++; |
if (tp->chip_id == LC82C168) { |
640 |
printf("%s: MII trcvr #%d " |
int i = 1000; |
641 |
"config %x status %x advertising %x reg4 %x.\n", |
outl(cmd, ioaddr + 0xA0); |
642 |
"LC82C168", phy, mii_reg0, mii_status, mii_advert, mii_reg4); |
do |
643 |
|
if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) |
644 |
|
break; |
645 |
|
while (--i > 0); |
646 |
|
return; |
647 |
|
} |
648 |
|
|
649 |
lc82c168_mdio_write(phy, 0, mii_reg0 | 0x1000); |
if (tp->chip_id == COMET) { |
650 |
if (mii_advert != mii_reg4) |
if (phy_id != 1) |
651 |
lc82c168_mdio_write(phy, 4, mii_reg4); |
return; |
652 |
|
if (location < 7) |
653 |
|
outl(value, ioaddr + 0xB4 + (location<<2)); |
654 |
|
else if (location == 17) |
655 |
|
outl(value, ioaddr + 0xD0); |
656 |
|
else if (location >= 29 && location <= 31) |
657 |
|
outl(value, ioaddr + 0xD4 + ((location-29)<<2)); |
658 |
|
return; |
659 |
} |
} |
|
} |
|
|
#ifdef TULIP_DEBUG |
|
|
printf("mii_cnt = %d\n", phy_idx); |
|
|
#endif |
|
660 |
|
|
661 |
|
/* Establish sync by sending 32 logic ones. */ |
662 |
|
for (i = 32; i >= 0; i--) { |
663 |
|
outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); |
664 |
|
mdio_delay(); |
665 |
|
outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); |
666 |
|
mdio_delay(); |
667 |
|
} |
668 |
|
/* Shift the command bits out. */ |
669 |
|
for (i = 31; i >= 0; i--) { |
670 |
|
int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; |
671 |
|
outl(MDIO_ENB | dataval, mdio_addr); |
672 |
|
mdio_delay(); |
673 |
|
outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); |
674 |
|
mdio_delay(); |
675 |
|
} |
676 |
|
/* Clear out extra bits. */ |
677 |
|
for (i = 2; i > 0; i--) { |
678 |
|
outl(MDIO_ENB_IN, mdio_addr); |
679 |
|
mdio_delay(); |
680 |
|
outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); |
681 |
|
mdio_delay(); |
682 |
|
} |
683 |
} |
} |
684 |
|
|
685 |
|
|
692 |
*/ |
*/ |
693 |
static int read_eeprom(unsigned long ioaddr, int location, int addr_len) |
static int read_eeprom(unsigned long ioaddr, int location, int addr_len) |
694 |
{ |
{ |
695 |
int i; |
int i; |
696 |
unsigned short retval = 0; |
unsigned short retval = 0; |
697 |
long ee_addr = ioaddr + CSR9; |
long ee_addr = ioaddr + CSR9; |
698 |
int read_cmd = location | EE_READ_CMD; |
int read_cmd = location | EE_READ_CMD; |
699 |
|
|
700 |
whereami("read_eeprom\n"); |
#ifdef TULIP_DEBUG_WHERE |
701 |
|
whereami("read_eeprom\n"); |
702 |
outl(EE_ENB & ~EE_CS, ee_addr); |
#endif |
703 |
outl(EE_ENB, ee_addr); |
|
704 |
|
outl(EE_ENB & ~EE_CS, ee_addr); |
705 |
/* Shift the read command bits out. */ |
outl(EE_ENB, ee_addr); |
706 |
for (i = 4 + addr_len; i >= 0; i--) { |
|
707 |
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; |
/* Shift the read command bits out. */ |
708 |
outl(EE_ENB | dataval, ee_addr); |
for (i = 4 + addr_len; i >= 0; i--) { |
709 |
eeprom_delay(); |
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; |
710 |
outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); |
outl(EE_ENB | dataval, ee_addr); |
711 |
eeprom_delay(); |
eeprom_delay(); |
712 |
} |
outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); |
713 |
outl(EE_ENB, ee_addr); |
eeprom_delay(); |
714 |
|
} |
|
for (i = 16; i > 0; i--) { |
|
|
outl(EE_ENB | EE_SHIFT_CLK, ee_addr); |
|
|
eeprom_delay(); |
|
|
retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); |
|
715 |
outl(EE_ENB, ee_addr); |
outl(EE_ENB, ee_addr); |
|
eeprom_delay(); |
|
|
} |
|
716 |
|
|
717 |
/* Terminate the EEPROM access. */ |
for (i = 16; i > 0; i--) { |
718 |
outl(EE_ENB & ~EE_CS, ee_addr); |
outl(EE_ENB | EE_SHIFT_CLK, ee_addr); |
719 |
return retval; |
eeprom_delay(); |
720 |
|
retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); |
721 |
|
outl(EE_ENB, ee_addr); |
722 |
|
eeprom_delay(); |
723 |
|
} |
724 |
|
|
725 |
|
/* Terminate the EEPROM access. */ |
726 |
|
outl(EE_ENB & ~EE_CS, ee_addr); |
727 |
|
return retval; |
728 |
|
} |
729 |
|
|
730 |
|
|
731 |
|
/*********************************************************************/ |
732 |
|
/* EEPROM Parsing Code */ |
733 |
|
/*********************************************************************/ |
734 |
|
static void parse_eeprom(struct nic *nic) |
735 |
|
{ |
736 |
|
unsigned char *p, *ee_data = tp->eeprom; |
737 |
|
int new_advertise = 0; |
738 |
|
int i; |
739 |
|
|
740 |
|
#ifdef TULIP_DEBUG_WHERE |
741 |
|
whereami("parse_eeprom\n"); |
742 |
|
#endif |
743 |
|
|
744 |
|
tp->mtable = 0; |
745 |
|
/* Detect an old-style (SA only) EEPROM layout: |
746 |
|
memcmp(ee_data, ee_data+16, 8). */ |
747 |
|
for (i = 0; i < 8; i ++) |
748 |
|
if (ee_data[i] != ee_data[16+i]) |
749 |
|
break; |
750 |
|
if (i >= 8) { |
751 |
|
/* Do a fix-up based on the vendor half of the station address. */ |
752 |
|
for (i = 0; eeprom_fixups[i].name; i++) { |
753 |
|
if (nic->node_addr[0] == eeprom_fixups[i].addr0 |
754 |
|
&& nic->node_addr[1] == eeprom_fixups[i].addr1 |
755 |
|
&& nic->node_addr[2] == eeprom_fixups[i].addr2) { |
756 |
|
if (nic->node_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) |
757 |
|
i++; /* An Accton EN1207, not an outlaw Maxtech. */ |
758 |
|
memcpy(ee_data + 26, eeprom_fixups[i].newtable, |
759 |
|
sizeof(eeprom_fixups[i].newtable)); |
760 |
|
#ifdef TULIP_DEBUG |
761 |
|
printf("%s: Old format EEPROM on '%s' board.\n%s: Using substitute media control info.\n", |
762 |
|
tp->nic_name, eeprom_fixups[i].name, tp->nic_name); |
763 |
|
#endif |
764 |
|
break; |
765 |
|
} |
766 |
|
} |
767 |
|
if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ |
768 |
|
#ifdef TULIP_DEBUG |
769 |
|
printf("%s: Old style EEPROM with no media selection information.\n", |
770 |
|
tp->nic_name); |
771 |
|
#endif |
772 |
|
return; |
773 |
|
} |
774 |
|
} |
775 |
|
|
776 |
|
if (ee_data[19] > 1) { |
777 |
|
#ifdef TULIP_DEBUG |
778 |
|
printf("%s: Multiport cards (%d ports) may not work correctly.\n", |
779 |
|
tp->nic_name, ee_data[19]); |
780 |
|
#endif |
781 |
|
} |
782 |
|
|
783 |
|
p = (void *)ee_data + ee_data[27]; |
784 |
|
|
785 |
|
if (ee_data[27] == 0) { /* No valid media table. */ |
786 |
|
#ifdef TULIP_DEBUG |
787 |
|
if (tulip_debug > 1) { |
788 |
|
printf("%s: No Valid Media Table. ee_data[27] = %hhX\n", |
789 |
|
tp->nic_name, ee_data[27]); |
790 |
|
} |
791 |
|
#endif |
792 |
|
} else if (tp->chip_id == DC21041) { |
793 |
|
int media = get_u16(p); |
794 |
|
int count = p[2]; |
795 |
|
p += 3; |
796 |
|
|
797 |
|
printf("%s: 21041 Media table, default media %hX (%s).\n", |
798 |
|
tp->nic_name, media, |
799 |
|
media & 0x0800 ? "Autosense" : medianame[media & 15]); |
800 |
|
for (i = 0; i < count; i++) { |
801 |
|
unsigned char media_block = *p++; |
802 |
|
int media_code = media_block & MEDIA_MASK; |
803 |
|
if (media_block & 0x40) |
804 |
|
p += 6; |
805 |
|
switch(media_code) { |
806 |
|
case 0: new_advertise |= 0x0020; break; |
807 |
|
case 4: new_advertise |= 0x0040; break; |
808 |
|
} |
809 |
|
printf("%s: 21041 media #%d, %s.\n", |
810 |
|
tp->nic_name, media_code, medianame[media_code]); |
811 |
|
} |
812 |
|
} else { |
813 |
|
unsigned char csr12dir = 0; |
814 |
|
int count; |
815 |
|
struct mediatable *mtable; |
816 |
|
u16 media = get_u16(p); |
817 |
|
|
818 |
|
p += 2; |
819 |
|
if (tp->flags & CSR12_IN_SROM) |
820 |
|
csr12dir = *p++; |
821 |
|
count = *p++; |
822 |
|
|
823 |
|
tp->mtable = mtable = (struct mediatable *)&tp->media_table_storage[0]; |
824 |
|
|
825 |
|
mtable->defaultmedia = media; |
826 |
|
mtable->leafcount = count; |
827 |
|
mtable->csr12dir = csr12dir; |
828 |
|
mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; |
829 |
|
mtable->csr15dir = mtable->csr15val = 0; |
830 |
|
|
831 |
|
printf("%s: EEPROM default media type %s.\n", tp->nic_name, |
832 |
|
media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); |
833 |
|
|
834 |
|
for (i = 0; i < count; i++) { |
835 |
|
struct medialeaf *leaf = &mtable->mleaf[i]; |
836 |
|
|
837 |
|
if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ |
838 |
|
leaf->type = 0; |
839 |
|
leaf->media = p[0] & 0x3f; |
840 |
|
leaf->leafdata = p; |
841 |
|
if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ |
842 |
|
mtable->has_mii = 1; |
843 |
|
p += 4; |
844 |
|
} else { |
845 |
|
switch(leaf->type = p[1]) { |
846 |
|
case 5: |
847 |
|
mtable->has_reset = i; |
848 |
|
leaf->media = p[2] & 0x0f; |
849 |
|
break; |
850 |
|
case 1: case 3: |
851 |
|
mtable->has_mii = 1; |
852 |
|
leaf->media = 11; |
853 |
|
break; |
854 |
|
case 2: |
855 |
|
if ((p[2] & 0x3f) == 0) { |
856 |
|
u32 base15 = (p[2] & 0x40) ? get_u16(p + 7) : 0x0008; |
857 |
|
u16 *p1 = (u16 *)(p + (p[2] & 0x40 ? 9 : 3)); |
858 |
|
mtable->csr15dir = (get_unaligned(p1 + 0)<<16) + base15; |
859 |
|
mtable->csr15val = (get_unaligned(p1 + 1)<<16) + base15; |
860 |
|
} |
861 |
|
/* Fall through. */ |
862 |
|
case 0: case 4: |
863 |
|
mtable->has_nonmii = 1; |
864 |
|
leaf->media = p[2] & MEDIA_MASK; |
865 |
|
switch (leaf->media) { |
866 |
|
case 0: new_advertise |= 0x0020; break; |
867 |
|
case 4: new_advertise |= 0x0040; break; |
868 |
|
case 3: new_advertise |= 0x0080; break; |
869 |
|
case 5: new_advertise |= 0x0100; break; |
870 |
|
case 6: new_advertise |= 0x0200; break; |
871 |
|
} |
872 |
|
break; |
873 |
|
default: |
874 |
|
leaf->media = 19; |
875 |
|
} |
876 |
|
leaf->leafdata = p + 2; |
877 |
|
p += (p[0] & 0x3f) + 1; |
878 |
|
} |
879 |
|
#ifdef TULIP_DEBUG |
880 |
|
if (tulip_debug > 1 && leaf->media == 11) { |
881 |
|
unsigned char *bp = leaf->leafdata; |
882 |
|
printf("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %hhX %hhX.\n", |
883 |
|
tp->nic_name, bp[0], bp[1], bp[2 + bp[1]*2], |
884 |
|
bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); |
885 |
|
} |
886 |
|
#endif |
887 |
|
printf("%s: Index #%d - Media %s (#%d) described " |
888 |
|
"by a %s (%d) block.\n", |
889 |
|
tp->nic_name, i, medianame[leaf->media], leaf->media, |
890 |
|
leaf->type < 6 ? block_name[leaf->type] : "UNKNOWN", |
891 |
|
leaf->type); |
892 |
|
} |
893 |
|
if (new_advertise) |
894 |
|
tp->sym_advertise = new_advertise; |
895 |
|
} |
896 |
} |
} |
897 |
|
|
898 |
|
|
899 |
/*********************************************************************/ |
/*********************************************************************/ |
900 |
/* tulip_init_ring - setup the tx and rx descriptors */ |
/* tulip_init_ring - setup the tx and rx descriptors */ |
901 |
/*********************************************************************/ |
/*********************************************************************/ |
902 |
static void tulip_init_ring(struct nic *nic) |
static void tulip_init_ring(struct nic *nic) |
903 |
{ |
{ |
904 |
int i; |
int i; |
905 |
|
|
906 |
|
#ifdef TULIP_DEBUG_WHERE |
907 |
|
whereami("tulip_init_ring\n"); |
908 |
|
#endif |
909 |
|
|
910 |
/* setup the transmit descriptor */ |
tp->cur_rx = 0; |
911 |
txd.buf1addr = &txb[0]; |
|
912 |
txd.buf2addr = &txb[0]; /* just in case */ |
for (i = 0; i < RX_RING_SIZE; i++) { |
913 |
txd.buf1sz = 192; /* setup packet must be 192 bytes */ |
rx_ring[i].status = cpu_to_le32(0x80000000); |
914 |
txd.buf2sz = 0; |
rx_ring[i].length = cpu_to_le32(BUFLEN); |
915 |
txd.control = 0x028; /* setup packet + TER */ |
rx_ring[i].buffer1 = virt_to_le32desc(&rxb[i * BUFLEN]); |
916 |
txd.status = 0x80000000; /* give ownership to device */ |
rx_ring[i].buffer2 = virt_to_le32desc(&rx_ring[i+1]); |
917 |
|
} |
918 |
/* construct perfect filter frame with mac address as first match |
/* Mark the last entry as wrapping the ring. */ |
919 |
and broadcast address for all others */ |
rx_ring[i-1].length = cpu_to_le32(DESC_RING_WRAP | BUFLEN); |
920 |
for (i=0; i<192; i++) txb[i] = 0xFF; |
rx_ring[i-1].buffer2 = virt_to_le32desc(&rx_ring[0]); |
921 |
txb[0] = nic->node_addr[0]; |
|
922 |
txb[1] = nic->node_addr[1]; |
/* We only use 1 transmit buffer, but we use 2 descriptors so |
923 |
txb[4] = nic->node_addr[2]; |
transmit engines have somewhere to point to if they feel the need */ |
924 |
txb[5] = nic->node_addr[3]; |
|
925 |
txb[8] = nic->node_addr[4]; |
tx_ring[0].status = 0x00000000; |
926 |
txb[9] = nic->node_addr[5]; |
tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]); |
927 |
|
tx_ring[0].buffer2 = virt_to_le32desc(&tx_ring[1]); |
928 |
/* setup receive descriptor */ |
|
929 |
for (i=0; i<NRXD; i++) { |
/* this descriptor should never get used, since it will never be owned |
930 |
rxd[i].buf1addr = &rxb[i * BUFLEN]; |
by the machine (status will always == 0) */ |
931 |
rxd[i].buf2addr = 0; /* not used */ |
tx_ring[1].status = 0x00000000; |
932 |
rxd[i].buf1sz = BUFLEN; |
tx_ring[1].buffer1 = virt_to_le32desc(&txb[0]); |
933 |
rxd[i].buf2sz = 0; /* not used */ |
tx_ring[1].buffer2 = virt_to_le32desc(&tx_ring[0]); |
934 |
rxd[i].control = 0x0; |
|
935 |
rxd[i].status = 0x80000000; /* give ownership to device */ |
/* Mark the last entry as wrapping the ring, though this should never happen */ |
936 |
} |
tx_ring[1].length = cpu_to_le32(DESC_RING_WRAP | BUFLEN); |
|
|
|
|
/* Set Receive end of ring on last descriptor */ |
|
|
rxd[NRXD - 1].control = 0x008; |
|
|
rxd_tail = 0; |
|
937 |
} |
} |
938 |
|
|
939 |
/*********************************************************************/ |
/*********************************************************************/ |
941 |
/*********************************************************************/ |
/*********************************************************************/ |
942 |
static void tulip_reset(struct nic *nic) |
static void tulip_reset(struct nic *nic) |
943 |
{ |
{ |
944 |
unsigned long to, csr6; |
int i; |
945 |
u32 addr_low, addr_high; |
unsigned long to; |
946 |
|
u32 addr_low, addr_high; |
947 |
|
|
948 |
|
#ifdef TULIP_DEBUG_WHERE |
949 |
|
whereami("tulip_reset\n"); |
950 |
|
#endif |
951 |
|
|
952 |
|
/* Stop Tx and RX */ |
953 |
|
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
954 |
|
|
955 |
|
/* On some chip revs we must set the MII/SYM port before the reset!? */ |
956 |
|
if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) { |
957 |
|
outl(0x814C0000, ioaddr + CSR6); |
958 |
|
} |
959 |
|
|
960 |
|
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ |
961 |
|
outl(0x00000001, ioaddr + CSR0); |
962 |
|
tulip_wait(1); |
963 |
|
|
964 |
|
/* turn off reset and set cache align=16lword, burst=unlimit */ |
965 |
|
outl(tp->csr0, ioaddr + CSR0); |
966 |
|
|
967 |
|
/* Wait the specified 50 PCI cycles after a reset */ |
968 |
|
tulip_wait(1); |
969 |
|
|
970 |
|
/* set up transmit and receive descriptors */ |
971 |
|
tulip_init_ring(nic); |
972 |
|
|
973 |
|
if (tp->chip_id == PNIC2) { |
974 |
|
u32 addr_high = (nic->node_addr[1]<<8) + (nic->node_addr[0]<<0); |
975 |
|
/* This address setting does not appear to impact chip operation?? */ |
976 |
|
outl((nic->node_addr[5]<<8) + nic->node_addr[4] + |
977 |
|
(nic->node_addr[3]<<24) + (nic->node_addr[2]<<16), |
978 |
|
ioaddr + 0xB0); |
979 |
|
outl(addr_high + (addr_high<<16), ioaddr + 0xB8); |
980 |
|
} |
981 |
|
|
982 |
|
/* MC_HASH_ONLY boards don't support setup packets */ |
983 |
|
if (tp->flags & MC_HASH_ONLY) { |
984 |
|
u32 addr_low = cpu_to_le32(get_unaligned((u32 *)nic->node_addr)); |
985 |
|
u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(nic->node_addr+4))); |
986 |
|
|
987 |
|
/* clear multicast hash filters and setup MAC address filters */ |
988 |
|
if (tp->flags & IS_ASIX) { |
989 |
|
outl(0, ioaddr + CSR13); |
990 |
|
outl(addr_low, ioaddr + CSR14); |
991 |
|
outl(1, ioaddr + CSR13); |
992 |
|
outl(addr_high, ioaddr + CSR14); |
993 |
|
outl(2, ioaddr + CSR13); |
994 |
|
outl(0, ioaddr + CSR14); |
995 |
|
outl(3, ioaddr + CSR13); |
996 |
|
outl(0, ioaddr + CSR14); |
997 |
|
} else if (tp->chip_id == COMET) { |
998 |
|
outl(addr_low, ioaddr + 0xA4); |
999 |
|
outl(addr_high, ioaddr + 0xA8); |
1000 |
|
outl(0, ioaddr + 0xAC); |
1001 |
|
outl(0, ioaddr + 0xB0); |
1002 |
|
} |
1003 |
|
} else { |
1004 |
|
/* for other boards we send a setup packet to initialize |
1005 |
|
the filters */ |
1006 |
|
u32 tx_flags = 0x08000000 | 192; |
1007 |
|
|
1008 |
|
/* construct perfect filter frame with mac address as first match |
1009 |
|
and broadcast address for all others */ |
1010 |
|
for (i=0; i<192; i++) |
1011 |
|
txb[i] = 0xFF; |
1012 |
|
txb[0] = nic->node_addr[0]; |
1013 |
|
txb[1] = nic->node_addr[1]; |
1014 |
|
txb[4] = nic->node_addr[2]; |
1015 |
|
txb[5] = nic->node_addr[3]; |
1016 |
|
txb[8] = nic->node_addr[4]; |
1017 |
|
txb[9] = nic->node_addr[5]; |
1018 |
|
|
1019 |
|
tx_ring[0].length = cpu_to_le32(tx_flags); |
1020 |
|
tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]); |
1021 |
|
tx_ring[0].status = cpu_to_le32(0x80000000); |
1022 |
|
} |
1023 |
|
|
1024 |
whereami("tulip_reset\n"); |
/* Point to rx and tx descriptors */ |
1025 |
|
outl((unsigned long)&rx_ring[0], ioaddr + CSR3); |
1026 |
|
outl((unsigned long)&tx_ring[0], ioaddr + CSR4); |
1027 |
|
|
1028 |
|
init_media(nic); |
1029 |
|
|
1030 |
|
/* set the chip's operating mode (but don't turn on xmit and recv yet) */ |
1031 |
|
outl((tp->csr6 & ~0x00002002), ioaddr + CSR6); |
1032 |
|
|
1033 |
|
/* send setup packet for cards that support it */ |
1034 |
|
if (!(tp->flags & MC_HASH_ONLY)) { |
1035 |
|
/* enable transmit wait for completion */ |
1036 |
|
outl(tp->csr6 | 0x00002000, ioaddr + CSR6); |
1037 |
|
/* immediate transmit demand */ |
1038 |
|
outl(0, ioaddr + CSR1); |
1039 |
|
|
1040 |
|
to = currticks() + TX_TIME_OUT; |
1041 |
|
while ((tx_ring[0].status & 0x80000000) && (currticks() < to)) |
1042 |
|
/* wait */ ; |
1043 |
|
|
1044 |
|
if (currticks() >= to) { |
1045 |
|
printf ("%s: TX Setup Timeout.\n", tp->nic_name); |
1046 |
|
} |
1047 |
|
} |
1048 |
|
|
1049 |
/* Stop Tx and RX */ |
if (tp->chip_id == LC82C168) |
1050 |
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
tulip_check_duplex(nic); |
1051 |
|
|
1052 |
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) { |
/* enable transmit and receive */ |
1053 |
/* set up 10-BASE-T Control Port */ |
outl(tp->csr6 | 0x00002002, ioaddr + CSR6); |
|
outl(0xFFFFFFFF, ioaddr + CSR14); |
|
|
/* set up 10-BASE-T Status Port */ |
|
|
outl(0x00001000, ioaddr + CSR12); |
|
|
/* Set Operation Control Register (CSR6) for MX987x5 |
|
|
to allow N-Way Active Speed selection, and |
|
|
start the chip's Tx to process setup frame. |
|
|
While it is possible to force speed selection, |
|
|
this is probably more useful most of the time. |
|
|
*/ |
|
|
outl(0x01A80200, ioaddr + CSR6); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_LC82C115) { |
|
|
/* This is MX987x5 init code. It seems to work for the LNE100TX |
|
|
but should be replaced when we figure out the right way |
|
|
to do this initialization |
|
|
*/ |
|
|
outl(0xFFFFFFFF, ioaddr + CSR14); |
|
|
outl(0x00001000, ioaddr + CSR12); |
|
|
outl(0x01A80200, ioaddr + CSR6); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) { |
|
|
|
|
|
lc82c168_do_mii(); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_DEC && dev_id == PCI_DEVICE_ID_DEC_21142) { |
|
|
/* nothing */ |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_ADMTEK && dev_id == PCI_DEVICE_ID_ADMTEK_0985) { |
|
|
/* nothing */ |
|
|
|
|
|
} else { |
|
|
/* If we don't know what to do with the card, set to 10Mbps half-duplex */ |
|
|
|
|
|
outl(0x00000000, ioaddr + CSR13); |
|
|
outl(0x7F3F0000, ioaddr + CSR14); |
|
|
outl(0x08000008, ioaddr + CSR15); |
|
|
outl(0x00000000, ioaddr + CSR13); |
|
|
outl(0x00000001, ioaddr + CSR13); |
|
|
outl(0x02404000, ioaddr + CSR6); |
|
|
outl(0x08AF0008, ioaddr + CSR15); |
|
|
outl(0x00050008, ioaddr + CSR15); |
|
|
|
|
|
} |
|
|
|
|
|
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ |
|
|
outl(0x00000001, ioaddr + CSR0); |
|
|
|
|
|
tulip_wait(3*TICKS_PER_SEC); |
|
|
|
|
|
/* turn off reset and set cache align=16lword, burst=unlimit */ |
|
|
outl(0x01A08000, ioaddr + CSR0); |
|
|
|
|
|
/* set up transmit and receive descriptors */ |
|
|
tulip_init_ring(nic); |
|
|
|
|
|
/* set up multicast hash address for Comet (ADKTEK 0985) */ |
|
|
/* possibly not needed for Etherboot, but seems to do no harm -mdc */ |
|
|
if (vendor == PCI_VENDOR_ID_ADMTEK && dev_id == PCI_DEVICE_ID_ADMTEK_0985) { |
|
|
addr_low = nic->node_addr[0] + (nic->node_addr[1] << 8) |
|
|
+ (nic->node_addr[2] << 16) + (nic->node_addr[3] << 24); |
|
|
addr_high = nic->node_addr[4] + (nic->node_addr[5] << 8); |
|
|
outl(addr_low, ioaddr + 0xA4); |
|
|
outl(addr_high, ioaddr + 0xA8); |
|
|
outl(0, ioaddr + 0xAC); |
|
|
outl(0, ioaddr + 0xB0); |
|
|
} |
|
|
|
|
|
/* Point to receive descriptor */ |
|
|
outl((unsigned long)&rxd[0], ioaddr + CSR3); |
|
|
outl((unsigned long)&txd , ioaddr + CSR4); |
|
|
|
|
|
csr6 = 0x02404000; |
|
|
|
|
|
/* Chip specific init code */ |
|
|
|
|
|
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) { |
|
|
csr6 = 0x01880200; |
|
|
/* Set CSR16 and CSR20 to values that allow device modification */ |
|
|
outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16); |
|
|
outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_LC82C115) { |
|
|
/* This is MX987x5 init code. It seems to work for the LNE100TX |
|
|
but should be replaced when we figure out the right way |
|
|
to do this initialization. |
|
|
*/ |
|
|
csr6 = 0x01880200; |
|
|
outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16); |
|
|
outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) { |
|
|
|
|
|
csr6 = 0x814C0000; |
|
|
outl(0x00000001, ioaddr + CSR15); |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_DEC && dev_id == PCI_DEVICE_ID_DEC_21142) { |
|
|
/* check SROM for evidence of an MII interface */ |
|
|
/* get Controller_0 Info Leaf Offset from SROM - assume already in ee_data */ |
|
|
int offset = ee_data [27] + (ee_data [28] << 8); |
|
|
|
|
|
/* check offset range and if we have an extended type 3 Info Block */ |
|
|
if ((offset >= 30) && (offset < 120) && (ee_data [offset + 3] > 128) && |
|
|
(ee_data [offset + 4] == 3)) { |
|
|
/* must have an MII interface - disable heartbeat, select port etc. */ |
|
|
csr6 |= (DEC_21142_CSR6_HBD | DEC_21142_CSR6_PS); |
|
|
csr6 &= ~(DEC_21142_CSR6_TTM); |
|
|
} |
|
|
} else if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9102){ |
|
|
/* setup CR12 */ |
|
|
outl(0x180, ioaddr + CSR12); /* Let bit 7 output port */ |
|
|
outl(0x80, ioaddr + CSR12); /* RESET DM9102 phyxcer */ |
|
|
outl(0x0, ioaddr + CSR12); /* Clear RESET signal */ |
|
|
|
|
|
} else if (vendor == PCI_VENDOR_ID_ADMTEK && dev_id == PCI_DEVICE_ID_ADMTEK_0985) { |
|
|
/* nothing */ |
|
|
|
|
|
} |
|
|
|
|
|
/* set the chip's operating mode */ |
|
|
outl(csr6, ioaddr + CSR6); |
|
|
|
|
|
/* Start Tx */ |
|
|
outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6); |
|
|
/* immediate transmit demand */ |
|
|
outl(0, ioaddr + CSR1); |
|
|
|
|
|
to = currticks() + TX_TIME_OUT; |
|
|
while ((txd.status & 0x80000000) && (currticks() < to)) |
|
|
/* wait */ ; |
|
|
|
|
|
if (currticks() >= to) { |
|
|
printf ("TX Setup Timeout!\n"); |
|
|
} |
|
|
|
|
|
#ifdef TULIP_DEBUG |
|
|
printf("txd.status = %X\n", txd.status); |
|
|
printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT)); |
|
|
tulip_more(); |
|
|
#endif |
|
|
|
|
|
/* enable RX */ |
|
|
outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6); |
|
|
/* immediate poll demand */ |
|
|
outl(0, ioaddr + CSR2); |
|
1054 |
} |
} |
1055 |
|
|
1056 |
|
|
1060 |
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, |
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, |
1061 |
unsigned int s, const char *p) |
unsigned int s, const char *p) |
1062 |
{ |
{ |
1063 |
unsigned long to; |
u16 nstype; |
1064 |
|
u32 to; |
1065 |
|
u32 csr6 = inl(ioaddr + CSR6); |
1066 |
|
|
1067 |
whereami("tulip_transmit\n"); |
#ifdef TULIP_DEBUG_WHERE |
1068 |
|
whereami("tulip_transmit\n"); |
1069 |
|
#endif |
1070 |
|
|
1071 |
|
/* Disable Tx */ |
1072 |
|
outl(csr6 & ~0x00002000, ioaddr + CSR6); |
1073 |
|
|
1074 |
/* Stop Tx */ |
memcpy(txb, d, ETH_ALEN); |
1075 |
outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); |
memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); |
1076 |
|
nstype = htons((u16) t); |
1077 |
|
memcpy(txb + 2 * ETH_ALEN, (u8 *)&nstype, 2); |
1078 |
|
memcpy(txb + ETH_HLEN, p, s); |
1079 |
|
|
1080 |
|
s += ETH_HLEN; |
1081 |
|
s &= 0x0FFF; |
1082 |
|
|
1083 |
|
/* pad to minimum packet size */ |
1084 |
|
while (s < ETH_ZLEN) |
1085 |
|
txb[s++] = '\0'; |
1086 |
|
|
1087 |
|
#ifdef TULIP_DEBUG |
1088 |
|
if (tulip_debug > 1) |
1089 |
|
printf("%s: sending %d bytes ethtype %hX\n", tp->nic_name, s, t); |
1090 |
|
#endif |
1091 |
|
|
1092 |
|
/* setup the transmit descriptor */ |
1093 |
|
/* 0x60000000 = no interrupt on completion */ |
1094 |
|
tx_ring[0].length = cpu_to_le32(0x60000000 | s); |
1095 |
|
tx_ring[0].status = cpu_to_le32(0x80000000); |
1096 |
|
|
1097 |
|
/* Point to transmit descriptor */ |
1098 |
|
outl((u32)&tx_ring[0], ioaddr + CSR4); |
1099 |
|
|
1100 |
|
/* Enable Tx */ |
1101 |
|
outl(csr6 | 0x00002000, ioaddr + CSR6); |
1102 |
|
/* immediate transmit demand */ |
1103 |
|
outl(0, ioaddr + CSR1); |
1104 |
|
|
1105 |
|
to = currticks() + TX_TIME_OUT; |
1106 |
|
while ((tx_ring[0].status & 0x80000000) && (currticks() < to)) |
1107 |
|
/* wait */ ; |
1108 |
|
|
1109 |
/* setup ethernet header */ |
if (currticks() >= to) { |
1110 |
memcpy(ehdr, d, ETHER_ADDR_SIZE); |
printf ("TX Timeout!\n"); |
1111 |
memcpy(&ehdr[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE); |
} |
|
ehdr[ETHER_ADDR_SIZE*2] = (t >> 8) & 0xFF; |
|
|
ehdr[ETHER_ADDR_SIZE*2+1] = t & 0xFF; |
|
|
|
|
|
/* setup the transmit descriptor */ |
|
|
txd.buf1addr = &ehdr[0]; /* ethernet header */ |
|
|
txd.buf1sz = ETHER_HDR_SIZE; |
|
|
txd.buf2addr = p; /* packet to transmit */ |
|
|
txd.buf2sz = s; |
|
|
txd.control = 0x00000188; /* LS+FS+TER */ |
|
|
txd.status = 0x80000000; /* give ownership to device */ |
|
|
|
|
|
/* Point to transmit descriptor */ |
|
|
outl((unsigned long)&txd, ioaddr + CSR4); |
|
|
|
|
|
/* Start Tx */ |
|
|
outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6); |
|
|
|
|
|
/* immediate transmit demand */ |
|
|
outl(0, ioaddr + CSR1); |
|
|
|
|
|
to = currticks() + TX_TIME_OUT; |
|
|
while ((txd.status & 0x80000000) && (currticks() < to)) |
|
|
/* wait */ ; |
|
|
|
|
|
if (currticks() >= to) { |
|
|
printf ("TX Timeout!\n"); |
|
|
} |
|
1112 |
|
|
1113 |
|
/* Disable Tx */ |
1114 |
|
outl(csr6 & ~0x00002000, ioaddr + CSR6); |
1115 |
} |
} |
1116 |
|
|
1117 |
/*********************************************************************/ |
/*********************************************************************/ |
1119 |
/*********************************************************************/ |
/*********************************************************************/ |
1120 |
static int tulip_poll(struct nic *nic) |
static int tulip_poll(struct nic *nic) |
1121 |
{ |
{ |
|
whereami("tulip_poll\n"); |
|
1122 |
|
|
1123 |
if (rxd[rxd_tail].status & 0x80000000) |
#ifdef TULIP_DEBUG_WHERE |
1124 |
return 0; |
whereami("tulip_poll\n"); |
1125 |
|
#endif |
1126 |
|
|
1127 |
whereami("tulip_poll got one\n"); |
/* no packet waiting. packet still owned by NIC */ |
1128 |
|
if (rx_ring[tp->cur_rx].status & 0x80000000) |
1129 |
|
return 0; |
1130 |
|
|
1131 |
nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16; |
#ifdef TULIP_DEBUG_WHERE |
1132 |
|
whereami("tulip_poll got one\n"); |
1133 |
|
#endif |
1134 |
|
|
1135 |
if( rxd[rxd_tail].status & 0x00008000){ |
nic->packetlen = (rx_ring[tp->cur_rx].status & 0x3FFF0000) >> 16; |
|
rxd[rxd_tail].status = 0x80000000; |
|
|
rxd_tail++; |
|
|
if (rxd_tail == NRXD) rxd_tail = 0; |
|
|
return 0; |
|
|
} |
|
1136 |
|
|
1137 |
/* copy packet to working buffer */ |
/* if we get a corrupted packet. throw it away and move on */ |
1138 |
/* XXX - this copy could be avoided with a little more work |
if (rx_ring[tp->cur_rx].status & 0x00008000) { |
1139 |
but for now we are content with it because the optimised |
/* return the descriptor and buffer to receive ring */ |
1140 |
memcpy is quite fast */ |
rx_ring[tp->cur_rx].status = 0x80000000; |
1141 |
|
tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; |
1142 |
|
return 0; |
1143 |
|
} |
1144 |
|
|
1145 |
memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen); |
/* copy packet to working buffer */ |
1146 |
|
memcpy(nic->packet, rxb + tp->cur_rx * BUFLEN, nic->packetlen); |
1147 |
|
|
1148 |
/* return the descriptor and buffer to receive ring */ |
/* return the descriptor and buffer to receive ring */ |
1149 |
rxd[rxd_tail].status = 0x80000000; |
rx_ring[tp->cur_rx].status = 0x80000000; |
1150 |
rxd_tail++; |
tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; |
|
if (rxd_tail == NRXD) rxd_tail = 0; |
|
1151 |
|
|
1152 |
return 1; |
return 1; |
1153 |
} |
} |
1154 |
|
|
1155 |
/*********************************************************************/ |
/*********************************************************************/ |
1157 |
/*********************************************************************/ |
/*********************************************************************/ |
1158 |
static void tulip_disable(struct nic *nic) |
static void tulip_disable(struct nic *nic) |
1159 |
{ |
{ |
|
whereami("tulip_disable\n"); |
|
1160 |
|
|
1161 |
/* disable interrupts */ |
#ifdef TULIP_DEBUG_WHERE |
1162 |
outl(0x00000000, ioaddr + CSR7); |
whereami("tulip_disable\n"); |
1163 |
|
#endif |
1164 |
|
|
1165 |
|
/* disable interrupts */ |
1166 |
|
outl(0x00000000, ioaddr + CSR7); |
1167 |
|
|
1168 |
/* Stop the chip's Tx and Rx processes. */ |
/* Stop the chip's Tx and Rx processes. */ |
1169 |
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
1170 |
|
|
1171 |
/* Clear the missed-packet counter. */ |
/* Clear the missed-packet counter. */ |
1172 |
(volatile unsigned long)inl(ioaddr + CSR8); |
(volatile unsigned long)inl(ioaddr + CSR8); |
1173 |
} |
} |
1174 |
|
|
1175 |
/*********************************************************************/ |
/*********************************************************************/ |
1176 |
/* eth_probe - Look for an adapter */ |
/* eth_probe - Look for an adapter */ |
1177 |
/*********************************************************************/ |
/*********************************************************************/ |
1178 |
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, |
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, |
1179 |
struct pci_device *pci) |
struct pci_device *pci) |
1180 |
{ |
{ |
1181 |
unsigned int i; |
u32 i, l1, l2; |
1182 |
u32 l1, l2; |
u8 chip_rev; |
1183 |
|
u8 ee_data[EEPROM_SIZE]; |
1184 |
|
unsigned short sum; |
1185 |
|
int chip_idx; |
1186 |
|
static unsigned char last_phys_addr[ETH_ALEN] = {0x00, 'L', 'i', 'n', 'u', 'x'}; |
1187 |
|
|
1188 |
|
if (io_addrs == 0 || *io_addrs == 0) |
1189 |
|
return 0; |
1190 |
|
|
1191 |
|
ioaddr = *io_addrs; |
1192 |
|
|
1193 |
|
/* point to private storage */ |
1194 |
|
tp = &tpx; |
1195 |
|
|
1196 |
|
tp->vendor_id = pci->vendor; |
1197 |
|
tp->dev_id = pci->dev_id; |
1198 |
|
tp->nic_name = pci->name; |
1199 |
|
|
1200 |
|
tp->if_port = 0; |
1201 |
|
tp->default_port = 0; |
1202 |
|
|
1203 |
|
adjust_pci_device(pci); |
1204 |
|
|
1205 |
|
/* disable interrupts */ |
1206 |
|
outl(0x00000000, ioaddr + CSR7); |
1207 |
|
|
1208 |
|
/* Stop the chip's Tx and Rx processes. */ |
1209 |
|
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
1210 |
|
|
1211 |
|
/* Clear the missed-packet counter. */ |
1212 |
|
(volatile unsigned long)inl(ioaddr + CSR8); |
1213 |
|
|
1214 |
|
printf("\n"); /* so we start on a fresh line */ |
1215 |
|
#ifdef TULIP_DEBUG_WHERE |
1216 |
|
whereami("tulip_probe\n"); |
1217 |
|
#endif |
1218 |
|
|
1219 |
|
#ifdef TULIP_DEBUG |
1220 |
|
if (tulip_debug > 1) |
1221 |
|
printf ("%s: Looking for Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, |
1222 |
|
tp->vendor_id, tp->dev_id); |
1223 |
|
#endif |
1224 |
|
|
1225 |
|
/* Figure out which chip we're dealing with */ |
1226 |
|
i = 0; |
1227 |
|
chip_idx = -1; |
1228 |
|
|
1229 |
|
while (pci_id_tbl[i].name) { |
1230 |
|
if ( (((u32) tp->dev_id << 16) | tp->vendor_id) == |
1231 |
|
(pci_id_tbl[i].id.pci & pci_id_tbl[i].id.pci_mask) ) { |
1232 |
|
chip_idx = pci_id_tbl[i].drv_flags; |
1233 |
|
break; |
1234 |
|
} |
1235 |
|
i++; |
1236 |
|
} |
1237 |
|
|
1238 |
|
if (chip_idx == -1) { |
1239 |
|
printf ("%s: Unknown Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, |
1240 |
|
tp->vendor_id, tp->dev_id); |
1241 |
|
return 0; |
1242 |
|
} |
1243 |
|
|
1244 |
|
tp->pci_id_idx = i; |
1245 |
|
tp->flags = tulip_tbl[chip_idx].flags; |
1246 |
|
|
1247 |
|
#ifdef TULIP_DEBUG |
1248 |
|
if (tulip_debug > 1) { |
1249 |
|
printf ("%s: tp->pci_id_idx == %d, name == %s\n", tp->nic_name, |
1250 |
|
tp->pci_id_idx, pci_id_tbl[tp->pci_id_idx].name); |
1251 |
|
printf ("%s: chip_idx == %d, name == %s\n", tp->nic_name, chip_idx, |
1252 |
|
tulip_tbl[chip_idx].chip_name); |
1253 |
|
} |
1254 |
|
#endif |
1255 |
|
|
1256 |
|
/* Bring the 21041/21143 out of sleep mode. |
1257 |
|
Caution: Snooze mode does not work with some boards! */ |
1258 |
|
if (tp->flags & HAS_PWRDWN) |
1259 |
|
pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000); |
1260 |
|
|
1261 |
|
if (inl(ioaddr + CSR5) == 0xFFFFFFFF) { |
1262 |
|
printf("%s: The Tulip chip at %X is not functioning.\n", |
1263 |
|
tp->nic_name, ioaddr); |
1264 |
|
return 0; |
1265 |
|
} |
1266 |
|
|
1267 |
|
pcibios_read_config_byte(pci->bus, pci->devfn, PCI_REVISION, &chip_rev); |
1268 |
|
|
1269 |
|
printf("%s: [chip: %s] rev %d at %hX\n", tp->nic_name, |
1270 |
|
tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); |
1271 |
|
printf("%s: Vendor=%hX Device=%hX", tp->nic_name, tp->vendor_id, tp->dev_id); |
1272 |
|
|
1273 |
|
if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { |
1274 |
|
printf(" 21040 compatible mode."); |
1275 |
|
chip_idx = DC21040; |
1276 |
|
} |
1277 |
|
|
1278 |
whereami("tulip_probe\n"); |
printf("\n"); |
1279 |
|
|
1280 |
if (io_addrs == 0 || *io_addrs == 0) |
/* The SROM/EEPROM interface varies dramatically. */ |
1281 |
return 0; |
sum = 0; |
1282 |
|
if (chip_idx == DC21040) { |
1283 |
vendor = pci->vendor; |
outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ |
1284 |
dev_id = pci->dev_id; |
for (i = 0; i < ETH_ALEN; i++) { |
1285 |
ioaddr = *io_addrs; |
int value, boguscnt = 100000; |
1286 |
|
do |
1287 |
/* wakeup chip */ |
value = inl(ioaddr + CSR9); |
1288 |
pcibios_write_config_dword(0, pci->devfn, 0x40, 0x00000000); |
while (value < 0 && --boguscnt > 0); |
1289 |
|
nic->node_addr[i] = value; |
1290 |
/* Stop the chip's Tx and Rx processes. */ |
sum += value & 0xff; |
1291 |
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); |
} |
1292 |
|
} else if (chip_idx == LC82C168) { |
1293 |
/* Clear the missed-packet counter. */ |
for (i = 0; i < 3; i++) { |
1294 |
(volatile unsigned long)inl(ioaddr + CSR8); |
int value, boguscnt = 100000; |
1295 |
|
outl(0x600 | i, ioaddr + 0x98); |
1296 |
/* Get MAC Address */ |
do |
1297 |
|
value = inl(ioaddr + CSR9); |
1298 |
/* Hardware Address retrieval method for LC82C168 */ |
while (value < 0 && --boguscnt > 0); |
1299 |
if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) { |
put_unaligned(le16_to_cpu(value), ((u16*)nic->node_addr) + i); |
1300 |
for (i = 0; i < 3; i++) { |
sum += value & 0xffff; |
1301 |
int value, boguscnt = 100000; |
} |
1302 |
outl(0x600 | i, ioaddr + 0x98); |
} else if (chip_idx == COMET) { |
1303 |
do |
/* No need to read the EEPROM. */ |
1304 |
value = inl(ioaddr + CSR9); |
put_unaligned(inl(ioaddr + 0xA4), (u32 *)nic->node_addr); |
1305 |
while (value < 0 && --boguscnt > 0); |
put_unaligned(inl(ioaddr + 0xA8), (u16 *)(nic->node_addr + 4)); |
1306 |
nic->node_addr[i*2] = (u8)((value >> 8) & 0xFF); |
for (i = 0; i < ETH_ALEN; i ++) |
1307 |
nic->node_addr[i*2 + 1] = (u8)( value & 0xFF); |
sum += nic->node_addr[i]; |
1308 |
} |
} else { |
1309 |
} else if (vendor == PCI_VENDOR_ID_ADMTEK && |
/* A serial EEPROM interface, we read now and sort it out later. */ |
1310 |
dev_id == PCI_DEVICE_ID_ADMTEK_0985) { |
int sa_offset = 0; |
1311 |
l1 = inl(ioaddr + 0xA4); |
int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; |
1312 |
l2 = inl(ioaddr + 0xA8); |
|
1313 |
nic->node_addr[0] = (l1 ) & 0xFF; |
for (i = 0; i < sizeof(ee_data)/2; i++) |
1314 |
nic->node_addr[1] = (l1 >> 8) & 0xFF; |
((u16 *)ee_data)[i] = |
1315 |
nic->node_addr[2] = (l1 >> 16) & 0xFF; |
le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); |
1316 |
nic->node_addr[3] = (l1 >> 24) & 0xFF; |
|
1317 |
nic->node_addr[4] = (l2 ) & 0xFF; |
/* DEC now has a specification (see Notes) but early board makers |
1318 |
nic->node_addr[5] = (l2 >> 8) & 0xFF; |
just put the address in the first EEPROM locations. */ |
1319 |
} else { |
/* This does memcmp(eedata, eedata+16, 8) */ |
1320 |
/* read EEPROM data */ |
for (i = 0; i < 8; i ++) |
1321 |
for (i = 0; i < sizeof(ee_data)/2; i++) |
if (ee_data[i] != ee_data[16+i]) |
1322 |
((unsigned short *)ee_data)[i] = |
sa_offset = 20; |
1323 |
le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); |
if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { |
1324 |
|
sa_offset = 2; /* Grrr, damn Matrox boards. */ |
1325 |
/* extract MAC address from EEPROM buffer */ |
} |
1326 |
for (i=0; i<6; i++) |
for (i = 0; i < ETH_ALEN; i ++) { |
1327 |
nic->node_addr[i] = ee_data[20+i]; |
nic->node_addr[i] = ee_data[i + sa_offset]; |
1328 |
} |
sum += ee_data[i + sa_offset]; |
1329 |
|
} |
1330 |
printf("Tulip %b:%b:%b:%b:%b:%b at ioaddr 0x%x\n", |
} |
1331 |
nic->node_addr[0],nic->node_addr[1],nic->node_addr[2],nic->node_addr[3], |
/* Lite-On boards have the address byte-swapped. */ |
1332 |
nic->node_addr[4],nic->node_addr[5],ioaddr); |
if ((nic->node_addr[0] == 0xA0 || nic->node_addr[0] == 0xC0) |
1333 |
|
&& nic->node_addr[1] == 0x00) |
1334 |
/* initialize device */ |
for (i = 0; i < ETH_ALEN; i+=2) { |
1335 |
tulip_reset(nic); |
char tmp = nic->node_addr[i]; |
1336 |
|
nic->node_addr[i] = nic->node_addr[i+1]; |
1337 |
nic->reset = tulip_reset; |
nic->node_addr[i+1] = tmp; |
1338 |
nic->poll = tulip_poll; |
} |
1339 |
nic->transmit = tulip_transmit; |
|
1340 |
nic->disable = tulip_disable; |
if (sum == 0 || sum == ETH_ALEN*0xff) { |
1341 |
|
printf("%s: EEPROM not present!\n", tp->nic_name); |
1342 |
|
for (i = 0; i < ETH_ALEN-1; i++) |
1343 |
|
nic->node_addr[i] = last_phys_addr[i]; |
1344 |
|
nic->node_addr[i] = last_phys_addr[i] + 1; |
1345 |
|
} |
1346 |
|
|
1347 |
|
for (i = 0; i < ETH_ALEN; i++) |
1348 |
|
last_phys_addr[i] = nic->node_addr[i]; |
1349 |
|
|
1350 |
|
printf("%s: %! at ioaddr %hX\n", tp->nic_name, nic->node_addr, ioaddr); |
1351 |
|
|
1352 |
|
tp->chip_id = chip_idx; |
1353 |
|
tp->revision = chip_rev; |
1354 |
|
tp->csr0 = csr0; |
1355 |
|
|
1356 |
|
/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. |
1357 |
|
And the ASIX must have a burst limit or horrible things happen. */ |
1358 |
|
if (chip_idx == DC21143 && chip_rev == 65) |
1359 |
|
tp->csr0 &= ~0x01000000; |
1360 |
|
else if (tp->flags & IS_ASIX) |
1361 |
|
tp->csr0 |= 0x2000; |
1362 |
|
|
1363 |
|
if (media_cap[tp->default_port] & MediaIsMII) { |
1364 |
|
u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; |
1365 |
|
tp->mii_advertise = media2advert[tp->default_port - 9]; |
1366 |
|
tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */ |
1367 |
|
} |
1368 |
|
|
1369 |
|
/* This is logically part of the probe routine, but too complex |
1370 |
|
to write inline. */ |
1371 |
|
if (tp->flags & HAS_MEDIA_TABLE) { |
1372 |
|
memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); |
1373 |
|
parse_eeprom(nic); |
1374 |
|
} |
1375 |
|
|
1376 |
|
start_link(nic); |
1377 |
|
|
1378 |
|
/* reset the device and make ready for tx and rx of packets */ |
1379 |
|
tulip_reset(nic); |
1380 |
|
|
1381 |
|
nic->reset = tulip_reset; |
1382 |
|
nic->poll = tulip_poll; |
1383 |
|
nic->transmit = tulip_transmit; |
1384 |
|
nic->disable = tulip_disable; |
1385 |
|
|
1386 |
|
/* give the board a chance to reset before returning */ |
1387 |
|
tulip_wait(4*TICKS_PER_SEC); |
1388 |
|
|
1389 |
|
return nic; |
1390 |
|
} |
1391 |
|
|
1392 |
|
static void start_link(struct nic *nic) |
1393 |
|
{ |
1394 |
|
int i; |
1395 |
|
|
1396 |
|
#ifdef TULIP_DEBUG_WHERE |
1397 |
|
whereami("start_link\n"); |
1398 |
|
#endif |
1399 |
|
|
1400 |
|
if ((tp->flags & ALWAYS_CHECK_MII) || |
1401 |
|
(tp->mtable && tp->mtable->has_mii) || |
1402 |
|
( ! tp->mtable && (tp->flags & HAS_MII))) { |
1403 |
|
unsigned int phy, phy_idx; |
1404 |
|
if (tp->mtable && tp->mtable->has_mii) { |
1405 |
|
for (i = 0; i < tp->mtable->leafcount; i++) |
1406 |
|
if (tp->mtable->mleaf[i].media == 11) { |
1407 |
|
tp->cur_index = i; |
1408 |
|
tp->saved_if_port = tp->if_port; |
1409 |
|
select_media(nic, 2); |
1410 |
|
tp->if_port = tp->saved_if_port; |
1411 |
|
break; |
1412 |
|
} |
1413 |
|
} |
1414 |
|
|
1415 |
|
/* Find the connected MII xcvrs. */ |
1416 |
|
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); |
1417 |
|
phy++) { |
1418 |
|
int mii_status = mdio_read(nic, phy, 1); |
1419 |
|
if ((mii_status & 0x8301) == 0x8001 || |
1420 |
|
((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { |
1421 |
|
int mii_reg0 = mdio_read(nic, phy, 0); |
1422 |
|
int mii_advert = mdio_read(nic, phy, 4); |
1423 |
|
int to_advert; |
1424 |
|
|
1425 |
|
if (tp->mii_advertise) |
1426 |
|
to_advert = tp->mii_advertise; |
1427 |
|
else if (tp->advertising[phy_idx]) |
1428 |
|
to_advert = tp->advertising[phy_idx]; |
1429 |
|
else /* Leave unchanged. */ |
1430 |
|
tp->mii_advertise = to_advert = mii_advert; |
1431 |
|
|
1432 |
|
tp->phys[phy_idx++] = phy; |
1433 |
|
printf("%s: MII transceiver %d config %hX status %hX advertising %hX.\n", |
1434 |
|
tp->nic_name, phy, mii_reg0, mii_status, mii_advert); |
1435 |
|
/* Fixup for DLink with miswired PHY. */ |
1436 |
|
if (mii_advert != to_advert) { |
1437 |
|
printf("%s: Advertising %hX on PHY %d previously advertising %hX.\n", |
1438 |
|
tp->nic_name, to_advert, phy, mii_advert); |
1439 |
|
mdio_write(nic, phy, 4, to_advert); |
1440 |
|
} |
1441 |
|
/* Enable autonegotiation: some boards default to off. */ |
1442 |
|
mdio_write(nic, phy, 0, mii_reg0 | |
1443 |
|
(tp->full_duplex ? 0x1100 : 0x1000) | |
1444 |
|
(media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); |
1445 |
|
} |
1446 |
|
} |
1447 |
|
tp->mii_cnt = phy_idx; |
1448 |
|
if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { |
1449 |
|
printf("%s: ***WARNING***: No MII transceiver found!\n", |
1450 |
|
tp->nic_name); |
1451 |
|
tp->phys[0] = 1; |
1452 |
|
} |
1453 |
|
} |
1454 |
|
|
1455 |
|
/* Reset the xcvr interface and turn on heartbeat. */ |
1456 |
|
switch (tp->chip_id) { |
1457 |
|
case DC21040: |
1458 |
|
outl(0x00000000, ioaddr + CSR13); |
1459 |
|
outl(0x00000004, ioaddr + CSR13); |
1460 |
|
break; |
1461 |
|
case DC21041: |
1462 |
|
/* This is nway_start(). */ |
1463 |
|
if (tp->sym_advertise == 0) |
1464 |
|
tp->sym_advertise = 0x0061; |
1465 |
|
outl(0x00000000, ioaddr + CSR13); |
1466 |
|
outl(0xFFFFFFFF, ioaddr + CSR14); |
1467 |
|
outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ |
1468 |
|
outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6); |
1469 |
|
outl(0x0000EF01, ioaddr + CSR13); |
1470 |
|
break; |
1471 |
|
case DC21140: default: |
1472 |
|
if (tp->mtable) |
1473 |
|
outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); |
1474 |
|
break; |
1475 |
|
case DC21142: |
1476 |
|
case PNIC2: |
1477 |
|
if (tp->mii_cnt || media_cap[tp->if_port] & MediaIsMII) { |
1478 |
|
outl(0x82020000, ioaddr + CSR6); |
1479 |
|
outl(0x0000, ioaddr + CSR13); |
1480 |
|
outl(0x0000, ioaddr + CSR14); |
1481 |
|
outl(0x820E0000, ioaddr + CSR6); |
1482 |
|
} else |
1483 |
|
nway_start(nic); |
1484 |
|
break; |
1485 |
|
case LC82C168: |
1486 |
|
if ( ! tp->mii_cnt) { |
1487 |
|
tp->nway = 1; |
1488 |
|
tp->nwayset = 0; |
1489 |
|
outl(0x00420000, ioaddr + CSR6); |
1490 |
|
outl(0x30, ioaddr + CSR12); |
1491 |
|
outl(0x0001F078, ioaddr + 0xB8); |
1492 |
|
outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ |
1493 |
|
} |
1494 |
|
break; |
1495 |
|
case MX98713: case COMPEX9881: |
1496 |
|
outl(0x00000000, ioaddr + CSR6); |
1497 |
|
outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ |
1498 |
|
outl(0x00000001, ioaddr + CSR13); |
1499 |
|
break; |
1500 |
|
case MX98715: case MX98725: |
1501 |
|
outl(0x01a80000, ioaddr + CSR6); |
1502 |
|
outl(0xFFFFFFFF, ioaddr + CSR14); |
1503 |
|
outl(0x00001000, ioaddr + CSR12); |
1504 |
|
break; |
1505 |
|
case COMET: |
1506 |
|
/* No initialization necessary. */ |
1507 |
|
break; |
1508 |
|
} |
1509 |
|
} |
1510 |
|
|
1511 |
|
static void nway_start(struct nic *nic) |
1512 |
|
{ |
1513 |
|
int csr14 = ((tp->sym_advertise & 0x0780) << 9) | |
1514 |
|
((tp->sym_advertise&0x0020)<<1) | 0xffbf; |
1515 |
|
|
1516 |
|
#ifdef TULIP_DEBUG_WHERE |
1517 |
|
whereami("nway_start\n"); |
1518 |
|
#endif |
1519 |
|
|
1520 |
|
tp->if_port = 0; |
1521 |
|
tp->nway = tp->mediasense = 1; |
1522 |
|
tp->nwayset = tp->lpar = 0; |
1523 |
|
if (tp->chip_id == PNIC2) { |
1524 |
|
tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0); |
1525 |
|
return; |
1526 |
|
} |
1527 |
|
#ifdef TULIP_DEBUG |
1528 |
|
if (tulip_debug > 1) |
1529 |
|
printf("%s: Restarting internal NWay autonegotiation, %X.\n", |
1530 |
|
tp->nic_name, csr14); |
1531 |
|
#endif |
1532 |
|
outl(0x0001, ioaddr + CSR13); |
1533 |
|
outl(csr14, ioaddr + CSR14); |
1534 |
|
tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? 0x0200 : 0); |
1535 |
|
outl(tp->csr6, ioaddr + CSR6); |
1536 |
|
if (tp->mtable && tp->mtable->csr15dir) { |
1537 |
|
outl(tp->mtable->csr15dir, ioaddr + CSR15); |
1538 |
|
outl(tp->mtable->csr15val, ioaddr + CSR15); |
1539 |
|
} else if (tp->chip_id != PNIC2) |
1540 |
|
outw(0x0008, ioaddr + CSR15); |
1541 |
|
if (tp->chip_id == DC21041) /* Trigger NWAY. */ |
1542 |
|
outl(0xEF01, ioaddr + CSR12); |
1543 |
|
else |
1544 |
|
outl(0x1301, ioaddr + CSR12); |
1545 |
|
} |
1546 |
|
|
1547 |
|
static void init_media(struct nic *nic) |
1548 |
|
{ |
1549 |
|
int i; |
1550 |
|
|
1551 |
|
#ifdef TULIP_DEBUG_WHERE |
1552 |
|
whereami("init_media\n"); |
1553 |
|
#endif |
1554 |
|
|
1555 |
|
tp->saved_if_port = tp->if_port; |
1556 |
|
if (tp->if_port == 0) |
1557 |
|
tp->if_port = tp->default_port; |
1558 |
|
|
1559 |
|
/* Allow selecting a default media. */ |
1560 |
|
i = 0; |
1561 |
|
if (tp->mtable == NULL) |
1562 |
|
goto media_picked; |
1563 |
|
if (tp->if_port) { |
1564 |
|
int looking_for = media_cap[tp->if_port] & MediaIsMII ? 11 : |
1565 |
|
(tp->if_port == 12 ? 0 : tp->if_port); |
1566 |
|
for (i = 0; i < tp->mtable->leafcount; i++) |
1567 |
|
if (tp->mtable->mleaf[i].media == looking_for) { |
1568 |
|
printf("%s: Using user-specified media %s.\n", |
1569 |
|
tp->nic_name, medianame[tp->if_port]); |
1570 |
|
goto media_picked; |
1571 |
|
} |
1572 |
|
} |
1573 |
|
if ((tp->mtable->defaultmedia & 0x0800) == 0) { |
1574 |
|
int looking_for = tp->mtable->defaultmedia & 15; |
1575 |
|
for (i = 0; i < tp->mtable->leafcount; i++) |
1576 |
|
if (tp->mtable->mleaf[i].media == looking_for) { |
1577 |
|
printf("%s: Using EEPROM-set media %s.\n", |
1578 |
|
tp->nic_name, medianame[looking_for]); |
1579 |
|
goto media_picked; |
1580 |
|
} |
1581 |
|
} |
1582 |
|
/* Start sensing first non-full-duplex media. */ |
1583 |
|
for (i = tp->mtable->leafcount - 1; |
1584 |
|
(media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) |
1585 |
|
; |
1586 |
|
media_picked: |
1587 |
|
|
1588 |
|
tp->csr6 = 0; |
1589 |
|
tp->cur_index = i; |
1590 |
|
tp->nwayset = 0; |
1591 |
|
|
1592 |
|
if (tp->if_port) { |
1593 |
|
if (tp->chip_id == DC21143 && media_cap[tp->if_port] & MediaIsMII) { |
1594 |
|
/* We must reset the media CSRs when we force-select MII mode. */ |
1595 |
|
outl(0x0000, ioaddr + CSR13); |
1596 |
|
outl(0x0000, ioaddr + CSR14); |
1597 |
|
outl(0x0008, ioaddr + CSR15); |
1598 |
|
} |
1599 |
|
select_media(nic, 1); |
1600 |
|
return; |
1601 |
|
} |
1602 |
|
switch(tp->chip_id) { |
1603 |
|
case DC21041: |
1604 |
|
/* tp->nway = 1;*/ |
1605 |
|
nway_start(nic); |
1606 |
|
break; |
1607 |
|
case DC21142: |
1608 |
|
if (tp->mii_cnt) { |
1609 |
|
select_media(nic, 1); |
1610 |
|
#ifdef TULIP_DEBUG |
1611 |
|
if (tulip_debug > 1) |
1612 |
|
printf("%s: Using MII transceiver %d, status %hX.\n", |
1613 |
|
tp->nic_name, tp->phys[0], mdio_read(nic, tp->phys[0], 1)); |
1614 |
|
#endif |
1615 |
|
outl(0x82020000, ioaddr + CSR6); |
1616 |
|
tp->csr6 = 0x820E0000; |
1617 |
|
tp->if_port = 11; |
1618 |
|
outl(0x0000, ioaddr + CSR13); |
1619 |
|
outl(0x0000, ioaddr + CSR14); |
1620 |
|
} else |
1621 |
|
nway_start(nic); |
1622 |
|
break; |
1623 |
|
case PNIC2: |
1624 |
|
nway_start(nic); |
1625 |
|
break; |
1626 |
|
case LC82C168: |
1627 |
|
if (tp->mii_cnt) { |
1628 |
|
tp->if_port = 11; |
1629 |
|
tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); |
1630 |
|
outl(0x0001, ioaddr + CSR15); |
1631 |
|
} else if (inl(ioaddr + CSR5) & TPLnkPass) |
1632 |
|
pnic_do_nway(nic); |
1633 |
|
else { |
1634 |
|
/* Start with 10mbps to do autonegotiation. */ |
1635 |
|
outl(0x32, ioaddr + CSR12); |
1636 |
|
tp->csr6 = 0x00420000; |
1637 |
|
outl(0x0001B078, ioaddr + 0xB8); |
1638 |
|
outl(0x0201B078, ioaddr + 0xB8); |
1639 |
|
} |
1640 |
|
break; |
1641 |
|
case MX98713: case COMPEX9881: |
1642 |
|
tp->if_port = 0; |
1643 |
|
tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); |
1644 |
|
outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); |
1645 |
|
break; |
1646 |
|
case MX98715: case MX98725: |
1647 |
|
/* Provided by BOLO, Macronix - 12/10/1998. */ |
1648 |
|
tp->if_port = 0; |
1649 |
|
tp->csr6 = 0x01a80200; |
1650 |
|
outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); |
1651 |
|
outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); |
1652 |
|
break; |
1653 |
|
case COMET: |
1654 |
|
tp->if_port = 0; |
1655 |
|
tp->csr6 = 0x00040000; |
1656 |
|
break; |
1657 |
|
case AX88140: case AX88141: |
1658 |
|
tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; |
1659 |
|
break; |
1660 |
|
default: |
1661 |
|
select_media(nic, 1); |
1662 |
|
} |
1663 |
|
} |
1664 |
|
|
1665 |
|
static void pnic_do_nway(struct nic *nic) |
1666 |
|
{ |
1667 |
|
u32 phy_reg = inl(ioaddr + 0xB8); |
1668 |
|
u32 new_csr6 = tp->csr6 & ~0x40C40200; |
1669 |
|
|
1670 |
|
#ifdef TULIP_DEBUG_WHERE |
1671 |
|
whereami("pnic_do_nway\n"); |
1672 |
|
#endif |
1673 |
|
|
1674 |
|
if (phy_reg & 0x78000000) { /* Ignore baseT4 */ |
1675 |
|
if (phy_reg & 0x20000000) tp->if_port = 5; |
1676 |
|
else if (phy_reg & 0x40000000) tp->if_port = 3; |
1677 |
|
else if (phy_reg & 0x10000000) tp->if_port = 4; |
1678 |
|
else if (phy_reg & 0x08000000) tp->if_port = 0; |
1679 |
|
tp->nwayset = 1; |
1680 |
|
new_csr6 = (tp->if_port & 1) ? 0x01860000 : 0x00420000; |
1681 |
|
outl(0x32 | (tp->if_port & 1), ioaddr + CSR12); |
1682 |
|
if (tp->if_port & 1) |
1683 |
|
outl(0x1F868, ioaddr + 0xB8); |
1684 |
|
if (phy_reg & 0x30000000) { |
1685 |
|
tp->full_duplex = 1; |
1686 |
|
new_csr6 |= 0x00000200; |
1687 |
|
} |
1688 |
|
#ifdef TULIP_DEBUG |
1689 |
|
if (tulip_debug > 1) |
1690 |
|
printf("%s: PNIC autonegotiated status %X, %s.\n", |
1691 |
|
tp->nic_name, phy_reg, medianame[tp->if_port]); |
1692 |
|
#endif |
1693 |
|
if (tp->csr6 != new_csr6) { |
1694 |
|
tp->csr6 = new_csr6; |
1695 |
|
outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */ |
1696 |
|
outl(tp->csr6 | 0x2002, ioaddr + CSR6); |
1697 |
|
} |
1698 |
|
} |
1699 |
|
} |
1700 |
|
|
1701 |
|
/* Set up the transceiver control registers for the selected media type. */ |
1702 |
|
static void select_media(struct nic *nic, int startup) |
1703 |
|
{ |
1704 |
|
struct mediatable *mtable = tp->mtable; |
1705 |
|
u32 new_csr6; |
1706 |
|
int i; |
1707 |
|
|
1708 |
|
#ifdef TULIP_DEBUG_WHERE |
1709 |
|
whereami("select_media\n"); |
1710 |
|
#endif |
1711 |
|
|
1712 |
|
if (mtable) { |
1713 |
|
struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; |
1714 |
|
unsigned char *p = mleaf->leafdata; |
1715 |
|
switch (mleaf->type) { |
1716 |
|
case 0: /* 21140 non-MII xcvr. */ |
1717 |
|
#ifdef TULIP_DEBUG |
1718 |
|
if (tulip_debug > 1) |
1719 |
|
printf("%s: Using a 21140 non-MII transceiver" |
1720 |
|
" with control setting %hhX.\n", |
1721 |
|
tp->nic_name, p[1]); |
1722 |
|
#endif |
1723 |
|
tp->if_port = p[0]; |
1724 |
|
if (startup) |
1725 |
|
outl(mtable->csr12dir | 0x100, ioaddr + CSR12); |
1726 |
|
outl(p[1], ioaddr + CSR12); |
1727 |
|
new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); |
1728 |
|
break; |
1729 |
|
case 2: case 4: { |
1730 |
|
u16 setup[5]; |
1731 |
|
u32 csr13val, csr14val, csr15dir, csr15val; |
1732 |
|
for (i = 0; i < 5; i++) |
1733 |
|
setup[i] = get_u16(&p[i*2 + 1]); |
1734 |
|
|
1735 |
|
tp->if_port = p[0] & 15; |
1736 |
|
if (media_cap[tp->if_port] & MediaAlwaysFD) |
1737 |
|
tp->full_duplex = 1; |
1738 |
|
|
1739 |
|
if (startup && mtable->has_reset) { |
1740 |
|
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; |
1741 |
|
unsigned char *rst = rleaf->leafdata; |
1742 |
|
#ifdef TULIP_DEBUG |
1743 |
|
if (tulip_debug > 1) |
1744 |
|
printf("%s: Resetting the transceiver.\n", |
1745 |
|
tp->nic_name); |
1746 |
|
#endif |
1747 |
|
for (i = 0; i < rst[0]; i++) |
1748 |
|
outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); |
1749 |
|
} |
1750 |
|
#ifdef TULIP_DEBUG |
1751 |
|
if (tulip_debug > 1) |
1752 |
|
printf("%s: 21143 non-MII %s transceiver control " |
1753 |
|
"%hX/%hX.\n", |
1754 |
|
tp->nic_name, medianame[tp->if_port], setup[0], setup[1]); |
1755 |
|
#endif |
1756 |
|
if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ |
1757 |
|
csr13val = setup[0]; |
1758 |
|
csr14val = setup[1]; |
1759 |
|
csr15dir = (setup[3]<<16) | setup[2]; |
1760 |
|
csr15val = (setup[4]<<16) | setup[2]; |
1761 |
|
outl(0, ioaddr + CSR13); |
1762 |
|
outl(csr14val, ioaddr + CSR14); |
1763 |
|
outl(csr15dir, ioaddr + CSR15); /* Direction */ |
1764 |
|
outl(csr15val, ioaddr + CSR15); /* Data */ |
1765 |
|
outl(csr13val, ioaddr + CSR13); |
1766 |
|
} else { |
1767 |
|
csr13val = 1; |
1768 |
|
csr14val = 0x0003FF7F; |
1769 |
|
csr15dir = (setup[0]<<16) | 0x0008; |
1770 |
|
csr15val = (setup[1]<<16) | 0x0008; |
1771 |
|
if (tp->if_port <= 4) |
1772 |
|
csr14val = t21142_csr14[tp->if_port]; |
1773 |
|
if (startup) { |
1774 |
|
outl(0, ioaddr + CSR13); |
1775 |
|
outl(csr14val, ioaddr + CSR14); |
1776 |
|
} |
1777 |
|
outl(csr15dir, ioaddr + CSR15); /* Direction */ |
1778 |
|
outl(csr15val, ioaddr + CSR15); /* Data */ |
1779 |
|
if (startup) outl(csr13val, ioaddr + CSR13); |
1780 |
|
} |
1781 |
|
#ifdef TULIP_DEBUG |
1782 |
|
if (tulip_debug > 1) |
1783 |
|
printf("%s: Setting CSR15 to %X/%X.\n", |
1784 |
|
tp->nic_name, csr15dir, csr15val); |
1785 |
|
#endif |
1786 |
|
if (mleaf->type == 4) |
1787 |
|
new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); |
1788 |
|
else |
1789 |
|
new_csr6 = 0x82420000; |
1790 |
|
break; |
1791 |
|
} |
1792 |
|
case 1: case 3: { |
1793 |
|
int phy_num = p[0]; |
1794 |
|
int init_length = p[1]; |
1795 |
|
u16 *misc_info; |
1796 |
|
|
1797 |
|
tp->if_port = 11; |
1798 |
|
new_csr6 = 0x020E0000; |
1799 |
|
if (mleaf->type == 3) { /* 21142 */ |
1800 |
|
u16 *init_sequence = (u16*)(p+2); |
1801 |
|
u16 *reset_sequence = &((u16*)(p+3))[init_length]; |
1802 |
|
int reset_length = p[2 + init_length*2]; |
1803 |
|
misc_info = reset_sequence + reset_length; |
1804 |
|
if (startup) |
1805 |
|
for (i = 0; i < reset_length; i++) |
1806 |
|
outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); |
1807 |
|
for (i = 0; i < init_length; i++) |
1808 |
|
outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); |
1809 |
|
} else { |
1810 |
|
u8 *init_sequence = p + 2; |
1811 |
|
u8 *reset_sequence = p + 3 + init_length; |
1812 |
|
int reset_length = p[2 + init_length]; |
1813 |
|
misc_info = (u16*)(reset_sequence + reset_length); |
1814 |
|
if (startup) { |
1815 |
|
outl(mtable->csr12dir | 0x100, ioaddr + CSR12); |
1816 |
|
for (i = 0; i < reset_length; i++) |
1817 |
|
outl(reset_sequence[i], ioaddr + CSR12); |
1818 |
|
} |
1819 |
|
for (i = 0; i < init_length; i++) |
1820 |
|
outl(init_sequence[i], ioaddr + CSR12); |
1821 |
|
} |
1822 |
|
tp->advertising[phy_num] = get_u16(&misc_info[1]) | 1; |
1823 |
|
if (startup < 2) { |
1824 |
|
if (tp->mii_advertise == 0) |
1825 |
|
tp->mii_advertise = tp->advertising[phy_num]; |
1826 |
|
#ifdef TULIP_DEBUG |
1827 |
|
if (tulip_debug > 1) |
1828 |
|
printf("%s: Advertising %hX on MII %d.\n", |
1829 |
|
tp->nic_name, tp->mii_advertise, tp->phys[phy_num]); |
1830 |
|
#endif |
1831 |
|
mdio_write(nic, tp->phys[phy_num], 4, tp->mii_advertise); |
1832 |
|
} |
1833 |
|
break; |
1834 |
|
} |
1835 |
|
default: |
1836 |
|
printf("%s: Invalid media table selection %d.\n", |
1837 |
|
tp->nic_name, mleaf->type); |
1838 |
|
new_csr6 = 0x020E0000; |
1839 |
|
} |
1840 |
|
#ifdef TULIP_DEBUG |
1841 |
|
if (tulip_debug > 1) |
1842 |
|
printf("%s: Using media type %s, CSR12 is %hhX.\n", |
1843 |
|
tp->nic_name, medianame[tp->if_port], |
1844 |
|
inl(ioaddr + CSR12) & 0xff); |
1845 |
|
#endif |
1846 |
|
} else if (tp->chip_id == DC21041) { |
1847 |
|
int port = tp->if_port <= 4 ? tp->if_port : 0; |
1848 |
|
#ifdef TULIP_DEBUG |
1849 |
|
if (tulip_debug > 1) |
1850 |
|
printf("%s: 21041 using media %s, CSR12 is %hX.\n", |
1851 |
|
tp->nic_name, medianame[port == 3 ? 12: port], |
1852 |
|
inl(ioaddr + CSR12)); |
1853 |
|
#endif |
1854 |
|
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ |
1855 |
|
outl(t21041_csr14[port], ioaddr + CSR14); |
1856 |
|
outl(t21041_csr15[port], ioaddr + CSR15); |
1857 |
|
outl(t21041_csr13[port], ioaddr + CSR13); |
1858 |
|
new_csr6 = 0x80020000; |
1859 |
|
} else if (tp->chip_id == LC82C168) { |
1860 |
|
if (startup && ! tp->medialock) |
1861 |
|
tp->if_port = tp->mii_cnt ? 11 : 0; |
1862 |
|
#ifdef TULIP_DEBUG |
1863 |
|
if (tulip_debug > 1) |
1864 |
|
printf("%s: PNIC PHY status is %hX, media %s.\n", |
1865 |
|
tp->nic_name, inl(ioaddr + 0xB8), medianame[tp->if_port]); |
1866 |
|
#endif |
1867 |
|
if (tp->mii_cnt) { |
1868 |
|
new_csr6 = 0x810C0000; |
1869 |
|
outl(0x0001, ioaddr + CSR15); |
1870 |
|
outl(0x0201B07A, ioaddr + 0xB8); |
1871 |
|
} else if (startup) { |
1872 |
|
/* Start with 10mbps to do autonegotiation. */ |
1873 |
|
outl(0x32, ioaddr + CSR12); |
1874 |
|
new_csr6 = 0x00420000; |
1875 |
|
outl(0x0001B078, ioaddr + 0xB8); |
1876 |
|
outl(0x0201B078, ioaddr + 0xB8); |
1877 |
|
} else if (tp->if_port == 3 || tp->if_port == 5) { |
1878 |
|
outl(0x33, ioaddr + CSR12); |
1879 |
|
new_csr6 = 0x01860000; |
1880 |
|
/* Trigger autonegotiation. */ |
1881 |
|
outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); |
1882 |
|
} else { |
1883 |
|
outl(0x32, ioaddr + CSR12); |
1884 |
|
new_csr6 = 0x00420000; |
1885 |
|
outl(0x1F078, ioaddr + 0xB8); |
1886 |
|
} |
1887 |
|
} else if (tp->chip_id == DC21040) { /* 21040 */ |
1888 |
|
/* Turn on the xcvr interface. */ |
1889 |
|
int csr12 = inl(ioaddr + CSR12); |
1890 |
|
#ifdef TULIP_DEBUG |
1891 |
|
if (tulip_debug > 1) |
1892 |
|
printf("%s: 21040 media type is %s, CSR12 is %hhX.\n", |
1893 |
|
tp->nic_name, medianame[tp->if_port], csr12); |
1894 |
|
#endif |
1895 |
|
if (media_cap[tp->if_port] & MediaAlwaysFD) |
1896 |
|
tp->full_duplex = 1; |
1897 |
|
new_csr6 = 0x20000; |
1898 |
|
/* Set the full duplux match frame. */ |
1899 |
|
outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); |
1900 |
|
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ |
1901 |
|
if (t21040_csr13[tp->if_port] & 8) { |
1902 |
|
outl(0x0705, ioaddr + CSR14); |
1903 |
|
outl(0x0006, ioaddr + CSR15); |
1904 |
|
} else { |
1905 |
|
outl(0xffff, ioaddr + CSR14); |
1906 |
|
outl(0x0000, ioaddr + CSR15); |
1907 |
|
} |
1908 |
|
outl(0x8f01 | t21040_csr13[tp->if_port], ioaddr + CSR13); |
1909 |
|
} else { /* Unknown chip type with no media table. */ |
1910 |
|
if (tp->default_port == 0) |
1911 |
|
tp->if_port = tp->mii_cnt ? 11 : 3; |
1912 |
|
if (media_cap[tp->if_port] & MediaIsMII) { |
1913 |
|
new_csr6 = 0x020E0000; |
1914 |
|
} else if (media_cap[tp->if_port] & MediaIsFx) { |
1915 |
|
new_csr6 = 0x028600000; |
1916 |
|
} else |
1917 |
|
new_csr6 = 0x038600000; |
1918 |
|
#ifdef TULIP_DEBUG |
1919 |
|
if (tulip_debug > 1) |
1920 |
|
printf("%s: No media description table, assuming " |
1921 |
|
"%s transceiver, CSR12 %hhX.\n", |
1922 |
|
tp->nic_name, medianame[tp->if_port], |
1923 |
|
inl(ioaddr + CSR12)); |
1924 |
|
#endif |
1925 |
|
} |
1926 |
|
|
1927 |
|
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); |
1928 |
|
return; |
1929 |
|
} |
1930 |
|
|
1931 |
|
/* |
1932 |
|
Check the MII negotiated duplex and change the CSR6 setting if |
1933 |
|
required. |
1934 |
|
Return 0 if everything is OK. |
1935 |
|
Return < 0 if the transceiver is missing or has no link beat. |
1936 |
|
*/ |
1937 |
|
static int tulip_check_duplex(struct nic *nic) |
1938 |
|
{ |
1939 |
|
unsigned int bmsr, lpa, negotiated, new_csr6; |
1940 |
|
|
1941 |
|
bmsr = mdio_read(nic, tp->phys[0], 1); |
1942 |
|
lpa = mdio_read(nic, tp->phys[0], 5); |
1943 |
|
|
1944 |
|
#ifdef TULIP_DEBUG |
1945 |
|
if (tulip_debug > 1) |
1946 |
|
printf("%s: MII status %#x, Link partner report " |
1947 |
|
"%#x.\n", tp->nic_name, bmsr, lpa); |
1948 |
|
#endif |
1949 |
|
|
1950 |
|
if (bmsr == 0xffff) |
1951 |
|
return -2; |
1952 |
|
if ((bmsr & 4) == 0) { |
1953 |
|
int new_bmsr = mdio_read(nic, tp->phys[0], 1); |
1954 |
|
if ((new_bmsr & 4) == 0) { |
1955 |
|
#ifdef TULIP_DEBUG |
1956 |
|
if (tulip_debug > 1) |
1957 |
|
printf("%s: No link beat on the MII interface," |
1958 |
|
" status %#x.\n", tp->nic_name, |
1959 |
|
new_bmsr); |
1960 |
|
#endif |
1961 |
|
return -1; |
1962 |
|
} |
1963 |
|
} |
1964 |
|
tp->full_duplex = lpa & 0x140; |
1965 |
|
|
1966 |
|
new_csr6 = tp->csr6; |
1967 |
|
negotiated = lpa & tp->advertising[0]; |
1968 |
|
|
1969 |
|
if(negotiated & 0x380) new_csr6 &= ~0x400000; |
1970 |
|
else new_csr6 |= 0x400000; |
1971 |
|
if (tp->full_duplex) new_csr6 |= 0x200; |
1972 |
|
else new_csr6 &= ~0x200; |
1973 |
|
|
1974 |
|
if (new_csr6 != tp->csr6) { |
1975 |
|
tp->csr6 = new_csr6; |
1976 |
|
|
1977 |
|
#ifdef TULIP_DEBUG |
1978 |
|
if (tulip_debug > 0) |
1979 |
|
printf("%s: Setting %s-duplex based on MII" |
1980 |
|
"#%d link partner capability of %#x.\n", |
1981 |
|
tp->nic_name, |
1982 |
|
tp->full_duplex ? "full" : "half", |
1983 |
|
tp->phys[0], lpa); |
1984 |
|
#endif |
1985 |
|
return 1; |
1986 |
|
} |
1987 |
|
|
1988 |
return nic; |
return 0; |
1989 |
} |
} |