Annotation of qemu/roms/ipxe/src/drivers/net/sis190.c, revision 1.1.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.