|
|
1.1 root 1: /*
2: * 3c515.c -- 3COM 3C515 Fast Etherlink ISA 10/100BASE-TX driver for etherboot
3: * Copyright (C) 2002 Timothy Legge <[email protected]>
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU General Public License for more details.
14: *
15: * You should have received a copy of the GNU General Public License
16: * along with this program; if not, write to the Free Software
17: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18: *
19: * Portions of this code:
20: * Copyright (C) 1997-2002 Donald Becker 3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux.
21: * Copyright (C) 2001 P.J.H.Fox ([email protected]) ISAPNP Tools
22: * Copyright (c) 2002 Jaroslav Kysela <[email protected]> ISA Plug & Play support Linux Kernel
23: * Copyright (C) 2000 Shusuke Nisiyama <[email protected]> etherboot-5.0.5 3c595.c
24: * Coptright (C) 1995 Martin Renters etherboot-5.0.5 3c509.c
25: * Copyright (C) 1999 LightSys Technology Services, Inc. etherboot-5.0.5 3c90x.c
26: * Portions Copyright (C) 1999 Steve Smith etherboot-5.0.5 3c90x.c
27: *
28: * The probe and reset functions and defines are direct copies from the
29: * Becker code modified where necessary to make it work for etherboot
30: *
31: * The poll and transmit functions either contain code from or were written by referencing
32: * the above referenced etherboot drivers. This driver would not have been
33: * possible without this prior work
34: *
35: * REVISION HISTORY:
36: * ================
37: * v0.10 4-17-2002 TJL Initial implementation.
38: * v0.11 4-17-2002 TJL Cleanup of the code
39: * v0.12 4-26-2002 TJL Added ISA Plug and Play for Non-PNP Bioses
40: * v0.13 6-10-2002 TJL Fixed ISA_PNP MAC Address problem
41: * v0.14 9-23-2003 TJL Replaced delay with currticks
42: *
43: * Indent Options: indent -kr -i8
44: * *********************************************************/
45:
46: FILE_LICENCE ( GPL2_OR_LATER );
47:
48: /* to get some global routines like printf */
49: #include "etherboot.h"
50: /* to get the interface to the body of the program */
51: #include "nic.h"
52: #include <ipxe/isapnp.h>
53: #include <ipxe/isa.h> /* for ISA_ROM */
54: #include <ipxe/ethernet.h>
55:
56: static void t3c515_wait(unsigned int nticks)
57: {
58: unsigned int to = currticks() + nticks;
59: while (currticks() < to)
60: /* wait */ ;
61: }
62:
63: /* TJL definations */
64: #define HZ 100
65: static int if_port;
66: static struct corkscrew_private *vp;
67: /* Brought directly from 3c515.c by Becker */
68: #define CORKSCREW 1
69:
70: /* Maximum events (Rx packets, etc.) to handle at each interrupt.
71: static int max_interrupt_work = 20;
72: */
73:
74: /* Enable the automatic media selection code -- usually set. */
75: #define AUTOMEDIA 1
76:
77: /* Allow the use of fragment bus master transfers instead of only
78: programmed-I/O for Vortex cards. Full-bus-master transfers are always
79: enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined,
80: the feature may be turned on using 'options'. */
81: #define VORTEX_BUS_MASTER
82:
83: /* A few values that may be tweaked. */
84: /* Keep the ring sizes a power of two for efficiency. */
85: #define TX_RING_SIZE 16
86: #define RX_RING_SIZE 16
87: #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
88:
89: /* "Knobs" for adjusting internal parameters. */
90: /* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
91: #define DRIVER_DEBUG 1
92: /* Some values here only for performance evaluation and path-coverage
93: debugging.
94: static int rx_nocopy, rx_copy, queued_packet;
95: */
96:
97: #define CORKSCREW_ID 10
98:
99: #define EL3WINDOW(win_num) \
100: outw(SelectWindow + (win_num), nic->ioaddr + EL3_CMD)
101: #define EL3_CMD 0x0e
102: #define EL3_STATUS 0x0e
103: #define RX_BYTES_MASK (unsigned short) (0x07ff)
104:
105: enum corkscrew_cmd {
106: TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
107: RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
108: UpStall = 6 << 11, UpUnstall = (6 << 11) + 1,
109: DownStall = (6 << 11) + 2, DownUnstall = (6 << 11) + 3,
110: RxDiscard = 8 << 11, TxEnable = 9 << 11, TxDisable =
111: 10 << 11, TxReset = 11 << 11,
112: FakeIntr = 12 << 11, AckIntr = 13 << 11, SetIntrEnb = 14 << 11,
113: SetStatusEnb = 15 << 11, SetRxFilter = 16 << 11, SetRxThreshold =
114: 17 << 11,
115: SetTxThreshold = 18 << 11, SetTxStart = 19 << 11,
116: StartDMAUp = 20 << 11, StartDMADown = (20 << 11) + 1, StatsEnable =
117: 21 << 11,
118: StatsDisable = 22 << 11, StopCoax = 23 << 11,
119: };
120:
121: /* The SetRxFilter command accepts the following classes: */
122: enum RxFilter {
123: RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
124: };
125:
126: /* Bits in the general status register. */
127: enum corkscrew_status {
128: IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
129: TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
130: IntReq = 0x0040, StatsFull = 0x0080,
131: DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
132: DMAInProgress = 1 << 11, /* DMA controller is still busy. */
133: CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */
134: };
135:
136: /* Register window 1 offsets, the window used in normal operation.
137: On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
138: enum Window1 {
139: TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
140: RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
141: TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
142: };
143: enum Window0 {
144: Wn0IRQ = 0x08,
145: #if defined(CORKSCREW)
146: Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */
147: Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */
148: #else
149: Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
150: Wn0EepromData = 12, /* Window 0: EEPROM results register. */
151: #endif
152: };
153: enum Win0_EEPROM_bits {
154: EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
155: EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
156: EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
157: };
158:
159: enum Window3 { /* Window 3: MAC/config bits. */
160: Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
161: };
162: union wn3_config {
163: int i;
164: struct w3_config_fields {
165: unsigned int ram_size:3, ram_width:1, ram_speed:2,
166: rom_size:2;
167: int pad8:8;
168: unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1,
169: autoselect:1;
170: int pad24:7;
171: } u;
172: };
173:
174: enum Window4 {
175: Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */
176: };
177: enum Win4_Media_bits {
178: Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
179: Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
180: Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
181: Media_LnkBeat = 0x0800,
182: };
183: enum Window7 { /* Window 7: Bus Master control. */
184: Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
185: };
186:
187: /* Boomerang-style bus master control registers. Note ISA aliases! */
188: enum MasterCtrl {
189: PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
190: 0x40c,
191: TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
192: };
193:
194: /* The Rx and Tx descriptor lists.
195: Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
196: alignment contraint on tx_ring[] and rx_ring[]. */
197: struct boom_rx_desc {
198: u32 next;
199: s32 status;
200: u32 addr;
201: s32 length;
202: };
203:
204: /* Values for the Rx status entry. */
205: enum rx_desc_status {
206: RxDComplete = 0x00008000, RxDError = 0x4000,
207: /* See boomerang_rx() for actual error bits */
208: };
209:
210: struct boom_tx_desc {
211: u32 next;
212: s32 status;
213: u32 addr;
214: s32 length;
215: };
216:
217: struct corkscrew_private {
218: const char *product_name;
219: struct net_device *next_module;
220: /* The Rx and Tx rings are here to keep them quad-word-aligned. */
221: struct boom_rx_desc rx_ring[RX_RING_SIZE];
222: struct boom_tx_desc tx_ring[TX_RING_SIZE];
223: /* The addresses of transmit- and receive-in-place skbuffs. */
224: struct sk_buff *rx_skbuff[RX_RING_SIZE];
225: struct sk_buff *tx_skbuff[TX_RING_SIZE];
226: unsigned int cur_rx, cur_tx; /* The next free ring entry */
227: unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
228: struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
229: int capabilities; /* Adapter capabilities word. */
230: int options; /* User-settable misc. driver options. */
231: int last_rx_packets; /* For media autoselection. */
232: unsigned int available_media:8, /* From Wn3_Options */
233: media_override:3, /* Passed-in media type. */
234: default_media:3, /* Read from the EEPROM. */
235: full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */
236: full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */
237: tx_full:1;
238: };
239:
240: /* The action to take with a media selection timer tick.
241: Note that we deviate from the 3Com order by checking 10base2 before AUI.
242: */
243: enum xcvr_types {
244: XCVR_10baseT =
245: 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
246: XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
247: };
248:
249: static struct media_table {
250: char *name;
251: unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
252: mask:8, /* The transceiver-present bit in Wn3_Config. */
253: next:8; /* The media type to try next. */
254: short wait; /* Time before we check media status. */
255: } media_tbl[] = {
256: {
257: "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10}
258: , {
259: "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10}
260: , {
261: "undefined", 0, 0x80, XCVR_10baseT, 10000}
262: , {
263: "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10}
264: , {
265: "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx,
266: (14 * HZ) / 10}
267: , {
268: "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10}
269: , {
270: "MII", 0, 0x40, XCVR_10baseT, 3 * HZ}
271: , {
272: "undefined", 0, 0x01, XCVR_10baseT, 10000}
273: , {
274: "Default", 0, 0xFF, XCVR_10baseT, 10000}
275: ,};
276:
277: /* TILEG Modified to remove reference to dev */
278: static int corkscrew_found_device(int ioaddr, int irq, int product_index,
279: int options, struct nic *nic);
280: static int corkscrew_probe1(int ioaddr, int irq, int product_index,
281: struct nic *nic);
282:
283: /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
284: /* Note: this is the only limit on the number of cards supported!! */
285: static int options = -1;
286:
287: /* End Brought directly from 3c515.c by Becker */
288:
289: /**************************************************************************
290: RESET - Reset adapter
291: ***************************************************************************/
292: static void t515_reset(struct nic *nic)
293: {
294: union wn3_config config;
295: int i;
296:
297: /* Before initializing select the active media port. */
298: EL3WINDOW(3);
299: if (vp->full_duplex)
300: outb(0x20, nic->ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
301: config.i = inl(nic->ioaddr + Wn3_Config);
302:
303: if (vp->media_override != 7) {
304: DBG ( "Media override to transceiver %d (%s).\n",
305: vp->media_override,
306: media_tbl[vp->media_override].name);
307: if_port = vp->media_override;
308: } else if (vp->autoselect) {
309: /* Find first available media type, starting with 100baseTx. */
310: if_port = 4;
311: while (!(vp->available_media & media_tbl[if_port].mask))
312: if_port = media_tbl[if_port].next;
313:
314: DBG ( "Initial media type %s.\n",
315: media_tbl[if_port].name);
316: } else
317: if_port = vp->default_media;
318:
319: config.u.xcvr = if_port;
320: outl(config.i, nic->ioaddr + Wn3_Config);
321:
322: DBG ( "corkscrew_open() InternalConfig 0x%hX.\n",
323: config.i);
324:
325: outw(TxReset, nic->ioaddr + EL3_CMD);
326: for (i = 20; i >= 0; i--)
327: if (!(inw(nic->ioaddr + EL3_STATUS) & CmdInProgress))
328: break;
329:
330: outw(RxReset, nic->ioaddr + EL3_CMD);
331: /* Wait a few ticks for the RxReset command to complete. */
332: for (i = 20; i >= 0; i--)
333: if (!(inw(nic->ioaddr + EL3_STATUS) & CmdInProgress))
334: break;
335:
336: outw(SetStatusEnb | 0x00, nic->ioaddr + EL3_CMD);
337:
338: #ifdef debug_3c515
339: EL3WINDOW(4);
340: DBG ( "FIXME: fix print for irq, not 9" );
341: DBG ( "corkscrew_open() irq %d media status 0x%hX.\n",
342: 9, inw(nic->ioaddr + Wn4_Media) );
343: #endif
344:
345: /* Set the station address and mask in window 2 each time opened. */
346: EL3WINDOW(2);
347: for (i = 0; i < 6; i++)
348: outb(nic->node_addr[i], nic->ioaddr + i);
349: for (; i < 12; i += 2)
350: outw(0, nic->ioaddr + i);
351:
352: if (if_port == 3)
353: /* Start the thinnet transceiver. We should really wait 50ms... */
354: outw(StartCoax, nic->ioaddr + EL3_CMD);
355: EL3WINDOW(4);
356: outw((inw(nic->ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
357: media_tbl[if_port].media_bits, nic->ioaddr + Wn4_Media);
358:
359: /* Switch to the stats window, and clear all stats by reading. */
360: /* outw(StatsDisable, nic->ioaddr + EL3_CMD);*/
361: EL3WINDOW(6);
362: for (i = 0; i < 10; i++)
363: inb(nic->ioaddr + i);
364: inw(nic->ioaddr + 10);
365: inw(nic->ioaddr + 12);
366: /* New: On the Vortex we must also clear the BadSSD counter. */
367: EL3WINDOW(4);
368: inb(nic->ioaddr + 12);
369: /* ..and on the Boomerang we enable the extra statistics bits. */
370: outw(0x0040, nic->ioaddr + Wn4_NetDiag);
371:
372: /* Switch to register set 7 for normal use. */
373: EL3WINDOW(7);
374:
375: /* Temporarily left in place. If these FIXMEs are printed
376: it meand that special logic for that card may need to be added
377: see Becker's 3c515.c driver */
378: if (vp->full_bus_master_rx) { /* Boomerang bus master. */
379: printf("FIXME: Is this if necessary");
380: vp->cur_rx = vp->dirty_rx = 0;
381: DBG ( " Filling in the Rx ring.\n" );
382: for (i = 0; i < RX_RING_SIZE; i++) {
383: printf("FIXME: Is this if necessary");
384: }
385: }
386: if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
387: vp->cur_tx = vp->dirty_tx = 0;
388: outb(PKT_BUF_SZ >> 8, nic->ioaddr + TxFreeThreshold); /* Room for a packet. */
389: /* Clear the Tx ring. */
390: for (i = 0; i < TX_RING_SIZE; i++)
391: vp->tx_skbuff[i] = 0;
392: outl(0, nic->ioaddr + DownListPtr);
393: }
394: /* Set receiver mode: presumably accept b-case and phys addr only. */
395: outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
396: nic->ioaddr + EL3_CMD);
397:
398: outw(RxEnable, nic->ioaddr + EL3_CMD); /* Enable the receiver. */
399: outw(TxEnable, nic->ioaddr + EL3_CMD); /* Enable transmitter. */
400: /* Allow status bits to be seen. */
401: outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
402: (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
403: (vp->full_bus_master_rx ? UpComplete : RxComplete) |
404: (vp->bus_master ? DMADone : 0), nic->ioaddr + EL3_CMD);
405: /* Ack all pending events, and set active indicator mask. */
406: outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
407: nic->ioaddr + EL3_CMD);
408: outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
409: | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
410: nic->ioaddr + EL3_CMD);
411:
412: }
413:
414: /**************************************************************************
415: POLL - Wait for a frame
416: ***************************************************************************/
417: static int t515_poll(struct nic *nic, int retrieve)
418: {
419: short status, cst;
420: register short rx_fifo;
421:
422: cst = inw(nic->ioaddr + EL3_STATUS);
423:
424: if ((cst & RxComplete) == 0) {
425: /* Ack all pending events, and set active indicator mask. */
426: outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
427: nic->ioaddr + EL3_CMD);
428: outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete |
429: StatsFull | (vp->
430: bus_master ? DMADone : 0) | UpComplete |
431: DownComplete, nic->ioaddr + EL3_CMD);
432: return 0;
433: }
434: status = inw(nic->ioaddr + RxStatus);
435:
436: if (status & RxDError) {
437: printf("RxDError\n");
438: outw(RxDiscard, nic->ioaddr + EL3_CMD);
439: return 0;
440: }
441:
442: rx_fifo = status & RX_BYTES_MASK;
443: if (rx_fifo == 0)
444: return 0;
445:
446: if ( ! retrieve ) return 1;
447:
448: DBG ( "[l=%d", rx_fifo );
449: insw(nic->ioaddr + RX_FIFO, nic->packet, rx_fifo / 2);
450: if (rx_fifo & 1)
451: nic->packet[rx_fifo - 1] = inb(nic->ioaddr + RX_FIFO);
452: nic->packetlen = rx_fifo;
453:
454: while (1) {
455: status = inw(nic->ioaddr + RxStatus);
456: DBG ( "0x%hX*", status );
457: rx_fifo = status & RX_BYTES_MASK;
458:
459: if (rx_fifo > 0) {
460: insw(nic->ioaddr + RX_FIFO, nic->packet + nic->packetlen,
461: rx_fifo / 2);
462: if (rx_fifo & 1)
463: nic->packet[nic->packetlen + rx_fifo - 1] =
464: inb(nic->ioaddr + RX_FIFO);
465: nic->packetlen += rx_fifo;
466: DBG ( "+%d", rx_fifo );
467: }
468: if ((status & RxComplete) == 0) {
469: DBG ( "=%d", nic->packetlen );
470: break;
471: }
472: udelay(1000);
473: }
474:
475: /* acknowledge reception of packet */
476: outw(RxDiscard, nic->ioaddr + EL3_CMD);
477: while (inw(nic->ioaddr + EL3_STATUS) & CmdInProgress);
478: #ifdef debug_3c515
479: {
480: unsigned short type = 0;
481: type = (nic->packet[12] << 8) | nic->packet[13];
482: if (nic->packet[0] + nic->packet[1] + nic->packet[2] +
483: nic->packet[3] + nic->packet[4] + nic->packet[5] ==
484: 0xFF * ETH_ALEN)
485: DBG ( ",t=0x%hX,b]", type );
486: else
487: DBG ( ",t=0x%hX]", type );
488: }
489: #endif
490:
491: return 1;
492: }
493:
494: /*************************************************************************
495: 3Com 515 - specific routines
496: **************************************************************************/
497: static char padmap[] = {
498: 0, 3, 2, 1
499: };
500: /**************************************************************************
501: TRANSMIT - Transmit a frame
502: ***************************************************************************/
503: static void t515_transmit(struct nic *nic, const char *d, /* Destination */
504: unsigned int t, /* Type */
505: unsigned int s, /* size */
506: const char *p)
507: { /* Packet */
508: register int len;
509: int pad;
510: int status;
511:
512: DBG ( "{l=%d,t=0x%hX}", s + ETH_HLEN, t );
513:
514: /* swap bytes of type */
515: t = htons(t);
516:
517: len = s + ETH_HLEN; /* actual length of packet */
518: pad = padmap[len & 3];
519:
520: /*
521: * The 3c515 automatically pads short packets to minimum ethernet length,
522: * but we drop packets that are too large. Perhaps we should truncate
523: * them instead?
524: Copied from 3c595. Is this true for the 3c515?
525: */
526: if (len + pad > ETH_FRAME_LEN) {
527: return;
528: }
529: /* drop acknowledgements */
530: while ((status = inb(nic->ioaddr + TxStatus)) & TxComplete) {
531: /*if(status & (TXS_UNDERRUN|0x88|TXS_STATUS_OVERFLOW)) { */
532: outw(TxReset, nic->ioaddr + EL3_CMD);
533: outw(TxEnable, nic->ioaddr + EL3_CMD);
534: /* } */
535:
536: outb(0x0, nic->ioaddr + TxStatus);
537: }
538:
539: while (inw(nic->ioaddr + TxFree) < len + pad + 4) {
540: /* no room in FIFO */
541: }
542:
543: outw(len, nic->ioaddr + TX_FIFO);
544: outw(0x0, nic->ioaddr + TX_FIFO); /* Second dword meaningless */
545:
546: /* write packet */
547: outsw(nic->ioaddr + TX_FIFO, d, ETH_ALEN / 2);
548: outsw(nic->ioaddr + TX_FIFO, nic->node_addr, ETH_ALEN / 2);
549: outw(t, nic->ioaddr + TX_FIFO);
550: outsw(nic->ioaddr + TX_FIFO, p, s / 2);
551:
552: if (s & 1)
553: outb(*(p + s - 1), nic->ioaddr + TX_FIFO);
554:
555: while (pad--)
556: outb(0, nic->ioaddr + TX_FIFO); /* Padding */
557:
558: /* wait for Tx complete */
559: while ((inw(nic->ioaddr + EL3_STATUS) & CmdInProgress) != 0);
560: }
561:
562: /**************************************************************************
563: DISABLE - Turn off ethernet interface
564: ***************************************************************************/
565: static void t515_disable ( struct nic *nic,
566: struct isapnp_device *isapnp ) {
567:
568: t515_reset(nic);
569:
570: /* This is a hack. Since ltsp worked on my
571: system without any disable functionality I
572: have no way to determine if this works */
573:
574: /* Disable the receiver and transmitter. */
575: outw(RxDisable, nic->ioaddr + EL3_CMD);
576: outw(TxDisable, nic->ioaddr + EL3_CMD);
577:
578: if (if_port == XCVR_10base2)
579: /* Turn off thinnet power. Green! */
580: outw(StopCoax, nic->ioaddr + EL3_CMD);
581:
582:
583: outw(SetIntrEnb | 0x0000, nic->ioaddr + EL3_CMD);
584:
585: deactivate_isapnp_device ( isapnp );
586: return;
587: }
588:
589: static void t515_irq(struct nic *nic __unused, irq_action_t action __unused)
590: {
591: switch ( action ) {
592: case DISABLE :
593: break;
594: case ENABLE :
595: break;
596: case FORCE :
597: break;
598: }
599: }
600:
601: static struct nic_operations t515_operations = {
602: .connect = dummy_connect,
603: .poll = t515_poll,
604: .transmit = t515_transmit,
605: .irq = t515_irq,
606:
607: };
608:
609: /**************************************************************************
610: PROBE - Look for an adapter, this routine's visible to the outside
611: You should omit the last argument struct pci_device * for a non-PCI NIC
612: ***************************************************************************/
613: static int t515_probe ( struct nic *nic, struct isapnp_device *isapnp ) {
614:
615: /* Direct copy from Beckers 3c515.c removing any ISAPNP sections */
616:
617: nic->ioaddr = isapnp->ioaddr;
618: nic->irqno = isapnp->irqno;
619: activate_isapnp_device ( isapnp );
620:
621: /* Check the resource configuration for a matching ioaddr. */
622: if ((unsigned)(inw(nic->ioaddr + 0x2002) & 0x1f0)
623: != (nic->ioaddr & 0x1f0)) {
624: DBG ( "3c515 ioaddr mismatch\n" );
625: return 0;
626: }
627:
628: /* Verify by reading the device ID from the EEPROM. */
629: {
630: int timer;
631: outw(EEPROM_Read + 7, nic->ioaddr + Wn0EepromCmd);
632: /* Pause for at least 162 us. for the read to take place. */
633: for (timer = 4; timer >= 0; timer--) {
634: t3c515_wait(1);
635: if ((inw(nic->ioaddr + Wn0EepromCmd) & 0x0200) == 0)
636: break;
637: }
638: if (inw(nic->ioaddr + Wn0EepromData) != 0x6d50) {
639: DBG ( "3c515 read incorrect vendor ID from EEPROM" );
640: return 0;
641: }
642:
643: }
644: DBG ( "3c515 Resource configuration register 0x%X, DCR 0x%hX.\n",
645: inl(nic->ioaddr + 0x2002), inw(nic->ioaddr + 0x2000) );
646: corkscrew_found_device(nic->ioaddr, nic->irqno, CORKSCREW_ID,
647: options, nic);
648:
649: t515_reset(nic);
650: nic->nic_op = &t515_operations;
651: return 1;
652: }
653:
654: static int
655: corkscrew_found_device(int ioaddr, int irq,
656: int product_index, int options, struct nic *nic)
657: {
658: /* Direct copy from Becker 3c515.c with unecessary parts removed */
659: vp->product_name = "3c515";
660: vp->options = options;
661: if (options >= 0) {
662: vp->media_override =
663: ((options & 7) == 2) ? 0 : options & 7;
664: vp->full_duplex = (options & 8) ? 1 : 0;
665: vp->bus_master = (options & 16) ? 1 : 0;
666: } else {
667: vp->media_override = 7;
668: vp->full_duplex = 0;
669: vp->bus_master = 0;
670: }
671:
672: corkscrew_probe1(ioaddr, irq, product_index, nic);
673: return 0;
674: }
675:
676: static int
677: corkscrew_probe1(int ioaddr, int irq, int product_index __unused,
678: struct nic *nic)
679: {
680: unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
681: int i;
682:
683: printf("3Com %s at 0x%hX, ", vp->product_name, ioaddr);
684:
685: /* Read the station address from the EEPROM. */
686: EL3WINDOW(0);
687: for (i = 0; i < 0x18; i++) {
688: short *phys_addr = (short *) nic->node_addr;
689: int timer;
690: outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
691: /* Pause for at least 162 us. for the read to take place. */
692: for (timer = 4; timer >= 0; timer--) {
693: t3c515_wait(1);
694: if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
695: break;
696: }
697: eeprom[i] = inw(ioaddr + Wn0EepromData);
698: DBG ( "Value %d: %hX ", i, eeprom[i] );
699: checksum ^= eeprom[i];
700: if (i < 3)
701: phys_addr[i] = htons(eeprom[i]);
702: }
703: checksum = (checksum ^ (checksum >> 8)) & 0xff;
704: if (checksum != 0x00)
705: printf(" ***INVALID CHECKSUM 0x%hX*** ", checksum);
706:
707: DBG ( "%s", eth_ntoa ( nic->node_addr ) );
708:
709: if (eeprom[16] == 0x11c7) { /* Corkscrew */
710:
711: }
712: printf(", IRQ %d\n", irq);
713: /* Tell them about an invalid IRQ. */
714: if ( (irq <= 0 || irq > 15) ) {
715: DBG (" *** Warning: this IRQ is unlikely to work! ***\n" );
716: }
717:
718: {
719: char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
720: union wn3_config config;
721: EL3WINDOW(3);
722: vp->available_media = inw(ioaddr + Wn3_Options);
723: config.i = inl(ioaddr + Wn3_Config);
724: DBG ( " Internal config register is %4.4x, "
725: "transceivers 0x%hX.\n",
726: config.i, inw(ioaddr + Wn3_Options) );
727: printf
728: (" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
729: 8 << config.u.ram_size,
730: config.u.ram_width ? "word" : "byte",
731: ram_split[config.u.ram_split],
732: config.u.autoselect ? "autoselect/" : "",
733: media_tbl[config.u.xcvr].name);
734: if_port = config.u.xcvr;
735: vp->default_media = config.u.xcvr;
736: vp->autoselect = config.u.autoselect;
737: }
738: if (vp->media_override != 7) {
739: printf(" Media override to transceiver type %d (%s).\n",
740: vp->media_override,
741: media_tbl[vp->media_override].name);
742: if_port = vp->media_override;
743: }
744:
745: vp->capabilities = eeprom[16];
746: vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
747: /* Rx is broken at 10mbps, so we always disable it. */
748: /* vp->full_bus_master_rx = 0; */
749: vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
750:
751: return 0;
752: }
753:
754: static struct isapnp_device_id t515_adapters[] = {
755: { "3c515 (ISAPnP)", ISAPNP_VENDOR('T','C','M'), 0x5051 },
756: };
757:
758: ISAPNP_DRIVER ( t515_driver, t515_adapters );
759:
760: DRIVER ( "3c515", nic_driver, isapnp_driver, t515_driver,
761: t515_probe, t515_disable );
762:
763: ISA_ROM ( "3c515", "3c515 Fast EtherLink ISAPnP" );
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.