Annotation of qemu/roms/ipxe/src/drivers/net/sis190.c, revision 1.1

1.1     ! root        1: /*
        !             2:    sis190.c: Silicon Integrated Systems SiS190 ethernet driver
        !             3: 
        !             4:    Copyright (c) 2003 K.M. Liu <[email protected]>
        !             5:    Copyright (c) 2003, 2004 Jeff Garzik <[email protected]>
        !             6:    Copyright (c) 2003, 2004, 2005 Francois Romieu <[email protected]>
        !             7: 
        !             8:    Modified for iPXE 2009 by Thomas Miletich <[email protected]>
        !             9: 
        !            10:    Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191
        !            11:    genuine driver.
        !            12: 
        !            13:    This software may be used and distributed according to the terms of
        !            14:    the GNU General Public License (GPL), incorporated herein by reference.
        !            15:    Drivers based on or derived from this code fall under the GPL and must
        !            16:    retain the authorship, copyright and license notice.  This file is not
        !            17:    a complete program and may only be used when the entire operating
        !            18:    system is licensed under the GPL.
        !            19: 
        !            20:    See the file COPYING in this distribution for more information.
        !            21: 
        !            22:  */
        !            23: 
        !            24: FILE_LICENCE ( GPL_ANY );
        !            25: 
        !            26: #include "sis190.h"
        !            27: 
        !            28: static struct pci_device_id sis190_pci_tbl[] = {
        !            29:        PCI_ROM (0x1039, 0x0190, "sis190", "sis190", 0),
        !            30:        PCI_ROM (0x1039, 0x0191, "sis191", "sis191", 0),
        !            31: };
        !            32: 
        !            33: /******************************************************************************
        !            34:  *************** HACK to keep ISA bridge in the PCI device list ***************
        !            35:  ******************************************************************************/
        !            36: 
        !            37: /* Some sis190 variants store the MAC address in the BIOS CMOS. To read it, we
        !            38:  * have to use a PCI to ISA bridge. To access the bridge we need a few things
        !            39:  * from it's struct pci_device. We fake the successful probe of a driver to
        !            40:  * keep the bridge's struct pci_device in the list of pci_devices.
        !            41:  * See details in sis190_get_mac_addr_from_apc().
        !            42:  */
        !            43: 
        !            44: static struct pci_device_id sis190_isa_bridge_tbl[] = {
        !            45:        PCI_ID (0x1039, 0x0965, "", "", 0),
        !            46:        PCI_ID (0x1039, 0x0966, "", "", 0),
        !            47:        PCI_ID (0x1039, 0x0968, "", "", 0),
        !            48: };
        !            49: 
        !            50: static int sis190_isa_bridge_probe(struct pci_device *pdev __unused)
        !            51: {
        !            52:        return 0;
        !            53: }
        !            54: 
        !            55: static void sis190_isa_bridge_remove(struct pci_device *pdev __unused)
        !            56: {
        !            57:        return;
        !            58: }
        !            59: 
        !            60: struct pci_driver sis190_isa_bridge_driver __pci_driver = {
        !            61:        .ids            = sis190_isa_bridge_tbl,
        !            62:        .id_count       = (sizeof(sis190_isa_bridge_tbl) /
        !            63:                           sizeof(sis190_isa_bridge_tbl[0])),
        !            64:        .probe          = sis190_isa_bridge_probe,
        !            65:        .remove         = sis190_isa_bridge_remove,
        !            66: };
        !            67: 
        !            68: /******************************************************************************
        !            69:  *********************************** </HACK> **********************************
        !            70:  ******************************************************************************/
        !            71: 
        !            72: static const u32 sis190_intr_mask =
        !            73:        RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
        !            74: 
        !            75: /*
        !            76:  * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
        !            77:  * The chips use a 64 element hash table based on the Ethernet CRC.
        !            78:  */
        !            79: static const int multicast_filter_limit = 32;
        !            80: 
        !            81: static void __mdio_cmd(void *ioaddr, u32 ctl)
        !            82: {
        !            83:        unsigned int i;
        !            84: 
        !            85:        SIS_W32(GMIIControl, ctl);
        !            86: 
        !            87:        mdelay(1);
        !            88: 
        !            89:        for (i = 0; i < 100; i++) {
        !            90:                if (!(SIS_R32(GMIIControl) & EhnMIInotDone))
        !            91:                        break;
        !            92:                mdelay(1);
        !            93:        }
        !            94: 
        !            95:        if (i > 99)
        !            96:                DBG("sis190: PHY command timed out !\n");
        !            97: }
        !            98: 
        !            99: static void mdio_write(void *ioaddr, int phy_id, int reg, int val)
        !           100: {
        !           101:        __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite |
        !           102:                (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) |
        !           103:                (((u32) val) << EhnMIIdataShift));
        !           104: }
        !           105: 
        !           106: static int mdio_read(void *ioaddr, int phy_id, int reg)
        !           107: {
        !           108:        __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread |
        !           109:                (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift));
        !           110: 
        !           111:        return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift);
        !           112: }
        !           113: 
        !           114: static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val)
        !           115: {
        !           116:        struct sis190_private *tp = netdev_priv(dev);
        !           117: 
        !           118:        mdio_write(tp->mmio_addr, phy_id, reg, val);
        !           119: }
        !           120: 
        !           121: static int __mdio_read(struct net_device *dev, int phy_id, int reg)
        !           122: {
        !           123:        struct sis190_private *tp = netdev_priv(dev);
        !           124: 
        !           125:        return mdio_read(tp->mmio_addr, phy_id, reg);
        !           126: }
        !           127: 
        !           128: static u16 mdio_read_latched(void *ioaddr, int phy_id, int reg)
        !           129: {
        !           130:        mdio_read(ioaddr, phy_id, reg);
        !           131:        return mdio_read(ioaddr, phy_id, reg);
        !           132: }
        !           133: 
        !           134: static u16 sis190_read_eeprom(void *ioaddr, u32 reg)
        !           135: {
        !           136:        u16 data = 0xffff;
        !           137:        unsigned int i;
        !           138: 
        !           139:        if (!(SIS_R32(ROMControl) & 0x0002))
        !           140:                return 0;
        !           141: 
        !           142:        SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10));
        !           143: 
        !           144:        for (i = 0; i < 200; i++) {
        !           145:                if (!(SIS_R32(ROMInterface) & EEREQ)) {
        !           146:                        data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16;
        !           147:                        break;
        !           148:                }
        !           149:                mdelay(1);
        !           150:        }
        !           151: 
        !           152:        return data;
        !           153: }
        !           154: 
        !           155: static void sis190_irq_mask_and_ack(void *ioaddr)
        !           156: {
        !           157:        SIS_W32(IntrMask, 0x00);
        !           158:        SIS_W32(IntrStatus, 0xffffffff);
        !           159:        SIS_PCI_COMMIT();
        !           160: }
        !           161: 
        !           162: static void sis190_asic_down(void *ioaddr)
        !           163: {
        !           164:        /* Stop the chip's Tx and Rx DMA processes. */
        !           165: 
        !           166:        SIS_W32(TxControl, 0x1a00);
        !           167:        SIS_W32(RxControl, 0x1a00);
        !           168: 
        !           169:        sis190_irq_mask_and_ack(ioaddr);
        !           170: }
        !           171: 
        !           172: static inline void sis190_mark_as_last_descriptor(struct RxDesc *desc)
        !           173: {
        !           174:        desc->size |= cpu_to_le32(RingEnd);
        !           175: }
        !           176: 
        !           177: static inline void sis190_give_to_asic(struct RxDesc *desc)
        !           178: {
        !           179:        u32 eor = le32_to_cpu(desc->size) & RingEnd;
        !           180: 
        !           181:        desc->PSize = 0x0;
        !           182:        desc->size = cpu_to_le32((RX_BUF_SIZE & RX_BUF_MASK) | eor);
        !           183:        wmb();
        !           184:        desc->status = cpu_to_le32(OWNbit | INTbit);
        !           185: }
        !           186: 
        !           187: static inline void sis190_map_to_asic(struct RxDesc *desc, u32 mapping)
        !           188: {
        !           189:        desc->addr = cpu_to_le32(mapping);
        !           190:        sis190_give_to_asic(desc);
        !           191: }
        !           192: 
        !           193: static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
        !           194: {
        !           195:        desc->PSize = 0x0;
        !           196:        desc->addr = cpu_to_le32(0xdeadbeef);
        !           197:        desc->size &= cpu_to_le32(RingEnd);
        !           198:        wmb();
        !           199:        desc->status = 0x0;
        !           200: }
        !           201: 
        !           202: static struct io_buffer *sis190_alloc_rx_iob(struct RxDesc *desc)
        !           203: {
        !           204:        struct io_buffer *iob;
        !           205: 
        !           206:        iob = alloc_iob(RX_BUF_SIZE);
        !           207:        if (iob) {
        !           208:                u32 mapping;
        !           209: 
        !           210:                mapping = virt_to_bus(iob->data);
        !           211:                sis190_map_to_asic(desc, mapping);
        !           212:        } else {
        !           213:                DBG("sis190: alloc_iob failed\n");
        !           214:                sis190_make_unusable_by_asic(desc);
        !           215:        }
        !           216: 
        !           217:        return iob;
        !           218: }
        !           219: 
        !           220: static u32 sis190_rx_fill(struct sis190_private *tp, u32 start, u32 end)
        !           221: {
        !           222:        u32 cur;
        !           223: 
        !           224:        for (cur = start; cur < end; cur++) {
        !           225:                unsigned int i = cur % NUM_RX_DESC;
        !           226: 
        !           227:                if (tp->Rx_iobuf[i])
        !           228:                        continue;
        !           229: 
        !           230:                tp->Rx_iobuf[i] = sis190_alloc_rx_iob(tp->RxDescRing + i);
        !           231: 
        !           232:                if (!tp->Rx_iobuf[i])
        !           233:                        break;
        !           234:        }
        !           235:        return cur - start;
        !           236: }
        !           237: 
        !           238: static inline int sis190_rx_pkt_err(u32 status)
        !           239: {
        !           240: #define ErrMask        (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT)
        !           241: 
        !           242:        if ((status & CRCOK) && !(status & ErrMask))
        !           243:                return 0;
        !           244: 
        !           245:        return -1;
        !           246: }
        !           247: 
        !           248: static int sis190_process_rx(struct sis190_private *tp)
        !           249: {
        !           250:        u32 rx_left, cur_rx = tp->cur_rx;
        !           251:        u32 delta, count;
        !           252: 
        !           253:        rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
        !           254: 
        !           255:        for (; rx_left > 0; rx_left--, cur_rx++) {
        !           256:                unsigned int entry = cur_rx % NUM_RX_DESC;
        !           257:                struct RxDesc *desc = tp->RxDescRing + entry;
        !           258:                u32 status;
        !           259: 
        !           260:                if (le32_to_cpu(desc->status) & OWNbit)
        !           261:                        break;
        !           262: 
        !           263:                status = le32_to_cpu(desc->PSize);
        !           264: 
        !           265:                if (sis190_rx_pkt_err(status) < 0) {
        !           266:                        sis190_give_to_asic(desc);
        !           267:                } else {
        !           268:                        struct io_buffer *iob = tp->Rx_iobuf[entry];
        !           269:                        unsigned int pkt_size = (status & RxSizeMask) - 4;
        !           270: 
        !           271:                        if (pkt_size > RX_BUF_SIZE) {
        !           272:                                DBG("sis190: (frag) status = %08x.\n", status);
        !           273:                                sis190_give_to_asic(desc);
        !           274:                                continue;
        !           275:                        }
        !           276: 
        !           277:                        sis190_make_unusable_by_asic(desc);
        !           278: 
        !           279:                        iob_put(iob, pkt_size);
        !           280: 
        !           281:                        DBG2("sis190: received packet. len: %d\n", pkt_size);
        !           282:                        netdev_rx(tp->dev, iob);
        !           283:                        DBGIO_HD(iob->data, 60);
        !           284:                        tp->Rx_iobuf[entry] = NULL;
        !           285:                }
        !           286:        }
        !           287:        count = cur_rx - tp->cur_rx;
        !           288:        tp->cur_rx = cur_rx;
        !           289: 
        !           290:        delta = sis190_rx_fill(tp, tp->dirty_rx, tp->cur_rx);
        !           291:        if (!delta && count)
        !           292:                DBG("sis190: no Rx buffer allocated.\n");
        !           293:        tp->dirty_rx += delta;
        !           294: 
        !           295:        if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx))
        !           296:                DBG("sis190: Rx buffers exhausted.\n");
        !           297: 
        !           298:        return count;
        !           299: }
        !           300: 
        !           301: static inline int sis190_tx_pkt_err(u32 status)
        !           302: {
        !           303: #define TxErrMask (WND | TABRT | FIFO | LINK)
        !           304: 
        !           305:        if (!(status & TxErrMask))
        !           306:                return 0;
        !           307: 
        !           308:        return -1;
        !           309: }
        !           310: 
        !           311: static void sis190_process_tx(struct sis190_private *tp)
        !           312: {
        !           313:        u32 pending, dirty_tx = tp->dirty_tx;
        !           314: 
        !           315:        pending = tp->cur_tx - dirty_tx;
        !           316: 
        !           317:        for (; pending; pending--, dirty_tx++) {
        !           318:                unsigned int entry = dirty_tx % NUM_TX_DESC;
        !           319:                struct TxDesc *txd = tp->TxDescRing + entry;
        !           320:                u32 status = le32_to_cpu(txd->status);
        !           321:                struct io_buffer *iob;
        !           322: 
        !           323:                if (status & OWNbit)
        !           324:                        break;
        !           325: 
        !           326:                iob = tp->Tx_iobuf[entry];
        !           327: 
        !           328:                if (!iob)
        !           329:                        break;
        !           330: 
        !           331:                if (sis190_tx_pkt_err(status) == 0) {
        !           332:                        DBG2("sis190: Transmitted packet: %#08x\n", status);
        !           333:                        netdev_tx_complete(tp->dev, iob);
        !           334:                } else {
        !           335:                        DBG("sis190: Transmit error: %#08x\n", status);
        !           336:                        netdev_tx_complete_err(tp->dev, iob, -EINVAL);
        !           337:                }
        !           338: 
        !           339:                tp->Tx_iobuf[entry] = NULL;
        !           340:        }
        !           341: 
        !           342:        if (tp->dirty_tx != dirty_tx)
        !           343:                tp->dirty_tx = dirty_tx;
        !           344: }
        !           345: 
        !           346: /*
        !           347:  * The interrupt handler does all of the Rx thread work and cleans up after
        !           348:  * the Tx thread.
        !           349:  */
        !           350: static void sis190_poll(struct net_device *dev)
        !           351: {
        !           352:        struct sis190_private *tp = netdev_priv(dev);
        !           353:        void  *ioaddr = tp->mmio_addr;
        !           354:        u32 status;
        !           355: 
        !           356:        status = SIS_R32(IntrStatus);
        !           357: 
        !           358:        if ((status == 0xffffffff) || !status)
        !           359:                return;
        !           360: 
        !           361:        SIS_W32(IntrStatus, status);
        !           362: 
        !           363:        /* sis190_phy_task() needs to be called in event of a LinkChange and
        !           364:         * after auto-negotiation is finished. Finishing auto-neg won't generate
        !           365:         * any indication, hence we call it every time if the link is bad. */
        !           366:        if ((status & LinkChange) || !netdev_link_ok(dev))
        !           367:                sis190_phy_task(tp);
        !           368: 
        !           369:        if (status & RxQInt)
        !           370:                sis190_process_rx(tp);
        !           371: 
        !           372:        if (status & TxQ0Int)
        !           373:                sis190_process_tx(tp);
        !           374: }
        !           375: 
        !           376: static inline void sis190_init_ring_indexes(struct sis190_private *tp)
        !           377: {
        !           378:        tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
        !           379: }
        !           380: 
        !           381: static int sis190_init_ring(struct net_device *dev)
        !           382: {
        !           383:        struct sis190_private *tp = netdev_priv(dev);
        !           384: 
        !           385:        sis190_init_ring_indexes(tp);
        !           386: 
        !           387:        memset(tp->Tx_iobuf, 0, NUM_TX_DESC * sizeof(struct io_buffer *));
        !           388:        memset(tp->Rx_iobuf, 0, NUM_RX_DESC * sizeof(struct io_buffer *));
        !           389: 
        !           390:        if (sis190_rx_fill(tp, 0, NUM_RX_DESC) != NUM_RX_DESC)
        !           391:                goto err;
        !           392: 
        !           393:        sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1);
        !           394: 
        !           395:        return 0;
        !           396: 
        !           397: err:
        !           398:        sis190_free(dev);
        !           399:        return -ENOMEM;
        !           400: }
        !           401: 
        !           402: static void sis190_set_rx_mode(struct net_device *dev)
        !           403: {
        !           404:        struct sis190_private *tp = netdev_priv(dev);
        !           405:        void *ioaddr = tp->mmio_addr;
        !           406:        u32 mc_filter[2];       /* Multicast hash filter */
        !           407:        u16 rx_mode;
        !           408: 
        !           409:        rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
        !           410:        mc_filter[1] = mc_filter[0] = 0xffffffff;
        !           411: 
        !           412:        SIS_W16(RxMacControl, rx_mode | 0x2);
        !           413:        SIS_W32(RxHashTable, mc_filter[0]);
        !           414:        SIS_W32(RxHashTable + 4, mc_filter[1]);
        !           415: 
        !           416: }
        !           417: 
        !           418: static void sis190_soft_reset(void  *ioaddr)
        !           419: {
        !           420:        SIS_W32(IntrControl, 0x8000);
        !           421:        SIS_PCI_COMMIT();
        !           422:        SIS_W32(IntrControl, 0x0);
        !           423:        sis190_asic_down(ioaddr);
        !           424: }
        !           425: 
        !           426: static void sis190_hw_start(struct net_device *dev)
        !           427: {
        !           428:        struct sis190_private *tp = netdev_priv(dev);
        !           429:        void *ioaddr = tp->mmio_addr;
        !           430: 
        !           431:        sis190_soft_reset(ioaddr);
        !           432: 
        !           433:        SIS_W32(TxDescStartAddr, tp->tx_dma);
        !           434:        SIS_W32(RxDescStartAddr, tp->rx_dma);
        !           435: 
        !           436:        SIS_W32(IntrStatus, 0xffffffff);
        !           437:        SIS_W32(IntrMask, 0x0);
        !           438:        SIS_W32(GMIIControl, 0x0);
        !           439:        SIS_W32(TxMacControl, 0x60);
        !           440:        SIS_W16(RxMacControl, 0x02);
        !           441:        SIS_W32(RxHashTable, 0x0);
        !           442:        SIS_W32(0x6c, 0x0);
        !           443:        SIS_W32(RxWolCtrl, 0x0);
        !           444:        SIS_W32(RxWolData, 0x0);
        !           445: 
        !           446:        SIS_PCI_COMMIT();
        !           447: 
        !           448:        sis190_set_rx_mode(dev);
        !           449: 
        !           450:        SIS_W32(TxControl, 0x1a00 | CmdTxEnb);
        !           451:        SIS_W32(RxControl, 0x1a1d);
        !           452: }
        !           453: 
        !           454: static void sis190_phy_task(struct sis190_private *tp)
        !           455: {
        !           456:        struct net_device *dev = tp->dev;
        !           457:        void *ioaddr = tp->mmio_addr;
        !           458:        int phy_id = tp->mii_if.phy_id;
        !           459:        int cnt = 0;
        !           460:        u16 val;
        !           461: 
        !           462:        val = mdio_read(ioaddr, phy_id, MII_BMCR);
        !           463: 
        !           464:        /* 100ms timeout is completely arbitrary. I have no datasheet to
        !           465:         * check whether that's a sensible value or not.
        !           466:         */
        !           467:        while ((val & BMCR_RESET) && (cnt < 100)) {
        !           468:                val = mdio_read(ioaddr, phy_id, MII_BMCR);
        !           469:                mdelay(1);
        !           470:                cnt++;
        !           471:        }
        !           472: 
        !           473:        if (cnt > 99) {
        !           474:                DBG("sis190: BMCR_RESET timeout\n");
        !           475:                return;
        !           476:        }
        !           477: 
        !           478:        if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
        !           479:                     BMSR_ANEGCOMPLETE)) {
        !           480:                DBG("sis190: auto-negotiating...\n");
        !           481:                netdev_link_down(dev);
        !           482:        } else {
        !           483:                /* Rejoice ! */
        !           484:                struct {
        !           485:                        int val;
        !           486:                        u32 ctl;
        !           487:                        const char *msg;
        !           488:                } reg31[] = {
        !           489:                        { LPA_1000FULL, 0x07000c00 | 0x00001000,
        !           490:                                "1000 Mbps Full Duplex" },
        !           491:                        { LPA_1000HALF, 0x07000c00,
        !           492:                                "1000 Mbps Half Duplex" },
        !           493:                        { LPA_100FULL, 0x04000800 | 0x00001000,
        !           494:                                "100 Mbps Full Duplex" },
        !           495:                        { LPA_100HALF, 0x04000800,
        !           496:                                "100 Mbps Half Duplex" },
        !           497:                        { LPA_10FULL, 0x04000400 | 0x00001000,
        !           498:                                "10 Mbps Full Duplex" },
        !           499:                        { LPA_10HALF, 0x04000400,
        !           500:                                "10 Mbps Half Duplex" },
        !           501:                        { 0, 0x04000400, "unknown" }
        !           502:                }, *p = NULL;
        !           503:                u16 adv, autoexp, gigadv, gigrec;
        !           504: 
        !           505:                val = mdio_read(ioaddr, phy_id, 0x1f);
        !           506: 
        !           507:                val = mdio_read(ioaddr, phy_id, MII_LPA);
        !           508:                adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
        !           509: 
        !           510:                autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION);
        !           511: 
        !           512:                if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) {
        !           513:                        /* check for gigabit speed */
        !           514:                        gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000);
        !           515:                        gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000);
        !           516:                        val = (gigadv & (gigrec >> 2));
        !           517:                        if (val & ADVERTISE_1000FULL)
        !           518:                                p = reg31;
        !           519:                        else if (val & ADVERTISE_1000HALF)
        !           520:                                p = reg31 + 1;
        !           521:                }
        !           522: 
        !           523:                if (!p) {
        !           524:                        val &= adv;
        !           525: 
        !           526:                        for (p = reg31; p->val; p++) {
        !           527:                                if ((val & p->val) == p->val)
        !           528:                                        break;
        !           529:                        }
        !           530:                }
        !           531: 
        !           532:                p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
        !           533: 
        !           534:                if ((tp->features & F_HAS_RGMII) &&
        !           535:                    (tp->features & F_PHY_BCM5461)) {
        !           536:                        // Set Tx Delay in RGMII mode.
        !           537:                        mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
        !           538:                        udelay(200);
        !           539:                        mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
        !           540:                        p->ctl |= 0x03000000;
        !           541:                }
        !           542: 
        !           543:                SIS_W32(StationControl, p->ctl);
        !           544: 
        !           545:                if (tp->features & F_HAS_RGMII) {
        !           546:                        SIS_W32(RGDelay, 0x0441);
        !           547:                        SIS_W32(RGDelay, 0x0440);
        !           548:                }
        !           549: 
        !           550:                DBG("sis190: link on %s mode.\n", p->msg);
        !           551:                netdev_link_up(dev);
        !           552:        }
        !           553: }
        !           554: 
        !           555: static int sis190_open(struct net_device *dev)
        !           556: {
        !           557:        struct sis190_private *tp = netdev_priv(dev);
        !           558:        int rc;
        !           559: 
        !           560:        /* Allocate TX ring */
        !           561:        tp->TxDescRing = malloc_dma(TX_RING_BYTES, RING_ALIGNMENT);
        !           562:        if (!tp->TxDescRing) {
        !           563:                DBG("sis190: TX ring allocation failed\n");
        !           564:                rc = -ENOMEM;
        !           565:                goto out;
        !           566:        }
        !           567:        tp->tx_dma = cpu_to_le32(virt_to_bus(tp->TxDescRing));
        !           568: 
        !           569:        /* Allocate RX ring */
        !           570:        tp->RxDescRing = malloc_dma(RX_RING_BYTES, RING_ALIGNMENT);
        !           571:        if (!tp->RxDescRing) {
        !           572:                DBG("sis190: RX ring allocation failed\n");
        !           573:                rc = -ENOMEM;
        !           574:                goto error;
        !           575:        }
        !           576:        tp->rx_dma = cpu_to_le32(virt_to_bus(tp->RxDescRing));
        !           577: 
        !           578:        rc = sis190_init_ring(dev);
        !           579:        if (rc < 0)
        !           580:                goto error;
        !           581: 
        !           582:        /* init rx filter, also program MAC address to card */
        !           583:        sis190_init_rxfilter(dev);
        !           584: 
        !           585:        sis190_hw_start(dev);
        !           586: out:
        !           587:        return rc;
        !           588: 
        !           589: error:
        !           590:        sis190_free(dev);
        !           591:        goto out;
        !           592: }
        !           593: 
        !           594: static void sis190_down(struct net_device *dev)
        !           595: {
        !           596:        struct sis190_private *tp = netdev_priv(dev);
        !           597:        void  *ioaddr = tp->mmio_addr;
        !           598: 
        !           599:        do {
        !           600:                sis190_asic_down(ioaddr);
        !           601:        } while (SIS_R32(IntrMask));
        !           602: }
        !           603: 
        !           604: static void sis190_free(struct net_device *dev)
        !           605: {
        !           606:        struct sis190_private *tp = netdev_priv(dev);
        !           607:        int i;
        !           608: 
        !           609:        free_dma(tp->TxDescRing, TX_RING_BYTES);
        !           610:        free_dma(tp->RxDescRing, RX_RING_BYTES);
        !           611: 
        !           612:        tp->TxDescRing = NULL;
        !           613:        tp->RxDescRing = NULL;
        !           614: 
        !           615:        tp->tx_dma = 0;
        !           616:        tp->rx_dma = 0;
        !           617: 
        !           618:        tp->cur_tx = tp->dirty_tx = 0;
        !           619:        tp->cur_rx = tp->dirty_rx = 0;
        !           620: 
        !           621:        for (i = 0; i < NUM_RX_DESC; i++) {
        !           622:                free_iob(tp->Rx_iobuf[i]);
        !           623:                tp->Rx_iobuf[i] = NULL;
        !           624:        }
        !           625: 
        !           626:        /* tx io_buffers aren't owned by the driver, so don't free them */
        !           627:        for(i = 0; i < NUM_TX_DESC; i++)
        !           628:                tp->Tx_iobuf[i] = NULL;
        !           629: }
        !           630: 
        !           631: static void sis190_close(struct net_device *dev)
        !           632: {
        !           633:        sis190_down(dev);
        !           634:        sis190_free(dev);
        !           635: }
        !           636: 
        !           637: static int sis190_transmit(struct net_device *dev, struct io_buffer *iob)
        !           638: {
        !           639:        struct sis190_private *tp = netdev_priv(dev);
        !           640:        void  *ioaddr = tp->mmio_addr;
        !           641:        u32 len, entry;
        !           642:        struct TxDesc *desc;
        !           643: 
        !           644:        len = iob_len(iob);
        !           645:        if (len < ETH_ZLEN) {
        !           646:                iob_pad(iob, ETH_ZLEN);
        !           647:                len = ETH_ZLEN;
        !           648:        }
        !           649: 
        !           650:        entry = tp->cur_tx % NUM_TX_DESC;
        !           651:        desc = tp->TxDescRing + entry;
        !           652: 
        !           653:        if (le32_to_cpu(desc->status) & OWNbit) {
        !           654:                DBG("sis190: Tx Ring full\n");
        !           655:                return -EINVAL;
        !           656:        }
        !           657: 
        !           658:        tp->Tx_iobuf[entry] = iob;
        !           659: 
        !           660:        desc->PSize = cpu_to_le32(len);
        !           661:        desc->addr = cpu_to_le32(virt_to_bus(iob->data));
        !           662: 
        !           663:        desc->size = cpu_to_le32(len);
        !           664:        if (entry == (NUM_TX_DESC - 1))
        !           665:                desc->size |= cpu_to_le32(RingEnd);
        !           666: 
        !           667:        wmb();
        !           668: 
        !           669:        desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
        !           670: 
        !           671:        tp->cur_tx++;
        !           672: 
        !           673:        SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb);
        !           674: 
        !           675:        return 0;
        !           676: }
        !           677: 
        !           678: static void sis190_free_phy(struct list_head *first_phy)
        !           679: {
        !           680:        struct sis190_phy *cur, *next;
        !           681: 
        !           682:        list_for_each_entry_safe(cur, next, first_phy, list) {
        !           683:                free(cur);
        !           684:        }
        !           685: }
        !           686: 
        !           687: /**
        !           688:  *     sis190_default_phy - Select default PHY for sis190 mac.
        !           689:  *     @dev: the net device to probe for
        !           690:  *
        !           691:  *     Select first detected PHY with link as default.
        !           692:  *     If no one is link on, select PHY whose types is HOME as default.
        !           693:  *     If HOME doesn't exist, select LAN.
        !           694:  */
        !           695: static u16 sis190_default_phy(struct sis190_private *tp)
        !           696: {
        !           697:        struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan;
        !           698:        struct mii_if_info *mii_if = &tp->mii_if;
        !           699:        void  *ioaddr = tp->mmio_addr;
        !           700:        u16 status;
        !           701: 
        !           702:        phy_home = phy_default = phy_lan = NULL;
        !           703: 
        !           704:        list_for_each_entry(phy, &tp->first_phy, list) {
        !           705:                status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR);
        !           706: 
        !           707:                // Link ON & Not select default PHY & not ghost PHY.
        !           708:                if ((status & BMSR_LSTATUS) &&
        !           709:                    !phy_default &&
        !           710:                    (phy->type != UNKNOWN)) {
        !           711:                        phy_default = phy;
        !           712:                } else {
        !           713:                        status = mdio_read(ioaddr, phy->phy_id, MII_BMCR);
        !           714:                        mdio_write(ioaddr, phy->phy_id, MII_BMCR,
        !           715:                                   status | BMCR_ANENABLE | BMCR_ISOLATE);
        !           716:                        if (phy->type == HOME)
        !           717:                                phy_home = phy;
        !           718:                        else if (phy->type == LAN)
        !           719:                                phy_lan = phy;
        !           720:                }
        !           721:        }
        !           722: 
        !           723:        if (!phy_default) {
        !           724:                if (phy_home)
        !           725:                        phy_default = phy_home;
        !           726:                else if (phy_lan)
        !           727:                        phy_default = phy_lan;
        !           728:                else
        !           729:                        phy_default = list_entry(&tp->first_phy,
        !           730:                                                 struct sis190_phy, list);
        !           731:        }
        !           732: 
        !           733:        if (mii_if->phy_id != phy_default->phy_id) {
        !           734:                mii_if->phy_id = phy_default->phy_id;
        !           735:                DBG("sis190: Using transceiver at address %d as default.\n",
        !           736:                     mii_if->phy_id);
        !           737:        }
        !           738: 
        !           739:        status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR);
        !           740:        status &= (~BMCR_ISOLATE);
        !           741: 
        !           742:        mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status);
        !           743:        status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR);
        !           744: 
        !           745:        return status;
        !           746: }
        !           747: 
        !           748: static void sis190_init_phy(struct sis190_private *tp,
        !           749:                            struct sis190_phy *phy, unsigned int phy_id,
        !           750:                            u16 mii_status)
        !           751: {
        !           752:        void *ioaddr = tp->mmio_addr;
        !           753:        struct mii_chip_info *p;
        !           754: 
        !           755:        INIT_LIST_HEAD(&phy->list);
        !           756:        phy->status = mii_status;
        !           757:        phy->phy_id = phy_id;
        !           758: 
        !           759:        phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1);
        !           760:        phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2);
        !           761: 
        !           762:        for (p = mii_chip_table; p->type; p++) {
        !           763:                if ((p->id[0] == phy->id[0]) &&
        !           764:                    (p->id[1] == (phy->id[1] & 0xfff0))) {
        !           765:                        break;
        !           766:                }
        !           767:        }
        !           768: 
        !           769:        if (p->id[1]) {
        !           770:                phy->type = (p->type == MIX) ?
        !           771:                        ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
        !           772:                                LAN : HOME) : p->type;
        !           773:                tp->features |= p->feature;
        !           774: 
        !           775:                DBG("sis190: %s transceiver at address %d.\n", p->name, phy_id);
        !           776:        } else {
        !           777:                phy->type = UNKNOWN;
        !           778: 
        !           779:                DBG("sis190: unknown PHY 0x%x:0x%x transceiver at address %d\n",
        !           780:                    phy->id[0], (phy->id[1] & 0xfff0), phy_id);
        !           781:        }
        !           782: }
        !           783: 
        !           784: static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
        !           785: {
        !           786:        if (tp->features & F_PHY_88E1111) {
        !           787:                void *ioaddr = tp->mmio_addr;
        !           788:                int phy_id = tp->mii_if.phy_id;
        !           789:                u16 reg[2][2] = {
        !           790:                        { 0x808b, 0x0ce1 },
        !           791:                        { 0x808f, 0x0c60 }
        !           792:                }, *p;
        !           793: 
        !           794:                p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
        !           795: 
        !           796:                mdio_write(ioaddr, phy_id, 0x1b, p[0]);
        !           797:                udelay(200);
        !           798:                mdio_write(ioaddr, phy_id, 0x14, p[1]);
        !           799:                udelay(200);
        !           800:        }
        !           801: }
        !           802: 
        !           803: /**
        !           804:  *     sis190_mii_probe - Probe MII PHY for sis190
        !           805:  *     @dev: the net device to probe for
        !           806:  *
        !           807:  *     Search for total of 32 possible mii phy addresses.
        !           808:  *     Identify and set current phy if found one,
        !           809:  *     return error if it failed to found.
        !           810:  */
        !           811: static int sis190_mii_probe(struct net_device *dev)
        !           812: {
        !           813:        struct sis190_private *tp = netdev_priv(dev);
        !           814:        struct mii_if_info *mii_if = &tp->mii_if;
        !           815:        void *ioaddr = tp->mmio_addr;
        !           816:        int phy_id;
        !           817:        int rc = 0;
        !           818: 
        !           819:        INIT_LIST_HEAD(&tp->first_phy);
        !           820: 
        !           821:        for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
        !           822:                struct sis190_phy *phy;
        !           823:                u16 status;
        !           824: 
        !           825:                status = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
        !           826: 
        !           827:                // Try next mii if the current one is not accessible.
        !           828:                if (status == 0xffff || status == 0x0000)
        !           829:                        continue;
        !           830: 
        !           831:                phy = zalloc(sizeof(*phy));
        !           832:                if (!phy) {
        !           833:                        sis190_free_phy(&tp->first_phy);
        !           834:                        rc = -ENOMEM;
        !           835:                        goto out;
        !           836:                }
        !           837: 
        !           838:                DBG("sis190: found PHY\n");
        !           839: 
        !           840:                sis190_init_phy(tp, phy, phy_id, status);
        !           841: 
        !           842:                list_add(&tp->first_phy, &phy->list);
        !           843:        }
        !           844: 
        !           845:        if (list_empty(&tp->first_phy)) {
        !           846:                DBG("sis190: No MII transceivers found!\n");
        !           847:                rc = -EIO;
        !           848:                goto out;
        !           849:        }
        !           850: 
        !           851:        /* Select default PHY for mac */
        !           852:        sis190_default_phy(tp);
        !           853: 
        !           854:        sis190_mii_probe_88e1111_fixup(tp);
        !           855: 
        !           856:        mii_if->dev = dev;
        !           857:        mii_if->mdio_read = __mdio_read;
        !           858:        mii_if->mdio_write = __mdio_write;
        !           859:        mii_if->phy_id_mask = PHY_ID_ANY;
        !           860:        mii_if->reg_num_mask = MII_REG_ANY;
        !           861: out:
        !           862:        return rc;
        !           863: }
        !           864: 
        !           865: static void sis190_mii_remove(struct net_device *dev)
        !           866: {
        !           867:        struct sis190_private *tp = netdev_priv(dev);
        !           868: 
        !           869:        sis190_free_phy(&tp->first_phy);
        !           870: }
        !           871: 
        !           872: static int sis190_init_board(struct pci_device *pdev, struct net_device **netdev)
        !           873: {
        !           874:        struct sis190_private *tp;
        !           875:        struct net_device *dev;
        !           876:        void *ioaddr;
        !           877:        int rc;
        !           878: 
        !           879:        dev = alloc_etherdev(sizeof(*tp));
        !           880:        if (!dev) {
        !           881:                DBG("sis190: unable to alloc new etherdev\n");
        !           882:                rc = -ENOMEM;
        !           883:                goto err;
        !           884:        }
        !           885: 
        !           886:        dev->dev = &pdev->dev;
        !           887: 
        !           888:        tp = netdev_priv(dev);
        !           889:        memset(tp, 0, sizeof(*tp));
        !           890: 
        !           891:        tp->dev = dev;
        !           892: 
        !           893:        adjust_pci_device(pdev);
        !           894: 
        !           895:        ioaddr = ioremap(pdev->membase, SIS190_REGS_SIZE);
        !           896:        if (!ioaddr) {
        !           897:                DBG("sis190: cannot remap MMIO, aborting\n");
        !           898:                rc = -EIO;
        !           899:                goto err;
        !           900:        }
        !           901: 
        !           902:        tp->pci_device = pdev;
        !           903:        tp->mmio_addr = ioaddr;
        !           904: 
        !           905:        sis190_irq_mask_and_ack(ioaddr);
        !           906: 
        !           907:        sis190_soft_reset(ioaddr);
        !           908: 
        !           909:        *netdev = dev;
        !           910: 
        !           911:        return 0;
        !           912: 
        !           913: err:
        !           914:        return rc;
        !           915: }
        !           916: 
        !           917: static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
        !           918: {
        !           919:        tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
        !           920: }
        !           921: 
        !           922: static int sis190_get_mac_addr_from_eeprom(struct pci_device *pdev __unused,
        !           923:                                                     struct net_device *dev)
        !           924: {
        !           925:        struct sis190_private *tp = netdev_priv(dev);
        !           926:        void *ioaddr = tp->mmio_addr;
        !           927:        u16 sig;
        !           928:        int i;
        !           929: 
        !           930:        DBG("sis190: Read MAC address from EEPROM\n");
        !           931: 
        !           932:        /* Check to see if there is a sane EEPROM */
        !           933:        sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature);
        !           934: 
        !           935:        if ((sig == 0xffff) || (sig == 0x0000)) {
        !           936:                DBG("sis190: Error EEPROM read.\n");
        !           937:                return -EIO;
        !           938:        }
        !           939: 
        !           940:        /* Get MAC address from EEPROM */
        !           941:        for (i = 0; i < ETH_ALEN / 2; i++) {
        !           942:                u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
        !           943: 
        !           944:                ((u16 *)dev->hw_addr)[i] = cpu_to_le16(w);
        !           945:        }
        !           946: 
        !           947:        sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
        !           948: 
        !           949:        return 0;
        !           950: }
        !           951: 
        !           952: /**
        !           953:  *     sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
        !           954:  *     @pdev: PCI device
        !           955:  *     @dev:  network device to get address for
        !           956:  *
        !           957:  *     SiS96x model, use APC CMOS RAM to store MAC address.
        !           958:  *     APC CMOS RAM is accessed through ISA bridge.
        !           959:  *     MAC address is read into @net_dev->dev_addr.
        !           960:  */
        !           961: static int sis190_get_mac_addr_from_apc(struct pci_device *pdev,
        !           962:                                        struct net_device *dev)
        !           963: {
        !           964:        struct sis190_private *tp = netdev_priv(dev);
        !           965:        struct pci_device *isa_bridge = NULL;
        !           966:        struct device *d;
        !           967:        u8 reg, tmp8;
        !           968:        unsigned int i;
        !           969: 
        !           970:        DBG("sis190: Read MAC address from APC.\n");
        !           971: 
        !           972:        list_for_each_entry(d, &(pdev->dev.siblings), siblings) {
        !           973:                unsigned int i;
        !           974:                isa_bridge = container_of(d, struct pci_device, dev);
        !           975:                for(i = 0; i < sis190_isa_bridge_driver.id_count; i++) {
        !           976:                        if(isa_bridge->vendor ==
        !           977:                             sis190_isa_bridge_driver.ids[i].vendor
        !           978:                             && isa_bridge->device ==
        !           979:                             sis190_isa_bridge_driver.ids[i].device) {
        !           980:                                DBG("sis190: ISA bridge found\n");
        !           981:                                break;
        !           982:                        } else {
        !           983:                                isa_bridge = NULL;
        !           984:                        }
        !           985:                }
        !           986:                if(isa_bridge)
        !           987:                        break;
        !           988:        }
        !           989: 
        !           990:        if (!isa_bridge) {
        !           991:                DBG("sis190: Can not find ISA bridge.\n");
        !           992:                return -EIO;
        !           993:        }
        !           994: 
        !           995:        /* Enable port 78h & 79h to access APC Registers. */
        !           996:        pci_read_config_byte(isa_bridge, 0x48, &tmp8);
        !           997:        reg = (tmp8 & ~0x02);
        !           998:        pci_write_config_byte(isa_bridge, 0x48, reg);
        !           999:        udelay(50);
        !          1000:        pci_read_config_byte(isa_bridge, 0x48, &reg);
        !          1001: 
        !          1002:         for (i = 0; i < ETH_ALEN; i++) {
        !          1003:                 outb(0x9 + i, 0x78);
        !          1004:                 dev->hw_addr[i] = inb(0x79);
        !          1005:         }
        !          1006: 
        !          1007:        outb(0x12, 0x78);
        !          1008:        reg = inb(0x79);
        !          1009: 
        !          1010:        sis190_set_rgmii(tp, reg);
        !          1011: 
        !          1012:        /* Restore the value to ISA Bridge */
        !          1013:        pci_write_config_byte(isa_bridge, 0x48, tmp8);
        !          1014: 
        !          1015:        return 0;
        !          1016: }
        !          1017: 
        !          1018: /**
        !          1019:  *      sis190_init_rxfilter - Initialize the Rx filter
        !          1020:  *      @dev: network device to initialize
        !          1021:  *
        !          1022:  *      Set receive filter address to our MAC address
        !          1023:  *      and enable packet filtering.
        !          1024:  */
        !          1025: static inline void sis190_init_rxfilter(struct net_device *dev)
        !          1026: {
        !          1027:        struct sis190_private *tp = netdev_priv(dev);
        !          1028:        void *ioaddr = tp->mmio_addr;
        !          1029:        u16 ctl;
        !          1030:        int i;
        !          1031: 
        !          1032:        ctl = SIS_R16(RxMacControl);
        !          1033:        /*
        !          1034:         * Disable packet filtering before setting filter.
        !          1035:         * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits
        !          1036:         * only and followed by RxMacAddr (6 bytes). Strange. -- FR
        !          1037:         */
        !          1038:        SIS_W16(RxMacControl, ctl & ~0x0f00);
        !          1039: 
        !          1040:        for (i = 0; i < ETH_ALEN; i++)
        !          1041:                SIS_W8(RxMacAddr + i, dev->ll_addr[i]);
        !          1042: 
        !          1043:        SIS_W16(RxMacControl, ctl);
        !          1044:        SIS_PCI_COMMIT();
        !          1045: }
        !          1046: 
        !          1047: static int sis190_get_mac_addr(struct pci_device *pdev,
        !          1048:                                         struct net_device *dev)
        !          1049: {
        !          1050:        int rc;
        !          1051: 
        !          1052:        rc = sis190_get_mac_addr_from_eeprom(pdev, dev);
        !          1053:        if (rc < 0) {
        !          1054:                u8 reg;
        !          1055: 
        !          1056:                pci_read_config_byte(pdev, 0x73, &reg);
        !          1057: 
        !          1058:                if (reg & 0x00000001)
        !          1059:                        rc = sis190_get_mac_addr_from_apc(pdev, dev);
        !          1060:        }
        !          1061:        return rc;
        !          1062: }
        !          1063: 
        !          1064: static void sis190_set_speed_auto(struct net_device *dev)
        !          1065: {
        !          1066:        struct sis190_private *tp = netdev_priv(dev);
        !          1067:        void *ioaddr = tp->mmio_addr;
        !          1068:        int phy_id = tp->mii_if.phy_id;
        !          1069:        int val;
        !          1070: 
        !          1071:        DBG("sis190: Enabling Auto-negotiation.\n");
        !          1072: 
        !          1073:        val = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
        !          1074: 
        !          1075:        // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0
        !          1076:        // unchanged.
        !          1077:        mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) |
        !          1078:                   ADVERTISE_100FULL | ADVERTISE_10FULL |
        !          1079:                   ADVERTISE_100HALF | ADVERTISE_10HALF);
        !          1080: 
        !          1081:        // Enable 1000 Full Mode.
        !          1082:        mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL);
        !          1083: 
        !          1084:        // Enable auto-negotiation and restart auto-negotiation.
        !          1085:        mdio_write(ioaddr, phy_id, MII_BMCR,
        !          1086:                   BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET);
        !          1087: }
        !          1088: 
        !          1089: static void sis190_irq(struct net_device *dev, int enable)
        !          1090: {
        !          1091:        struct sis190_private *tp = netdev_priv(dev);
        !          1092:        void *ioaddr = tp->mmio_addr;
        !          1093: 
        !          1094:        SIS_W32(IntrStatus, 0xffffffff);
        !          1095: 
        !          1096:        if (enable == 0)
        !          1097:                SIS_W32(IntrMask, 0x00);
        !          1098:        else
        !          1099:                SIS_W32(IntrMask, sis190_intr_mask);
        !          1100: 
        !          1101:        SIS_PCI_COMMIT();
        !          1102: }
        !          1103: 
        !          1104: static struct net_device_operations sis190_netdev_ops = {
        !          1105:        .open = sis190_open,
        !          1106:        .close = sis190_close,
        !          1107:        .poll = sis190_poll,
        !          1108:        .transmit = sis190_transmit,
        !          1109:        .irq = sis190_irq,
        !          1110: };
        !          1111: 
        !          1112: static int sis190_probe(struct pci_device *pdev)
        !          1113: {
        !          1114:        struct sis190_private *tp;
        !          1115:        struct net_device *dev;
        !          1116:        int rc;
        !          1117: 
        !          1118:        rc = sis190_init_board(pdev, &dev);
        !          1119:        if (rc < 0)
        !          1120:                goto out;
        !          1121:        netdev_init(dev, &sis190_netdev_ops);
        !          1122: 
        !          1123:        pci_set_drvdata(pdev, dev);
        !          1124: 
        !          1125:        tp = netdev_priv(dev);
        !          1126: 
        !          1127:        rc = sis190_get_mac_addr(pdev, dev);
        !          1128:        if (rc < 0)
        !          1129:                goto err;
        !          1130: 
        !          1131:        rc = sis190_mii_probe(dev);
        !          1132:        if (rc < 0)
        !          1133:                goto err;
        !          1134: 
        !          1135:        rc = register_netdev(dev);
        !          1136:        if (rc < 0)
        !          1137:                goto err;
        !          1138: 
        !          1139:        sis190_set_speed_auto(dev);
        !          1140:        sis190_phy_task(tp);
        !          1141: 
        !          1142: out:
        !          1143:        return rc;
        !          1144: 
        !          1145: err:
        !          1146:        sis190_mii_remove(dev);
        !          1147:        iounmap(tp->mmio_addr);
        !          1148:        goto out;
        !          1149: }
        !          1150: 
        !          1151: static void sis190_remove(struct pci_device *pdev)
        !          1152: {
        !          1153:        struct net_device *dev = pci_get_drvdata(pdev);
        !          1154:        struct sis190_private *tp = dev->priv;
        !          1155:        void *ioaddr = tp->mmio_addr;
        !          1156: 
        !          1157:        sis190_mii_remove(dev);
        !          1158: 
        !          1159:        /* shutdown chip, disable interrupts, etc */
        !          1160:        sis190_soft_reset(ioaddr);
        !          1161: 
        !          1162:        iounmap(tp->mmio_addr);
        !          1163: 
        !          1164:        unregister_netdev(dev);
        !          1165:        netdev_nullify(dev);
        !          1166:        netdev_put(dev);
        !          1167: }
        !          1168: 
        !          1169: struct pci_driver sis190_pci_driver __pci_driver = {
        !          1170:        .ids            = sis190_pci_tbl,
        !          1171:        .id_count       = (sizeof(sis190_pci_tbl) / sizeof(sis190_pci_tbl[0])),
        !          1172:        .probe          = sis190_probe,
        !          1173:        .remove         = sis190_remove,
        !          1174: };

unix.superglobalmegacorp.com

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