Annotation of Gnu-Mach/linux/pcmcia-cs/clients/3c574_cs.c, revision 1.1

1.1     ! root        1: /* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
        !             2: 
        !             3:        Written 1993-1998 by
        !             4:        Donald Becker, [email protected], (driver core) and
        !             5:        David Hinds, [email protected] (from his PC card code).
        !             6: 
        !             7:        This software may be used and distributed according to the terms of
        !             8:        the GNU General Public License, incorporated herein by reference.
        !             9: 
        !            10:        This driver derives from Donald Becker's 3c509 core, which has the
        !            11:        following copyright:
        !            12:        Copyright 1993 United States Government as represented by the
        !            13:        Director, National Security Agency.
        !            14: 
        !            15: */
        !            16: 
        !            17: /*
        !            18:                                Theory of Operation
        !            19: 
        !            20: I. Board Compatibility
        !            21: 
        !            22: This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
        !            23: Adapter.
        !            24: 
        !            25: II. Board-specific settings
        !            26: 
        !            27: None -- PC cards are autoconfigured.
        !            28: 
        !            29: III. Driver operation
        !            30: 
        !            31: The 3c574 uses a Boomerang-style interface, without the bus-master capability.
        !            32: See the Boomerang driver and documentation for most details.
        !            33: 
        !            34: IV. Notes and chip documentation.
        !            35: 
        !            36: Two added registers are used to enhance PIO performance, RunnerRdCtrl and
        !            37: RunnerWrCtrl.  These are 11 bit down-counters that are preloaded with the
        !            38: count of word (16 bits) reads or writes the driver is about to do to the Rx
        !            39: or Tx FIFO.  The chip is then able to hide the internal-PCI-bus to PC-card
        !            40: translation latency by buffering the I/O operations with an 8 word FIFO.
        !            41: Note: No other chip accesses are permitted when this buffer is used.
        !            42: 
        !            43: A second enhancement is that both attribute and common memory space
        !            44: 0x0800-0x0fff can translated to the PIO FIFO.  Thus memory operations (faster
        !            45: with *some* PCcard bridges) may be used instead of I/O operations.
        !            46: This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
        !            47: 
        !            48: Some slow PC card bridges work better if they never see a WAIT signal.
        !            49: This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
        !            50: Only do this after testing that it is reliable and improves performance.
        !            51: 
        !            52: The upper five bits of RunnerRdCtrl are used to window into PCcard
        !            53: configuration space registers.  Window 0 is the regular Boomerang/Odie
        !            54: register set, 1-5 are various PC card control registers, and 16-31 are
        !            55: the (reversed!) CIS table.
        !            56: 
        !            57: A final note: writing the InternalConfig register in window 3 with an
        !            58: invalid ramWidth is Very Bad.
        !            59: 
        !            60: V. References
        !            61: 
        !            62: http://www.scyld.com/expert/NWay.html
        !            63: http://www.national.com/pf/DP/DP83840.html
        !            64: 
        !            65: Thanks to Terry Murphy of 3Com for providing development information for
        !            66: earlier 3Com products.
        !            67: 
        !            68: */
        !            69: 
        !            70: #include <linux/module.h>
        !            71: #include <linux/kernel.h>
        !            72: #include <linux/init.h>
        !            73: #include <linux/sched.h>
        !            74: #include <linux/slab.h>
        !            75: #include <linux/string.h>
        !            76: #include <linux/timer.h>
        !            77: #include <linux/interrupt.h>
        !            78: #include <linux/in.h>
        !            79: #include <linux/delay.h>
        !            80: #include <asm/io.h>
        !            81: #include <asm/system.h>
        !            82: #include <asm/bitops.h>
        !            83: 
        !            84: #include <linux/netdevice.h>
        !            85: #include <linux/etherdevice.h>
        !            86: #include <linux/skbuff.h>
        !            87: #include <linux/if_arp.h>
        !            88: #include <linux/ioport.h>
        !            89: 
        !            90: #include <pcmcia/version.h>
        !            91: #include <pcmcia/cs_types.h>
        !            92: #include <pcmcia/cs.h>
        !            93: #include <pcmcia/cistpl.h>
        !            94: #include <pcmcia/cisreg.h>
        !            95: #include <pcmcia/ciscode.h>
        !            96: #include <pcmcia/ds.h>
        !            97: #include <pcmcia/mem_op.h>
        !            98: 
        !            99: /*====================================================================*/
        !           100: 
        !           101: /* Module parameters */
        !           102: 
        !           103: MODULE_AUTHOR("David Hinds <[email protected]>");
        !           104: MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver");
        !           105: MODULE_LICENSE("GPL");
        !           106: 
        !           107: #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
        !           108: 
        !           109: /* Now-standard PC card module parameters. */
        !           110: INT_MODULE_PARM(irq_mask, 0xdeb8);
        !           111: static int irq_list[4] = { -1 };
        !           112: MODULE_PARM(irq_list, "1-4i");
        !           113: 
        !           114: /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
        !           115: INT_MODULE_PARM(max_interrupt_work, 32);
        !           116: 
        !           117: /* Force full duplex modes? */
        !           118: INT_MODULE_PARM(full_duplex, 0);
        !           119: 
        !           120: /* Autodetect link polarity reversal? */
        !           121: INT_MODULE_PARM(auto_polarity, 1);
        !           122: 
        !           123: #ifdef PCMCIA_DEBUG
        !           124: INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
        !           125: #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
        !           126: static char *version =
        !           127: "3c574_cs.c 1.70 2003/08/25 15:57:40 Donald Becker/David Hinds, [email protected].\n";
        !           128: #else
        !           129: #define DEBUG(n, args...)
        !           130: #endif
        !           131: 
        !           132: /*====================================================================*/
        !           133: 
        !           134: /* Time in jiffies before concluding the transmitter is hung. */
        !           135: #define TX_TIMEOUT  ((800*HZ)/1000)
        !           136: 
        !           137: /* To minimize the size of the driver source and make the driver more
        !           138:    readable not all constants are symbolically defined.
        !           139:    You'll need the manual if you want to understand driver details anyway. */
        !           140: /* Offsets from base I/O address. */
        !           141: #define EL3_DATA       0x00
        !           142: #define EL3_CMD                0x0e
        !           143: #define EL3_STATUS     0x0e
        !           144: 
        !           145: #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
        !           146: 
        !           147: /* The top five bits written to EL3_CMD are a command, the lower
        !           148:    11 bits are the parameter, if applicable. */
        !           149: enum el3_cmds {
        !           150:        TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
        !           151:        RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
        !           152:        TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
        !           153:        FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
        !           154:        SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
        !           155:        SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
        !           156:        StatsDisable = 22<<11, StopCoax = 23<<11,
        !           157: };
        !           158: 
        !           159: enum elxl_status {
        !           160:        IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
        !           161:        TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
        !           162:        IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
        !           163: 
        !           164: /* The SetRxFilter command accepts the following classes: */
        !           165: enum RxFilter {
        !           166:        RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
        !           167: };
        !           168: 
        !           169: enum Window0 {
        !           170:        Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
        !           171:        IntrStatus=0x0E,                /* Valid in all windows. */
        !           172: };
        !           173: /* These assumes the larger EEPROM. */
        !           174: enum Win0_EEPROM_cmds {
        !           175:        EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
        !           176:        EEPROM_EWENB = 0x30,            /* Enable erasing/writing for 10 msec. */
        !           177:        EEPROM_EWDIS = 0x00,            /* Disable EWENB before 10 msec timeout. */
        !           178: };
        !           179: 
        !           180: /* Register window 1 offsets, the window used in normal operation.
        !           181:    On the "Odie" this window is always mapped at offsets 0x10-0x1f.
        !           182:    Except for TxFree, which is overlapped by RunnerWrCtrl. */
        !           183: enum Window1 {
        !           184:        TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
        !           185:        RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
        !           186:        TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
        !           187:        RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
        !           188: };
        !           189: 
        !           190: enum Window3 {                 /* Window 3: MAC/config bits. */
        !           191:        Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
        !           192: };
        !           193: union wn3_config {
        !           194:        int i;
        !           195:        struct w3_config_fields {
        !           196:                unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
        !           197:                int pad8:8;
        !           198:                unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
        !           199:                int pad24:7;
        !           200:        } u;
        !           201: };
        !           202: 
        !           203: enum Window4 {         /* Window 4: Xcvr/media bits. */
        !           204:        Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
        !           205: };
        !           206: 
        !           207: 
        !           208: #define MEDIA_TP       0x00C0  /* Enable link beat and jabber for 10baseT. */
        !           209: 
        !           210: struct el3_private {
        !           211:        dev_link_t link;
        !           212:        struct net_device dev;
        !           213:        dev_node_t node;
        !           214:        struct net_device_stats stats;
        !           215:        u16 advertising, partner;                       /* NWay media advertisement */
        !           216:        unsigned char phys;                                     /* MII device address */
        !           217:        unsigned int
        !           218:          autoselect:1, default_media:3;        /* Read from the EEPROM/Wn3_Config. */
        !           219:        /* for transceiver monitoring */
        !           220:        struct timer_list media;
        !           221:        u_short media_status;
        !           222:        u_short fast_poll;
        !           223:        u_long last_irq;
        !           224: };
        !           225: 
        !           226: /* Set iff a MII transceiver on any interface requires mdio preamble.
        !           227:    This only set with the original DP83840 on older 3c905 boards, so the extra
        !           228:    code size of a per-interface flag is not worthwhile. */
        !           229: static char mii_preamble_required = 0;
        !           230: 
        !           231: /* Index of functions. */
        !           232: 
        !           233: static void tc574_config(dev_link_t *link);
        !           234: static void tc574_release(u_long arg);
        !           235: static int tc574_event(event_t event, int priority,
        !           236:                                           event_callback_args_t *args);
        !           237: 
        !           238: static void mdio_sync(ioaddr_t ioaddr, int bits);
        !           239: static int mdio_read(ioaddr_t ioaddr, int phy_id, int location);
        !           240: static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value);
        !           241: static u_short read_eeprom(ioaddr_t ioaddr, int index);
        !           242: static void tc574_wait_for_completion(struct net_device *dev, int cmd);
        !           243: 
        !           244: static void tc574_reset(struct net_device *dev);
        !           245: static void media_check(u_long arg);
        !           246: static int el3_open(struct net_device *dev);
        !           247: static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
        !           248: static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
        !           249: static void update_stats(struct net_device *dev);
        !           250: static struct net_device_stats *el3_get_stats(struct net_device *dev);
        !           251: static int el3_rx(struct net_device *dev, int worklimit);
        !           252: static int el3_close(struct net_device *dev);
        !           253: static void el3_tx_timeout(struct net_device *dev);
        !           254: static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
        !           255: static void set_rx_mode(struct net_device *dev);
        !           256: 
        !           257: static dev_info_t dev_info = "3c574_cs";
        !           258: 
        !           259: static dev_link_t *tc574_attach(void);
        !           260: static void tc574_detach(dev_link_t *);
        !           261: 
        !           262: static dev_link_t *dev_list = NULL;
        !           263: 
        !           264: static void flush_stale_links(void)
        !           265: {
        !           266:        dev_link_t *link, *next;
        !           267:        for (link = dev_list; link; link = next) {
        !           268:                next = link->next;
        !           269:            if (link->state & DEV_STALE_LINK)
        !           270:                        tc574_detach(link);
        !           271:     }
        !           272: }
        !           273: 
        !           274: static void cs_error(client_handle_t handle, int func, int ret)
        !           275: {
        !           276: #if CS_RELEASE_CODE < 0x2911
        !           277:     CardServices(ReportError, dev_info, (void *)func, (void *)ret);
        !           278: #else
        !           279:        error_info_t err = { func, ret };
        !           280:        CardServices(ReportError, handle, &err);
        !           281: #endif
        !           282: }
        !           283: 
        !           284: /*
        !           285:        tc574_attach() creates an "instance" of the driver, allocating
        !           286:        local data structures for one device.  The device is registered
        !           287:        with Card Services.
        !           288: */
        !           289: 
        !           290: static dev_link_t *tc574_attach(void)
        !           291: {
        !           292:        struct el3_private *lp;
        !           293:        client_reg_t client_reg;
        !           294:        dev_link_t *link;
        !           295:        struct net_device *dev;
        !           296:        int i, ret;
        !           297: 
        !           298:        DEBUG(0, "3c574_attach()\n");
        !           299:        flush_stale_links();
        !           300: 
        !           301:        /* Create the PC card device object. */
        !           302:        lp = kmalloc(sizeof(*lp), GFP_KERNEL);
        !           303:        if (!lp) return NULL;
        !           304:        memset(lp, 0, sizeof(*lp));
        !           305:        link = &lp->link; dev = &lp->dev;
        !           306:        link->priv = dev->priv = link->irq.Instance = lp;
        !           307: 
        !           308:        init_timer(&link->release);
        !           309:        link->release.function = &tc574_release;
        !           310:        link->release.data = (u_long)link;
        !           311:        link->io.NumPorts1 = 32;
        !           312:        link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
        !           313:        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
        !           314:        link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
        !           315:        if (irq_list[0] == -1)
        !           316:                link->irq.IRQInfo2 = irq_mask;
        !           317:        else
        !           318:                for (i = 0; i < 4; i++)
        !           319:                        link->irq.IRQInfo2 |= 1 << irq_list[i];
        !           320:        link->irq.Handler = &el3_interrupt;
        !           321:        link->conf.Attributes = CONF_ENABLE_IRQ;
        !           322:        link->conf.Vcc = 50;
        !           323:        link->conf.IntType = INT_MEMORY_AND_IO;
        !           324:        link->conf.ConfigIndex = 1;
        !           325:        link->conf.Present = PRESENT_OPTION;
        !           326: 
        !           327:        /* The EL3-specific entries in the device structure. */
        !           328:        dev->hard_start_xmit = &el3_start_xmit;
        !           329:        dev->get_stats = &el3_get_stats;
        !           330:        dev->do_ioctl = &el3_ioctl;
        !           331:        dev->set_multicast_list = &set_rx_mode;
        !           332:        ether_setup(dev);
        !           333:        init_dev_name(dev, lp->node);
        !           334:        dev->open = &el3_open;
        !           335:        dev->stop = &el3_close;
        !           336: #ifdef HAVE_TX_TIMEOUT
        !           337:        dev->tx_timeout = el3_tx_timeout;
        !           338:        dev->watchdog_timeo = TX_TIMEOUT;
        !           339: #endif
        !           340: 
        !           341:        /* Register with Card Services */
        !           342:        link->next = dev_list;
        !           343:        dev_list = link;
        !           344:        client_reg.dev_info = &dev_info;
        !           345:        client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
        !           346:        client_reg.EventMask =
        !           347:                CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
        !           348:                        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
        !           349:                                CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
        !           350:        client_reg.event_handler = &tc574_event;
        !           351:        client_reg.Version = 0x0210;
        !           352:        client_reg.event_callback_args.client_data = link;
        !           353:        ret = CardServices(RegisterClient, &link->handle, &client_reg);
        !           354:        if (ret != 0) {
        !           355:                cs_error(link->handle, RegisterClient, ret);
        !           356:                tc574_detach(link);
        !           357:                return NULL;
        !           358:        }
        !           359: 
        !           360:        return link;
        !           361: } /* tc574_attach */
        !           362: 
        !           363: /*
        !           364: 
        !           365:        This deletes a driver "instance".  The device is de-registered
        !           366:        with Card Services.  If it has been released, all local data
        !           367:        structures are freed.  Otherwise, the structures will be freed
        !           368:        when the device is released.
        !           369: 
        !           370: */
        !           371: 
        !           372: static void tc574_detach(dev_link_t *link)
        !           373: {
        !           374:        struct el3_private *lp = link->priv;
        !           375:        dev_link_t **linkp;
        !           376: 
        !           377:        DEBUG(0, "3c574_detach(0x%p)\n", link);
        !           378: 
        !           379:        /* Locate device structure */
        !           380:        for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
        !           381:                if (*linkp == link) break;
        !           382:        if (*linkp == NULL)
        !           383:        return;
        !           384: 
        !           385:        del_timer(&link->release);
        !           386:        if (link->state & DEV_CONFIG) {
        !           387:                tc574_release((u_long)link);
        !           388:                if (link->state & DEV_STALE_CONFIG) {
        !           389:                        link->state |= DEV_STALE_LINK;
        !           390:                        return;
        !           391:                }
        !           392:        }
        !           393: 
        !           394:        if (link->handle)
        !           395:                CardServices(DeregisterClient, link->handle);
        !           396: 
        !           397:        /* Unlink device structure, free bits */
        !           398:        *linkp = link->next;
        !           399:        if (link->dev)
        !           400:                unregister_netdev(&lp->dev);
        !           401:        kfree(lp);
        !           402: 
        !           403: } /* tc574_detach */
        !           404: 
        !           405: /*
        !           406:        tc574_config() is scheduled to run after a CARD_INSERTION event
        !           407:        is received, to configure the PCMCIA socket, and to make the
        !           408:        ethernet device available to the system.
        !           409: */
        !           410: 
        !           411: #define CS_CHECK(fn, args...) \
        !           412: while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
        !           413: 
        !           414: static void tc574_config(dev_link_t *link)
        !           415: {
        !           416:        client_handle_t handle = link->handle;
        !           417:        struct el3_private *lp = link->priv;
        !           418:        struct net_device *dev = &lp->dev;
        !           419:        tuple_t tuple;
        !           420:        cisparse_t parse;
        !           421:        u_short buf[32];
        !           422:        int last_fn, last_ret, i, j;
        !           423:        ioaddr_t ioaddr;
        !           424:        u16 *phys_addr;
        !           425:        char *cardname;
        !           426: 
        !           427:        phys_addr = (u16 *)dev->dev_addr;
        !           428: 
        !           429:        DEBUG(0, "3c574_config(0x%p)\n", link);
        !           430: 
        !           431:        tuple.Attributes = 0;
        !           432:        tuple.DesiredTuple = CISTPL_CONFIG;
        !           433:        CS_CHECK(GetFirstTuple, handle, &tuple);
        !           434:        tuple.TupleData = (cisdata_t *)buf;
        !           435:        tuple.TupleDataMax = 64;
        !           436:        tuple.TupleOffset = 0;
        !           437:        CS_CHECK(GetTupleData, handle, &tuple);
        !           438:        CS_CHECK(ParseTuple, handle, &tuple, &parse);
        !           439:        link->conf.ConfigBase = parse.config.base;
        !           440:        link->conf.Present = parse.config.rmask[0];
        !           441: 
        !           442:        /* Configure card */
        !           443:        link->state |= DEV_CONFIG;
        !           444: 
        !           445:        link->io.IOAddrLines = 16;
        !           446:        for (i = j = 0; j < 0x400; j += 0x20) {
        !           447:                link->io.BasePort1 = j ^ 0x300;
        !           448:                i = CardServices(RequestIO, link->handle, &link->io);
        !           449:                if (i == CS_SUCCESS) break;
        !           450:        }
        !           451:        if (i != CS_SUCCESS) {
        !           452:                cs_error(link->handle, RequestIO, i);
        !           453:                goto failed;
        !           454:        }
        !           455:        CS_CHECK(RequestIRQ, link->handle, &link->irq);
        !           456:        CS_CHECK(RequestConfiguration, link->handle, &link->conf);
        !           457: 
        !           458:        dev->irq = link->irq.AssignedIRQ;
        !           459:        dev->base_addr = link->io.BasePort1;
        !           460: 
        !           461:        if (register_netdev(dev) != 0) {
        !           462:                printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
        !           463:                goto failed;
        !           464:        }
        !           465: 
        !           466:        ioaddr = dev->base_addr;
        !           467:        copy_dev_name(lp->node, dev);
        !           468:        link->dev = &lp->node;
        !           469: 
        !           470:        /* The 3c574 normally uses an EEPROM for configuration info, including
        !           471:           the hardware address.  The future products may include a modem chip
        !           472:           and put the address in the CIS. */
        !           473:        tuple.DesiredTuple = 0x88;
        !           474:        if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
        !           475:                CardServices(GetTupleData, handle, &tuple);
        !           476:                for (i = 0; i < 3; i++)
        !           477:                        phys_addr[i] = htons(buf[i]);
        !           478:        } else {
        !           479:                EL3WINDOW(0);
        !           480:                for (i = 0; i < 3; i++)
        !           481:                        phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
        !           482:                if (phys_addr[0] == 0x6060) {
        !           483:                        printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
        !           484:                                   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
        !           485:                        goto failed;
        !           486:                }
        !           487:        }
        !           488:        tuple.DesiredTuple = CISTPL_VERS_1;
        !           489:        if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS &&
        !           490:                CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS &&
        !           491:                CardServices(ParseTuple, handle, &tuple, &parse) == CS_SUCCESS) {
        !           492:                cardname = parse.version_1.str + parse.version_1.ofs[1];
        !           493:        } else
        !           494:                cardname = "3Com 3c574";
        !           495: 
        !           496:        printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
        !           497:                   dev->name, cardname, dev->base_addr, dev->irq);
        !           498: 
        !           499:        for (i = 0; i < 6; i++)
        !           500:                printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
        !           501: 
        !           502:        {
        !           503:                u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
        !           504:                union wn3_config config;
        !           505:                outw(2<<11, ioaddr + RunnerRdCtrl);
        !           506:                mcr = inb(ioaddr + 2);
        !           507:                outw(0<<11, ioaddr + RunnerRdCtrl);
        !           508:                printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
        !           509:                EL3WINDOW(3);
        !           510:                config.i = inl(ioaddr + Wn3_Config);
        !           511:                printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
        !           512:                           8 << config.u.ram_size, ram_split[config.u.ram_split],
        !           513:                           config.u.autoselect ? "autoselect " : "");
        !           514:                lp->default_media = config.u.xcvr;
        !           515:                lp->autoselect = config.u.autoselect;
        !           516:        }
        !           517: 
        !           518:        {
        !           519:                int phy;
        !           520:                
        !           521:                /* Roadrunner only: Turn on the MII transceiver */
        !           522:                outw(0x8040, ioaddr + Wn3_Options);
        !           523:                mdelay(1);
        !           524:                outw(0xc040, ioaddr + Wn3_Options);
        !           525:                tc574_wait_for_completion(dev, TxReset);
        !           526:                tc574_wait_for_completion(dev, RxReset);
        !           527:                mdelay(1);
        !           528:                outw(0x8040, ioaddr + Wn3_Options);
        !           529:                
        !           530:                EL3WINDOW(4);
        !           531:                for (phy = 1; phy <= 32; phy++) {
        !           532:                        int mii_status;
        !           533:                        mdio_sync(ioaddr, 32);
        !           534:                        mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
        !           535:                        if (mii_status != 0xffff) {
        !           536:                                lp->phys = phy & 0x1f;
        !           537:                                DEBUG(0, "  MII transceiver at index %d, status %x.\n",
        !           538:                                          phy, mii_status);
        !           539:                                if ((mii_status & 0x0040) == 0)
        !           540:                                        mii_preamble_required = 1;
        !           541:                                break;
        !           542:                        }
        !           543:                }
        !           544:                if (phy > 32) {
        !           545:                        printk(KERN_NOTICE "  No MII transceivers found!\n");
        !           546:                        goto failed;
        !           547:                }
        !           548:                i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
        !           549:                mdio_write(ioaddr, lp->phys, 16, i);
        !           550:                lp->advertising = mdio_read(ioaddr, lp->phys, 4);
        !           551:                if (full_duplex) {
        !           552:                        /* Only advertise the FD media types. */
        !           553:                        lp->advertising &= ~0x02a0;
        !           554:                        mdio_write(ioaddr, lp->phys, 4, lp->advertising);
        !           555:                }
        !           556:        }
        !           557: 
        !           558:        link->state &= ~DEV_CONFIG_PENDING;
        !           559:        return;
        !           560: 
        !           561: cs_failed:
        !           562:        cs_error(link->handle, last_fn, last_ret);
        !           563: failed:
        !           564:        tc574_release((u_long)link);
        !           565:        link->state &= ~DEV_CONFIG_PENDING;
        !           566:        return;
        !           567: 
        !           568: } /* tc574_config */
        !           569: 
        !           570: /*
        !           571:        After a card is removed, tc574_release() will unregister the net
        !           572:        device, and release the PCMCIA configuration.  If the device is
        !           573:        still open, this will be postponed until it is closed.
        !           574: */
        !           575: 
        !           576: static void tc574_release(u_long arg)
        !           577: {
        !           578:        dev_link_t *link = (dev_link_t *)arg;
        !           579: 
        !           580:        DEBUG(0, "3c574_release(0x%p)\n", link);
        !           581: 
        !           582:        if (link->open) {
        !           583:                DEBUG(1, "3c574_cs: release postponed, '%s' still open\n",
        !           584:                          link->dev->dev_name);
        !           585:                link->state |= DEV_STALE_CONFIG;
        !           586:                return;
        !           587:        }
        !           588: 
        !           589:        CardServices(ReleaseConfiguration, link->handle);
        !           590:        CardServices(ReleaseIO, link->handle, &link->io);
        !           591:        CardServices(ReleaseIRQ, link->handle, &link->irq);
        !           592: 
        !           593:        link->state &= ~DEV_CONFIG;
        !           594: 
        !           595: } /* tc574_release */
        !           596: 
        !           597: /*
        !           598:        The card status event handler.  Mostly, this schedules other
        !           599:        stuff to run after an event is received.  A CARD_REMOVAL event
        !           600:        also sets some flags to discourage the net drivers from trying
        !           601:        to talk to the card any more.
        !           602: */
        !           603: 
        !           604: static int tc574_event(event_t event, int priority,
        !           605:                                           event_callback_args_t *args)
        !           606: {
        !           607:        dev_link_t *link = args->client_data;
        !           608:        struct el3_private *lp = link->priv;
        !           609:        struct net_device *dev = &lp->dev;
        !           610: 
        !           611:        DEBUG(1, "3c574_event(0x%06x)\n", event);
        !           612: 
        !           613:        switch (event) {
        !           614:        case CS_EVENT_CARD_REMOVAL:
        !           615:                link->state &= ~DEV_PRESENT;
        !           616:                if (link->state & DEV_CONFIG) {
        !           617:                        netif_device_detach(dev);
        !           618:                        mod_timer(&link->release, jiffies + HZ/20);
        !           619:                }
        !           620:                break;
        !           621:        case CS_EVENT_CARD_INSERTION:
        !           622:                link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
        !           623:                tc574_config(link);
        !           624:                break;
        !           625:        case CS_EVENT_PM_SUSPEND:
        !           626:                link->state |= DEV_SUSPEND;
        !           627:                /* Fall through... */
        !           628:        case CS_EVENT_RESET_PHYSICAL:
        !           629:                if (link->state & DEV_CONFIG) {
        !           630:                        if (link->open)
        !           631:                                netif_device_detach(dev);
        !           632:                        CardServices(ReleaseConfiguration, link->handle);
        !           633:                }
        !           634:                break;
        !           635:        case CS_EVENT_PM_RESUME:
        !           636:                link->state &= ~DEV_SUSPEND;
        !           637:                /* Fall through... */
        !           638:        case CS_EVENT_CARD_RESET:
        !           639:                if (link->state & DEV_CONFIG) {
        !           640:                        CardServices(RequestConfiguration, link->handle, &link->conf);
        !           641:                        if (link->open) {
        !           642:                                tc574_reset(dev);
        !           643:                                netif_device_attach(dev);
        !           644:                        }
        !           645:                }
        !           646:                break;
        !           647:        }
        !           648:        return 0;
        !           649: } /* tc574_event */
        !           650: 
        !           651: static void dump_status(struct net_device *dev)
        !           652: {
        !           653:        ioaddr_t ioaddr = dev->base_addr;
        !           654:        EL3WINDOW(1);
        !           655:     printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
        !           656:                   "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
        !           657:                   inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
        !           658:                   inw(ioaddr+TxFree));
        !           659:        EL3WINDOW(4);
        !           660:     printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
        !           661:                   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
        !           662:                   inw(ioaddr+0x08), inw(ioaddr+0x0a));
        !           663:        EL3WINDOW(1);
        !           664: }
        !           665: 
        !           666: /*
        !           667:   Use this for commands that may take time to finish
        !           668: */
        !           669: static void tc574_wait_for_completion(struct net_device *dev, int cmd)
        !           670: {
        !           671:     int i = 1500;
        !           672:     outw(cmd, dev->base_addr + EL3_CMD);
        !           673:     while (--i > 0)
        !           674:                if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
        !           675:     if (i == 0)
        !           676:                printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
        !           677:                           dev->name, cmd);
        !           678: }
        !           679: 
        !           680: /* Read a word from the EEPROM using the regular EEPROM access register.
        !           681:    Assume that we are in register window zero.
        !           682:  */
        !           683: static u_short read_eeprom(ioaddr_t ioaddr, int index)
        !           684: {
        !           685:        int timer;
        !           686:        outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
        !           687:        /* Pause for at least 162 usec for the read to take place. */
        !           688:        for (timer = 1620; timer >= 0; timer--) {
        !           689:                if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
        !           690:                        break;
        !           691:        }
        !           692:        return inw(ioaddr + Wn0EepromData);
        !           693: }
        !           694: 
        !           695: /* MII transceiver control section.
        !           696:    Read and write the MII registers using software-generated serial
        !           697:    MDIO protocol.  See the MII specifications or DP83840A data sheet
        !           698:    for details.
        !           699:    The maxium data clock rate is 2.5 Mhz.  The timing is easily met by the
        !           700:    slow PC card interface. */
        !           701: 
        !           702: #define MDIO_SHIFT_CLK 0x01
        !           703: #define MDIO_DIR_WRITE 0x04
        !           704: #define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
        !           705: #define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
        !           706: #define MDIO_DATA_READ 0x02
        !           707: #define MDIO_ENB_IN            0x00
        !           708: 
        !           709: /* Generate the preamble required for initial synchronization and
        !           710:    a few older transceivers. */
        !           711: static void mdio_sync(ioaddr_t ioaddr, int bits)
        !           712: {
        !           713:        int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
        !           714: 
        !           715:        /* Establish sync by sending at least 32 logic ones. */
        !           716:        while (-- bits >= 0) {
        !           717:                outw(MDIO_DATA_WRITE1, mdio_addr);
        !           718:                outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
        !           719:        }
        !           720: }
        !           721: 
        !           722: static int mdio_read(ioaddr_t ioaddr, int phy_id, int location)
        !           723: {
        !           724:        int i;
        !           725:        int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
        !           726:        unsigned int retval = 0;
        !           727:        int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
        !           728: 
        !           729:        if (mii_preamble_required)
        !           730:                mdio_sync(ioaddr, 32);
        !           731: 
        !           732:        /* Shift the read command bits out. */
        !           733:        for (i = 14; i >= 0; i--) {
        !           734:                int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
        !           735:                outw(dataval, mdio_addr);
        !           736:                outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
        !           737:        }
        !           738:        /* Read the two transition, 16 data, and wire-idle bits. */
        !           739:        for (i = 19; i > 0; i--) {
        !           740:                outw(MDIO_ENB_IN, mdio_addr);
        !           741:                retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
        !           742:                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
        !           743:        }
        !           744:        return (retval>>1) & 0xffff;
        !           745: }
        !           746: 
        !           747: static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value)
        !           748: {
        !           749:        int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
        !           750:        int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
        !           751:        int i;
        !           752: 
        !           753:        if (mii_preamble_required)
        !           754:                mdio_sync(ioaddr, 32);
        !           755: 
        !           756:        /* Shift the command bits out. */
        !           757:        for (i = 31; i >= 0; i--) {
        !           758:                int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
        !           759:                outw(dataval, mdio_addr);
        !           760:                outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
        !           761:        }
        !           762:        /* Leave the interface idle. */
        !           763:        for (i = 1; i >= 0; i--) {
        !           764:                outw(MDIO_ENB_IN, mdio_addr);
        !           765:                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
        !           766:        }
        !           767: 
        !           768:        return;
        !           769: }
        !           770: 
        !           771: /* Reset and restore all of the 3c574 registers. */
        !           772: static void tc574_reset(struct net_device *dev)
        !           773: {
        !           774:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !           775:        int i, ioaddr = dev->base_addr;
        !           776: 
        !           777:        tc574_wait_for_completion(dev, TotalReset|0x10);
        !           778: 
        !           779:        /* Clear any transactions in progress. */
        !           780:        outw(0, ioaddr + RunnerWrCtrl);
        !           781:        outw(0, ioaddr + RunnerRdCtrl);
        !           782: 
        !           783:        /* Set the station address and mask. */
        !           784:        EL3WINDOW(2);
        !           785:        for (i = 0; i < 6; i++)
        !           786:                outb(dev->dev_addr[i], ioaddr + i);
        !           787:        for (; i < 12; i+=2)
        !           788:                outw(0, ioaddr + i);
        !           789: 
        !           790:        /* Reset config options */
        !           791:        EL3WINDOW(3);
        !           792:        outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
        !           793:        outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
        !           794:                 ioaddr + Wn3_Config);
        !           795:        
        !           796:        /* Roadrunner only: Turn on the MII transceiver. */
        !           797:        outw(0x8040, ioaddr + Wn3_Options);
        !           798:        mdelay(1);
        !           799:        outw(0xc040, ioaddr + Wn3_Options);
        !           800:        tc574_wait_for_completion(dev, TxReset);
        !           801:        tc574_wait_for_completion(dev, RxReset);
        !           802:        mdelay(1);
        !           803:        outw(0x8040, ioaddr + Wn3_Options);
        !           804: 
        !           805:        /* Switch to the stats window, and clear all stats by reading. */
        !           806:        outw(StatsDisable, ioaddr + EL3_CMD);
        !           807:        EL3WINDOW(6);
        !           808:        for (i = 0; i < 10; i++)
        !           809:                inb(ioaddr + i);
        !           810:        inw(ioaddr + 10);
        !           811:        inw(ioaddr + 12);
        !           812:        EL3WINDOW(4);
        !           813:        inb(ioaddr + 12);
        !           814:        inb(ioaddr + 13);
        !           815: 
        !           816:        /* .. enable any extra statistics bits.. */
        !           817:        outw(0x0040, ioaddr + Wn4_NetDiag);
        !           818:        /* .. re-sync MII and re-fill what NWay is advertising. */
        !           819:        mdio_sync(ioaddr, 32);
        !           820:        mdio_write(ioaddr, lp->phys, 4, lp->advertising);
        !           821:        if (!auto_polarity) {
        !           822:                /* works for TDK 78Q2120 series MII's */
        !           823:                int i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
        !           824:                mdio_write(ioaddr, lp->phys, 16, i);
        !           825:        }
        !           826: 
        !           827:        /* Switch to register set 1 for normal use, just for TxFree. */
        !           828:        EL3WINDOW(1);
        !           829: 
        !           830:        set_rx_mode(dev);
        !           831:        outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
        !           832:        outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
        !           833:        outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
        !           834:        /* Allow status bits to be seen. */
        !           835:        outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
        !           836:        /* Ack all pending events, and set active indicator mask. */
        !           837:        outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
        !           838:                 ioaddr + EL3_CMD);
        !           839:        outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
        !           840:                 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
        !           841: }
        !           842: 
        !           843: static int el3_open(struct net_device *dev)
        !           844: {
        !           845:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !           846:        dev_link_t *link = &lp->link;
        !           847: 
        !           848:        if (!DEV_OK(link))
        !           849:                return -ENODEV;
        !           850:        
        !           851:        link->open++;
        !           852:        MOD_INC_USE_COUNT;
        !           853:        netif_start_queue(dev);
        !           854:        netif_mark_up(dev);
        !           855:        
        !           856:        tc574_reset(dev);
        !           857:        lp->media.function = &media_check;
        !           858:        lp->media.data = (u_long)lp;
        !           859:        lp->media.expires = jiffies + HZ;
        !           860:        add_timer(&lp->media);
        !           861:        
        !           862:        DEBUG(2, "%s: opened, status %4.4x.\n",
        !           863:                  dev->name, inw(dev->base_addr + EL3_STATUS));
        !           864:        
        !           865:        return 0;
        !           866: }
        !           867: 
        !           868: static void el3_tx_timeout(struct net_device *dev)
        !           869: {
        !           870:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !           871:        ioaddr_t ioaddr = dev->base_addr;
        !           872:        
        !           873:        printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
        !           874:        dump_status(dev);
        !           875:        lp->stats.tx_errors++;
        !           876:        dev->trans_start = jiffies;
        !           877:        /* Issue TX_RESET and TX_START commands. */
        !           878:        tc574_wait_for_completion(dev, TxReset);
        !           879:        outw(TxEnable, ioaddr + EL3_CMD);
        !           880:        netif_wake_queue(dev);
        !           881: }
        !           882: 
        !           883: static void pop_tx_status(struct net_device *dev)
        !           884: {
        !           885:     struct el3_private *lp = (struct el3_private *)dev->priv;
        !           886:     ioaddr_t ioaddr = dev->base_addr;
        !           887:     int i;
        !           888:     
        !           889:     /* Clear the Tx status stack. */
        !           890:     for (i = 32; i > 0; i--) {
        !           891:                u_char tx_status = inb(ioaddr + TxStatus);
        !           892:                if (!(tx_status & 0x84)) break;
        !           893:                /* reset transmitter on jabber error or underrun */
        !           894:                if (tx_status & 0x30)
        !           895:                        tc574_wait_for_completion(dev, TxReset);
        !           896:                if (tx_status & 0x38) {
        !           897:                        DEBUG(1, "%s: transmit error: status 0x%02x\n",
        !           898:                                  dev->name, tx_status);
        !           899:                        outw(TxEnable, ioaddr + EL3_CMD);
        !           900:                        lp->stats.tx_aborted_errors++;
        !           901:                }
        !           902:                outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
        !           903:     }
        !           904: }
        !           905: 
        !           906: static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        !           907: {
        !           908:        ioaddr_t ioaddr = dev->base_addr;
        !           909: 
        !           910:        tx_timeout_check(dev, el3_tx_timeout);
        !           911:        skb_tx_check(dev, skb);
        !           912: 
        !           913:        DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
        !           914:                  "status %4.4x.\n", dev->name, (long)skb->len,
        !           915:                  inw(ioaddr + EL3_STATUS));
        !           916: 
        !           917:        outw(skb->len, ioaddr + TX_FIFO);
        !           918:        outw(0, ioaddr + TX_FIFO);
        !           919:        outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
        !           920: 
        !           921:        dev->trans_start = jiffies;
        !           922: 
        !           923:        /* TxFree appears only in Window 1, not offset 0x1c. */
        !           924:        if (inw(ioaddr + TxFree) > 1536) {
        !           925:                netif_start_queue(dev);
        !           926:        } else
        !           927:                /* Interrupt us when the FIFO has room for max-sized packet. 
        !           928:                   The threshold is in units of dwords. */
        !           929:                outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
        !           930: 
        !           931:        DEV_KFREE_SKB (skb);
        !           932:        pop_tx_status(dev);
        !           933: 
        !           934:        return 0;
        !           935: }
        !           936: 
        !           937: /* The EL3 interrupt handler. */
        !           938: static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        !           939: {
        !           940:        struct el3_private *lp = dev_id;
        !           941:        struct net_device *dev = &lp->dev;
        !           942:        ioaddr_t ioaddr, status;
        !           943:        int work_budget = max_interrupt_work;
        !           944: 
        !           945:        if (!netif_device_present(dev))
        !           946:                return;
        !           947:        ioaddr = dev->base_addr;
        !           948: 
        !           949:        DEBUG(3, "%s: interrupt, status %4.4x.\n",
        !           950:                  dev->name, inw(ioaddr + EL3_STATUS));
        !           951: 
        !           952:        while ((status = inw(ioaddr + EL3_STATUS)) &
        !           953:                   (IntLatch | RxComplete | RxEarly | StatsFull)) {
        !           954:                if (!netif_device_present(dev) ||
        !           955:                        ((status & 0xe000) != 0x2000)) {
        !           956:                        DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
        !           957:                        break;
        !           958:                }
        !           959: 
        !           960:                if (status & RxComplete)
        !           961:                        work_budget = el3_rx(dev, work_budget);
        !           962: 
        !           963:                if (status & TxAvailable) {
        !           964:                        DEBUG(3, "  TX room bit was handled.\n");
        !           965:                        /* There's room in the FIFO for a full-sized packet. */
        !           966:                        outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
        !           967:                        netif_wake_queue(dev);
        !           968:                }
        !           969: 
        !           970:                if (status & TxComplete)
        !           971:                        pop_tx_status(dev);
        !           972: 
        !           973:                if (status & (AdapterFailure | RxEarly | StatsFull)) {
        !           974:                        /* Handle all uncommon interrupts. */
        !           975:                        if (status & StatsFull)
        !           976:                                update_stats(dev);
        !           977:                        if (status & RxEarly) {
        !           978:                                work_budget = el3_rx(dev, work_budget);
        !           979:                                outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
        !           980:                        }
        !           981:                        if (status & AdapterFailure) {
        !           982:                                u16 fifo_diag;
        !           983:                                EL3WINDOW(4);
        !           984:                                fifo_diag = inw(ioaddr + Wn4_FIFODiag);
        !           985:                                EL3WINDOW(1);
        !           986:                                printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
        !           987:                                           " register %04x.\n", dev->name, fifo_diag);
        !           988:                                if (fifo_diag & 0x0400) {
        !           989:                                        /* Tx overrun */
        !           990:                                        tc574_wait_for_completion(dev, TxReset);
        !           991:                                        outw(TxEnable, ioaddr + EL3_CMD);
        !           992:                                }
        !           993:                                if (fifo_diag & 0x2000) {
        !           994:                                        /* Rx underrun */
        !           995:                                        tc574_wait_for_completion(dev, RxReset);
        !           996:                                        set_rx_mode(dev);
        !           997:                                        outw(RxEnable, ioaddr + EL3_CMD);
        !           998:                                }
        !           999:                                outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
        !          1000:                        }
        !          1001:                }
        !          1002: 
        !          1003:                if (--work_budget < 0) {
        !          1004:                        DEBUG(0, "%s: Too much work in interrupt, "
        !          1005:                                  "status %4.4x.\n", dev->name, status);
        !          1006:                        /* Clear all interrupts */
        !          1007:                        outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
        !          1008:                        break;
        !          1009:                }
        !          1010:                /* Acknowledge the IRQ. */
        !          1011:                outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
        !          1012:        }
        !          1013: 
        !          1014:        DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
        !          1015:                  dev->name, inw(ioaddr + EL3_STATUS));
        !          1016:        return;
        !          1017: }
        !          1018: 
        !          1019: /*
        !          1020:     This timer serves two purposes: to check for missed interrupts
        !          1021:        (and as a last resort, poll the NIC for events), and to monitor
        !          1022:        the MII, reporting changes in cable status.
        !          1023: */
        !          1024: static void media_check(u_long arg)
        !          1025: {
        !          1026:     struct el3_private *lp = (struct el3_private *)arg;
        !          1027:     struct net_device *dev = &lp->dev;
        !          1028:     ioaddr_t ioaddr = dev->base_addr;
        !          1029:     u_long flags;
        !          1030:        u_short /* cable, */ media, partner;
        !          1031: 
        !          1032:        if (!netif_device_present(dev))
        !          1033:                goto reschedule;
        !          1034:        
        !          1035:     /* Check for pending interrupt with expired latency timer: with
        !          1036:        this, we can limp along even if the interrupt is blocked */
        !          1037:     if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
        !          1038:                (inb(ioaddr + Timer) == 0xff)) {
        !          1039:                if (!lp->fast_poll)
        !          1040:                        printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
        !          1041:                el3_interrupt(dev->irq, lp, NULL);
        !          1042:                lp->fast_poll = HZ;
        !          1043:     }
        !          1044:     if (lp->fast_poll) {
        !          1045:                lp->fast_poll--;
        !          1046:                lp->media.expires = jiffies + 2;
        !          1047:                add_timer(&lp->media);
        !          1048:                return;
        !          1049:     }
        !          1050: 
        !          1051:        save_flags(flags);
        !          1052:        cli();
        !          1053: #if 0
        !          1054:        outw(2<<11, ioaddr + RunnerRdCtrl);
        !          1055:        cable = inb(ioaddr);
        !          1056:        outb(0x20, ioaddr);
        !          1057:        outw(0, ioaddr + RunnerRdCtrl);
        !          1058: #endif
        !          1059:        EL3WINDOW(4);
        !          1060:        media = mdio_read(ioaddr, lp->phys, 1);
        !          1061:        partner = mdio_read(ioaddr, lp->phys, 5);
        !          1062:        EL3WINDOW(1);
        !          1063:        restore_flags(flags);
        !          1064: 
        !          1065: #if 0
        !          1066:        if (cable & 0x20)
        !          1067:                printk(KERN_INFO "%s: cable %s\n", dev->name,
        !          1068:                           ((cable & 0x08) ? "fixed" : "problem"));
        !          1069: #endif
        !          1070:        if (media != lp->media_status) {
        !          1071:                if ((media ^ lp->media_status) & 0x0004)
        !          1072:                        printk(KERN_INFO "%s: %s link beat\n", dev->name,
        !          1073:                                   (lp->media_status & 0x0004) ? "lost" : "found");
        !          1074:                if ((media ^ lp->media_status) & 0x0020) {
        !          1075:                        lp->partner = 0;
        !          1076:                        if (lp->media_status & 0x0020) {
        !          1077:                                printk(KERN_INFO "%s: autonegotiation restarted\n",
        !          1078:                                           dev->name);
        !          1079:                        } else if (partner) {
        !          1080:                                partner &= lp->advertising;
        !          1081:                                lp->partner = partner;
        !          1082:                                printk(KERN_INFO "%s: autonegotiation complete: "
        !          1083:                                           "%sbaseT-%cD selected\n", dev->name,
        !          1084:                                           ((partner & 0x0180) ? "100" : "10"),
        !          1085:                                           ((partner & 0x0140) ? 'F' : 'H'));
        !          1086:                        } else {
        !          1087:                                printk(KERN_INFO "%s: link partner did not autonegotiate\n",
        !          1088:                                           dev->name);
        !          1089:                        }
        !          1090: 
        !          1091:                        EL3WINDOW(3);
        !          1092:                        outb((partner & 0x0140 ? 0x20 : 0) |
        !          1093:                                 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
        !          1094:                        EL3WINDOW(1);
        !          1095: 
        !          1096:                }
        !          1097:                if (media & 0x0010)
        !          1098:                        printk(KERN_INFO "%s: remote fault detected\n",
        !          1099:                                   dev->name);
        !          1100:                if (media & 0x0002)
        !          1101:                        printk(KERN_INFO "%s: jabber detected\n", dev->name);
        !          1102:                lp->media_status = media;
        !          1103:        }
        !          1104: 
        !          1105: reschedule:
        !          1106:     lp->media.expires = jiffies + HZ;
        !          1107:     add_timer(&lp->media);
        !          1108: }
        !          1109: 
        !          1110: static struct net_device_stats *el3_get_stats(struct net_device *dev)
        !          1111: {
        !          1112:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !          1113: 
        !          1114:        if (netif_device_present(dev))
        !          1115:                update_stats(dev);
        !          1116:        return &lp->stats;
        !          1117: }
        !          1118: 
        !          1119: /*  Update statistics.
        !          1120:        Suprisingly this need not be run single-threaded, but it effectively is.
        !          1121:        The counters clear when read, so the adds must merely be atomic.
        !          1122:  */
        !          1123: static void update_stats(struct net_device *dev)
        !          1124: {
        !          1125:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !          1126:        ioaddr_t ioaddr = dev->base_addr;
        !          1127:        u8 rx, tx, up;
        !          1128: 
        !          1129:        DEBUG(2, "%s: updating the statistics.\n", dev->name);
        !          1130: 
        !          1131:        if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
        !          1132:                return;
        !          1133: 
        !          1134:        /* Unlike the 3c509 we need not turn off stats updates while reading. */
        !          1135:        /* Switch to the stats window, and read everything. */
        !          1136:        EL3WINDOW(6);
        !          1137:        lp->stats.tx_carrier_errors     += inb(ioaddr + 0);
        !          1138:        lp->stats.tx_heartbeat_errors   += inb(ioaddr + 1);
        !          1139:        /* Multiple collisions. */              inb(ioaddr + 2);
        !          1140:        lp->stats.collisions                    += inb(ioaddr + 3);
        !          1141:        lp->stats.tx_window_errors              += inb(ioaddr + 4);
        !          1142:        lp->stats.rx_fifo_errors                += inb(ioaddr + 5);
        !          1143:        lp->stats.tx_packets                    += inb(ioaddr + 6);
        !          1144:        up                                                               = inb(ioaddr + 9);
        !          1145:        lp->stats.tx_packets                    += (up&0x30) << 4;
        !          1146:        /* Rx packets   */                                 inb(ioaddr + 7);
        !          1147:        /* Tx deferrals */                                 inb(ioaddr + 8);
        !          1148:        rx                                                               = inw(ioaddr + 10);
        !          1149:        tx                                                               = inw(ioaddr + 12);
        !          1150: 
        !          1151:        EL3WINDOW(4);
        !          1152:        /* BadSSD */                                       inb(ioaddr + 12);
        !          1153:        up                                                               = inb(ioaddr + 13);
        !          1154: 
        !          1155:        add_tx_bytes(&lp->stats, tx + ((up & 0xf0) << 12));
        !          1156: 
        !          1157:        EL3WINDOW(1);
        !          1158: }
        !          1159: 
        !          1160: static int el3_rx(struct net_device *dev, int worklimit)
        !          1161: {
        !          1162:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !          1163:        ioaddr_t ioaddr = dev->base_addr;
        !          1164:        short rx_status;
        !          1165:        
        !          1166:        DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
        !          1167:                  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
        !          1168:     while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
        !          1169:                   (--worklimit >= 0)) {
        !          1170:                if (rx_status & 0x4000) { /* Error, update stats. */
        !          1171:                        short error = rx_status & 0x3800;
        !          1172:                        lp->stats.rx_errors++;
        !          1173:                        switch (error) {
        !          1174:                        case 0x0000:    lp->stats.rx_over_errors++; break;
        !          1175:                        case 0x0800:    lp->stats.rx_length_errors++; break;
        !          1176:                        case 0x1000:    lp->stats.rx_frame_errors++; break;
        !          1177:                        case 0x1800:    lp->stats.rx_length_errors++; break;
        !          1178:                        case 0x2000:    lp->stats.rx_frame_errors++; break;
        !          1179:                        case 0x2800:    lp->stats.rx_crc_errors++; break;
        !          1180:                        }
        !          1181:                } else {
        !          1182:                        short pkt_len = rx_status & 0x7ff;
        !          1183:                        struct sk_buff *skb;
        !          1184: 
        !          1185:                        skb = dev_alloc_skb(pkt_len+5);
        !          1186: 
        !          1187:                        DEBUG(3, "  Receiving packet size %d status %4.4x.\n",
        !          1188:                                  pkt_len, rx_status);
        !          1189:                        if (skb != NULL) {
        !          1190:                                skb->dev = dev;
        !          1191:                                skb_reserve(skb, 2);
        !          1192:                                insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
        !          1193:                                         ((pkt_len+3)>>2));
        !          1194:                                skb->protocol = eth_type_trans(skb, dev);
        !          1195:                                netif_rx(skb);
        !          1196:                                dev->last_rx = jiffies;
        !          1197:                                lp->stats.rx_packets++;
        !          1198:                                add_rx_bytes(&lp->stats, pkt_len);
        !          1199:                        } else {
        !          1200:                                DEBUG(1, "%s: couldn't allocate a sk_buff of"
        !          1201:                                          " size %d.\n", dev->name, pkt_len);
        !          1202:                                lp->stats.rx_dropped++;
        !          1203:                        }
        !          1204:                }
        !          1205:                tc574_wait_for_completion(dev, RxDiscard);
        !          1206:        }
        !          1207: 
        !          1208:        return worklimit;
        !          1209: }
        !          1210: 
        !          1211: /* Provide ioctl() calls to examine the MII xcvr state. */
        !          1212: static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        !          1213: {
        !          1214:        struct el3_private *lp = (struct el3_private *)dev->priv;
        !          1215:        ioaddr_t ioaddr = dev->base_addr;
        !          1216:        u16 *data = (u16 *)&rq->ifr_data;
        !          1217:        int phy = lp->phys & 0x1f;
        !          1218: 
        !          1219:        DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
        !          1220:                  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
        !          1221:                  data[0], data[1], data[2], data[3]);
        !          1222: 
        !          1223:     switch(cmd) {
        !          1224:        case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
        !          1225:                data[0] = phy;
        !          1226:        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
        !          1227:                {
        !          1228:                        int saved_window;
        !          1229:                        long flags;
        !          1230: 
        !          1231:                        save_flags(flags);
        !          1232:                        cli();
        !          1233:                        saved_window = inw(ioaddr + EL3_CMD) >> 13;
        !          1234:                        EL3WINDOW(4);
        !          1235:                        data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
        !          1236:                        EL3WINDOW(saved_window);
        !          1237:                        restore_flags(flags);
        !          1238:                        return 0;
        !          1239:                }
        !          1240:        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
        !          1241:                {
        !          1242:                        int saved_window;
        !          1243:                        long flags;
        !          1244: 
        !          1245:                        if (!capable(CAP_NET_ADMIN))
        !          1246:                                return -EPERM;
        !          1247:                        save_flags(flags);
        !          1248:                        cli();
        !          1249:                        saved_window = inw(ioaddr + EL3_CMD) >> 13;
        !          1250:                        EL3WINDOW(4);
        !          1251:                        mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
        !          1252:                        EL3WINDOW(saved_window);
        !          1253:                        restore_flags(flags);
        !          1254:                        return 0;
        !          1255:                }
        !          1256:        default:
        !          1257:                return -EOPNOTSUPP;
        !          1258:        }
        !          1259: }
        !          1260: 
        !          1261: /* The Odie chip has a 64 bin multicast filter, but the bit layout is not
        !          1262:    documented.  Until it is we revert to receiving all multicast frames when
        !          1263:    any multicast reception is desired.
        !          1264:    Note: My other drivers emit a log message whenever promiscuous mode is
        !          1265:    entered to help detect password sniffers.  This is less desirable on
        !          1266:    typical PC card machines, so we omit the message.
        !          1267:    */
        !          1268: 
        !          1269: static void set_rx_mode(struct net_device *dev)
        !          1270: {
        !          1271:        ioaddr_t ioaddr = dev->base_addr;
        !          1272: 
        !          1273:        if (dev->flags & IFF_PROMISC)
        !          1274:                outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
        !          1275:                         ioaddr + EL3_CMD);
        !          1276:        else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
        !          1277:                outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
        !          1278:        else
        !          1279:                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
        !          1280: }
        !          1281: 
        !          1282: static int el3_close(struct net_device *dev)
        !          1283: {
        !          1284:        ioaddr_t ioaddr = dev->base_addr;
        !          1285:        struct el3_private *lp = dev->priv;
        !          1286:        dev_link_t *link = &lp->link;
        !          1287: 
        !          1288:        DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
        !          1289:        
        !          1290:        if (DEV_OK(link)) {
        !          1291:                /* Turn off statistics ASAP.  We update lp->stats below. */
        !          1292:                outw(StatsDisable, ioaddr + EL3_CMD);
        !          1293:                
        !          1294:                /* Disable the receiver and transmitter. */
        !          1295:                outw(RxDisable, ioaddr + EL3_CMD);
        !          1296:                outw(TxDisable, ioaddr + EL3_CMD);
        !          1297:                
        !          1298:                /* Note: Switching to window 0 may disable the IRQ. */
        !          1299:                EL3WINDOW(0);
        !          1300:                
        !          1301:                update_stats(dev);
        !          1302:        }
        !          1303: 
        !          1304:        link->open--;
        !          1305:        netif_stop_queue(dev);
        !          1306:        netif_mark_down(dev);
        !          1307:        del_timer(&lp->media);
        !          1308:        if (link->state & DEV_STALE_CONFIG)
        !          1309:                mod_timer(&link->release, jiffies + HZ/20);
        !          1310: 
        !          1311:        MOD_DEC_USE_COUNT;
        !          1312: 
        !          1313:        return 0;
        !          1314: }
        !          1315: 
        !          1316: static int __init init_3c574_cs(void)
        !          1317: {
        !          1318:        servinfo_t serv;
        !          1319: 
        !          1320:        DEBUG(0, "%s\n", version);
        !          1321:        CardServices(GetCardServicesInfo, &serv);
        !          1322:        if (serv.Revision != CS_RELEASE_CODE) {
        !          1323:                printk(KERN_NOTICE "3c574_cs: Card Services release "
        !          1324:                           "does not match!\n");
        !          1325:                return -EINVAL;
        !          1326:        }
        !          1327:        register_pccard_driver(&dev_info, &tc574_attach, &tc574_detach);
        !          1328:        return 0;
        !          1329: }
        !          1330: 
        !          1331: static void __exit exit_3c574_cs(void)
        !          1332: {
        !          1333:        DEBUG(0, "3c574_cs: unloading\n");
        !          1334:        unregister_pccard_driver(&dev_info);
        !          1335:        while (dev_list != NULL)
        !          1336:                tc574_detach(dev_list);
        !          1337: }
        !          1338: 
        !          1339: module_init(init_3c574_cs);
        !          1340: module_exit(exit_3c574_cs);
        !          1341: 
        !          1342: /*
        !          1343:  * Local variables:
        !          1344:  *  compile-command: "make 3c574_cs.o"
        !          1345:  *  c-indent-level: 4
        !          1346:  *  c-basic-offset: 4
        !          1347:  *  tab-width: 4
        !          1348:  * End:
        !          1349:  */

unix.superglobalmegacorp.com

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