1 /* 2 * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot 3 * 4 * Copyright (C) 2000 Shusuke Nisiyama <shu (at) athena.qe.eng.hokudai.ac.jp> 5 * All rights reserved. 6 * Mar. 14, 2000 7 * 8 * This software may be used, modified, copied, distributed, and sold, in 9 * both source and binary form provided that the above copyright and these 10 * terms are retained. Under no circumstances are the authors responsible for 11 * the proper functioning of this software, nor do the authors assume any 12 * responsibility for damages incurred with its use. 13 * 14 * This code is based on Martin Renters' etherboot-4.4.3 3c509.c and 15 * Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver. 16 * 17 * Copyright (C) 1993-1994, David Greenman, Martin Renters. 18 * Copyright (C) 1993-1995, Andres Vega Garcia. 19 * Copyright (C) 1995, Serge Babkin. 20 * 21 * Copyright (c) 1994 Herb Peyerl <hpeyerl (at) novatel.ca> 22 * 23 * timlegge 08-24-2003 Add Multicast Support 24 */ 25 26 FILE_LICENCE ( BSD2 ); 27 28 /* #define EDEBUG */ 29 30 #include "etherboot.h" 31 #include "nic.h" 32 #include <gpxe/pci.h> 33 #include <gpxe/ethernet.h> 34 #include "3c595.h" 35 36 static struct nic_operations t595_operations; 37 38 static unsigned short eth_nic_base; 39 static unsigned short vx_connector, vx_connectors; 40 41 static struct connector_entry { 42 int bit; 43 char *name; 44 } conn_tab[VX_CONNECTORS] = { 45 #define CONNECTOR_UTP 0 46 { 0x08, "utp"}, 47 #define CONNECTOR_AUI 1 48 { 0x20, "aui"}, 49 /* dummy */ 50 { 0, "???"}, 51 #define CONNECTOR_BNC 3 52 { 0x10, "bnc"}, 53 #define CONNECTOR_TX 4 54 { 0x02, "tx"}, 55 #define CONNECTOR_FX 5 56 { 0x04, "fx"}, 57 #define CONNECTOR_MII 6 58 { 0x40, "mii"}, 59 { 0, "???"} 60 }; 61 62 static void vxgetlink(void); 63 static void vxsetlink(void); 64 65 /************************************************************************** 66 ETH_RESET - Reset adapter 67 ***************************************************************************/ 68 static void t595_reset(struct nic *nic) 69 { 70 int i; 71 72 /*********************************************************** 73 Reset 3Com 595 card 74 *************************************************************/ 75 76 /* stop card */ 77 outw(RX_DISABLE, BASE + VX_COMMAND); 78 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND); 79 VX_BUSY_WAIT; 80 outw(TX_DISABLE, BASE + VX_COMMAND); 81 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND); 82 udelay(8000); 83 outw(RX_RESET, BASE + VX_COMMAND); 84 VX_BUSY_WAIT; 85 outw(TX_RESET, BASE + VX_COMMAND); 86 VX_BUSY_WAIT; 87 outw(C_INTR_LATCH, BASE + VX_COMMAND); 88 outw(SET_RD_0_MASK, BASE + VX_COMMAND); 89 outw(SET_INTR_MASK, BASE + VX_COMMAND); 90 outw(SET_RX_FILTER, BASE + VX_COMMAND); 91 92 /* 93 * initialize card 94 */ 95 VX_BUSY_WAIT; 96 97 GO_WINDOW(0); 98 99 /* Disable the card */ 100 /* outw(0, BASE + VX_W0_CONFIG_CTRL); */ 101 102 /* Configure IRQ to none */ 103 /* outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */ 104 105 /* Enable the card */ 106 /* outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */ 107 108 GO_WINDOW(2); 109 110 /* Reload the ether_addr. */ 111 for (i = 0; i < ETH_ALEN; i++) 112 outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i); 113 114 outw(RX_RESET, BASE + VX_COMMAND); 115 VX_BUSY_WAIT; 116 outw(TX_RESET, BASE + VX_COMMAND); 117 VX_BUSY_WAIT; 118 119 /* Window 1 is operating window */ 120 GO_WINDOW(1); 121 for (i = 0; i < 31; i++) 122 inb(BASE + VX_W1_TX_STATUS); 123 124 outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 125 S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND); 126 outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE | 127 S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND); 128 129 /* 130 * Attempt to get rid of any stray interrupts that occured during 131 * configuration. On the i386 this isn't possible because one may 132 * already be queued. However, a single stray interrupt is 133 * unimportant. 134 */ 135 136 outw(ACK_INTR | 0xff, BASE + VX_COMMAND); 137 138 outw(SET_RX_FILTER | FIL_INDIVIDUAL | 139 FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND); 140 141 vxsetlink(); 142 /*{ 143 int i,j; 144 i = CONNECTOR_TX; 145 GO_WINDOW(3); 146 j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 147 outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS)); 148 GO_WINDOW(4); 149 outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE); 150 GO_WINDOW(1); 151 }*/ 152 153 /* start tranciever and receiver */ 154 outw(RX_ENABLE, BASE + VX_COMMAND); 155 outw(TX_ENABLE, BASE + VX_COMMAND); 156 157 } 158 159 /************************************************************************** 160 ETH_TRANSMIT - Transmit a frame 161 ***************************************************************************/ 162 static char padmap[] = { 163 0, 3, 2, 1}; 164 165 static void t595_transmit( 166 struct nic *nic, 167 const char *d, /* Destination */ 168 unsigned int t, /* Type */ 169 unsigned int s, /* size */ 170 const char *p) /* Packet */ 171 { 172 register int len; 173 int pad; 174 int status; 175 176 #ifdef EDEBUG 177 printf("{l=%d,t=%hX}",s+ETH_HLEN,t); 178 #endif 179 180 /* swap bytes of type */ 181 t= htons(t); 182 183 len=s+ETH_HLEN; /* actual length of packet */ 184 pad = padmap[len & 3]; 185 186 /* 187 * The 3c595 automatically pads short packets to minimum ethernet length, 188 * but we drop packets that are too large. Perhaps we should truncate 189 * them instead? 190 */ 191 if (len + pad > ETH_FRAME_LEN) { 192 return; 193 } 194 195 /* drop acknowledgements */ 196 while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) { 197 if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { 198 outw(TX_RESET, BASE + VX_COMMAND); 199 outw(TX_ENABLE, BASE + VX_COMMAND); 200 } 201 202 outb(0x0, BASE + VX_W1_TX_STATUS); 203 } 204 205 while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { 206 /* no room in FIFO */ 207 } 208 209 outw(len, BASE + VX_W1_TX_PIO_WR_1); 210 outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */ 211 212 /* write packet */ 213 outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2); 214 outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); 215 outw(t, BASE + VX_W1_TX_PIO_WR_1); 216 outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2); 217 if (s & 1) 218 outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1); 219 220 while (pad--) 221 outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */ 222 223 /* wait for Tx complete */ 224 while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0) 225 ; 226 } 227 228 /************************************************************************** 229 ETH_POLL - Wait for a frame 230 ***************************************************************************/ 231 static int t595_poll(struct nic *nic, int retrieve) 232 { 233 /* common variables */ 234 /* variables for 3C595 */ 235 short status, cst; 236 register short rx_fifo; 237 238 cst=inw(BASE + VX_STATUS); 239 240 #ifdef EDEBUG 241 if(cst & 0x1FFF) 242 printf("-%hX-",cst); 243 #endif 244 245 if( (cst & S_RX_COMPLETE)==0 ) { 246 /* acknowledge everything */ 247 outw(ACK_INTR | cst, BASE + VX_COMMAND); 248 outw(C_INTR_LATCH, BASE + VX_COMMAND); 249 250 return 0; 251 } 252 253 status = inw(BASE + VX_W1_RX_STATUS); 254 #ifdef EDEBUG 255 printf("*%hX*",status); 256 #endif 257 258 if (status & ERR_RX) { 259 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND); 260 return 0; 261 } 262 263 rx_fifo = status & RX_BYTES_MASK; 264 if (rx_fifo==0) 265 return 0; 266 267 if ( ! retrieve ) return 1; 268 269 /* read packet */ 270 #ifdef EDEBUG 271 printf("[l=%d",rx_fifo); 272 #endif 273 insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2); 274 if(rx_fifo & 1) 275 nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1); 276 nic->packetlen=rx_fifo; 277 278 while(1) { 279 status = inw(BASE + VX_W1_RX_STATUS); 280 #ifdef EDEBUG 281 printf("*%hX*",status); 282 #endif 283 rx_fifo = status & RX_BYTES_MASK; 284 285 if(rx_fifo>0) { 286 insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2); 287 if(rx_fifo & 1) 288 nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1); 289 nic->packetlen+=rx_fifo; 290 #ifdef EDEBUG 291 printf("+%d",rx_fifo); 292 #endif 293 } 294 if(( status & RX_INCOMPLETE )==0) { 295 #ifdef EDEBUG 296 printf("=%d",nic->packetlen); 297 #endif 298 break; 299 } 300 udelay(1000); 301 } 302 303 /* acknowledge reception of packet */ 304 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND); 305 while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS); 306 #ifdef EDEBUG 307 { 308 unsigned short type = 0; /* used by EDEBUG */ 309 type = (nic->packet[12]<<8) | nic->packet[13]; 310 if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ 311 nic->packet[5] == 0xFF*ETH_ALEN) 312 printf(",t=%hX,b]",type); 313 else 314 printf(",t=%hX]",type); 315 } 316 #endif 317 return 1; 318 } 319 320 321 /************************************************************************* 322 3Com 595 - specific routines 323 **************************************************************************/ 324 325 static int 326 eeprom_rdy() 327 { 328 int i; 329 330 for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) 331 udelay(1000); 332 if (i >= MAX_EEPROMBUSY) { 333 /* printf("3c595: eeprom failed to come ready.\n"); */ 334 printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */ 335 return (0); 336 } 337 return (1); 338 } 339 340 /* 341 * get_e: gets a 16 bits word from the EEPROM. we must have set the window 342 * before 343 */ 344 static int 345 get_e(offset) 346 int offset; 347 { 348 if (!eeprom_rdy()) 349 return (0xffff); 350 outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND); 351 if (!eeprom_rdy()) 352 return (0xffff); 353 return (inw(BASE + VX_W0_EEPROM_DATA)); 354 } 355 356 static void 357 vxgetlink(void) 358 { 359 int n, k; 360 361 GO_WINDOW(3); 362 vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f; 363 for (n = 0, k = 0; k < VX_CONNECTORS; k++) { 364 if (vx_connectors & conn_tab[k].bit) { 365 if (n > 0) { 366 printf("/"); 367 } 368 printf("%s", conn_tab[k].name ); 369 n++; 370 } 371 } 372 if (vx_connectors == 0) { 373 printf("no connectors!"); 374 return; 375 } 376 GO_WINDOW(3); 377 vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 378 & INTERNAL_CONNECTOR_MASK) 379 >> INTERNAL_CONNECTOR_BITS; 380 if (vx_connector & 0x10) { 381 vx_connector &= 0x0f; 382 printf("[*%s*]", conn_tab[vx_connector].name); 383 printf(": disable 'auto select' with DOS util!"); 384 } else { 385 printf("[*%s*]", conn_tab[vx_connector].name); 386 } 387 } 388 389 static void 390 vxsetlink(void) 391 { 392 int i, j; 393 char *reason, *warning; 394 static char prev_conn = -1; 395 396 if (prev_conn == -1) { 397 prev_conn = vx_connector; 398 } 399 400 i = vx_connector; /* default in EEPROM */ 401 reason = "default"; 402 warning = 0; 403 404 if ((vx_connectors & conn_tab[vx_connector].bit) == 0) { 405 warning = "strange connector type in EEPROM."; 406 reason = "forced"; 407 i = CONNECTOR_UTP; 408 } 409 410 if (warning != 0) { 411 printf("warning: %s\n", warning); 412 } 413 printf("selected %s. (%s)\n", conn_tab[i].name, reason); 414 415 /* Set the selected connector. */ 416 GO_WINDOW(3); 417 j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK; 418 outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG); 419 420 /* First, disable all. */ 421 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND); 422 udelay(8000); 423 GO_WINDOW(4); 424 outw(0, BASE + VX_W4_MEDIA_TYPE); 425 426 /* Second, enable the selected one. */ 427 switch(i) { 428 case CONNECTOR_UTP: 429 GO_WINDOW(4); 430 outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE); 431 break; 432 case CONNECTOR_BNC: 433 outw(START_TRANSCEIVER,BASE + VX_COMMAND); 434 udelay(8000); 435 break; 436 case CONNECTOR_TX: 437 case CONNECTOR_FX: 438 GO_WINDOW(4); 439 outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE); 440 break; 441 default: /* AUI and MII fall here */ 442 break; 443 } 444 GO_WINDOW(1); 445 } 446 447 static void t595_disable ( struct nic *nic ) { 448 449 t595_reset(nic); 450 451 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND); 452 udelay(8000); 453 GO_WINDOW(4); 454 outw(0, BASE + VX_W4_MEDIA_TYPE); 455 GO_WINDOW(1); 456 } 457 458 static void t595_irq(struct nic *nic __unused, irq_action_t action __unused) 459 { 460 switch ( action ) { 461 case DISABLE : 462 break; 463 case ENABLE : 464 break; 465 case FORCE : 466 break; 467 } 468 } 469 470 /************************************************************************** 471 ETH_PROBE - Look for an adapter 472 ***************************************************************************/ 473 static int t595_probe ( struct nic *nic, struct pci_device *pci ) { 474 475 int i; 476 unsigned short *p; 477 478 if (pci->ioaddr == 0) 479 return 0; 480 eth_nic_base = pci->ioaddr; 481 482 nic->irqno = 0; 483 nic->ioaddr = pci->ioaddr; 484 485 GO_WINDOW(0); 486 outw(GLOBAL_RESET, BASE + VX_COMMAND); 487 VX_BUSY_WAIT; 488 489 vxgetlink(); 490 491 /* 492 printf("\nEEPROM:"); 493 for (i = 0; i < (EEPROMSIZE/2); i++) { 494 printf("%hX:", get_e(i)); 495 } 496 printf("\n"); 497 */ 498 /* 499 * Read the station address from the eeprom 500 */ 501 p = (unsigned short *) nic->node_addr; 502 for (i = 0; i < 3; i++) { 503 GO_WINDOW(0); 504 p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i)); 505 GO_WINDOW(2); 506 outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2)); 507 } 508 509 DBG ( "Ethernet address: %s\n", eth_ntoa (nic->node_addr) ); 510 511 t595_reset(nic); 512 nic->nic_op = &t595_operations; 513 return 1; 514 515 } 516 517 static struct nic_operations t595_operations = { 518 .connect = dummy_connect, 519 .poll = t595_poll, 520 .transmit = t595_transmit, 521 .irq = t595_irq, 522 523 }; 524 525 static struct pci_device_id t595_nics[] = { 526 PCI_ROM(0x10b7, 0x5900, "3c590", "3Com590", 0), /* Vortex 10Mbps */ 527 PCI_ROM(0x10b7, 0x5950, "3c595", "3Com595", 0), /* Vortex 100baseTx */ 528 PCI_ROM(0x10b7, 0x5951, "3c595-1", "3Com595", 0), /* Vortex 100baseT4 */ 529 PCI_ROM(0x10b7, 0x5952, "3c595-2", "3Com595", 0), /* Vortex 100base-MII */ 530 PCI_ROM(0x10b7, 0x9000, "3c900-tpo", "3Com900-TPO", 0), /* 10 Base TPO */ 531 PCI_ROM(0x10b7, 0x9001, "3c900-t4", "3Com900-Combo", 0), /* 10/100 T4 */ 532 PCI_ROM(0x10b7, 0x9004, "3c900b-tpo", "3Com900B-TPO", 0), /* 10 Base TPO */ 533 PCI_ROM(0x10b7, 0x9005, "3c900b-combo", "3Com900B-Combo", 0), /* 10 Base Combo */ 534 PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2", "3Com900B-2/T", 0), /* 10 Base TP and Base2 */ 535 PCI_ROM(0x10b7, 0x900a, "3c900b-fl", "3Com900B-FL", 0), /* 10 Base F */ 536 PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone", 0), /* Cyclone */ 537 PCI_ROM(0x10b7, 0x9805, "3c9805-1", "3Com9805", 0), /* Dual Port Server Cyclone */ 538 PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1", "3CSOHO100-TX", 0), /* Hurricane */ 539 PCI_ROM(0x10b7, 0x4500, "3c450-1", "3Com450 HomePNA Tornado", 0), 540 }; 541 542 PCI_DRIVER ( t595_driver, t595_nics, PCI_NO_CLASS ); 543 544 DRIVER ( "3C595", nic_driver, pci_driver, t595_driver, 545 t595_probe, t595_disable ); 546 547 /* 548 * Local variables: 549 * c-basic-offset: 8 550 * c-indent-level: 8 551 * tab-width: 8 552 * End: 553 */ 554