VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/Etherboot-src/drivers/net/ns8390.c@ 895

Last change on this file since 895 was 1, checked in by vboxsync, 55 years ago

import

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette