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