1 /************************************************************************** 2 ETHERBOOT - BOOTP/TFTP Bootstrap Program 3 4 Author: Martin Renters. 5 Date: Mar 22 1995 6 7 This code is based heavily on David Greenman's if_ed.c driver and 8 Andres Vega Garcia's if_ep.c driver. 9 10 Copyright (C) 1993-1994, David Greenman, Martin Renters. 11 Copyright (C) 1993-1995, Andres Vega Garcia. 12 Copyright (C) 1995, Serge Babkin. 13 This software may be used, modified, copied, distributed, and sold, in 14 both source and binary form provided that the above copyright and these 15 terms are retained. Under no circumstances are the authors responsible for 16 the proper functioning of this software, nor do the authors assume any 17 responsibility for damages incurred with its use. 18 19 3c509 support added by Serge Babkin (babkin (at) hq.icb.chel.su) 20 21 $Id: 3c509.c,v 1.4 2002/01/02 21:56:40 okuji Exp $ 22 23 ***************************************************************************/ 24 25 /* #define EDEBUG */ 26 27 #include "etherboot.h" 28 #include "nic.h" 29 #include "cards.h" 30 #include "timer.h" 31 #include "3c509.h" 32 33 #define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) 34 35 static unsigned short eth_nic_base; 36 static enum { none, bnc, utp } connector = none; /* for 3C509 */ 37 38 #ifdef INCLUDE_3C529 39 /* 40 * This table and several other pieces of the MCA support 41 * code were shamelessly borrowed from the Linux kernel source. 42 * 43 * MCA support added by Adam Fritzler (mid (at) auk.cx) 44 * 45 */ 46 struct el3_mca_adapters_struct { 47 const char *name; 48 int id; 49 }; 50 static struct el3_mca_adapters_struct el3_mca_adapters[] = { 51 { "3Com 3c529 EtherLink III (10base2)", 0x627c }, 52 { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, 53 { "3Com 3c529 EtherLink III (test mode)", 0x62db }, 54 { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 }, 55 { "3Com 3c529 EtherLink III (TP)", 0x62f7 }, 56 { NULL, 0 }, 57 }; 58 #endif 59 60 /************************************************************************** 61 ETH_RESET - Reset adapter 62 ***************************************************************************/ 63 static void t509_reset(struct nic *nic) 64 { 65 int i; 66 67 /*********************************************************** 68 Reset 3Com 509 card 69 *************************************************************/ 70 71 /* stop card */ 72 outw(RX_DISABLE, BASE + EP_COMMAND); 73 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND); 74 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 75 ; 76 outw(TX_DISABLE, BASE + EP_COMMAND); 77 outw(STOP_TRANSCEIVER, BASE + EP_COMMAND); 78 udelay(1000); 79 outw(RX_RESET, BASE + EP_COMMAND); 80 outw(TX_RESET, BASE + EP_COMMAND); 81 outw(C_INTR_LATCH, BASE + EP_COMMAND); 82 outw(SET_RD_0_MASK, BASE + EP_COMMAND); 83 outw(SET_INTR_MASK, BASE + EP_COMMAND); 84 outw(SET_RX_FILTER, BASE + EP_COMMAND); 85 86 /* 87 * initialize card 88 */ 89 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 90 ; 91 92 GO_WINDOW(0); 93 94 /* Disable the card */ 95 outw(0, BASE + EP_W0_CONFIG_CTRL); 96 97 /* Configure IRQ to none */ 98 outw(SET_IRQ(0), BASE + EP_W0_RESOURCE_CFG); 99 100 /* Enable the card */ 101 outw(ENABLE_DRQ_IRQ, BASE + EP_W0_CONFIG_CTRL); 102 103 GO_WINDOW(2); 104 105 /* Reload the ether_addr. */ 106 for (i = 0; i < ETH_ALEN; i++) 107 outb(nic->node_addr[i], BASE + EP_W2_ADDR_0 + i); 108 109 outw(RX_RESET, BASE + EP_COMMAND); 110 outw(TX_RESET, BASE + EP_COMMAND); 111 112 /* Window 1 is operating window */ 113 GO_WINDOW(1); 114 for (i = 0; i < 31; i++) 115 inb(BASE + EP_W1_TX_STATUS); 116 117 /* get rid of stray intr's */ 118 outw(ACK_INTR | 0xff, BASE + EP_COMMAND); 119 120 outw(SET_RD_0_MASK | S_5_INTS, BASE + EP_COMMAND); 121 122 outw(SET_INTR_MASK, BASE + EP_COMMAND); 123 124 outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + EP_COMMAND); 125 126 /* configure BNC */ 127 if (connector == bnc) { 128 outw(START_TRANSCEIVER, BASE + EP_COMMAND); 129 udelay(1000); 130 } 131 /* configure UTP */ 132 else if (connector == utp) { 133 GO_WINDOW(4); 134 outw(ENABLE_UTP, BASE + EP_W4_MEDIA_TYPE); 135 sleep(2); /* Give time for media to negotiate */ 136 GO_WINDOW(1); 137 } 138 139 /* start transceiver and receiver */ 140 outw(RX_ENABLE, BASE + EP_COMMAND); 141 outw(TX_ENABLE, BASE + EP_COMMAND); 142 143 /* set early threshold for minimal packet length */ 144 outw(SET_RX_EARLY_THRESH | ETH_ZLEN, BASE + EP_COMMAND); 145 outw(SET_TX_START_THRESH | 16, BASE + EP_COMMAND); 146 } 147 148 /************************************************************************** 149 ETH_TRANSMIT - Transmit a frame 150 ***************************************************************************/ 151 static char padmap[] = { 152 0, 3, 2, 1}; 153 154 static void t509_transmit( 155 struct nic *nic, 156 const char *d, /* Destination */ 157 unsigned int t, /* Type */ 158 unsigned int s, /* size */ 159 const char *p) /* Packet */ 160 { 161 register unsigned int len; 162 int pad; 163 int status; 164 165 #ifdef EDEBUG 166 printf("{l=%d,t=%hX}",s+ETH_HLEN,t); 167 #endif 168 169 /* swap bytes of type */ 170 t= htons(t); 171 172 len=s+ETH_HLEN; /* actual length of packet */ 173 pad = padmap[len & 3]; 174 175 /* 176 * The 3c509 automatically pads short packets to minimum ethernet length, 177 * but we drop packets that are too large. Perhaps we should truncate 178 * them instead? 179 */ 180 if (len + pad > ETH_FRAME_LEN) { 181 return; 182 } 183 184 /* drop acknowledgements */ 185 while ((status=inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) { 186 if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { 187 outw(TX_RESET, BASE + EP_COMMAND); 188 outw(TX_ENABLE, BASE + EP_COMMAND); 189 } 190 outb(0x0, BASE + EP_W1_TX_STATUS); 191 } 192 193 while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4) 194 ; /* no room in FIFO */ 195 196 outw(len, BASE + EP_W1_TX_PIO_WR_1); 197 outw(0x0, BASE + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */ 198 199 /* write packet */ 200 outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2); 201 outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); 202 outw(t, BASE + EP_W1_TX_PIO_WR_1); 203 outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2); 204 if (s & 1) 205 outb(*(p+s - 1), BASE + EP_W1_TX_PIO_WR_1); 206 207 while (pad--) 208 outb(0, BASE + EP_W1_TX_PIO_WR_1); /* Padding */ 209 210 /* wait for Tx complete */ 211 while((inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0) 212 ; 213 } 214 215 /************************************************************************** 216 ETH_POLL - Wait for a frame 217 ***************************************************************************/ 218 static int t509_poll(struct nic *nic) 219 { 220 /* common variables */ 221 unsigned short type = 0; /* used by EDEBUG */ 222 /* variables for 3C509 */ 223 short status, cst; 224 register short rx_fifo; 225 226 cst=inw(BASE + EP_STATUS); 227 228 #ifdef EDEBUG 229 if(cst & 0x1FFF) 230 printf("-%hX-",cst); 231 #endif 232 233 if( (cst & S_RX_COMPLETE)==0 ) { 234 /* acknowledge everything */ 235 outw(ACK_INTR| (cst & S_5_INTS), BASE + EP_COMMAND); 236 outw(C_INTR_LATCH, BASE + EP_COMMAND); 237 238 return 0; 239 } 240 241 status = inw(BASE + EP_W1_RX_STATUS); 242 #ifdef EDEBUG 243 printf("*%hX*",status); 244 #endif 245 246 if (status & ERR_RX) { 247 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND); 248 return 0; 249 } 250 251 rx_fifo = status & RX_BYTES_MASK; 252 if (rx_fifo==0) 253 return 0; 254 255 /* read packet */ 256 #ifdef EDEBUG 257 printf("[l=%d",rx_fifo); 258 #endif 259 insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2); 260 if(rx_fifo & 1) 261 nic->packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1); 262 nic->packetlen=rx_fifo; 263 264 while(1) { 265 status = inw(BASE + EP_W1_RX_STATUS); 266 #ifdef EDEBUG 267 printf("*%hX*",status); 268 #endif 269 rx_fifo = status & RX_BYTES_MASK; 270 if(rx_fifo>0) { 271 insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2); 272 if(rx_fifo & 1) 273 nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1); 274 nic->packetlen+=rx_fifo; 275 #ifdef EDEBUG 276 printf("+%d",rx_fifo); 277 #endif 278 } 279 if(( status & RX_INCOMPLETE )==0) { 280 #ifdef EDEBUG 281 printf("=%d",nic->packetlen); 282 #endif 283 break; 284 } 285 udelay(1000); /* if incomplete wait 1 ms */ 286 } 287 /* acknowledge reception of packet */ 288 outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND); 289 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) 290 ; 291 #ifdef EDEBUG 292 type = (nic->packet[12]<<8) | nic->packet[13]; 293 if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ 294 nic->packet[5] == 0xFF*ETH_ALEN) 295 printf(",t=%hX,b]",type); 296 else 297 printf(",t=%hX]",type); 298 #endif 299 return (1); 300 } 301 302 /************************************************************************* 303 3Com 509 - specific routines 304 **************************************************************************/ 305 306 static int 307 eeprom_rdy(void) 308 { 309 int i; 310 311 for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++); 312 if (i >= MAX_EEPROMBUSY) { 313 /* printf("3c509: eeprom failed to come ready.\n"); */ 314 printf("3c509: eeprom busy.\n"); /* memory in EPROM is tight */ 315 return (0); 316 } 317 return (1); 318 } 319 320 /* 321 * get_e: gets a 16 bits word from the EEPROM. we must have set the window 322 * before 323 */ 324 static int 325 get_e(int offset) 326 { 327 if (!eeprom_rdy()) 328 return (0xffff); 329 outw(EEPROM_CMD_RD | offset, IS_BASE + EP_W0_EEPROM_COMMAND); 330 if (!eeprom_rdy()) 331 return (0xffff); 332 return (inw(IS_BASE + EP_W0_EEPROM_DATA)); 333 } 334 335 static int 336 send_ID_sequence(int port) 337 { 338 int cx, al; 339 340 for (al = 0xff, cx = 0; cx < 255; cx++) { 341 outb(al, port); 342 al <<= 1; 343 if (al & 0x100) 344 al ^= 0xcf; 345 } 346 return (1); 347 } 348 349 350 /* 351 * We get eeprom data from the id_port given an offset into the eeprom. 352 * Basically; after the ID_sequence is sent to all of the cards; they enter 353 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads 354 * the eeprom data. We then read the port 16 times and with every read; the 355 * cards check for contention (ie: if one card writes a 0 bit and another 356 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card 357 * compares the data on the bus; if there is a difference then that card goes 358 * into ID_WAIT state again). In the meantime; one bit of data is returned in 359 * the AX register which is conveniently returned to us by inb(). Hence; we 360 * read 16 times getting one bit of data with each read. 361 */ 362 static int 363 get_eeprom_data(int id_port, int offset) 364 { 365 int i, data = 0; 366 outb(0x80 + offset, id_port); 367 /* Do we really need this wait? Won't be noticeable anyway */ 368 udelay(10000); 369 for (i = 0; i < 16; i++) 370 data = (data << 1) | (inw(id_port) & 1); 371 return (data); 372 } 373 374 static void t509_disable(struct nic *nic) 375 { 376 outb(0xc0, EP_ID_PORT); 377 } 378 379 /************************************************************************** 380 ETH_PROBE - Look for an adapter 381 ***************************************************************************/ 382 #ifdef INCLUDE_3C529 383 struct nic *t529_probe(struct nic *nic, unsigned short *probe_addrs) 384 #else 385 struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) 386 #endif 387 { 388 /* common variables */ 389 int i; 390 int failcount; 391 392 #ifdef INCLUDE_3C529 393 struct el3_mca_adapters_struct *mcafound = NULL; 394 int mca_pos4 = 0, mca_pos5 = 0, mca_irq = 0; 395 #endif 396 397 t509_disable(nic); /* in case board was active */ 398 /* note that nic is not used */ 399 for (failcount = 0; failcount < 4000; failcount++) { 400 int data, j, io_base, id_port; 401 unsigned short k; 402 int ep_current_tag; 403 short *p; 404 #ifdef INCLUDE_3C529 405 int curboard; 406 #endif 407 408 id_port = EP_ID_PORT; 409 ep_current_tag = EP_LAST_TAG + 1; 410 411 /********************************************************* 412 Search for 3Com 509 card 413 ***********************************************************/ 414 #ifdef INCLUDE_3C529 415 /* 416 * XXX: We should really check to make sure we have an MCA 417 * bus controller before going ahead with this... 418 * 419 * For now, we avoid any hassle by making it a compile 420 * time option. 421 * 422 */ 423 printf("\nWarning: Assuming presence of MCA bus\n"); 424 425 /* Make sure motherboard setup is off */ 426 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG); 427 428 /* Cycle through slots */ 429 for(curboard=0; curboard<MCA_MAX_SLOT_NR; curboard++) { 430 int boardid; 431 int curcard; 432 433 outb_p(0x8|(curboard&0xf), MCA_ADAPTER_SETUP_REG); 434 435 boardid = inb_p(MCA_POS_REG(0)); 436 boardid += inb_p(MCA_POS_REG(1)) << 8; 437 438 curcard = 0; 439 while (el3_mca_adapters[curcard].name) { 440 if (el3_mca_adapters[curcard].id == boardid) { 441 mcafound = &el3_mca_adapters[curcard]; 442 443 mca_pos4 = inb_p(MCA_POS_REG(4)); 444 mca_pos5 = inb_p(MCA_POS_REG(5)); 445 446 goto donewithdetect; 447 } 448 else 449 curcard++; 450 } 451 452 } 453 donewithdetect: 454 /* Kill all setup modes */ 455 outb_p(0, MCA_ADAPTER_SETUP_REG); 456 457 if (mcafound) { 458 eth_nic_base = ((short)((mca_pos4&0xfc)|0x02)) << 8; 459 mca_irq = mca_pos5 & 0x0f; 460 ep_current_tag--; 461 } 462 else 463 printf("MCA Card not found\n"); 464 #endif 465 /* Look for the EISA boards, leave them activated */ 466 /* search for the first card, ignore all others */ 467 for(j = 1; j < 16; j++) { 468 io_base = (j * EP_EISA_START) | EP_EISA_W0; 469 if (inw(io_base + EP_W0_MFG_ID) != MFG_ID) 470 continue; 471 472 /* we must have found 0x1f if the board is EISA configurated */ 473 if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) 474 continue; 475 476 /* Reset and Enable the card */ 477 outb(W0_P4_CMD_RESET_ADAPTER, io_base + EP_W0_CONFIG_CTRL); 478 udelay(1000); /* Must wait 800 s, be conservative */ 479 outb(W0_P4_CMD_ENABLE_ADAPTER, io_base + EP_W0_CONFIG_CTRL); 480 481 /* 482 * Once activated, all the registers are mapped in the range 483 * x000 - x00F, where x is the slot number. 484 */ 485 eth_nic_base = j * EP_EISA_START; 486 break; 487 } 488 ep_current_tag--; 489 490 /* Look for the ISA boards. Init and leave them actived */ 491 /* search for the first card, ignore all others */ 492 outb(0xc0, id_port); /* Global reset */ 493 udelay(1000); /* wait 1 ms */ 494 for (i = 0; i < EP_MAX_BOARDS; i++) { 495 outb(0, id_port); 496 outb(0, id_port); 497 send_ID_sequence(id_port); 498 499 data = get_eeprom_data(id_port, EEPROM_MFG_ID); 500 if (data != MFG_ID) 501 break; 502 503 /* resolve contention using the Ethernet address */ 504 for (j = 0; j < 3; j++) 505 data = get_eeprom_data(id_port, j); 506 507 eth_nic_base = 508 (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; 509 outb(ep_current_tag, id_port); /* tags board */ 510 outb(ACTIVATE_ADAPTER_TO_CONFIG, id_port); 511 ep_current_tag--; 512 break; 513 } 514 515 if (i >= EP_MAX_BOARDS) 516 goto no3c509; 517 518 /* 519 * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be 520 * 0x9[0-f]50 521 */ 522 GO_WINDOW(0); 523 k = get_e(EEPROM_PROD_ID); 524 #ifdef INCLUDE_3C529 525 /* 526 * On MCA, the PROD_ID matches the MCA card ID (POS0+POS1) 527 */ 528 if (mcafound) { 529 if (mcafound->id != k) { 530 printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k, mcafound->id); 531 goto no3c509; 532 } 533 } else { /* for ISA/EISA */ 534 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) 535 goto no3c509; 536 } 537 #else 538 if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) 539 goto no3c509; 540 #endif 541 542 #ifdef INCLUDE_3C529 543 if (mcafound) { 544 printf("%s board found on MCA at %#hx IRQ %d -", 545 mcafound->name, eth_nic_base, mca_irq); 546 } else { 547 #endif 548 if(eth_nic_base >= EP_EISA_START) 549 printf("3C5x9 board on EISA at %#hx - ",eth_nic_base); 550 else 551 printf("3C5x9 board on ISA at %#hx - ",eth_nic_base); 552 #ifdef INCLUDE_3C529 553 } 554 #endif 555 556 /* test for presence of connectors */ 557 i = inw(IS_BASE + EP_W0_CONFIG_CTRL); 558 j = (inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14) & 0x3; 559 560 switch(j) { 561 case 0: 562 if (i & IS_UTP) { 563 printf("10baseT\n"); 564 connector = utp; 565 } 566 else { 567 printf("10baseT not present\n"); 568 goto no3c509; 569 } 570 break; 571 case 1: 572 if (i & IS_AUI) 573 printf("10base5\n"); 574 else { 575 printf("10base5 not present\n"); 576 goto no3c509; 577 } 578 break; 579 case 3: 580 if (i & IS_BNC) { 581 printf("10base2\n"); 582 connector = bnc; 583 } 584 else { 585 printf("10base2 not present\n"); 586 goto no3c509; 587 } 588 break; 589 default: 590 printf("unknown connector\n"); 591 goto no3c509; 592 } 593 /* 594 * Read the station address from the eeprom 595 */ 596 p = (unsigned short *) nic->node_addr; 597 for (i = 0; i < ETH_ALEN / 2; i++) { 598 GO_WINDOW(0); 599 p[i] = htons(get_e(i)); 600 GO_WINDOW(2); 601 outw(ntohs(p[i]), BASE + EP_W2_ADDR_0 + (i * 2)); 602 } 603 printf("Ethernet address: %!\n", nic->node_addr); 604 t509_reset(nic); 605 nic->reset = t509_reset; 606 nic->poll = t509_poll; 607 nic->transmit = t509_transmit; 608 nic->disable = t509_disable; 609 return nic; 610 no3c509: 611 printf("(probe fail)"); 612 } 613 return 0; 614 } 615 616 /* 617 * Local variables: 618 * c-basic-offset: 8 619 * End: 620 */ 621