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

1.1     ! root        1: /* -*- Mode:C; c-basic-offset:4; -*- */
        !             2: 
        !             3: /* 
        !             4:    sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot
        !             5:    Copyright (C) 2001 Entity Cyber, Inc.
        !             6: 
        !             7:    Revision:   1.0     March 1, 2001
        !             8:    
        !             9:    Author: Marty Connor ([email protected])
        !            10: 
        !            11:    Adapted from a Linux driver which was written by Donald Becker
        !            12:    and modified by Ollie Lho and Chin-Shan Li of SiS Corporation.
        !            13:    Rewritten for Etherboot by Marty Connor.
        !            14:    
        !            15:    This software may be used and distributed according to the terms
        !            16:    of the GNU Public License (GPL), incorporated herein by reference.
        !            17:    
        !            18:    References:
        !            19:    SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
        !            20:    preliminary Rev. 1.0 Jan. 14, 1998
        !            21:    SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
        !            22:    preliminary Rev. 1.0 Nov. 10, 1998
        !            23:    SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
        !            24:    preliminary Rev. 1.0 Jan. 18, 1998
        !            25:    http://www.sis.com.tw/support/databook.htm */
        !            26: 
        !            27: FILE_LICENCE ( GPL_ANY );
        !            28: 
        !            29: /* Revision History */
        !            30: 
        !            31: /*
        !            32:   07 Dec 2003  timlegge - Enabled Multicast Support
        !            33:   06 Dec 2003  timlegge - Fixed relocation issue in 5.2
        !            34:   04 Jan 2002  Chien-Yu Chen, Doug Ambrisko, Marty Connor  Patch to Etherboot 5.0.5
        !            35:      Added support for the SiS 630ET plus various bug fixes from linux kernel
        !            36:      source 2.4.17.
        !            37:   01 March 2001  mdc     1.0
        !            38:      Initial Release.  Tested with PCI based sis900 card and ThinkNIC
        !            39:      computer.
        !            40:   20 March 2001 P.Koegel
        !            41:      added support for sis630e and PHY ICS1893 and RTL8201
        !            42:      Testet with SIS730S chipset + ICS1893
        !            43: */
        !            44: 
        !            45: 
        !            46: /* Includes */
        !            47: 
        !            48: #include "etherboot.h"
        !            49: #include <ipxe/pci.h>
        !            50: #include "nic.h"
        !            51: 
        !            52: #include "sis900.h"
        !            53: 
        !            54: /* Globals */
        !            55: 
        !            56: static struct nic_operations sis900_operations;
        !            57: 
        !            58: static int sis900_debug = 0;
        !            59: 
        !            60: static unsigned short vendor, dev_id;
        !            61: static unsigned long ioaddr;
        !            62: static u8 pci_revision;
        !            63: 
        !            64: static unsigned int cur_phy;
        !            65: 
        !            66: static unsigned int cur_rx;
        !            67: 
        !            68: struct {
        !            69:     BufferDesc txd;
        !            70:     BufferDesc rxd[NUM_RX_DESC];
        !            71:     unsigned char txb[TX_BUF_SIZE];
        !            72:     unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
        !            73: } sis900_bufs __shared;
        !            74: #define txd sis900_bufs.txd
        !            75: #define rxd sis900_bufs.rxd
        !            76: #define txb sis900_bufs.txb
        !            77: #define rxb sis900_bufs.rxb
        !            78: 
        !            79: #if 0
        !            80: static struct mac_chip_info {
        !            81:     const char *name;
        !            82:     u16 vendor_id, device_id, flags;
        !            83:     int io_size;
        !            84: } mac_chip_table[] = {
        !            85:     { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
        !            86:       PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
        !            87:     { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
        !            88:       PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
        !            89:     {0,0,0,0,0} /* 0 terminated list. */
        !            90: };
        !            91: #endif
        !            92: 
        !            93: static void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
        !            94: static void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
        !            95: static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
        !            96: static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
        !            97: static void vt6103_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
        !            98: 
        !            99: static struct mii_chip_info {
        !           100:     const char * name;
        !           101:     u16 phy_id0;
        !           102:     u16 phy_id1;
        !           103:     void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex);
        !           104: } mii_chip_table[] = {
        !           105:     {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
        !           106:     {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
        !           107:     {"SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, sis900_read_mode},
        !           108:     {"AMD 79C901 10BASE-T PHY",  0x0000, 0x6B70, amd79c901_read_mode},
        !           109:     {"AMD 79C901 HomePNA PHY",   0x0000, 0x6B90, amd79c901_read_mode},
        !           110:     {"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf440,ics1893_read_mode},
        !           111: //  {"NS 83851 PHY",0x2000, 0x5C20, MIX },
        !           112:     {"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8200,rtl8201_read_mode},
        !           113:     {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode},
        !           114:     {0,0,0,0}
        !           115: };
        !           116: 
        !           117: static struct mii_phy {
        !           118:     struct mii_phy * next;
        !           119:     struct mii_chip_info * chip_info;
        !           120:     int phy_addr;
        !           121:     u16 status;
        !           122: } mii;
        !           123: 
        !           124: 
        !           125: 
        !           126: #if 0
        !           127: // PCI to ISA bridge for SIS640E access
        !           128: static struct pci_device_id pci_isa_bridge_list[] = {
        !           129:        { .vendor = 0x1039, .device = 0x0008,
        !           130:                .name = "SIS 85C503/5513 PCI to ISA bridge"},
        !           131: };
        !           132: 
        !           133: PCI_DRIVER( sis_bridge_pci_driver, pci_isa_bridge_list, PCI_NO_CLASS );
        !           134: 
        !           135: static struct device_driver sis_bridge_driver = {
        !           136:     .name = "SIS ISA bridge",
        !           137:     .bus_driver = &pci_driver,
        !           138:     .bus_driver_info = ( struct bus_driver_info * ) &sis_bridge_pci_driver,
        !           139: };
        !           140: #endif
        !           141: 
        !           142: /* Function Prototypes */
        !           143: 
        !           144: static int sis900_probe(struct nic *nic,struct pci_device *pci);
        !           145: 
        !           146: static u16  sis900_read_eeprom(int location);
        !           147: static void sis900_mdio_reset(long mdio_addr);
        !           148: static void sis900_mdio_idle(long mdio_addr);
        !           149: static u16  sis900_mdio_read(int phy_id, int location);
        !           150: #if 0
        !           151: static void sis900_mdio_write(int phy_id, int location, int val);
        !           152: #endif
        !           153: static void sis900_init(struct nic *nic);
        !           154: 
        !           155: static void sis900_reset(struct nic *nic);
        !           156: 
        !           157: static void sis900_init_rxfilter(struct nic *nic);
        !           158: static void sis900_init_txd(struct nic *nic);
        !           159: static void sis900_init_rxd(struct nic *nic);
        !           160: static void sis900_set_rx_mode(struct nic *nic);
        !           161: static void sis900_check_mode(struct nic *nic);
        !           162: 
        !           163: static void sis900_transmit(struct nic *nic, const char *d, 
        !           164:                             unsigned int t, unsigned int s, const char *p);
        !           165: static int  sis900_poll(struct nic *nic, int retrieve);
        !           166: 
        !           167: static void sis900_disable(struct nic *nic);
        !           168: 
        !           169: static void sis900_irq(struct nic *nic, irq_action_t action);
        !           170: 
        !           171: /**
        !           172:  *     sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
        !           173:  *     @pci_dev: the sis900 pci device
        !           174:  *     @net_dev: the net device to get address for
        !           175:  *
        !           176:  *     Older SiS900 and friends, use EEPROM to store MAC address.
        !           177:  *     MAC address is read from read_eeprom() into @net_dev->dev_addr.
        !           178:  */
        !           179: 
        !           180: static int sis900_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
        !           181: {
        !           182:        u16 signature;
        !           183:        int i;
        !           184: 
        !           185:        /* check to see if we have sane EEPROM */
        !           186:        signature = (u16) sis900_read_eeprom( EEPROMSignature);
        !           187:        if (signature == 0xffff || signature == 0x0000) {
        !           188:                printf ("sis900_probe: Error EERPOM read %hX\n", signature);
        !           189:                return 0;
        !           190:        }
        !           191: 
        !           192:        /* get MAC address from EEPROM */
        !           193:        for (i = 0; i < 3; i++)
        !           194:                        ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
        !           195:        return 1;
        !           196: }
        !           197: 
        !           198: /**
        !           199:  *     sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
        !           200:  *     @pci_dev: the sis900 pci device
        !           201:  *     @net_dev: the net device to get address for 
        !           202:  *
        !           203:  *     SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM 
        !           204:  *     is shared by
        !           205:  *     LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
        !           206:  *     and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
        !           207:  *     by LAN, otherwise is not. After MAC address is read from EEPROM, send
        !           208:  *     EEDONE signal to refuse EEPROM access by LAN. 
        !           209:  *     The EEPROM map of SiS962 or SiS963 is different to SiS900. 
        !           210:  *     The signature field in SiS962 or SiS963 spec is meaningless. 
        !           211:  *     MAC address is read into @net_dev->dev_addr.
        !           212:  */
        !           213: 
        !           214: static int sis96x_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
        !           215: {
        !           216: /*     long ioaddr = net_dev->base_addr; */
        !           217:        long ee_addr = ioaddr + mear;
        !           218:        u32 waittime = 0;
        !           219:        int i;
        !           220:        
        !           221:        printf("Alternate function\n");
        !           222: 
        !           223:        outl(EEREQ, ee_addr);
        !           224:        while(waittime < 2000) {
        !           225:                if(inl(ee_addr) & EEGNT) {
        !           226: 
        !           227:                        /* get MAC address from EEPROM */
        !           228:                        for (i = 0; i < 3; i++)
        !           229:                                ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
        !           230: 
        !           231:                        outl(EEDONE, ee_addr);
        !           232:                        return 1;
        !           233:                } else {
        !           234:                        udelay(1);      
        !           235:                        waittime ++;
        !           236:                }
        !           237:        }
        !           238:        outl(EEDONE, ee_addr);
        !           239:        return 0;
        !           240: }
        !           241: 
        !           242: /**
        !           243:  *     sis630e_get_mac_addr: - Get MAC address for SiS630E model
        !           244:  *     @pci_dev: the sis900 pci device
        !           245:  *     @net_dev: the net device to get address for
        !           246:  *
        !           247:  *     SiS630E model, use APC CMOS RAM to store MAC address.
        !           248:  *     APC CMOS RAM is accessed through ISA bridge.
        !           249:  *     MAC address is read into @net_dev->dev_addr.
        !           250:  */
        !           251: 
        !           252: static int sis630e_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
        !           253: {
        !           254: #if 0
        !           255:        u8 reg;
        !           256:        int i;
        !           257:        struct bus_loc bus_loc;
        !           258:        union {
        !           259:            struct bus_dev bus_dev;
        !           260:            struct pci_device isa_bridge;
        !           261:        } u;
        !           262: 
        !           263:        /* find PCI to ISA bridge */
        !           264:        memset(&bus_loc, 0, sizeof(bus_loc));
        !           265:        if ( ! find_by_driver ( &bus_loc, &u.bus_dev, &sis_bridge_driver, 0 ) )
        !           266:            return 0;
        !           267: 
        !           268:        pci_read_config_byte(&u.isa_bridge, 0x48, &reg);
        !           269:        pci_write_config_byte(&u.isa_bridge, 0x48, reg | 0x40);
        !           270: 
        !           271:        for (i = 0; i < ETH_ALEN; i++)
        !           272:        {
        !           273:                outb(0x09 + i, 0x70);
        !           274:                ((u8 *)(nic->node_addr))[i] = inb(0x71);
        !           275:        }
        !           276:        pci_write_config_byte(&u.isa_bridge, 0x48, reg & ~0x40);
        !           277: 
        !           278:        return 1;
        !           279: #endif
        !           280: 
        !           281:        /* Does not work with current bus/device model */
        !           282:        memset ( nic->node_addr, 0, sizeof ( nic->node_addr ) );
        !           283:        return 0;
        !           284: }
        !           285: 
        !           286: /**
        !           287:  *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
        !           288:  *      @pci_dev: the sis900 pci device
        !           289:  *      @net_dev: the net device to get address for
        !           290:  *
        !           291:  *      SiS630E model, use APC CMOS RAM to store MAC address.
        !           292:  *      APC CMOS RAM is accessed through ISA bridge.
        !           293:  *      MAC address is read into @net_dev->dev_addr.
        !           294:  */
        !           295: 
        !           296: static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
        !           297: {
        !           298:         u32 rfcrSave;
        !           299:         u32 i;
        !           300:        
        !           301:        
        !           302:         rfcrSave = inl(rfcr + ioaddr);
        !           303: 
        !           304:         outl(rfcrSave | RELOAD, ioaddr + cr);
        !           305:         outl(0, ioaddr + cr);
        !           306: 
        !           307:         /* disable packet filtering before setting filter */
        !           308:         outl(rfcrSave & ~RFEN, rfcr + ioaddr);
        !           309: 
        !           310:         /* load MAC addr to filter data register */
        !           311:         for (i = 0 ; i < 3 ; i++) {
        !           312:                 outl((i << RFADDR_shift), ioaddr + rfcr);
        !           313:                 *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
        !           314:         }
        !           315: 
        !           316:         /* enable packet filitering */
        !           317:         outl(rfcrSave | RFEN, rfcr + ioaddr);
        !           318: 
        !           319:         return 1;
        !           320: }
        !           321: 
        !           322: /* 
        !           323:  * Function: sis900_probe
        !           324:  *
        !           325:  * Description: initializes initializes the NIC, retrieves the
        !           326:  *    MAC address of the card, and sets up some globals required by 
        !           327:  *    other routines.
        !           328:  *
        !           329:  * Side effects:
        !           330:  *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
        !           331:  *            leaves the sis900 initialized, and ready to recieve packets.
        !           332:  *
        !           333:  * Returns:   struct nic *:          pointer to NIC data structure
        !           334:  */
        !           335: 
        !           336: static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
        !           337: 
        !           338:     int i;
        !           339:     int found=0;
        !           340:     int phy_addr;
        !           341:     u8 revision;
        !           342:     int ret;
        !           343: 
        !           344:     if (pci->ioaddr == 0)
        !           345:         return 0;
        !           346: 
        !           347:     nic->irqno  = 0;
        !           348:     nic->ioaddr = pci->ioaddr;
        !           349: 
        !           350:     ioaddr  = pci->ioaddr;
        !           351:     vendor  = pci->vendor;
        !           352:     dev_id  = pci->device;
        !           353: 
        !           354:     /* wakeup chip */
        !           355:     pci_write_config_dword(pci, 0x40, 0x00000000);
        !           356: 
        !           357:     adjust_pci_device(pci);
        !           358: 
        !           359:     /* get MAC address */
        !           360:     ret = 0;
        !           361:     pci_read_config_byte(pci, PCI_REVISION, &revision);
        !           362:     
        !           363:     /* save for use later in sis900_reset() */
        !           364:     pci_revision = revision; 
        !           365: 
        !           366:     if (revision == SIS630E_900_REV)
        !           367:         ret = sis630e_get_mac_addr(pci, nic);
        !           368:     else if ((revision > 0x81) && (revision <= 0x90))
        !           369:         ret = sis635_get_mac_addr(pci, nic);
        !           370:     else if (revision == SIS96x_900_REV)
        !           371:        ret = sis96x_get_mac_addr(pci, nic);
        !           372:     else
        !           373:         ret = sis900_get_mac_addr(pci, nic);
        !           374: 
        !           375:     if (ret == 0)
        !           376:     {
        !           377:         printf ("sis900_probe: Error MAC address not found\n");
        !           378:         return 0;
        !           379:     }
        !           380: 
        !           381:     /* 630ET : set the mii access mode as software-mode */
        !           382:     if (revision == SIS630ET_900_REV)
        !           383:        outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
        !           384: 
        !           385:     DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
        !           386: 
        !           387:     /* probe for mii transceiver */
        !           388:     /* search for total of 32 possible mii phy addresses */
        !           389: 
        !           390:     found = 0;
        !           391:     for (phy_addr = 0; phy_addr < 32; phy_addr++) {
        !           392:         u16 mii_status;
        !           393:         u16 phy_id0, phy_id1;
        !           394: 
        !           395:         mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
        !           396:         if (mii_status == 0xffff || mii_status == 0x0000)
        !           397:             /* the mii is not accessable, try next one */
        !           398:             continue;
        !           399:                 
        !           400:         phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
        !           401:         phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
        !           402: 
        !           403:         /* search our mii table for the current mii */ 
        !           404:         for (i = 0; mii_chip_table[i].phy_id1; i++) {
        !           405: 
        !           406:             if ((phy_id0 == mii_chip_table[i].phy_id0) &&
        !           407:                 ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
        !           408: 
        !           409:                 printf("sis900_probe: %s transceiver found at address %d.\n",
        !           410:                        mii_chip_table[i].name, phy_addr);
        !           411: 
        !           412:                 mii.chip_info = &mii_chip_table[i];
        !           413:                 mii.phy_addr  = phy_addr;
        !           414:                 mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
        !           415:                 mii.next      = NULL;
        !           416: 
        !           417:                 found=1;
        !           418:                 break;
        !           419:             }
        !           420:         }
        !           421:     }
        !           422:         
        !           423:     if (found == 0) {
        !           424:         printf("sis900_probe: No MII transceivers found!\n");
        !           425:         return 0;
        !           426:     }
        !           427: 
        !           428:     /* Arbitrarily select the last PHY found as current PHY */
        !           429:     cur_phy = mii.phy_addr;
        !           430:     printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
        !           431: 
        !           432:     /* initialize device */
        !           433:     sis900_init(nic);
        !           434:     nic->nic_op        = &sis900_operations;
        !           435: 
        !           436:     return 1;
        !           437: }
        !           438: 
        !           439: 
        !           440: 
        !           441: 
        !           442: /* 
        !           443:  * EEPROM Routines:  These functions read and write to EEPROM for 
        !           444:  *    retrieving the MAC address and other configuration information about 
        !           445:  *    the card.
        !           446:  */
        !           447: 
        !           448: /* Delay between EEPROM clock transitions. */
        !           449: #define eeprom_delay()  inl(ee_addr)
        !           450: 
        !           451: 
        !           452: /* Function: sis900_read_eeprom
        !           453:  *
        !           454:  * Description: reads and returns a given location from EEPROM
        !           455:  *
        !           456:  * Arguments: int location:       requested EEPROM location
        !           457:  *
        !           458:  * Returns:   u16:                contents of requested EEPROM location
        !           459:  *
        !           460:  */
        !           461: 
        !           462: /* Read Serial EEPROM through EEPROM Access Register, Note that location is 
        !           463:    in word (16 bits) unit */
        !           464: static u16 sis900_read_eeprom(int location)
        !           465: {
        !           466:     int i;
        !           467:     u16 retval = 0;
        !           468:     long ee_addr = ioaddr + mear;
        !           469:     u32 read_cmd = location | EEread;
        !           470: 
        !           471:     outl(0, ee_addr);
        !           472:     eeprom_delay();
        !           473:     outl(EECS, ee_addr);
        !           474:     eeprom_delay();
        !           475: 
        !           476:     /* Shift the read command (9) bits out. */
        !           477:     for (i = 8; i >= 0; i--) {
        !           478:         u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
        !           479:         outl(dataval, ee_addr);
        !           480:         eeprom_delay();
        !           481:         outl(dataval | EECLK, ee_addr);
        !           482:         eeprom_delay();
        !           483:     }
        !           484:     outl(EECS, ee_addr);
        !           485:     eeprom_delay();
        !           486: 
        !           487:     /* read the 16-bits data in */
        !           488:     for (i = 16; i > 0; i--) {
        !           489:         outl(EECS, ee_addr);
        !           490:         eeprom_delay();
        !           491:         outl(EECS | EECLK, ee_addr);
        !           492:         eeprom_delay();
        !           493:         retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
        !           494:         eeprom_delay();
        !           495:     }
        !           496:                 
        !           497:     /* Terminate the EEPROM access. */
        !           498:     outl(0, ee_addr);
        !           499:     eeprom_delay();
        !           500: //  outl(EECLK, ee_addr);
        !           501: 
        !           502:     return (retval);
        !           503: }
        !           504: 
        !           505: #define sis900_mdio_delay()    inl(mdio_addr)
        !           506: 
        !           507: 
        !           508: /* 
        !           509:    Read and write the MII management registers using software-generated
        !           510:    serial MDIO protocol. Note that the command bits and data bits are
        !           511:    send out seperately 
        !           512: */
        !           513: 
        !           514: static void sis900_mdio_idle(long mdio_addr)
        !           515: {
        !           516:     outl(MDIO | MDDIR, mdio_addr);
        !           517:     sis900_mdio_delay();
        !           518:     outl(MDIO | MDDIR | MDC, mdio_addr);
        !           519: }
        !           520: 
        !           521: /* Syncronize the MII management interface by shifting 32 one bits out. */
        !           522: static void sis900_mdio_reset(long mdio_addr)
        !           523: {
        !           524:     int i;
        !           525: 
        !           526:     for (i = 31; i >= 0; i--) {
        !           527:         outl(MDDIR | MDIO, mdio_addr);
        !           528:         sis900_mdio_delay();
        !           529:         outl(MDDIR | MDIO | MDC, mdio_addr);
        !           530:         sis900_mdio_delay();
        !           531:     }
        !           532:     return;
        !           533: }
        !           534: 
        !           535: static u16 sis900_mdio_read(int phy_id, int location)
        !           536: {
        !           537:     long mdio_addr = ioaddr + mear;
        !           538:     int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
        !           539:     u16 retval = 0;
        !           540:     int i;
        !           541: 
        !           542:     sis900_mdio_reset(mdio_addr);
        !           543:     sis900_mdio_idle(mdio_addr);
        !           544: 
        !           545:     for (i = 15; i >= 0; i--) {
        !           546:         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
        !           547:         outl(dataval, mdio_addr);
        !           548:         sis900_mdio_delay();
        !           549:         outl(dataval | MDC, mdio_addr);
        !           550:         sis900_mdio_delay();
        !           551:     }
        !           552: 
        !           553:     /* Read the 16 data bits. */
        !           554:     for (i = 16; i > 0; i--) {
        !           555:         outl(0, mdio_addr);
        !           556:         sis900_mdio_delay();
        !           557:         retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
        !           558:         outl(MDC, mdio_addr);
        !           559:         sis900_mdio_delay();
        !           560:     }
        !           561:     outl(0x00, mdio_addr);
        !           562:     return retval;
        !           563: }
        !           564: 
        !           565: #if 0
        !           566: static void sis900_mdio_write(int phy_id, int location, int value)
        !           567: {
        !           568:     long mdio_addr = ioaddr + mear;
        !           569:     int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
        !           570:     int i;
        !           571: 
        !           572:     sis900_mdio_reset(mdio_addr);
        !           573:     sis900_mdio_idle(mdio_addr);
        !           574: 
        !           575:     /* Shift the command bits out. */
        !           576:     for (i = 15; i >= 0; i--) {
        !           577:         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
        !           578:         outb(dataval, mdio_addr);
        !           579:         sis900_mdio_delay();
        !           580:         outb(dataval | MDC, mdio_addr);
        !           581:         sis900_mdio_delay();
        !           582:     }
        !           583:     sis900_mdio_delay();
        !           584: 
        !           585:     /* Shift the value bits out. */
        !           586:     for (i = 15; i >= 0; i--) {
        !           587:         int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
        !           588:         outl(dataval, mdio_addr);
        !           589:         sis900_mdio_delay();
        !           590:         outl(dataval | MDC, mdio_addr);
        !           591:         sis900_mdio_delay();
        !           592:     }
        !           593:     sis900_mdio_delay();
        !           594:         
        !           595:     /* Clear out extra bits. */
        !           596:     for (i = 2; i > 0; i--) {
        !           597:         outb(0, mdio_addr);
        !           598:         sis900_mdio_delay();
        !           599:         outb(MDC, mdio_addr);
        !           600:         sis900_mdio_delay();
        !           601:     }
        !           602:     outl(0x00, mdio_addr);
        !           603:     return;
        !           604: }
        !           605: #endif
        !           606: 
        !           607: 
        !           608: /* Function: sis900_init
        !           609:  *
        !           610:  * Description: resets the ethernet controller chip and various
        !           611:  *    data structures required for sending and receiving packets.
        !           612:  *    
        !           613:  * Arguments: struct nic *nic:          NIC data structure
        !           614:  *
        !           615:  * returns:   void.
        !           616:  */
        !           617: 
        !           618: static void
        !           619: sis900_init(struct nic *nic)
        !           620: {
        !           621:     /* Soft reset the chip. */
        !           622:     sis900_reset(nic);
        !           623: 
        !           624:     sis900_init_rxfilter(nic);
        !           625: 
        !           626:     sis900_init_txd(nic);
        !           627:     sis900_init_rxd(nic);
        !           628: 
        !           629:     sis900_set_rx_mode(nic);
        !           630: 
        !           631:     sis900_check_mode(nic);
        !           632: 
        !           633:     outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
        !           634: }
        !           635: 
        !           636: 
        !           637: /* 
        !           638:  * Function: sis900_reset
        !           639:  *
        !           640:  * Description: disables interrupts and soft resets the controller chip
        !           641:  *
        !           642:  * Arguments: struct nic *nic:          NIC data structure
        !           643:  *
        !           644:  * Returns:   void.
        !           645:  */
        !           646: 
        !           647: static void 
        !           648: sis900_reset(struct nic *nic __unused)
        !           649: {
        !           650:     int i = 0;
        !           651:     u32 status = TxRCMP | RxRCMP;
        !           652: 
        !           653:     outl(0, ioaddr + ier);
        !           654:     outl(0, ioaddr + imr);
        !           655:     outl(0, ioaddr + rfcr);
        !           656: 
        !           657:     outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
        !           658: 
        !           659:     /* Check that the chip has finished the reset. */
        !           660:     while (status && (i++ < 1000)) {
        !           661:         status ^= (inl(isr + ioaddr) & status);
        !           662:     }
        !           663: 
        !           664:     if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
        !           665:             outl(PESEL | RND_CNT, ioaddr + cfg);
        !           666:     else
        !           667:             outl(PESEL, ioaddr + cfg);
        !           668: }
        !           669: 
        !           670: 
        !           671: /* Function: sis_init_rxfilter
        !           672:  *
        !           673:  * Description: sets receive filter address to our MAC address
        !           674:  *
        !           675:  * Arguments: struct nic *nic:          NIC data structure
        !           676:  *
        !           677:  * returns:   void.
        !           678:  */
        !           679: 
        !           680: static void
        !           681: sis900_init_rxfilter(struct nic *nic)
        !           682: {
        !           683:     u32 rfcrSave;
        !           684:     int i;
        !           685:         
        !           686:     rfcrSave = inl(rfcr + ioaddr);
        !           687: 
        !           688:     /* disable packet filtering before setting filter */
        !           689:     outl(rfcrSave & ~RFEN, rfcr + ioaddr);
        !           690: 
        !           691:     /* load MAC addr to filter data register */
        !           692:     for (i = 0 ; i < 3 ; i++) {
        !           693:         u32 w;
        !           694: 
        !           695:         w = (u32) *((u16 *)(nic->node_addr)+i);
        !           696:         outl((i << RFADDR_shift), ioaddr + rfcr);
        !           697:         outl(w, ioaddr + rfdr);
        !           698: 
        !           699:         if (sis900_debug > 0)
        !           700:             printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
        !           701:                    i, inl(ioaddr + rfdr));
        !           702:     }
        !           703: 
        !           704:     /* enable packet filitering */
        !           705:     outl(rfcrSave | RFEN, rfcr + ioaddr);
        !           706: }
        !           707: 
        !           708: 
        !           709: /* 
        !           710:  * Function: sis_init_txd
        !           711:  *
        !           712:  * Description: initializes the Tx descriptor
        !           713:  *
        !           714:  * Arguments: struct nic *nic:          NIC data structure
        !           715:  *
        !           716:  * returns:   void.
        !           717:  */
        !           718: 
        !           719: static void
        !           720: sis900_init_txd(struct nic *nic __unused)
        !           721: {
        !           722:     txd.link   = (u32) 0;
        !           723:     txd.cmdsts = (u32) 0;
        !           724:     txd.bufptr = virt_to_bus(&txb[0]);
        !           725: 
        !           726:     /* load Transmit Descriptor Register */
        !           727:     outl(virt_to_bus(&txd), ioaddr + txdp); 
        !           728:     if (sis900_debug > 0)
        !           729:         printf("sis900_init_txd: TX descriptor register loaded with: %X\n", 
        !           730:                inl(ioaddr + txdp));
        !           731: }
        !           732: 
        !           733: 
        !           734: /* Function: sis_init_rxd
        !           735:  *
        !           736:  * Description: initializes the Rx descriptor ring
        !           737:  *    
        !           738:  * Arguments: struct nic *nic:          NIC data structure
        !           739:  *
        !           740:  * Returns:   void.
        !           741:  */
        !           742: 
        !           743: static void 
        !           744: sis900_init_rxd(struct nic *nic __unused) 
        !           745: { 
        !           746:     int i;
        !           747: 
        !           748:     cur_rx = 0; 
        !           749: 
        !           750:     /* init RX descriptor */
        !           751:     for (i = 0; i < NUM_RX_DESC; i++) {
        !           752:         rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
        !           753:         rxd[i].cmdsts = (u32) RX_BUF_SIZE;
        !           754:         rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
        !           755:         if (sis900_debug > 0)
        !           756:             printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n", 
        !           757:                    i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
        !           758:                   (unsigned int) rxd[i].bufptr);
        !           759:     }
        !           760: 
        !           761:     /* load Receive Descriptor Register */
        !           762:     outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
        !           763: 
        !           764:     if (sis900_debug > 0)
        !           765:         printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", 
        !           766:                inl(ioaddr + rxdp));
        !           767: 
        !           768: }
        !           769: 
        !           770: 
        !           771: /* Function: sis_init_rxd
        !           772:  *
        !           773:  * Description: 
        !           774:  *    sets the receive mode to accept all broadcast packets and packets
        !           775:  *    with our MAC address, and reject all multicast packets.      
        !           776:  *    
        !           777:  * Arguments: struct nic *nic:          NIC data structure
        !           778:  *
        !           779:  * Returns:   void.
        !           780:  */
        !           781: 
        !           782: static void sis900_set_rx_mode(struct nic *nic __unused)
        !           783: {
        !           784:     int i, table_entries;
        !           785:     u32 rx_mode; 
        !           786:     u16 mc_filter[16] = {0};   /* 256/128 bits multicast hash table */
        !           787:        
        !           788:     if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
        !           789:        table_entries = 16;
        !           790:     else
        !           791:        table_entries = 8;
        !           792: 
        !           793:     /* accept all multicast packet */
        !           794:     rx_mode = RFAAB | RFAAM;
        !           795:     for (i = 0; i < table_entries; i++)
        !           796:                mc_filter[i] = 0xffff;
        !           797:                                        
        !           798:     /* update Multicast Hash Table in Receive Filter */
        !           799:     for (i = 0; i < table_entries; i++) {
        !           800:         /* why plus 0x04? That makes the correct value for hash table. */
        !           801:         outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
        !           802:         outl(mc_filter[i], ioaddr + rfdr);
        !           803:     }
        !           804: 
        !           805:     /* Accept Broadcast and multicast packets, destination addresses that match 
        !           806:        our MAC address */
        !           807:     outl(RFEN | rx_mode, ioaddr + rfcr);
        !           808: 
        !           809:     return;
        !           810: }
        !           811: 
        !           812: 
        !           813: /* Function: sis900_check_mode
        !           814:  *
        !           815:  * Description: checks the state of transmit and receive
        !           816:  *    parameters on the NIC, and updates NIC registers to match
        !           817:  *    
        !           818:  * Arguments: struct nic *nic:          NIC data structure
        !           819:  *
        !           820:  * Returns:   void.
        !           821:  */
        !           822: 
        !           823: static void
        !           824: sis900_check_mode(struct nic *nic)
        !           825: {
        !           826:     int speed, duplex;
        !           827:     u32 tx_flags = 0, rx_flags = 0;
        !           828: 
        !           829:     mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
        !           830: 
        !           831:     if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
        !           832:         tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
        !           833:        rx_flags = DMA_BURST_64 << RxMXDMA_shift;
        !           834:     }
        !           835:     else {
        !           836:             tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
        !           837:             rx_flags = DMA_BURST_512 << RxMXDMA_shift;
        !           838:     }
        !           839: 
        !           840:     if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
        !           841:         rx_flags |= (RxDRNT_10 << RxDRNT_shift);
        !           842:         tx_flags |= (TxDRNT_10 << TxDRNT_shift);
        !           843:     }
        !           844:     else {
        !           845:         rx_flags |= (RxDRNT_100 << RxDRNT_shift);
        !           846:         tx_flags |= (TxDRNT_100 << TxDRNT_shift);
        !           847:     }
        !           848: 
        !           849:     if (duplex == FDX_CAPABLE_FULL_SELECTED) {
        !           850:         tx_flags |= (TxCSI | TxHBI);
        !           851:         rx_flags |= RxATX;
        !           852:     }
        !           853: 
        !           854:     outl (tx_flags, ioaddr + txcfg);
        !           855:     outl (rx_flags, ioaddr + rxcfg);
        !           856: }
        !           857: 
        !           858: 
        !           859: /* Function: sis900_read_mode
        !           860:  *
        !           861:  * Description: retrieves and displays speed and duplex
        !           862:  *    parameters from the NIC
        !           863:  *    
        !           864:  * Arguments: struct nic *nic:          NIC data structure
        !           865:  *
        !           866:  * Returns:   void.
        !           867:  */
        !           868: 
        !           869: static void
        !           870: sis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
        !           871: {
        !           872:     int i = 0;
        !           873:     u32 status;
        !           874:     u16 phy_id0, phy_id1;
        !           875:         
        !           876:     /* STSOUT register is Latched on Transition, read operation updates it */
        !           877:     do {
        !           878:         status = sis900_mdio_read(phy_addr, MII_STSOUT);
        !           879:     } while (i++ < 2);
        !           880: 
        !           881:     *speed = HW_SPEED_10_MBPS;
        !           882:     *duplex = FDX_CAPABLE_HALF_SELECTED;
        !           883:     
        !           884:     if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
        !           885:        *speed = HW_SPEED_100_MBPS;
        !           886:     if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
        !           887:        *duplex = FDX_CAPABLE_FULL_SELECTED;
        !           888:        
        !           889:     /* Workaround for Realtek RTL8201 PHY issue */
        !           890:     phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
        !           891:     phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
        !           892:     if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
        !           893:        if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
        !           894:            *duplex = FDX_CAPABLE_FULL_SELECTED;
        !           895:        if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
        !           896:            *speed = HW_SPEED_100_MBPS;
        !           897:     }
        !           898: 
        !           899:     if (status & MII_STSOUT_LINK_FAIL)
        !           900:         printf("sis900_read_mode: Media Link Off\n");
        !           901:     else
        !           902:         printf("sis900_read_mode: Media Link On %s %s-duplex \n", 
        !           903:                *speed == HW_SPEED_100_MBPS ? 
        !           904:                "100mbps" : "10mbps",
        !           905:                *duplex == FDX_CAPABLE_FULL_SELECTED ?
        !           906:                "full" : "half");
        !           907: }
        !           908: 
        !           909: 
        !           910: /* Function: amd79c901_read_mode
        !           911:  *
        !           912:  * Description: retrieves and displays speed and duplex
        !           913:  *    parameters from the NIC
        !           914:  *    
        !           915:  * Arguments: struct nic *nic:          NIC data structure
        !           916:  *
        !           917:  * Returns:   void.
        !           918:  */
        !           919: 
        !           920: static void
        !           921: amd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
        !           922: {
        !           923:     int i;
        !           924:     u16 status;
        !           925:         
        !           926:     for (i = 0; i < 2; i++)
        !           927:         status = sis900_mdio_read(phy_addr, MII_STATUS);
        !           928: 
        !           929:     if (status & MII_STAT_CAN_AUTO) {
        !           930:         /* 10BASE-T PHY */
        !           931:         for (i = 0; i < 2; i++)
        !           932:             status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
        !           933:         if (status & MII_STSSUM_SPD)
        !           934:             *speed = HW_SPEED_100_MBPS;
        !           935:         else
        !           936:             *speed = HW_SPEED_10_MBPS;
        !           937:         if (status & MII_STSSUM_DPLX)
        !           938:             *duplex = FDX_CAPABLE_FULL_SELECTED;
        !           939:         else
        !           940:             *duplex = FDX_CAPABLE_HALF_SELECTED;
        !           941: 
        !           942:         if (status & MII_STSSUM_LINK)
        !           943:             printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", 
        !           944:                    *speed == HW_SPEED_100_MBPS ? 
        !           945:                    "100mbps" : "10mbps",
        !           946:                    *duplex == FDX_CAPABLE_FULL_SELECTED ?
        !           947:                    "full" : "half");
        !           948:         else
        !           949:             printf("amd79c901_read_mode: Media Link Off\n");
        !           950:     }
        !           951:     else {
        !           952:         /* HomePNA */
        !           953:         *speed = HW_SPEED_HOME;
        !           954:         *duplex = FDX_CAPABLE_HALF_SELECTED;
        !           955:         if (status & MII_STAT_LINK)
        !           956:             printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
        !           957:         else
        !           958:             printf("amd79c901_read_mode: Media Link Off\n");
        !           959:     }
        !           960: }
        !           961: 
        !           962: 
        !           963: /**
        !           964:  *     ics1893_read_mode: - read media mode for ICS1893 PHY
        !           965:  *     @net_dev: the net device to read mode for
        !           966:  *     @phy_addr: mii phy address
        !           967:  *     @speed: the transmit speed to be determined
        !           968:  *     @duplex: the duplex mode to be determined
        !           969:  *
        !           970:  *     ICS1893 PHY use Quick Poll Detailed Status register
        !           971:  *     to determine the speed and duplex mode for sis900
        !           972:  */
        !           973: 
        !           974: static void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
        !           975: {
        !           976:        int i = 0;
        !           977:        u32 status;
        !           978: 
        !           979:        /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
        !           980:        for (i = 0; i < 2; i++)
        !           981:                status = sis900_mdio_read(phy_addr, MII_QPDSTS);
        !           982: 
        !           983:        if (status & MII_STSICS_SPD)
        !           984:                *speed = HW_SPEED_100_MBPS;
        !           985:        else
        !           986:                *speed = HW_SPEED_10_MBPS;
        !           987: 
        !           988:        if (status & MII_STSICS_DPLX)
        !           989:                *duplex = FDX_CAPABLE_FULL_SELECTED;
        !           990:        else
        !           991:                *duplex = FDX_CAPABLE_HALF_SELECTED;
        !           992: 
        !           993:        if (status & MII_STSICS_LINKSTS)
        !           994:                printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
        !           995:                       *speed == HW_SPEED_100_MBPS ?
        !           996:                       "100mbps" : "10mbps",
        !           997:                       *duplex == FDX_CAPABLE_FULL_SELECTED ?
        !           998:                       "full" : "half");
        !           999:        else
        !          1000:                printf("ics1893_read_mode: Media Link Off\n");
        !          1001: }
        !          1002: 
        !          1003: /**
        !          1004:  *     rtl8201_read_mode: - read media mode for rtl8201 phy
        !          1005:  *     @nic: the net device to read mode for
        !          1006:  *     @phy_addr: mii phy address
        !          1007:  *     @speed: the transmit speed to be determined
        !          1008:  *     @duplex: the duplex mode to be determined
        !          1009:  *
        !          1010:  *     read MII_STATUS register from rtl8201 phy
        !          1011:  *     to determine the speed and duplex mode for sis900
        !          1012:  */
        !          1013: 
        !          1014: static void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
        !          1015: {
        !          1016:        u32 status;
        !          1017: 
        !          1018:        status = sis900_mdio_read(phy_addr, MII_STATUS);
        !          1019: 
        !          1020:        if (status & MII_STAT_CAN_TX_FDX) {
        !          1021:                *speed = HW_SPEED_100_MBPS;
        !          1022:                *duplex = FDX_CAPABLE_FULL_SELECTED;
        !          1023:        }
        !          1024:        else if (status & MII_STAT_CAN_TX) {
        !          1025:                *speed = HW_SPEED_100_MBPS;
        !          1026:                *duplex = FDX_CAPABLE_HALF_SELECTED;
        !          1027:        }
        !          1028:        else if (status & MII_STAT_CAN_T_FDX) {
        !          1029:                *speed = HW_SPEED_10_MBPS;
        !          1030:                *duplex = FDX_CAPABLE_FULL_SELECTED;
        !          1031:        }
        !          1032:        else if (status & MII_STAT_CAN_T) {
        !          1033:                *speed = HW_SPEED_10_MBPS;
        !          1034:                *duplex = FDX_CAPABLE_HALF_SELECTED;
        !          1035:        }
        !          1036: 
        !          1037:        if (status & MII_STAT_LINK)
        !          1038:                printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
        !          1039:                       *speed == HW_SPEED_100_MBPS ?
        !          1040:                       "100mbps" : "10mbps",
        !          1041:                       *duplex == FDX_CAPABLE_FULL_SELECTED ?
        !          1042:                       "full" : "half");
        !          1043:        else
        !          1044:                printf("rtl8201_read_config_mode: Media Link Off\n");
        !          1045: }
        !          1046: 
        !          1047: /**
        !          1048:  *     vt6103_read_mode: - read media mode for vt6103 phy
        !          1049:  *     @nic: the net device to read mode for
        !          1050:  *     @phy_addr: mii phy address
        !          1051:  *     @speed: the transmit speed to be determined
        !          1052:  *     @duplex: the duplex mode to be determined
        !          1053:  *
        !          1054:  *     read MII_STATUS register from rtl8201 phy
        !          1055:  *     to determine the speed and duplex mode for sis900
        !          1056:  */
        !          1057: 
        !          1058: static void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
        !          1059: {
        !          1060:        u32 status;
        !          1061: 
        !          1062:        status = sis900_mdio_read(phy_addr, MII_STATUS);
        !          1063: 
        !          1064:        if (status & MII_STAT_CAN_TX_FDX) {
        !          1065:                *speed = HW_SPEED_100_MBPS;
        !          1066:                *duplex = FDX_CAPABLE_FULL_SELECTED;
        !          1067:        }
        !          1068:        else if (status & MII_STAT_CAN_TX) {
        !          1069:                *speed = HW_SPEED_100_MBPS;
        !          1070:                *duplex = FDX_CAPABLE_HALF_SELECTED;
        !          1071:        }
        !          1072:        else if (status & MII_STAT_CAN_T_FDX) {
        !          1073:                *speed = HW_SPEED_10_MBPS;
        !          1074:                *duplex = FDX_CAPABLE_FULL_SELECTED;
        !          1075:        }
        !          1076:        else if (status & MII_STAT_CAN_T) {
        !          1077:                *speed = HW_SPEED_10_MBPS;
        !          1078:                *duplex = FDX_CAPABLE_HALF_SELECTED;
        !          1079:        }
        !          1080: 
        !          1081:        if (status & MII_STAT_LINK)
        !          1082:                printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
        !          1083:                       *speed == HW_SPEED_100_MBPS ?
        !          1084:                       "100mbps" : "10mbps",
        !          1085:                       *duplex == FDX_CAPABLE_FULL_SELECTED ?
        !          1086:                       "full" : "half");
        !          1087:        else
        !          1088:                printf("vt6103_read_config_mode: Media Link Off\n");
        !          1089: }
        !          1090: 
        !          1091: /* Function: sis900_transmit
        !          1092:  *
        !          1093:  * Description: transmits a packet and waits for completion or timeout.
        !          1094:  *
        !          1095:  * Arguments: char d[6]:          destination ethernet address.
        !          1096:  *            unsigned short t:   ethernet protocol type.
        !          1097:  *            unsigned short s:   size of the data-part of the packet.
        !          1098:  *            char *p:            the data for the packet.
        !          1099:  *    
        !          1100:  * Returns:   void.
        !          1101:  */
        !          1102: 
        !          1103: static void
        !          1104: sis900_transmit(struct nic  *nic,
        !          1105:                 const char  *d,     /* Destination */
        !          1106:                 unsigned int t,     /* Type */
        !          1107:                 unsigned int s,     /* size */
        !          1108:                 const char  *p)     /* Packet */
        !          1109: {
        !          1110:     u32 to, nstype;
        !          1111:     volatile u32 tx_status;
        !          1112:     
        !          1113:     /* Stop the transmitter */
        !          1114:     outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
        !          1115: 
        !          1116:     /* load Transmit Descriptor Register */
        !          1117:     outl(virt_to_bus(&txd), ioaddr + txdp); 
        !          1118:     if (sis900_debug > 1)
        !          1119:         printf("sis900_transmit: TX descriptor register loaded with: %X\n", 
        !          1120:                inl(ioaddr + txdp));
        !          1121: 
        !          1122:     memcpy(txb, d, ETH_ALEN);
        !          1123:     memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
        !          1124:     nstype = htons(t);
        !          1125:     memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
        !          1126:     memcpy(txb + ETH_HLEN, p, s);
        !          1127: 
        !          1128:     s += ETH_HLEN;
        !          1129:     s &= DSIZE;
        !          1130: 
        !          1131:     if (sis900_debug > 1)
        !          1132:         printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
        !          1133: 
        !          1134:     /* pad to minimum packet size */
        !          1135:     while (s < ETH_ZLEN)  
        !          1136:         txb[s++] = '\0';
        !          1137: 
        !          1138:     /* set the transmit buffer descriptor and enable Transmit State Machine */
        !          1139:     txd.bufptr = virt_to_bus(&txb[0]);
        !          1140:     txd.cmdsts = (u32) OWN | s;
        !          1141: 
        !          1142:     /* restart the transmitter */
        !          1143:     outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
        !          1144: 
        !          1145:     if (sis900_debug > 1)
        !          1146:         printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
        !          1147: 
        !          1148:     to = currticks() + TX_TIMEOUT;
        !          1149: 
        !          1150:     while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
        !          1151:         /* wait */ ;
        !          1152: 
        !          1153:     if (currticks() >= to) {
        !          1154:         printf("sis900_transmit: TX Timeout! Tx status %X.\n", 
        !          1155:               (unsigned int) tx_status);
        !          1156:     }
        !          1157:     
        !          1158:     if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
        !          1159:         /* packet unsuccessfully transmited */
        !          1160:         printf("sis900_transmit: Transmit error, Tx status %X.\n", 
        !          1161:               (unsigned int) tx_status);
        !          1162:     }
        !          1163:     /* Disable interrupts by clearing the interrupt mask. */
        !          1164:     outl(0, ioaddr + imr);
        !          1165: }
        !          1166: 
        !          1167: 
        !          1168: /* Function: sis900_poll
        !          1169:  *
        !          1170:  * Description: checks for a received packet and returns it if found.
        !          1171:  *
        !          1172:  * Arguments: struct nic *nic:          NIC data structure
        !          1173:  *
        !          1174:  * Returns:   1 if a packet was recieved.
        !          1175:  *            0 if no pacet was recieved.
        !          1176:  *
        !          1177:  * Side effects:
        !          1178:  *            Returns (copies) the packet to the array nic->packet.
        !          1179:  *            Returns the length of the packet in nic->packetlen.
        !          1180:  */
        !          1181: 
        !          1182: static int
        !          1183: sis900_poll(struct nic *nic, int retrieve)
        !          1184: {
        !          1185:     u32 rx_status = rxd[cur_rx].cmdsts;
        !          1186:     int retstat = 0;
        !          1187: 
        !          1188:      /* acknowledge interrupts by reading interrupt status register */
        !          1189:     inl(ioaddr + isr);
        !          1190: 
        !          1191:     if (sis900_debug > 2)
        !          1192:         printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, 
        !          1193:               (unsigned int) rx_status);
        !          1194: 
        !          1195:     if (!(rx_status & OWN))
        !          1196:         return retstat;
        !          1197: 
        !          1198:     if (sis900_debug > 1)
        !          1199:         printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
        !          1200:                cur_rx, (unsigned int) rx_status);
        !          1201: 
        !          1202:     if ( ! retrieve ) return 1;
        !          1203:     
        !          1204:     nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
        !          1205: 
        !          1206:     if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
        !          1207:         /* corrupted packet received */
        !          1208:         printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
        !          1209:                (unsigned int) rx_status);
        !          1210:         retstat = 0;
        !          1211:     } else {
        !          1212:         /* give packet to higher level routine */
        !          1213:         memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
        !          1214:         retstat = 1;
        !          1215:     }
        !          1216: 
        !          1217:     /* return the descriptor and buffer to receive ring */
        !          1218:     rxd[cur_rx].cmdsts = RX_BUF_SIZE;
        !          1219:     rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
        !          1220:         
        !          1221:     if (++cur_rx == NUM_RX_DESC)
        !          1222:         cur_rx = 0;
        !          1223: 
        !          1224:     /* re-enable the potentially idle receive state machine */
        !          1225:     outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
        !          1226: 
        !          1227:     return retstat;
        !          1228: 
        !          1229: }
        !          1230: 
        !          1231: 
        !          1232: /* Function: sis900_disable
        !          1233:  *
        !          1234:  * Description: Turns off interrupts and stops Tx and Rx engines
        !          1235:  *    
        !          1236:  * Arguments: struct nic *nic:          NIC data structure
        !          1237:  *
        !          1238:  * Returns:   void.
        !          1239:  */
        !          1240: 
        !          1241: static void
        !          1242: sis900_disable ( struct nic *nic ) {
        !          1243: 
        !          1244:     sis900_init(nic);
        !          1245: 
        !          1246:     /* Disable interrupts by clearing the interrupt mask. */
        !          1247:     outl(0, ioaddr + imr);
        !          1248:     outl(0, ioaddr + ier);
        !          1249:     
        !          1250:     /* Stop the chip's Tx and Rx Status Machine */
        !          1251:     outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
        !          1252: }
        !          1253: 
        !          1254: 
        !          1255: /* Function: sis900_irq
        !          1256:  *
        !          1257:  * Description: Enable, Disable, or Force, interrupts
        !          1258:  *    
        !          1259:  * Arguments: struct nic *nic:          NIC data structure
        !          1260:  *            irq_action_t action:      Requested action       
        !          1261:  *
        !          1262:  * Returns:   void.
        !          1263:  */
        !          1264: 
        !          1265: static void
        !          1266: sis900_irq(struct nic *nic __unused, irq_action_t action __unused)
        !          1267: {
        !          1268:   switch ( action ) {
        !          1269:   case DISABLE :
        !          1270:     outl(0, ioaddr + imr);
        !          1271:     break;
        !          1272:   case ENABLE :
        !          1273:     outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
        !          1274:     break;
        !          1275:   case FORCE :
        !          1276:     break;
        !          1277:   }
        !          1278: }
        !          1279: 
        !          1280: static struct nic_operations sis900_operations = {
        !          1281:        .connect        = dummy_connect,
        !          1282:        .poll           = sis900_poll,
        !          1283:        .transmit       = sis900_transmit,
        !          1284:        .irq            = sis900_irq,
        !          1285: };
        !          1286: 
        !          1287: static struct pci_device_id sis900_nics[] = {
        !          1288: PCI_ROM(0x1039, 0x0900, "sis900",  "SIS900", 0),
        !          1289: PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016", 0),
        !          1290: };
        !          1291: 
        !          1292: PCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
        !          1293: 
        !          1294: DRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
        !          1295:         sis900_probe, sis900_disable );
        !          1296: 
        !          1297: /*
        !          1298:  * Local variables:
        !          1299:  *  c-basic-offset: 8
        !          1300:  *  c-indent-level: 8
        !          1301:  *  tab-width: 8
        !          1302:  * End:
        !          1303:  */

unix.superglobalmegacorp.com

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