|
|
1.1 ! root 1: /* ! 2: * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot ! 3: * ! 4: * Copyright (C) 2000 Shusuke Nisiyama <[email protected]> ! 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 <[email protected]> ! 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 <ipxe/pci.h> ! 33: #include <ipxe/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: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.