|
|
1.1 ! root 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 ([email protected]) ! 20: ! 21: $Id$ ! 22: ! 23: ***************************************************************************/ ! 24: ! 25: FILE_LICENCE ( BSD2 ); ! 26: ! 27: /* #define EDEBUG */ ! 28: ! 29: #include <ipxe/ethernet.h> ! 30: #include "etherboot.h" ! 31: #include "nic.h" ! 32: #include <ipxe/isa.h> ! 33: #include "3c509.h" ! 34: ! 35: static enum { none, bnc, utp } connector = none; /* for 3C509 */ ! 36: ! 37: /************************************************************************** ! 38: ETH_RESET - Reset adapter ! 39: ***************************************************************************/ ! 40: void t5x9_disable ( struct nic *nic ) { ! 41: /* stop card */ ! 42: outw(RX_DISABLE, nic->ioaddr + EP_COMMAND); ! 43: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND); ! 44: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) ! 45: ; ! 46: outw(TX_DISABLE, nic->ioaddr + EP_COMMAND); ! 47: outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND); ! 48: udelay(1000); ! 49: outw(RX_RESET, nic->ioaddr + EP_COMMAND); ! 50: outw(TX_RESET, nic->ioaddr + EP_COMMAND); ! 51: outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND); ! 52: outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND); ! 53: outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND); ! 54: outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND); ! 55: ! 56: /* ! 57: * wait for reset to complete ! 58: */ ! 59: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) ! 60: ; ! 61: ! 62: GO_WINDOW(nic->ioaddr,0); ! 63: ! 64: /* Disable the card */ ! 65: outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL); ! 66: ! 67: /* Configure IRQ to none */ ! 68: outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG); ! 69: } ! 70: ! 71: static void t509_enable ( struct nic *nic ) { ! 72: int i; ! 73: ! 74: /* Enable the card */ ! 75: GO_WINDOW(nic->ioaddr,0); ! 76: outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL); ! 77: ! 78: GO_WINDOW(nic->ioaddr,2); ! 79: ! 80: /* Reload the ether_addr. */ ! 81: for (i = 0; i < ETH_ALEN; i++) ! 82: outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i); ! 83: ! 84: outw(RX_RESET, nic->ioaddr + EP_COMMAND); ! 85: outw(TX_RESET, nic->ioaddr + EP_COMMAND); ! 86: ! 87: /* Window 1 is operating window */ ! 88: GO_WINDOW(nic->ioaddr,1); ! 89: for (i = 0; i < 31; i++) ! 90: inb(nic->ioaddr + EP_W1_TX_STATUS); ! 91: ! 92: /* get rid of stray intr's */ ! 93: outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND); ! 94: ! 95: outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND); ! 96: ! 97: outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND); ! 98: ! 99: outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST, ! 100: nic->ioaddr + EP_COMMAND); ! 101: ! 102: /* configure BNC */ ! 103: if (connector == bnc) { ! 104: outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND); ! 105: udelay(1000); ! 106: } ! 107: /* configure UTP */ ! 108: else if (connector == utp) { ! 109: GO_WINDOW(nic->ioaddr,4); ! 110: outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE); ! 111: sleep(2); /* Give time for media to negotiate */ ! 112: GO_WINDOW(nic->ioaddr,1); ! 113: } ! 114: ! 115: /* start transceiver and receiver */ ! 116: outw(RX_ENABLE, nic->ioaddr + EP_COMMAND); ! 117: outw(TX_ENABLE, nic->ioaddr + EP_COMMAND); ! 118: ! 119: /* set early threshold for minimal packet length */ ! 120: outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND); ! 121: outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND); ! 122: } ! 123: ! 124: static void t509_reset ( struct nic *nic ) { ! 125: t5x9_disable ( nic ); ! 126: t509_enable ( nic ); ! 127: } ! 128: ! 129: /************************************************************************** ! 130: ETH_TRANSMIT - Transmit a frame ! 131: ***************************************************************************/ ! 132: static char padmap[] = { ! 133: 0, 3, 2, 1}; ! 134: ! 135: static void t509_transmit( ! 136: struct nic *nic, ! 137: const char *d, /* Destination */ ! 138: unsigned int t, /* Type */ ! 139: unsigned int s, /* size */ ! 140: const char *p) /* Packet */ ! 141: { ! 142: register unsigned int len; ! 143: int pad; ! 144: int status; ! 145: ! 146: #ifdef EDEBUG ! 147: printf("{l=%d,t=%hX}",s+ETH_HLEN,t); ! 148: #endif ! 149: ! 150: /* swap bytes of type */ ! 151: t= htons(t); ! 152: ! 153: len=s+ETH_HLEN; /* actual length of packet */ ! 154: pad = padmap[len & 3]; ! 155: ! 156: /* ! 157: * The 3c509 automatically pads short packets to minimum ethernet length, ! 158: * but we drop packets that are too large. Perhaps we should truncate ! 159: * them instead? ! 160: */ ! 161: if (len + pad > ETH_FRAME_LEN) { ! 162: return; ! 163: } ! 164: ! 165: /* drop acknowledgements */ ! 166: while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) { ! 167: if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { ! 168: outw(TX_RESET, nic->ioaddr + EP_COMMAND); ! 169: outw(TX_ENABLE, nic->ioaddr + EP_COMMAND); ! 170: } ! 171: outb(0x0, nic->ioaddr + EP_W1_TX_STATUS); ! 172: } ! 173: ! 174: while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4) ! 175: ; /* no room in FIFO */ ! 176: ! 177: outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1); ! 178: outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */ ! 179: ! 180: /* write packet */ ! 181: outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2); ! 182: outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2); ! 183: outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1); ! 184: outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2); ! 185: if (s & 1) ! 186: outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1); ! 187: ! 188: while (pad--) ! 189: outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Padding */ ! 190: ! 191: /* wait for Tx complete */ ! 192: while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0) ! 193: ; ! 194: } ! 195: ! 196: /************************************************************************** ! 197: ETH_POLL - Wait for a frame ! 198: ***************************************************************************/ ! 199: static int t509_poll(struct nic *nic, int retrieve) ! 200: { ! 201: /* common variables */ ! 202: /* variables for 3C509 */ ! 203: short status, cst; ! 204: register short rx_fifo; ! 205: ! 206: cst=inw(nic->ioaddr + EP_STATUS); ! 207: ! 208: #ifdef EDEBUG ! 209: if(cst & 0x1FFF) ! 210: printf("-%hX-",cst); ! 211: #endif ! 212: ! 213: if( (cst & S_RX_COMPLETE)==0 ) { ! 214: /* acknowledge everything */ ! 215: outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND); ! 216: outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND); ! 217: ! 218: return 0; ! 219: } ! 220: ! 221: status = inw(nic->ioaddr + EP_W1_RX_STATUS); ! 222: #ifdef EDEBUG ! 223: printf("*%hX*",status); ! 224: #endif ! 225: ! 226: if (status & ERR_RX) { ! 227: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND); ! 228: return 0; ! 229: } ! 230: ! 231: rx_fifo = status & RX_BYTES_MASK; ! 232: if (rx_fifo==0) ! 233: return 0; ! 234: ! 235: if ( ! retrieve ) return 1; ! 236: ! 237: /* read packet */ ! 238: #ifdef EDEBUG ! 239: printf("[l=%d",rx_fifo); ! 240: #endif ! 241: insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2); ! 242: if(rx_fifo & 1) ! 243: nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1); ! 244: nic->packetlen=rx_fifo; ! 245: ! 246: while(1) { ! 247: status = inw(nic->ioaddr + EP_W1_RX_STATUS); ! 248: #ifdef EDEBUG ! 249: printf("*%hX*",status); ! 250: #endif ! 251: rx_fifo = status & RX_BYTES_MASK; ! 252: if(rx_fifo>0) { ! 253: insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2); ! 254: if(rx_fifo & 1) ! 255: nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1); ! 256: nic->packetlen+=rx_fifo; ! 257: #ifdef EDEBUG ! 258: printf("+%d",rx_fifo); ! 259: #endif ! 260: } ! 261: if(( status & RX_INCOMPLETE )==0) { ! 262: #ifdef EDEBUG ! 263: printf("=%d",nic->packetlen); ! 264: #endif ! 265: break; ! 266: } ! 267: udelay(1000); /* if incomplete wait 1 ms */ ! 268: } ! 269: /* acknowledge reception of packet */ ! 270: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND); ! 271: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) ! 272: ; ! 273: #ifdef EDEBUG ! 274: { ! 275: unsigned short type = 0; /* used by EDEBUG */ ! 276: type = (nic->packet[12]<<8) | nic->packet[13]; ! 277: if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ ! 278: nic->packet[5] == 0xFF*ETH_ALEN) ! 279: printf(",t=%hX,b]",type); ! 280: else ! 281: printf(",t=%hX]",type); ! 282: } ! 283: #endif ! 284: return (1); ! 285: } ! 286: ! 287: /************************************************************************** ! 288: ETH_IRQ - interrupt handling ! 289: ***************************************************************************/ ! 290: static void t509_irq(struct nic *nic __unused, irq_action_t action __unused) ! 291: { ! 292: switch ( action ) { ! 293: case DISABLE : ! 294: break; ! 295: case ENABLE : ! 296: break; ! 297: case FORCE : ! 298: break; ! 299: } ! 300: } ! 301: ! 302: /************************************************************************* ! 303: 3Com 509 - specific routines ! 304: **************************************************************************/ ! 305: ! 306: static int eeprom_rdy ( uint16_t ioaddr ) { ! 307: int i; ! 308: ! 309: for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++); ! 310: if (i >= MAX_EEPROMBUSY) { ! 311: /* printf("3c509: eeprom failed to come ready.\n"); */ ! 312: /* memory in EPROM is tight */ ! 313: /* printf("3c509: eeprom busy.\n"); */ ! 314: return (0); ! 315: } ! 316: return (1); ! 317: } ! 318: ! 319: /* ! 320: * get_e: gets a 16 bits word from the EEPROM. ! 321: */ ! 322: static int get_e ( uint16_t ioaddr, int offset ) { ! 323: GO_WINDOW(ioaddr,0); ! 324: if (!eeprom_rdy(ioaddr)) ! 325: return (0xffff); ! 326: outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND); ! 327: if (!eeprom_rdy(ioaddr)) ! 328: return (0xffff); ! 329: return (inw(ioaddr + EP_W0_EEPROM_DATA)); ! 330: } ! 331: ! 332: static struct nic_operations t509_operations = { ! 333: .connect = dummy_connect, ! 334: .poll = t509_poll, ! 335: .transmit = t509_transmit, ! 336: .irq = t509_irq, ! 337: }; ! 338: ! 339: /************************************************************************** ! 340: ETH_PROBE - Look for an adapter ! 341: ***************************************************************************/ ! 342: int t5x9_probe ( struct nic *nic, ! 343: uint16_t prod_id_check, uint16_t prod_id_mask ) { ! 344: uint16_t prod_id; ! 345: int i,j; ! 346: unsigned short *p; ! 347: ! 348: /* Check product ID */ ! 349: prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID ); ! 350: if ( ( prod_id & prod_id_mask ) != prod_id_check ) { ! 351: printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n", ! 352: prod_id, prod_id_mask, prod_id_check ); ! 353: return 0; ! 354: } ! 355: ! 356: /* test for presence of connectors */ ! 357: GO_WINDOW(nic->ioaddr,0); ! 358: i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL); ! 359: j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3; ! 360: ! 361: switch(j) { ! 362: case 0: ! 363: if (i & IS_UTP) { ! 364: printf("10baseT\n"); ! 365: connector = utp; ! 366: } else { ! 367: printf("10baseT not present\n"); ! 368: return 0; ! 369: } ! 370: break; ! 371: case 1: ! 372: if (i & IS_AUI) { ! 373: printf("10base5\n"); ! 374: } else { ! 375: printf("10base5 not present\n"); ! 376: return 0; ! 377: } ! 378: break; ! 379: case 3: ! 380: if (i & IS_BNC) { ! 381: printf("10base2\n"); ! 382: connector = bnc; ! 383: } else { ! 384: printf("10base2 not present\n"); ! 385: return 0; ! 386: } ! 387: break; ! 388: default: ! 389: printf("unknown connector\n"); ! 390: return 0; ! 391: } ! 392: ! 393: /* ! 394: * Read the station address from the eeprom ! 395: */ ! 396: p = (unsigned short *) nic->node_addr; ! 397: for (i = 0; i < ETH_ALEN / 2; i++) { ! 398: p[i] = htons(get_e(nic->ioaddr,i)); ! 399: GO_WINDOW(nic->ioaddr,2); ! 400: outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2)); ! 401: } ! 402: ! 403: DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) ); ! 404: ! 405: t509_reset(nic); ! 406: ! 407: nic->nic_op = &t509_operations; ! 408: return 1; ! 409: ! 410: } ! 411: ! 412: /* ! 413: * Local variables: ! 414: * c-basic-offset: 8 ! 415: * End: ! 416: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.