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