Annotation of qemu/roms/ipxe/src/drivers/net/3c5x9.c, revision 1.1.1.1

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:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.