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

1.1       root        1: /*
                      2:  * Split out into 3c509.c and 3c5x9.c, to make it possible to build a
                      3:  * 3c529 module without including ISA, ISAPnP and EISA code.
                      4:  *
                      5:  */
                      6: 
                      7: FILE_LICENCE ( BSD2 );
                      8: 
                      9: #include <stdint.h>
                     10: #include <stdlib.h>
                     11: #include <string.h>
                     12: #include <errno.h>
                     13: #include <ipxe/io.h>
                     14: #include <unistd.h>
                     15: #include <ipxe/device.h>
                     16: #include <ipxe/isa.h>
                     17: #include "3c509.h"
                     18: 
                     19: /*
                     20:  * 3c509 cards have their own method of contention resolution; this
                     21:  * effectively defines another bus type similar to ISAPnP.  Even the
                     22:  * original ISA cards can be programatically mapped to any I/O address
                     23:  * in the range 0x200-0x3e0.
                     24:  * 
                     25:  * However, there is a small problem: once you've activated a card,
                     26:  * the only ways to deactivate it will also wipe its tag, meaning that
                     27:  * you won't be able to subsequently reactivate it without going
                     28:  * through the whole ID sequence again.  The solution we adopt is to
                     29:  * isolate and tag all cards at the start, and to immediately
                     30:  * re-isolate and re-tag a card after disabling it.
                     31:  *
                     32:  */
                     33: 
                     34: static void t509bus_remove ( struct root_device *rootdev );
                     35: 
                     36: static unsigned int t509_id_port = 0;
                     37: static unsigned int t509_max_tag = 0;
                     38: 
                     39: /** A 3c509 device */
                     40: struct t509_device {
                     41:        /** Generic device */
                     42:        struct device dev;
                     43:        /** Tag */
                     44:        unsigned int tag;
                     45:        /** I/O address */
                     46:        uint16_t ioaddr;
                     47:        /** Driver-private data
                     48:         *
                     49:         * Use t509_set_drvdata() and t509_get_drvdata() to access
                     50:         * this field.
                     51:         */
                     52:        void *priv;
                     53: };
                     54: 
                     55: /**
                     56:  * Set 3c509 driver-private data
                     57:  *
                     58:  * @v t509             3c509 device
                     59:  * @v priv             Private data
                     60:  */
                     61: static inline void t509_set_drvdata ( struct t509_device *t509, void *priv ) {
                     62:        t509->priv = priv;
                     63: }
                     64: 
                     65: /**
                     66:  * Get 3c509 driver-private data
                     67:  *
                     68:  * @v t509             3c509 device
                     69:  * @ret priv           Private data
                     70:  */
                     71: static inline void * t509_get_drvdata ( struct t509_device *t509 ) {
                     72:        return t509->priv;
                     73: }
                     74: 
                     75: /*
                     76:  * t509 utility functions
                     77:  *
                     78:  */
                     79: 
                     80: static inline void t509_set_id_port ( void ) {
                     81:        outb ( 0x00, t509_id_port );
                     82: }
                     83: 
                     84: static inline void t509_wait_for_id_sequence ( void ) {
                     85:        outb ( 0x00, t509_id_port );
                     86: }
                     87: 
                     88: static inline void t509_global_reset ( void ) {
                     89:        outb ( 0xc0, t509_id_port );
                     90: }
                     91: 
                     92: static inline void t509_reset_tag ( void ) {
                     93:        outb ( 0xd0, t509_id_port );
                     94: }
                     95: 
                     96: static inline void t509_set_tag ( uint8_t tag ) {
                     97:        outb ( 0xd0 | tag, t509_id_port );
                     98: }
                     99: 
                    100: static inline void t509_select_tag ( uint8_t tag ) {
                    101:        outb ( 0xd8 | tag, t509_id_port );
                    102: }
                    103: 
                    104: static inline void t509_activate ( uint16_t ioaddr ) {
                    105:        outb ( 0xe0 | ( ioaddr >> 4 ), t509_id_port );
                    106: }
                    107: 
                    108: static inline void t509_deactivate_and_reset_tag ( uint16_t ioaddr ) {
                    109:        outb ( GLOBAL_RESET, ioaddr + EP_COMMAND );
                    110: }
                    111: 
                    112: static inline void t509_load_eeprom_word ( uint8_t offset ) {
                    113:        outb ( 0x80 | offset, t509_id_port );
                    114: }
                    115: 
                    116: /*
                    117:  * Find a suitable ID port
                    118:  *
                    119:  */
                    120: static inline int t509_find_id_port ( void ) {
                    121: 
                    122:        for ( t509_id_port = EP_ID_PORT_START ;
                    123:              t509_id_port < EP_ID_PORT_END ;
                    124:              t509_id_port += EP_ID_PORT_INC ) {
                    125:                t509_set_id_port ();
                    126:                /* See if anything's listening */
                    127:                outb ( 0xff, t509_id_port );
                    128:                if ( inb ( t509_id_port ) & 0x01 ) {
                    129:                        /* Found a suitable port */
                    130:                        DBG ( "T509 using ID port at %04x\n", t509_id_port );
                    131:                        return 0;
                    132:                }
                    133:        }
                    134:        /* No id port available */
                    135:        DBG ( "T509 found no available ID port\n" );
                    136:        return -ENOENT;
                    137: }
                    138: 
                    139: /*
                    140:  * Send ID sequence to the ID port
                    141:  *
                    142:  */
                    143: static void t509_send_id_sequence ( void ) {
                    144:        unsigned short lrs_state, i;
                    145: 
                    146:        t509_set_id_port ();
                    147:        /* Reset IDS on cards */
                    148:        t509_wait_for_id_sequence ();
                    149:        lrs_state = 0xff;
                    150:         for ( i = 0; i < 255; i++ ) {
                    151:                 outb ( lrs_state, t509_id_port );
                    152:                 lrs_state <<= 1;
                    153:                 lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
                    154:         }
                    155: }
                    156: 
                    157: /*
                    158:  * We get eeprom data from the id_port given an offset into the eeprom.
                    159:  * Basically; after the ID_sequence is sent to all of the cards; they enter
                    160:  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
                    161:  * the eeprom data.  We then read the port 16 times and with every read; the
                    162:  * cards check for contention (ie: if one card writes a 0 bit and another
                    163:  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
                    164:  * compares the data on the bus; if there is a difference then that card goes
                    165:  * into ID_WAIT state again). In the meantime; one bit of data is returned in
                    166:  * the AX register which is conveniently returned to us by inb().  Hence; we
                    167:  * read 16 times getting one bit of data with each read.
                    168:  */
                    169: static uint16_t t509_id_read_eeprom ( int offset ) {
                    170:        int i, data = 0;
                    171: 
                    172:        t509_load_eeprom_word ( offset );
                    173:        /* Do we really need this wait? Won't be noticeable anyway */
                    174:        udelay(10000);
                    175: 
                    176:        for ( i = 0; i < 16; i++ ) {
                    177:                data = ( data << 1 ) | ( inw ( t509_id_port ) & 1 );
                    178:        }
                    179:        return data;
                    180: }
                    181: 
                    182: /*
                    183:  * Isolate and tag all t509 cards
                    184:  *
                    185:  */
                    186: static int t509_isolate ( void ) {
                    187:        unsigned int i;
                    188:        uint16_t contend[3];
                    189:        int rc;
                    190: 
                    191:        /* Find a suitable ID port */
                    192:        if ( ( rc = t509_find_id_port() ) != 0 )
                    193:                return rc;
                    194: 
                    195:        while ( 1 ) {
                    196: 
                    197:                /* All cards are in ID_WAIT state each time we go
                    198:                 * through this loop.
                    199:                 */
                    200: 
                    201:                /* Send the ID sequence */
                    202:                t509_send_id_sequence();
                    203: 
                    204:                /* First time through, reset all tags.  On subsequent
                    205:                 * iterations, kill off any already-tagged cards
                    206:                 */
                    207:                if ( t509_max_tag == 0 ) {
                    208:                        t509_reset_tag();
                    209:                } else {
                    210:                        t509_select_tag ( 0 );
                    211:                }
                    212:        
                    213:                /* Read the manufacturer ID, to see if there are any
                    214:                 * more cards
                    215:                 */
                    216:                if ( t509_id_read_eeprom ( EEPROM_MFG_ID ) != MFG_ID ) {
                    217:                        DBG ( "T509 saw %s signs of life\n",
                    218:                              t509_max_tag ? "no further" : "no" );
                    219:                        break;
                    220:                }
                    221: 
                    222:                /* Perform contention selection on the MAC address */
                    223:                for ( i = 0 ; i < 3 ; i++ ) {
                    224:                        contend[i] = t509_id_read_eeprom ( i );
                    225:                }
                    226: 
                    227:                /* Only one device will still be left alive.  Tag it. */
                    228:                ++t509_max_tag;
                    229:                DBG ( "T509 found card %04x%04x%04x, assigning tag %02x\n",
                    230:                      contend[0], contend[1], contend[2], t509_max_tag );
                    231:                t509_set_tag ( t509_max_tag );
                    232: 
                    233:                /* Return all cards back to ID_WAIT state */
                    234:                t509_wait_for_id_sequence();
                    235:        }
                    236: 
                    237:        DBG ( "T509 found %d cards using ID port %04x\n",
                    238:              t509_max_tag, t509_id_port );
                    239:        return 0;
                    240: }
                    241: 
                    242: /*
                    243:  * Activate a T509 device
                    244:  *
                    245:  * The device will be enabled at whatever ioaddr is specified in the
                    246:  * struct t509_device; there is no need to stick with the default
                    247:  * ioaddr read from the EEPROM.
                    248:  *
                    249:  */
                    250: static inline void activate_t509_device ( struct t509_device *t509 ) {
                    251:        t509_send_id_sequence ();
                    252:        t509_select_tag ( t509->tag );
                    253:        t509_activate ( t509->ioaddr );
                    254:        DBG ( "T509 activated device %02x at ioaddr %04x\n",
                    255:              t509->tag, t509->ioaddr );
                    256: }
                    257: 
                    258: /*
                    259:  * Deactivate a T509 device
                    260:  *
                    261:  * Disabling also clears the tag, so we immediately isolate and re-tag
                    262:  * this card.
                    263:  *
                    264:  */
                    265: static inline void deactivate_t509_device ( struct t509_device *t509 ) {
                    266:        t509_deactivate_and_reset_tag ( t509->ioaddr );
                    267:        udelay ( 1000 );
                    268:        t509_send_id_sequence ();
                    269:        t509_select_tag ( 0 );
                    270:        t509_set_tag ( t509->tag );
                    271:        t509_wait_for_id_sequence ();
                    272:        DBG ( "T509 deactivated device at %04x and re-tagged as %02x\n",
                    273:              t509->ioaddr, t509->tag );
                    274: }
                    275: 
                    276: /*
                    277:  * The ISA probe function
                    278:  *
                    279:  */
                    280: static int legacy_t509_probe ( struct nic *nic, void *hwdev ) {
                    281:        struct t509_device *t509 = hwdev;
                    282: 
                    283:        /* We could change t509->ioaddr if we wanted to */
                    284:        activate_t509_device ( t509 );
                    285:        nic->ioaddr = t509->ioaddr;
                    286: 
                    287:        /* Hand off to generic t5x9 probe routine */
                    288:        return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
                    289: }
                    290: 
                    291: static void legacy_t509_disable ( struct nic *nic, void *hwdev ) {
                    292:        struct t509_device *t509 = hwdev;
                    293: 
                    294:        t5x9_disable ( nic );
                    295:        deactivate_t509_device ( t509 );
                    296: }
                    297: 
                    298: static inline void legacy_t509_set_drvdata ( void *hwdev, void *priv ) {
                    299:        t509_set_drvdata ( hwdev, priv );
                    300: }
                    301: 
                    302: static inline void * legacy_t509_get_drvdata ( void *hwdev ) {
                    303:        return t509_get_drvdata ( hwdev );
                    304: }
                    305: 
                    306: /**
                    307:  * Probe a 3c509 device
                    308:  *
                    309:  * @v t509             3c509 device
                    310:  * @ret rc             Return status code
                    311:  *
                    312:  * Searches for a driver for the 3c509 device.  If a driver is found,
                    313:  * its probe() routine is called.
                    314:  */
                    315: static int t509_probe ( struct t509_device *t509 ) {
                    316:        DBG ( "Adding 3c509 device %02x (I/O %04x)\n",
                    317:              t509->tag, t509->ioaddr );
                    318:        return legacy_probe ( t509, legacy_t509_set_drvdata, &t509->dev,
                    319:                              legacy_t509_probe, legacy_t509_disable );
                    320: }
                    321: 
                    322: /**
                    323:  * Remove a 3c509 device
                    324:  *
                    325:  * @v t509             3c509 device
                    326:  */
                    327: static void t509_remove ( struct t509_device *t509 ) {
                    328:        legacy_remove ( t509, legacy_t509_get_drvdata, legacy_t509_disable );
                    329:        DBG ( "Removed 3c509 device %02x\n", t509->tag );
                    330: }
                    331: 
                    332: /**
                    333:  * Probe 3c509 root bus
                    334:  *
                    335:  * @v rootdev          3c509 bus root device
                    336:  *
                    337:  * Scans the 3c509 bus for devices and registers all devices it can
                    338:  * find.
                    339:  */
                    340: static int t509bus_probe ( struct root_device *rootdev ) {
                    341:        struct t509_device *t509 = NULL;
                    342:        unsigned int tag;
                    343:        unsigned int iobase;
                    344:        int rc;
                    345: 
                    346:        /* Perform isolation and tagging */
                    347:        if ( ( rc = t509_isolate() ) != 0 )
                    348:                return rc;
                    349: 
                    350:        for ( tag = 1 ; tag <= t509_max_tag ; tag++ ) {
                    351:                /* Allocate struct t509_device */
                    352:                if ( ! t509 )
                    353:                        t509 = malloc ( sizeof ( *t509 ) );
                    354:                if ( ! t509 ) {
                    355:                        rc = -ENOMEM;
                    356:                        goto err;
                    357:                }
                    358:                memset ( t509, 0, sizeof ( *t509 ) );
                    359:                t509->tag = tag;
                    360: 
                    361:                /* Send the ID sequence */
                    362:                t509_send_id_sequence ();
                    363: 
                    364:                /* Select the specified tag */
                    365:                t509_select_tag ( t509->tag );
                    366: 
                    367:                /* Read the default I/O address */
                    368:                iobase = t509_id_read_eeprom ( EEPROM_ADDR_CFG );
                    369:                t509->ioaddr = 0x200 + ( ( iobase & 0x1f ) << 4 );
                    370: 
                    371:                /* Send card back to ID_WAIT */
                    372:                t509_wait_for_id_sequence();
                    373: 
                    374:                /* Add to device hierarchy */
                    375:                snprintf ( t509->dev.name, sizeof ( t509->dev.name ),
                    376:                           "t509%02x", tag );
                    377:                t509->dev.desc.bus_type = BUS_TYPE_ISA;
                    378:                t509->dev.desc.vendor = MFG_ID;
                    379:                t509->dev.desc.device = PROD_ID;
                    380:                t509->dev.parent = &rootdev->dev;
                    381:                list_add ( &t509->dev.siblings, &rootdev->dev.children );
                    382:                INIT_LIST_HEAD ( &t509->dev.children );
                    383:                        
                    384:                /* Look for a driver */
                    385:                if ( t509_probe ( t509 ) == 0 ) {
                    386:                        /* t509dev registered, we can drop our ref */
                    387:                        t509 = NULL;
                    388:                } else {
                    389:                        /* Not registered; re-use struct */
                    390:                        list_del ( &t509->dev.siblings );
                    391:                }
                    392:        }
                    393: 
                    394:        free ( t509 );
                    395:        return 0;
                    396: 
                    397:  err:
                    398:        free ( t509 );
                    399:        t509bus_remove ( rootdev );
                    400:        return rc;
                    401: }
                    402: 
                    403: /**
                    404:  * Remove 3c509 root bus
                    405:  *
                    406:  * @v rootdev          3c509 bus root device
                    407:  */
                    408: static void t509bus_remove ( struct root_device *rootdev ) {
                    409:        struct t509_device *t509;
                    410:        struct t509_device *tmp;
                    411: 
                    412:        list_for_each_entry_safe ( t509, tmp, &rootdev->dev.children,
                    413:                                   dev.siblings ) {
                    414:                t509_remove ( t509 );
                    415:                list_del ( &t509->dev.siblings );
                    416:                free ( t509 );
                    417:        }
                    418: }
                    419: 
                    420: /** 3c509 bus root device driver */
                    421: static struct root_driver t509_root_driver = {
                    422:        .probe = t509bus_probe,
                    423:        .remove = t509bus_remove,
                    424: };
                    425: 
                    426: /** 3c509 bus root device */
                    427: struct root_device t509_root_device __root_device = {
                    428:        .dev = { .name = "3c509" },
                    429:        .driver = &t509_root_driver,
                    430: };
                    431: 
                    432: ISA_ROM ( "3c509", "3c509" );

unix.superglobalmegacorp.com

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