|
|
1.1 root 1: /**************************************************************************
2: ETHERBOOT - BOOTP/TFTP Bootstrap Program
3:
4: Author: Martin Renters
5: Date: May/94
6:
7: This code is based heavily on David Greenman's if_ed.c driver
8:
9: Copyright (C) 1993-1994, David Greenman, Martin Renters.
10: This software may be used, modified, copied, distributed, and sold, in
11: both source and binary form provided that the above copyright and these
12: terms are retained. Under no circumstances are the authors responsible for
13: the proper functioning of this software, nor do the authors assume any
14: responsibility for damages incurred with its use.
15:
16: Multicast support added by Timothy Legge ([email protected]) 09/28/2003
17: Relocation support added by Ken Yap ([email protected]) 28/12/02
18: 3c503 support added by Bill Paul ([email protected]) on 11/15/94
19: SMC8416 support added by Bill Paul ([email protected]) on 12/25/94
20: 3c503 PIO support added by Jim Hague ([email protected]) on 2/17/98
21: RX overrun by Klaus Espenlaub ([email protected]) on 3/10/99
22: parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
23: SMC8416 PIO support added by Andrew Bettison ([email protected]) on 4/3/02
24: based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
25:
26: **************************************************************************/
27:
28: FILE_LICENCE ( BSD2 );
29:
30: /* #warning "ns8390.c: FIXME: split ISA and PCI, clean up" */
31:
32: #if 1
33:
34: #if !defined(INCLUDE_NS8390) && !defined(INCLUDE_WD) && \
35: !defined(INCLUDE_NE) && !defined(INCLUDE_3C503)
36: /* The driver named ns8390 is the PCI driver, often called
37: "PCI ne2000 clones". */
38: # define INCLUDE_NS8390 1
39: #endif
40:
41: #include "etherboot.h"
42: #include "nic.h"
43: #include "ns8390.h"
44: #include <ipxe/ethernet.h>
45: #ifdef INCLUDE_NS8390
46: #include <ipxe/pci.h>
47: #else
48: #include <ipxe/isa.h>
49: #endif
50:
51: static unsigned char eth_vendor, eth_flags;
52: #ifdef INCLUDE_WD
53: static unsigned char eth_laar;
54: #endif
55: static unsigned short eth_nic_base, eth_asic_base;
56: static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
57: static Address eth_bmem, eth_rmem;
58: static unsigned char eth_drain_receiver;
59:
60: #ifdef INCLUDE_WD
61: static struct wd_board {
62: const char *name;
63: char id;
64: char flags;
65: char memsize;
66: } wd_boards[] = {
67: {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
68: {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
69: {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
70: {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
71: {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
72: {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
73: {"WD8003EP/WD8013EP",
74: TYPE_WD8013EP, 0, MEM_8192},
75: {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
76: {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
77: {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
78: {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
79: {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
80: {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
81: {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
82: {NULL, 0, 0, 0}
83: };
84: #endif
85:
86: #ifdef INCLUDE_3C503
87: static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
88: #endif
89:
90: #if defined(INCLUDE_WD)
91: #define ASIC_PIO WD_IAR
92: #define eth_probe wd_probe
93: #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
94: Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
95: #endif
96: #endif
97:
98: #if defined(INCLUDE_3C503)
99: #define eth_probe t503_probe
100: #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
101: Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
102: #endif
103: #endif
104:
105: #if defined(INCLUDE_NE)
106: #define eth_probe ne_probe
107: #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
108: Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
109: #endif
110: #endif
111:
112: #if defined(INCLUDE_NS8390)
113: #define eth_probe nepci_probe
114: #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
115: Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
116: #endif
117: #endif
118:
119: #if defined(INCLUDE_3C503)
120: #define ASIC_PIO _3COM_RFMSB
121: #else
122: #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
123: #define ASIC_PIO NE_DATA
124: #endif
125: #endif
126:
127: #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
128: /**************************************************************************
129: ETH_PIO_READ - Read a frame via Programmed I/O
130: **************************************************************************/
131: static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
132: {
133: #ifdef INCLUDE_WD
134: outb(src & 0xff, eth_asic_base + WD_GP2);
135: outb(src >> 8, eth_asic_base + WD_GP2);
136: #else
137: outb(D8390_COMMAND_RD2 |
138: D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
139: outb(cnt, eth_nic_base + D8390_P0_RBCR0);
140: outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
141: outb(src, eth_nic_base + D8390_P0_RSAR0);
142: outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
143: outb(D8390_COMMAND_RD0 |
144: D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
145:
146: #ifdef INCLUDE_3C503
147: outb(src & 0xff, eth_asic_base + _3COM_DALSB);
148: outb(src >> 8, eth_asic_base + _3COM_DAMSB);
149: outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
150: #endif
151: #endif
152:
153: if (eth_flags & FLAG_16BIT)
154: cnt = (cnt + 1) >> 1;
155:
156: while(cnt--) {
157: #ifdef INCLUDE_3C503
158: while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
159: ;
160: #endif
161:
162: if (eth_flags & FLAG_16BIT) {
163: *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
164: dst += 2;
165: }
166: else
167: *(dst++) = inb(eth_asic_base + ASIC_PIO);
168: }
169:
170: #ifdef INCLUDE_3C503
171: outb(t503_output, eth_asic_base + _3COM_CR);
172: #endif
173: }
174:
175: /**************************************************************************
176: ETH_PIO_WRITE - Write a frame via Programmed I/O
177: **************************************************************************/
178: static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
179: {
180: #ifdef COMPEX_RL2000_FIX
181: unsigned int x;
182: #endif /* COMPEX_RL2000_FIX */
183: #ifdef INCLUDE_WD
184: outb(dst & 0xff, eth_asic_base + WD_GP2);
185: outb(dst >> 8, eth_asic_base + WD_GP2);
186: #else
187: outb(D8390_COMMAND_RD2 |
188: D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
189: outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
190: outb(cnt, eth_nic_base + D8390_P0_RBCR0);
191: outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
192: outb(dst, eth_nic_base + D8390_P0_RSAR0);
193: outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
194: outb(D8390_COMMAND_RD1 |
195: D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
196:
197: #ifdef INCLUDE_3C503
198: outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
199: outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
200:
201: outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
202: #endif
203: #endif
204:
205: if (eth_flags & FLAG_16BIT)
206: cnt = (cnt + 1) >> 1;
207:
208: while(cnt--)
209: {
210: #ifdef INCLUDE_3C503
211: while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
212: ;
213: #endif
214:
215: if (eth_flags & FLAG_16BIT) {
216: outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
217: src += 2;
218: }
219: else
220: outb(*(src++), eth_asic_base + ASIC_PIO);
221: }
222:
223: #ifdef INCLUDE_3C503
224: outb(t503_output, eth_asic_base + _3COM_CR);
225: #else
226: #ifdef COMPEX_RL2000_FIX
227: for (x = 0;
228: x < COMPEX_RL2000_TRIES &&
229: (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
230: != D8390_ISR_RDC;
231: ++x);
232: if (x >= COMPEX_RL2000_TRIES)
233: printf("Warning: Compex RL2000 aborted wait!\n");
234: #endif /* COMPEX_RL2000_FIX */
235: #ifndef INCLUDE_WD
236: while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
237: != D8390_ISR_RDC);
238: #endif
239: #endif
240: }
241: #else
242: /**************************************************************************
243: ETH_PIO_READ - Dummy routine when NE2000 not compiled in
244: **************************************************************************/
245: static void eth_pio_read(unsigned int src __unused, unsigned char *dst __unused, unsigned int cnt __unused) {}
246: #endif
247:
248:
249: /**************************************************************************
250: enable_multycast - Enable Multicast
251: **************************************************************************/
252: static void enable_multicast(unsigned short eth_nic_base)
253: {
254: unsigned char mcfilter[8];
255: int i;
256: memset(mcfilter, 0xFF, 8);
257: outb(4, eth_nic_base+D8390_P0_RCR);
258: outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
259: for(i=0;i<8;i++)
260: {
261: outb(mcfilter[i], eth_nic_base + 8 + i);
262: if(inb(eth_nic_base + 8 + i)!=mcfilter[i])
263: printf("Error SMC 83C690 Multicast filter read/write mishap %d\n",i);
264: }
265: outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
266: outb(4 | 0x08, eth_nic_base+D8390_P0_RCR);
267: }
268:
269: /**************************************************************************
270: NS8390_RESET - Reset adapter
271: **************************************************************************/
272: static void ns8390_reset(struct nic *nic)
273: {
274: int i;
275:
276: eth_drain_receiver = 0;
277: #ifdef INCLUDE_WD
278: if (eth_flags & FLAG_790)
279: outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
280: else
281: #endif
282: outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
283: D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
284: if (eth_flags & FLAG_16BIT)
285: outb(0x49, eth_nic_base+D8390_P0_DCR);
286: else
287: outb(0x48, eth_nic_base+D8390_P0_DCR);
288: outb(0, eth_nic_base+D8390_P0_RBCR0);
289: outb(0, eth_nic_base+D8390_P0_RBCR1);
290: outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
291: outb(2, eth_nic_base+D8390_P0_TCR);
292: outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
293: outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
294: #ifdef INCLUDE_WD
295: if (eth_flags & FLAG_790) {
296: #ifdef WD_790_PIO
297: outb(0x10, eth_asic_base + 0x06); /* disable interrupts, enable PIO */
298: outb(0x01, eth_nic_base + 0x09); /* enable ring read auto-wrap */
299: #else
300: outb(0, eth_nic_base + 0x09);
301: #endif
302: }
303: #endif
304: outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
305: outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
306: outb(0xFF, eth_nic_base+D8390_P0_ISR);
307: outb(0, eth_nic_base+D8390_P0_IMR);
308: #ifdef INCLUDE_WD
309: if (eth_flags & FLAG_790)
310: outb(D8390_COMMAND_PS1 |
311: D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
312: else
313: #endif
314: outb(D8390_COMMAND_PS1 |
315: D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
316: for (i=0; i<ETH_ALEN; i++)
317: outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
318: for (i=0; i<ETH_ALEN; i++)
319: outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
320: outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
321: #ifdef INCLUDE_WD
322: if (eth_flags & FLAG_790)
323: outb(D8390_COMMAND_PS0 |
324: D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
325: else
326: #endif
327: outb(D8390_COMMAND_PS0 |
328: D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
329: outb(0xFF, eth_nic_base+D8390_P0_ISR);
330: outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
331: outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
332:
333: enable_multicast(eth_nic_base);
334:
335: #ifdef INCLUDE_3C503
336: /*
337: * No way to tell whether or not we're supposed to use
338: * the 3Com's transceiver unless the user tells us.
339: * 'flags' should have some compile time default value
340: * which can be changed from the command menu.
341: */
342: t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
343: outb(t503_output, eth_asic_base + _3COM_CR);
344: #endif
345: }
346:
347: static int ns8390_poll(struct nic *nic, int retrieve);
348:
349: #ifndef INCLUDE_3C503
350: /**************************************************************************
351: ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
352: **************************************************************************/
353: static void eth_rx_overrun(struct nic *nic)
354: {
355: int start_time;
356:
357: #ifdef INCLUDE_WD
358: if (eth_flags & FLAG_790)
359: outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
360: else
361: #endif
362: outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
363: D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
364:
365: /* wait for at least 1.6ms - we wait one timer tick */
366: start_time = currticks();
367: while (currticks() - start_time <= 1)
368: /* Nothing */;
369:
370: outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
371: outb(0, eth_nic_base+D8390_P0_RBCR1);
372:
373: /*
374: * Linux driver checks for interrupted TX here. This is not necessary,
375: * because the transmit routine waits until the frame is sent.
376: */
377:
378: /* enter loopback mode and restart NIC */
379: outb(2, eth_nic_base+D8390_P0_TCR);
380: #ifdef INCLUDE_WD
381: if (eth_flags & FLAG_790)
382: outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
383: else
384: #endif
385: outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
386: D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
387:
388: /* clear the RX ring, acknowledge overrun interrupt */
389: eth_drain_receiver = 1;
390: while (ns8390_poll(nic, 1))
391: /* Nothing */;
392: eth_drain_receiver = 0;
393: outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
394:
395: /* leave loopback mode - no packets to be resent (see Linux driver) */
396: outb(0, eth_nic_base+D8390_P0_TCR);
397: }
398: #endif /* INCLUDE_3C503 */
399:
400: /**************************************************************************
401: NS8390_TRANSMIT - Transmit a frame
402: **************************************************************************/
403: static void ns8390_transmit(
404: struct nic *nic,
405: const char *d, /* Destination */
406: unsigned int t, /* Type */
407: unsigned int s, /* size */
408: const char *p) /* Packet */
409: {
410: #if defined(INCLUDE_3C503) || (defined(INCLUDE_WD) && ! defined(WD_790_PIO))
411: Address eth_vmem = bus_to_virt(eth_bmem);
412: #endif
413: #ifdef INCLUDE_3C503
414: if (!(eth_flags & FLAG_PIO)) {
415: memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
416: memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
417: *((char *)eth_vmem+12) = t>>8; /* type */
418: *((char *)eth_vmem+13) = t;
419: memcpy((char *)eth_vmem+ETH_HLEN, p, s);
420: s += ETH_HLEN;
421: while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
422: }
423: #endif
424:
425: #ifdef INCLUDE_WD
426: if (eth_flags & FLAG_16BIT) {
427: outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
428: inb(0x84);
429: }
430: #ifndef WD_790_PIO
431: /* Memory interface */
432: if (eth_flags & FLAG_790) {
433: outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
434: inb(0x84);
435: }
436: inb(0x84);
437: memcpy((char *)eth_vmem, d, ETH_ALEN); /* dst */
438: memcpy((char *)eth_vmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
439: *((char *)eth_vmem+12) = t>>8; /* type */
440: *((char *)eth_vmem+13) = t;
441: memcpy((char *)eth_vmem+ETH_HLEN, p, s);
442: s += ETH_HLEN;
443: while (s < ETH_ZLEN) *((char *)eth_vmem+(s++)) = 0;
444: if (eth_flags & FLAG_790) {
445: outb(0, eth_asic_base + WD_MSR);
446: inb(0x84);
447: }
448: #else
449: inb(0x84);
450: #endif
451: #endif
452:
453: #if defined(INCLUDE_3C503)
454: if (eth_flags & FLAG_PIO)
455: #endif
456: #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM)) || (defined(INCLUDE_WD) && defined(WD_790_PIO))
457: {
458: /* Programmed I/O */
459: unsigned short type;
460: type = (t >> 8) | (t << 8);
461: eth_pio_write( (unsigned char *) d, eth_tx_start<<8, ETH_ALEN);
462: eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
463: /* bcc generates worse code without (const+const) below */
464: eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
465: eth_pio_write( (unsigned char *) p, (eth_tx_start<<8)+ETH_HLEN, s);
466: s += ETH_HLEN;
467: if (s < ETH_ZLEN) s = ETH_ZLEN;
468: }
469: #endif
470: #if defined(INCLUDE_3C503)
471: #endif
472:
473: #ifdef INCLUDE_WD
474: if (eth_flags & FLAG_16BIT) {
475: outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
476: inb(0x84);
477: }
478: if (eth_flags & FLAG_790)
479: outb(D8390_COMMAND_PS0 |
480: D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
481: else
482: #endif
483: outb(D8390_COMMAND_PS0 |
484: D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
485: outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
486: outb(s, eth_nic_base+D8390_P0_TBCR0);
487: outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
488: #ifdef INCLUDE_WD
489: if (eth_flags & FLAG_790)
490: outb(D8390_COMMAND_PS0 |
491: D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
492: else
493: #endif
494: outb(D8390_COMMAND_PS0 |
495: D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
496: D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
497: }
498:
499: /**************************************************************************
500: NS8390_POLL - Wait for a frame
501: **************************************************************************/
502: static int ns8390_poll(struct nic *nic, int retrieve)
503: {
504: int ret = 0;
505: unsigned char rstat, curr, next;
506: unsigned short len, frag;
507: unsigned short pktoff;
508: unsigned char *p;
509: struct ringbuffer pkthdr;
510:
511: #ifndef INCLUDE_3C503
512: /* avoid infinite recursion: see eth_rx_overrun() */
513: if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
514: eth_rx_overrun(nic);
515: return(0);
516: }
517: #endif /* INCLUDE_3C503 */
518: rstat = inb(eth_nic_base+D8390_P0_RSR);
519: if (!(rstat & D8390_RSTAT_PRX)) return(0);
520: next = inb(eth_nic_base+D8390_P0_BOUND)+1;
521: if (next >= eth_memsize) next = eth_rx_start;
522: outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
523: curr = inb(eth_nic_base+D8390_P1_CURR);
524: outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
525: if (curr >= eth_memsize) curr=eth_rx_start;
526: if (curr == next) return(0);
527:
528: if ( ! retrieve ) return 1;
529:
530: #ifdef INCLUDE_WD
531: if (eth_flags & FLAG_16BIT) {
532: outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
533: inb(0x84);
534: }
535: #ifndef WD_790_PIO
536: if (eth_flags & FLAG_790) {
537: outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
538: inb(0x84);
539: }
540: #endif
541: inb(0x84);
542: #endif
543: pktoff = next << 8;
544: if (eth_flags & FLAG_PIO)
545: eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
546: else
547: memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
548: pktoff += sizeof(pkthdr);
549: /* incoming length includes FCS so must sub 4 */
550: len = pkthdr.len - 4;
551: if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
552: || len > ETH_FRAME_LEN) {
553: printf("Bogus packet, ignoring\n");
554: return (0);
555: }
556: else {
557: p = nic->packet;
558: nic->packetlen = len; /* available to caller */
559: frag = (eth_memsize << 8) - pktoff;
560: if (len > frag) { /* We have a wrap-around */
561: /* read first part */
562: if (eth_flags & FLAG_PIO)
563: eth_pio_read(pktoff, p, frag);
564: else
565: memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
566: pktoff = eth_rx_start << 8;
567: p += frag;
568: len -= frag;
569: }
570: /* read second part */
571: if (eth_flags & FLAG_PIO)
572: eth_pio_read(pktoff, p, len);
573: else
574: memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
575: ret = 1;
576: }
577: #ifdef INCLUDE_WD
578: #ifndef WD_790_PIO
579: if (eth_flags & FLAG_790) {
580: outb(0, eth_asic_base + WD_MSR);
581: inb(0x84);
582: }
583: #endif
584: if (eth_flags & FLAG_16BIT) {
585: outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
586: inb(0x84);
587: }
588: inb(0x84);
589: #endif
590: next = pkthdr.next; /* frame number of next packet */
591: if (next == eth_rx_start)
592: next = eth_memsize;
593: outb(next-1, eth_nic_base+D8390_P0_BOUND);
594: return(ret);
595: }
596:
597: /**************************************************************************
598: NS8390_DISABLE - Turn off adapter
599: **************************************************************************/
600: static void ns8390_disable ( struct nic *nic ) {
601: ns8390_reset(nic);
602: }
603:
604: /**************************************************************************
605: NS8390_IRQ - Enable, Disable, or Force interrupts
606: **************************************************************************/
607: static void ns8390_irq(struct nic *nic __unused, irq_action_t action __unused)
608: {
609: switch ( action ) {
610: case DISABLE :
611: break;
612: case ENABLE :
613: break;
614: case FORCE :
615: break;
616: }
617: }
618:
619: static struct nic_operations ns8390_operations;
620: static struct nic_operations ns8390_operations = {
621: .connect = dummy_connect,
622: .poll = ns8390_poll,
623: .transmit = ns8390_transmit,
624: .irq = ns8390_irq,
625: };
626:
627: /**************************************************************************
628: ETH_PROBE - Look for an adapter
629: **************************************************************************/
630: #ifdef INCLUDE_NS8390
631: static int eth_probe (struct nic *nic, struct pci_device *pci)
632: #else
633: static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused)
634: #endif
635: {
636: int i;
637: #ifdef INCLUDE_NS8390
638: unsigned short pci_probe_addrs[] = { pci->ioaddr, 0 };
639: unsigned short *probe_addrs = pci_probe_addrs;
640: #endif
641: eth_vendor = VENDOR_NONE;
642: eth_drain_receiver = 0;
643:
644: nic->irqno = 0;
645:
646: #ifdef INCLUDE_WD
647: {
648: /******************************************************************
649: Search for WD/SMC cards
650: ******************************************************************/
651: struct wd_board *brd;
652: unsigned short chksum;
653: unsigned char c;
654: for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
655: eth_asic_base += 0x20) {
656: chksum = 0;
657: for (i=8; i<16; i++)
658: chksum += inb(eth_asic_base+i);
659: /* Extra checks to avoid soundcard */
660: if ((chksum & 0xFF) == 0xFF &&
661: inb(eth_asic_base+8) != 0xFF &&
662: inb(eth_asic_base+9) != 0xFF)
663: break;
664: }
665: if (eth_asic_base > WD_HIGH_BASE)
666: return (0);
667: /* We've found a board */
668: eth_vendor = VENDOR_WD;
669: eth_nic_base = eth_asic_base + WD_NIC_ADDR;
670:
671: nic->ioaddr = eth_nic_base;
672:
673: c = inb(eth_asic_base+WD_BID); /* Get board id */
674: for (brd = wd_boards; brd->name; brd++)
675: if (brd->id == c) break;
676: if (!brd->name) {
677: printf("Unknown WD/SMC NIC type %hhX\n", c);
678: return (0); /* Unknown type */
679: }
680: eth_flags = brd->flags;
681: eth_memsize = brd->memsize;
682: eth_tx_start = 0;
683: eth_rx_start = D8390_TXBUF_SIZE;
684: if ((c == TYPE_WD8013EP) &&
685: (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
686: eth_flags = FLAG_16BIT;
687: eth_memsize = MEM_16384;
688: }
689: if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
690: eth_bmem = (0x80000 |
691: ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
692: } else
693: eth_bmem = WD_DEFAULT_MEM;
694: if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
695: /* from Linux driver, 8416BT detects as 8216 sometimes */
696: unsigned int addr = inb(eth_asic_base + 0xb);
697: if (((addr >> 4) & 3) == 0) {
698: brd += 2;
699: eth_memsize = brd->memsize;
700: }
701: }
702: outb(0x80, eth_asic_base + WD_MSR); /* Reset */
703: for (i=0; i<ETH_ALEN; i++) {
704: nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
705: }
706: DBG ( "\n%s base %4.4x", brd->name, eth_asic_base );
707: if (eth_flags & FLAG_790) {
708: #ifdef WD_790_PIO
709: DBG ( ", PIO mode, addr %s\n", eth_ntoa ( nic->node_addr ) );
710: eth_bmem = 0;
711: eth_flags |= FLAG_PIO; /* force PIO mode */
712: outb(0, eth_asic_base+WD_MSR);
713: #else
714: DBG ( ", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
715:
716: outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
717: outb((inb(eth_asic_base+0x04) |
718: 0x80), eth_asic_base+0x04);
719: outb(((unsigned)(eth_bmem >> 13) & 0x0F) |
720: ((unsigned)(eth_bmem >> 11) & 0x40) |
721: (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
722: outb((inb(eth_asic_base+0x04) &
723: ~0x80), eth_asic_base+0x04);
724: #endif
725: } else {
726:
727: DBG (", Memory %x, MAC Addr %s\n", eth_bmem, eth_ntoa ( nic->node_addr) );
728:
729: outb(((unsigned)(eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
730: }
731: if (eth_flags & FLAG_16BIT) {
732: if (eth_flags & FLAG_790) {
733: eth_laar = inb(eth_asic_base + WD_LAAR);
734: outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
735: } else {
736: outb((eth_laar =
737: WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
738: /*
739: The previous line used to be
740: WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
741: [email protected] reported that removing WD_LAAR_M16EN made
742: it work for WD8013s. This seems to work for my 8013 boards. I
743: don't know what is really happening. I wish I had data sheets
744: or more time to decode the Linux driver. - Ken
745: */
746: }
747: inb(0x84);
748: }
749: }
750: #endif
751: #ifdef INCLUDE_3C503
752: #ifdef T503_AUI
753: nic->flags = 1; /* aui */
754: #else
755: nic->flags = 0; /* no aui */
756: #endif
757: /******************************************************************
758: Search for 3Com 3c503 if no WD/SMC cards
759: ******************************************************************/
760: if (eth_vendor == VENDOR_NONE) {
761: int idx;
762: int iobase_reg, membase_reg;
763: static unsigned short base[] = {
764: 0x300, 0x310, 0x330, 0x350,
765: 0x250, 0x280, 0x2A0, 0x2E0, 0 };
766:
767: /* Loop through possible addresses checking each one */
768:
769: for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
770:
771: eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
772: /*
773: * Note that we use the same settings for both 8 and 16 bit cards:
774: * both have an 8K bank of memory at page 1 while only the 16 bit
775: * cards have a bank at page 0.
776: */
777: eth_memsize = MEM_16384;
778: eth_tx_start = 32;
779: eth_rx_start = 32 + D8390_TXBUF_SIZE;
780:
781: /* Check our base address. iobase and membase should */
782: /* both have a maximum of 1 bit set or be 0. */
783:
784: iobase_reg = inb(eth_asic_base + _3COM_BCFR);
785: membase_reg = inb(eth_asic_base + _3COM_PCFR);
786:
787: if ((iobase_reg & (iobase_reg - 1)) ||
788: (membase_reg & (membase_reg - 1)))
789: continue; /* nope */
790:
791: /* Now get the shared memory address */
792:
793: eth_flags = 0;
794:
795: switch (membase_reg) {
796: case _3COM_PCFR_DC000:
797: eth_bmem = 0xdc000;
798: break;
799: case _3COM_PCFR_D8000:
800: eth_bmem = 0xd8000;
801: break;
802: case _3COM_PCFR_CC000:
803: eth_bmem = 0xcc000;
804: break;
805: case _3COM_PCFR_C8000:
806: eth_bmem = 0xc8000;
807: break;
808: case _3COM_PCFR_PIO:
809: eth_flags |= FLAG_PIO;
810: eth_bmem = 0;
811: break;
812: default:
813: continue; /* nope */
814: }
815: break;
816: }
817:
818: if (base[idx] == 0) /* not found */
819: return (0);
820: #ifndef T503_SHMEM
821: eth_flags |= FLAG_PIO; /* force PIO mode */
822: eth_bmem = 0;
823: #endif
824: eth_vendor = VENDOR_3COM;
825:
826:
827: /* Need this to make ns8390_poll() happy. */
828:
829: eth_rmem = eth_bmem - 0x2000;
830:
831: /* Reset NIC and ASIC */
832:
833: outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
834: outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
835:
836: /* Get our ethernet address */
837:
838: outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
839: nic->ioaddr = eth_nic_base;
840: DBG ( "\n3Com 3c503 base %4.4x, ", eth_nic_base );
841: if (eth_flags & FLAG_PIO)
842: DBG ( "PIO mode" );
843: else
844: DBG ( "memory %4.4x", eth_bmem );
845: for (i=0; i<ETH_ALEN; i++) {
846: nic->node_addr[i] = inb(eth_nic_base+i);
847: }
848: DBG ( ", %s, MAC Addr %s\n", nic->flags ? "AUI" : "internal xcvr",
849: eth_ntoa ( nic->node_addr ) );
850:
851: outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
852: /*
853: * Initialize GA configuration register. Set bank and enable shared
854: * mem. We always use bank 1. Disable interrupts.
855: */
856: outb(_3COM_GACFR_RSEL |
857: _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
858:
859: outb(0xff, eth_asic_base + _3COM_VPTR2);
860: outb(0xff, eth_asic_base + _3COM_VPTR1);
861: outb(0x00, eth_asic_base + _3COM_VPTR0);
862: /*
863: * Clear memory and verify that it worked (we use only 8K)
864: */
865:
866: if (!(eth_flags & FLAG_PIO)) {
867: memset(bus_to_virt(eth_bmem), 0, 0x2000);
868: for(i = 0; i < 0x2000; ++i)
869: if (*((char *)(bus_to_virt(eth_bmem+i)))) {
870: printf ("Failed to clear 3c503 shared mem.\n");
871: return (0);
872: }
873: }
874: /*
875: * Initialize GA page/start/stop registers.
876: */
877: outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
878: outb(eth_memsize, eth_asic_base + _3COM_PSPR);
879: }
880: #endif
881: #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
882: {
883: /******************************************************************
884: Search for NE1000/2000 if no WD/SMC or 3com cards
885: ******************************************************************/
886: unsigned char c;
887: if (eth_vendor == VENDOR_NONE) {
888: unsigned char romdata[16];
889: unsigned char testbuf[32];
890: int idx;
891: static unsigned char test[] = "NE*000 memory";
892: static unsigned short base[] = {
893: #ifdef NE_SCAN
894: NE_SCAN,
895: #endif
896: 0 };
897: /* if no addresses supplied, fall back on defaults */
898: if (probe_addrs == 0 || probe_addrs[0] == 0)
899: probe_addrs = base;
900: eth_bmem = 0; /* No shared memory */
901: for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
902: eth_flags = FLAG_PIO;
903: eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
904: eth_memsize = MEM_16384;
905: eth_tx_start = 32;
906: eth_rx_start = 32 + D8390_TXBUF_SIZE;
907: c = inb(eth_asic_base + NE_RESET);
908: outb(c, eth_asic_base + NE_RESET);
909: (void) inb(0x84);
910: outb(D8390_COMMAND_STP |
911: D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
912: outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
913: outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
914: outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
915: outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
916: #ifdef NS8390_FORCE_16BIT
917: eth_flags |= FLAG_16BIT; /* force 16-bit mode */
918: #endif
919:
920: eth_pio_write( (unsigned char *) test, 8192, sizeof(test));
921: eth_pio_read(8192, testbuf, sizeof(test));
922: if (!memcmp(test, testbuf, sizeof(test)))
923: break;
924: eth_flags |= FLAG_16BIT;
925: eth_memsize = MEM_32768;
926: eth_tx_start = 64;
927: eth_rx_start = 64 + D8390_TXBUF_SIZE;
928: outb(D8390_DCR_WTS |
929: D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
930: outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
931: outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
932: eth_pio_write( (unsigned char *) test, 16384, sizeof(test));
933: eth_pio_read(16384, testbuf, sizeof(test));
934: if (!memcmp(testbuf, test, sizeof(test)))
935: break;
936: }
937: if (eth_nic_base == 0)
938: return (0);
939: if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
940: eth_flags |= FLAG_16BIT;
941: eth_vendor = VENDOR_NOVELL;
942: eth_pio_read(0, romdata, sizeof(romdata));
943: for (i=0; i<ETH_ALEN; i++) {
944: nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
945: }
946: nic->ioaddr = eth_nic_base;
947: DBG ( "\nNE%c000 base %4.4x, MAC Addr %s\n",
948: (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
949: eth_ntoa ( nic->node_addr ) );
950: }
951: }
952: #endif
953: if (eth_vendor == VENDOR_NONE)
954: return(0);
955: if (eth_vendor != VENDOR_3COM)
956: eth_rmem = eth_bmem;
957: ns8390_reset(nic);
958: nic->nic_op = &ns8390_operations;
959:
960: /* Based on PnP ISA map */
961: #ifdef INCLUDE_WD
962: dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
963: dev->devid.device_id = htons(0x812a);
964: #endif
965: #ifdef INCLUDE_3C503
966: dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
967: dev->devid.device_id = htons(0x80f3);
968: #endif
969: #ifdef INCLUDE_NE
970: dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
971: dev->devid.device_id = htons(0x80d6);
972: #endif
973: return 1;
974: }
975:
976: #ifdef INCLUDE_WD
977: struct isa_driver wd_driver __isa_driver = {
978: .type = NIC_DRIVER,
979: .name = "WD",
980: .probe = wd_probe,
981: .ioaddrs = 0,
982: };
983: ISA_ROM("wd","WD8003/8013, SMC8216/8416, SMC 83c790 (EtherEZ)");
984: #endif
985:
986: #ifdef INCLUDE_3C503
987: struct isa_driver t503_driver __isa_driver = {
988: .type = NIC_DRIVER,
989: .name = "3C503",
990: .probe = t503_probe,
991: .ioaddrs = 0,
992: };
993: ISA_ROM("3c503","3Com503, Etherlink II[/16]");
994: #endif
995:
996: #ifdef INCLUDE_NE
997: struct isa_driver ne_driver __isa_driver = {
998: .type = NIC_DRIVER,
999: .name = "NE*000",
1000: .probe = ne_probe,
1001: .ioaddrs = 0,
1002: };
1003: ISA_ROM("ne","NE1000/2000 and clones");
1004: #endif
1005:
1006: #ifdef INCLUDE_NS8390
1007: static struct pci_device_id nepci_nics[] = {
1008: /* A few NE2000 PCI clones, list not exhaustive */
1009: PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029", 0),
1010: PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528", 0),
1011: PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI", 0), /* Winbond 86C940 / 89C940 */
1012: PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F", 0), /* Winbond 89C940F */
1013: PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0),
1014: PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2", 0),
1015: PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC", 0),
1016: PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232", 0),
1017: PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229", 0),
1018: PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0),
1019: PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926", 0),
1020: };
1021:
1022: PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS );
1023:
1024: DRIVER ( "NE2000/PCI", nic_driver, pci_driver, nepci_driver,
1025: nepci_probe, ns8390_disable );
1026:
1027: #endif /* INCLUDE_NS8390 */
1028:
1029: #endif
1030:
1031: /*
1032: * Local variables:
1033: * c-basic-offset: 8
1034: * c-indent-level: 8
1035: * tab-width: 8
1036: * End:
1037: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.