iPXE
sis900.c
Go to the documentation of this file.
00001 /* -*- Mode:C; c-basic-offset:4; -*- */
00002 
00003 /* 
00004    sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot
00005    Copyright (C) 2001 Entity Cyber, Inc.
00006 
00007    Revision:    1.0     March 1, 2001
00008    
00009    Author: Marty Connor (mdc@etherboot.org)
00010 
00011    Adapted from a Linux driver which was written by Donald Becker
00012    and modified by Ollie Lho and Chin-Shan Li of SiS Corporation.
00013    Rewritten for Etherboot by Marty Connor.
00014    
00015    This software may be used and distributed according to the terms
00016    of the GNU Public License (GPL), incorporated herein by reference.
00017    
00018    References:
00019    SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
00020    preliminary Rev. 1.0 Jan. 14, 1998
00021    SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
00022    preliminary Rev. 1.0 Nov. 10, 1998
00023    SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
00024    preliminary Rev. 1.0 Jan. 18, 1998
00025    http://www.sis.com.tw/support/databook.htm */
00026 
00027 FILE_LICENCE ( GPL_ANY );
00028 
00029 /* Revision History */
00030 
00031 /*
00032   07 Dec 2003  timlegge - Enabled Multicast Support
00033   06 Dec 2003  timlegge - Fixed relocation issue in 5.2
00034   04 Jan 2002  Chien-Yu Chen, Doug Ambrisko, Marty Connor  Patch to Etherboot 5.0.5
00035      Added support for the SiS 630ET plus various bug fixes from linux kernel
00036      source 2.4.17.
00037   01 March 2001  mdc     1.0
00038      Initial Release.  Tested with PCI based sis900 card and ThinkNIC
00039      computer.
00040   20 March 2001 P.Koegel
00041      added support for sis630e and PHY ICS1893 and RTL8201
00042      Testet with SIS730S chipset + ICS1893
00043 */
00044 
00045 
00046 /* Includes */
00047 
00048 #include "etherboot.h"
00049 #include <ipxe/pci.h>
00050 #include "nic.h"
00051 
00052 #include "sis900.h"
00053 
00054 /* Globals */
00055 
00056 static struct nic_operations sis900_operations;
00057 
00058 static int sis900_debug = 0;
00059 
00060 static unsigned short vendor, dev_id;
00061 static unsigned long ioaddr;
00062 static u8 pci_revision;
00063 
00064 static unsigned int cur_phy;
00065 
00066 static unsigned int cur_rx;
00067 
00068 struct {
00069     BufferDesc txd;
00070     BufferDesc rxd[NUM_RX_DESC];
00071     unsigned char txb[TX_BUF_SIZE];
00072     unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
00073 } sis900_bufs __shared;
00074 #define txd sis900_bufs.txd
00075 #define rxd sis900_bufs.rxd
00076 #define txb sis900_bufs.txb
00077 #define rxb sis900_bufs.rxb
00078 
00079 #if 0
00080 static struct mac_chip_info {
00081     const char *name;
00082     u16 vendor_id, device_id, flags;
00083     int io_size;
00084 } mac_chip_table[] = {
00085     { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
00086       PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
00087     { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
00088       PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
00089     {0,0,0,0,0} /* 0 terminated list. */
00090 };
00091 #endif
00092 
00093 static void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
00094 static void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
00095 static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
00096 static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
00097 static void vt6103_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
00098 
00099 static struct mii_chip_info {
00100     const char * name;
00101     u16 phy_id0;
00102     u16 phy_id1;
00103     void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex);
00104 } mii_chip_table[] = {
00105     {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
00106     {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
00107     {"SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, sis900_read_mode},
00108     {"AMD 79C901 10BASE-T PHY",  0x0000, 0x6B70, amd79c901_read_mode},
00109     {"AMD 79C901 HomePNA PHY",   0x0000, 0x6B90, amd79c901_read_mode},
00110     {"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf440,ics1893_read_mode},
00111 //  {"NS 83851 PHY",0x2000, 0x5C20, MIX },
00112     {"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8200,rtl8201_read_mode},
00113     {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode},
00114     {NULL,0,0,NULL}
00115 };
00116 
00117 static struct mii_phy {
00118     struct mii_phy * next;
00119     struct mii_chip_info * chip_info;
00120     int phy_addr;
00121     u16 status;
00122 } mii;
00123 
00124 
00125 
00126 #if 0
00127 // PCI to ISA bridge for SIS640E access
00128 static struct pci_device_id pci_isa_bridge_list[] = {
00129         { .vendor = 0x1039, .device = 0x0008,
00130                 .name = "SIS 85C503/5513 PCI to ISA bridge"},
00131 };
00132 
00133 PCI_DRIVER( sis_bridge_pci_driver, pci_isa_bridge_list, PCI_NO_CLASS );
00134 
00135 static struct device_driver sis_bridge_driver = {
00136     .name = "SIS ISA bridge",
00137     .bus_driver = &pci_driver,
00138     .bus_driver_info = ( struct bus_driver_info * ) &sis_bridge_pci_driver,
00139 };
00140 #endif
00141 
00142 /* Function Prototypes */
00143 
00144 static int sis900_probe(struct nic *nic,struct pci_device *pci);
00145 
00146 static u16  sis900_read_eeprom(int location);
00147 static void sis900_mdio_reset(long mdio_addr);
00148 static void sis900_mdio_idle(long mdio_addr);
00149 static u16  sis900_mdio_read(int phy_id, int location);
00150 #if 0
00151 static void sis900_mdio_write(int phy_id, int location, int val);
00152 #endif
00153 static void sis900_init(struct nic *nic);
00154 
00155 static void sis900_reset(struct nic *nic);
00156 
00157 static void sis900_init_rxfilter(struct nic *nic);
00158 static void sis900_init_txd(struct nic *nic);
00159 static void sis900_init_rxd(struct nic *nic);
00160 static void sis900_set_rx_mode(struct nic *nic);
00161 static void sis900_check_mode(struct nic *nic);
00162 
00163 static void sis900_transmit(struct nic *nic, const char *d, 
00164                             unsigned int t, unsigned int s, const char *p);
00165 static int  sis900_poll(struct nic *nic, int retrieve);
00166 
00167 static void sis900_disable(struct nic *nic);
00168 
00169 static void sis900_irq(struct nic *nic, irq_action_t action);
00170 
00171 /**
00172  *      sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
00173  *      @pci_dev: the sis900 pci device
00174  *      @net_dev: the net device to get address for
00175  *
00176  *      Older SiS900 and friends, use EEPROM to store MAC address.
00177  *      MAC address is read from read_eeprom() into @net_dev->dev_addr.
00178  */
00179 
00180 static int sis900_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
00181 {
00182         u16 signature;
00183         int i;
00184 
00185         /* check to see if we have sane EEPROM */
00186         signature = (u16) sis900_read_eeprom( EEPROMSignature);
00187         if (signature == 0xffff || signature == 0x0000) {
00188                 printf ("sis900_probe: Error EERPOM read %hX\n", signature);
00189                 return 0;
00190         }
00191 
00192         /* get MAC address from EEPROM */
00193         for (i = 0; i < 3; i++)
00194                         ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
00195         return 1;
00196 }
00197 
00198 /**
00199  *      sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
00200  *      @pci_dev: the sis900 pci device
00201  *      @net_dev: the net device to get address for 
00202  *
00203  *      SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM 
00204  *      is shared by
00205  *      LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
00206  *      and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
00207  *      by LAN, otherwise is not. After MAC address is read from EEPROM, send
00208  *      EEDONE signal to refuse EEPROM access by LAN. 
00209  *      The EEPROM map of SiS962 or SiS963 is different to SiS900. 
00210  *      The signature field in SiS962 or SiS963 spec is meaningless. 
00211  *      MAC address is read into @net_dev->dev_addr.
00212  */
00213 
00214 static int sis96x_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
00215 {
00216 /*      long ioaddr = net_dev->base_addr; */
00217         long ee_addr = ioaddr + mear;
00218         u32 waittime = 0;
00219         int i;
00220         
00221         printf("Alternate function\n");
00222 
00223         outl(EEREQ, ee_addr);
00224         while(waittime < 2000) {
00225                 if(inl(ee_addr) & EEGNT) {
00226 
00227                         /* get MAC address from EEPROM */
00228                         for (i = 0; i < 3; i++)
00229                                 ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
00230 
00231                         outl(EEDONE, ee_addr);
00232                         return 1;
00233                 } else {
00234                         udelay(1);      
00235                         waittime ++;
00236                 }
00237         }
00238         outl(EEDONE, ee_addr);
00239         return 0;
00240 }
00241 
00242 /**
00243  *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
00244  *      @pci_dev: the sis900 pci device
00245  *      @net_dev: the net device to get address for
00246  *
00247  *      SiS630E model, use APC CMOS RAM to store MAC address.
00248  *      APC CMOS RAM is accessed through ISA bridge.
00249  *      MAC address is read into @net_dev->dev_addr.
00250  */
00251 
00252 static int sis630e_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic __unused)
00253 {
00254 #if 0
00255         u8 reg;
00256         int i;
00257         struct bus_loc bus_loc;
00258         union {
00259             struct bus_dev bus_dev;
00260             struct pci_device isa_bridge;
00261         } u;
00262 
00263         /* find PCI to ISA bridge */
00264         memset(&bus_loc, 0, sizeof(bus_loc));
00265         if ( ! find_by_driver ( &bus_loc, &u.bus_dev, &sis_bridge_driver, 0 ) )
00266             return 0;
00267 
00268         pci_read_config_byte(&u.isa_bridge, 0x48, &reg);
00269         pci_write_config_byte(&u.isa_bridge, 0x48, reg | 0x40);
00270 
00271         for (i = 0; i < ETH_ALEN; i++)
00272         {
00273                 outb(0x09 + i, 0x70);
00274                 ((u8 *)(nic->node_addr))[i] = inb(0x71);
00275         }
00276         pci_write_config_byte(&u.isa_bridge, 0x48, reg & ~0x40);
00277 
00278         return 1;
00279 #endif
00280 
00281         /* Does not work with current bus/device model */
00282         return 0;
00283 }
00284 
00285 /**
00286  *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
00287  *      @pci_dev: the sis900 pci device
00288  *      @net_dev: the net device to get address for
00289  *
00290  *      SiS630E model, use APC CMOS RAM to store MAC address.
00291  *      APC CMOS RAM is accessed through ISA bridge.
00292  *      MAC address is read into @net_dev->dev_addr.
00293  */
00294 
00295 static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
00296 {
00297         u32 rfcrSave;
00298         u32 i;
00299         
00300         
00301         rfcrSave = inl(rfcr + ioaddr);
00302 
00303         outl(rfcrSave | RELOAD, ioaddr + cr);
00304         outl(0, ioaddr + cr);
00305 
00306         /* disable packet filtering before setting filter */
00307         outl(rfcrSave & ~RFEN, rfcr + ioaddr);
00308 
00309         /* load MAC addr to filter data register */
00310         for (i = 0 ; i < 3 ; i++) {
00311                 outl((i << RFADDR_shift), ioaddr + rfcr);
00312                 *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
00313         }
00314 
00315         /* enable packet filitering */
00316         outl(rfcrSave | RFEN, rfcr + ioaddr);
00317 
00318         return 1;
00319 }
00320 
00321 /* 
00322  * Function: sis900_probe
00323  *
00324  * Description: initializes initializes the NIC, retrieves the
00325  *    MAC address of the card, and sets up some globals required by 
00326  *    other routines.
00327  *
00328  * Side effects:
00329  *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
00330  *            leaves the sis900 initialized, and ready to receive packets.
00331  *
00332  * Returns:   struct nic *:          pointer to NIC data structure
00333  */
00334 
00335 static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
00336 
00337     int i;
00338     int found=0;
00339     int phy_addr;
00340     u8 revision;
00341     int ret;
00342 
00343     if (pci->ioaddr == 0)
00344         return 0;
00345 
00346     nic->irqno  = 0;
00347     nic->ioaddr = pci->ioaddr;
00348 
00349     ioaddr  = pci->ioaddr;
00350     vendor  = pci->vendor;
00351     dev_id  = pci->device;
00352 
00353     /* wakeup chip */
00354     pci_write_config_dword(pci, 0x40, 0x00000000);
00355 
00356     adjust_pci_device(pci);
00357 
00358     /* get MAC address */
00359     ret = 0;
00360     pci_read_config_byte(pci, PCI_REVISION, &revision);
00361     
00362     /* save for use later in sis900_reset() */
00363     pci_revision = revision; 
00364 
00365     if (revision == SIS630E_900_REV)
00366         ret = sis630e_get_mac_addr(pci, nic);
00367     else if ((revision > 0x81) && (revision <= 0x90))
00368         ret = sis635_get_mac_addr(pci, nic);
00369     else if (revision == SIS96x_900_REV)
00370         ret = sis96x_get_mac_addr(pci, nic);
00371     else
00372         ret = sis900_get_mac_addr(pci, nic);
00373 
00374     if (ret == 0)
00375     {
00376         printf ("sis900_probe: Error MAC address not found\n");
00377         return 0;
00378     }
00379 
00380     /* 630ET : set the mii access mode as software-mode */
00381     if (revision == SIS630ET_900_REV)
00382         outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
00383 
00384     DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
00385 
00386     /* probe for mii transceiver */
00387     /* search for total of 32 possible mii phy addresses */
00388 
00389     found = 0;
00390     for (phy_addr = 0; phy_addr < 32; phy_addr++) {
00391         u16 mii_status;
00392         u16 phy_id0, phy_id1;
00393 
00394         mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
00395         if (mii_status == 0xffff || mii_status == 0x0000)
00396             /* the mii is not accessible, try next one */
00397             continue;
00398                 
00399         phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
00400         phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
00401 
00402         /* search our mii table for the current mii */ 
00403         for (i = 0; mii_chip_table[i].phy_id1; i++) {
00404 
00405             if ((phy_id0 == mii_chip_table[i].phy_id0) &&
00406                 ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
00407 
00408                 printf("sis900_probe: %s transceiver found at address %d.\n",
00409                        mii_chip_table[i].name, phy_addr);
00410 
00411                 mii.chip_info = &mii_chip_table[i];
00412                 mii.phy_addr  = phy_addr;
00413                 mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
00414                 mii.next      = NULL;
00415 
00416                 found=1;
00417                 break;
00418             }
00419         }
00420     }
00421         
00422     if (found == 0) {
00423         printf("sis900_probe: No MII transceivers found!\n");
00424         return 0;
00425     }
00426 
00427     /* Arbitrarily select the last PHY found as current PHY */
00428     cur_phy = mii.phy_addr;
00429     printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
00430 
00431     /* initialize device */
00432     sis900_init(nic);
00433     nic->nic_op = &sis900_operations;
00434 
00435     return 1;
00436 }
00437 
00438 
00439 
00440 
00441 /* 
00442  * EEPROM Routines:  These functions read and write to EEPROM for 
00443  *    retrieving the MAC address and other configuration information about 
00444  *    the card.
00445  */
00446 
00447 /* Delay between EEPROM clock transitions. */
00448 #define eeprom_delay()  inl(ee_addr)
00449 
00450 
00451 /* Function: sis900_read_eeprom
00452  *
00453  * Description: reads and returns a given location from EEPROM
00454  *
00455  * Arguments: int location:       requested EEPROM location
00456  *
00457  * Returns:   u16:                contents of requested EEPROM location
00458  *
00459  */
00460 
00461 /* Read Serial EEPROM through EEPROM Access Register, Note that location is 
00462    in word (16 bits) unit */
00463 static u16 sis900_read_eeprom(int location)
00464 {
00465     int i;
00466     u16 retval = 0;
00467     long ee_addr = ioaddr + mear;
00468     u32 read_cmd = location | EEread;
00469 
00470     outl(0, ee_addr);
00471     eeprom_delay();
00472     outl(EECS, ee_addr);
00473     eeprom_delay();
00474 
00475     /* Shift the read command (9) bits out. */
00476     for (i = 8; i >= 0; i--) {
00477         u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
00478         outl(dataval, ee_addr);
00479         eeprom_delay();
00480         outl(dataval | EECLK, ee_addr);
00481         eeprom_delay();
00482     }
00483     outl(EECS, ee_addr);
00484     eeprom_delay();
00485 
00486     /* read the 16-bits data in */
00487     for (i = 16; i > 0; i--) {
00488         outl(EECS, ee_addr);
00489         eeprom_delay();
00490         outl(EECS | EECLK, ee_addr);
00491         eeprom_delay();
00492         retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
00493         eeprom_delay();
00494     }
00495                 
00496     /* Terminate the EEPROM access. */
00497     outl(0, ee_addr);
00498     eeprom_delay();
00499 //  outl(EECLK, ee_addr);
00500 
00501     return (retval);
00502 }
00503 
00504 #define sis900_mdio_delay()    inl(mdio_addr)
00505 
00506 
00507 /* 
00508    Read and write the MII management registers using software-generated
00509    serial MDIO protocol. Note that the command bits and data bits are
00510    sent out separately
00511 */
00512 
00513 static void sis900_mdio_idle(long mdio_addr)
00514 {
00515     outl(MDIO | MDDIR, mdio_addr);
00516     sis900_mdio_delay();
00517     outl(MDIO | MDDIR | MDC, mdio_addr);
00518 }
00519 
00520 /* Syncronize the MII management interface by shifting 32 one bits out. */
00521 static void sis900_mdio_reset(long mdio_addr)
00522 {
00523     int i;
00524 
00525     for (i = 31; i >= 0; i--) {
00526         outl(MDDIR | MDIO, mdio_addr);
00527         sis900_mdio_delay();
00528         outl(MDDIR | MDIO | MDC, mdio_addr);
00529         sis900_mdio_delay();
00530     }
00531     return;
00532 }
00533 
00534 static u16 sis900_mdio_read(int phy_id, int location)
00535 {
00536     long mdio_addr = ioaddr + mear;
00537     int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
00538     u16 retval = 0;
00539     int i;
00540 
00541     sis900_mdio_reset(mdio_addr);
00542     sis900_mdio_idle(mdio_addr);
00543 
00544     for (i = 15; i >= 0; i--) {
00545         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
00546         outl(dataval, mdio_addr);
00547         sis900_mdio_delay();
00548         outl(dataval | MDC, mdio_addr);
00549         sis900_mdio_delay();
00550     }
00551 
00552     /* Read the 16 data bits. */
00553     for (i = 16; i > 0; i--) {
00554         outl(0, mdio_addr);
00555         sis900_mdio_delay();
00556         retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
00557         outl(MDC, mdio_addr);
00558         sis900_mdio_delay();
00559     }
00560     outl(0x00, mdio_addr);
00561     return retval;
00562 }
00563 
00564 #if 0
00565 static void sis900_mdio_write(int phy_id, int location, int value)
00566 {
00567     long mdio_addr = ioaddr + mear;
00568     int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
00569     int i;
00570 
00571     sis900_mdio_reset(mdio_addr);
00572     sis900_mdio_idle(mdio_addr);
00573 
00574     /* Shift the command bits out. */
00575     for (i = 15; i >= 0; i--) {
00576         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
00577         outb(dataval, mdio_addr);
00578         sis900_mdio_delay();
00579         outb(dataval | MDC, mdio_addr);
00580         sis900_mdio_delay();
00581     }
00582     sis900_mdio_delay();
00583 
00584     /* Shift the value bits out. */
00585     for (i = 15; i >= 0; i--) {
00586         int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
00587         outl(dataval, mdio_addr);
00588         sis900_mdio_delay();
00589         outl(dataval | MDC, mdio_addr);
00590         sis900_mdio_delay();
00591     }
00592     sis900_mdio_delay();
00593         
00594     /* Clear out extra bits. */
00595     for (i = 2; i > 0; i--) {
00596         outb(0, mdio_addr);
00597         sis900_mdio_delay();
00598         outb(MDC, mdio_addr);
00599         sis900_mdio_delay();
00600     }
00601     outl(0x00, mdio_addr);
00602     return;
00603 }
00604 #endif
00605 
00606 
00607 /* Function: sis900_init
00608  *
00609  * Description: resets the ethernet controller chip and various
00610  *    data structures required for sending and receiving packets.
00611  *    
00612  * Arguments: struct nic *nic:          NIC data structure
00613  *
00614  * returns:   void.
00615  */
00616 
00617 static void
00618 sis900_init(struct nic *nic)
00619 {
00620     /* Soft reset the chip. */
00621     sis900_reset(nic);
00622 
00623     sis900_init_rxfilter(nic);
00624 
00625     sis900_init_txd(nic);
00626     sis900_init_rxd(nic);
00627 
00628     sis900_set_rx_mode(nic);
00629 
00630     sis900_check_mode(nic);
00631 
00632     outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
00633 }
00634 
00635 
00636 /* 
00637  * Function: sis900_reset
00638  *
00639  * Description: disables interrupts and soft resets the controller chip
00640  *
00641  * Arguments: struct nic *nic:          NIC data structure
00642  *
00643  * Returns:   void.
00644  */
00645 
00646 static void 
00647 sis900_reset(struct nic *nic __unused)
00648 {
00649     int i = 0;
00650     u32 status = TxRCMP | RxRCMP;
00651 
00652     outl(0, ioaddr + ier);
00653     outl(0, ioaddr + imr);
00654     outl(0, ioaddr + rfcr);
00655 
00656     outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
00657 
00658     /* Check that the chip has finished the reset. */
00659     while (status && (i++ < 1000)) {
00660         status ^= (inl(isr + ioaddr) & status);
00661     }
00662 
00663     if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
00664             outl(PESEL | RND_CNT, ioaddr + cfg);
00665     else
00666             outl(PESEL, ioaddr + cfg);
00667 }
00668 
00669 
00670 /* Function: sis_init_rxfilter
00671  *
00672  * Description: sets receive filter address to our MAC address
00673  *
00674  * Arguments: struct nic *nic:          NIC data structure
00675  *
00676  * returns:   void.
00677  */
00678 
00679 static void
00680 sis900_init_rxfilter(struct nic *nic)
00681 {
00682     u32 rfcrSave;
00683     int i;
00684         
00685     rfcrSave = inl(rfcr + ioaddr);
00686 
00687     /* disable packet filtering before setting filter */
00688     outl(rfcrSave & ~RFEN, rfcr + ioaddr);
00689 
00690     /* load MAC addr to filter data register */
00691     for (i = 0 ; i < 3 ; i++) {
00692         u32 w;
00693 
00694         w = (u32) *((u16 *)(nic->node_addr)+i);
00695         outl((i << RFADDR_shift), ioaddr + rfcr);
00696         outl(w, ioaddr + rfdr);
00697 
00698         if (sis900_debug > 0)
00699             printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
00700                    i, inl(ioaddr + rfdr));
00701     }
00702 
00703     /* enable packet filitering */
00704     outl(rfcrSave | RFEN, rfcr + ioaddr);
00705 }
00706 
00707 
00708 /* 
00709  * Function: sis_init_txd
00710  *
00711  * Description: initializes the Tx descriptor
00712  *
00713  * Arguments: struct nic *nic:          NIC data structure
00714  *
00715  * returns:   void.
00716  */
00717 
00718 static void
00719 sis900_init_txd(struct nic *nic __unused)
00720 {
00721     txd.link   = (u32) 0;
00722     txd.cmdsts = (u32) 0;
00723     txd.bufptr = virt_to_bus(&txb[0]);
00724 
00725     /* load Transmit Descriptor Register */
00726     outl(virt_to_bus(&txd), ioaddr + txdp); 
00727     if (sis900_debug > 0)
00728         printf("sis900_init_txd: TX descriptor register loaded with: %X\n", 
00729                inl(ioaddr + txdp));
00730 }
00731 
00732 
00733 /* Function: sis_init_rxd
00734  *
00735  * Description: initializes the Rx descriptor ring
00736  *    
00737  * Arguments: struct nic *nic:          NIC data structure
00738  *
00739  * Returns:   void.
00740  */
00741 
00742 static void 
00743 sis900_init_rxd(struct nic *nic __unused) 
00744 { 
00745     int i;
00746 
00747     cur_rx = 0; 
00748 
00749     /* init RX descriptor */
00750     for (i = 0; i < NUM_RX_DESC; i++) {
00751         rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
00752         rxd[i].cmdsts = (u32) RX_BUF_SIZE;
00753         rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
00754         if (sis900_debug > 0)
00755             printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n", 
00756                    i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
00757                    (unsigned int) rxd[i].bufptr);
00758     }
00759 
00760     /* load Receive Descriptor Register */
00761     outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
00762 
00763     if (sis900_debug > 0)
00764         printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", 
00765                inl(ioaddr + rxdp));
00766 
00767 }
00768 
00769 
00770 /* Function: sis_init_rxd
00771  *
00772  * Description: 
00773  *    sets the receive mode to accept all broadcast packets and packets
00774  *    with our MAC address, and reject all multicast packets.      
00775  *    
00776  * Arguments: struct nic *nic:          NIC data structure
00777  *
00778  * Returns:   void.
00779  */
00780 
00781 static void sis900_set_rx_mode(struct nic *nic __unused)
00782 {
00783     int i, table_entries;
00784     u32 rx_mode; 
00785     u16 mc_filter[16] = {0};    /* 256/128 bits multicast hash table */
00786         
00787     if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
00788         table_entries = 16;
00789     else
00790         table_entries = 8;
00791 
00792     /* accept all multicast packet */
00793     rx_mode = RFAAB | RFAAM;
00794     for (i = 0; i < table_entries; i++)
00795                 mc_filter[i] = 0xffff;
00796                                         
00797     /* update Multicast Hash Table in Receive Filter */
00798     for (i = 0; i < table_entries; i++) {
00799         /* why plus 0x04? That makes the correct value for hash table. */
00800         outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
00801         outl(mc_filter[i], ioaddr + rfdr);
00802     }
00803 
00804     /* Accept Broadcast and multicast packets, destination addresses that match 
00805        our MAC address */
00806     outl(RFEN | rx_mode, ioaddr + rfcr);
00807 
00808     return;
00809 }
00810 
00811 
00812 /* Function: sis900_check_mode
00813  *
00814  * Description: checks the state of transmit and receive
00815  *    parameters on the NIC, and updates NIC registers to match
00816  *    
00817  * Arguments: struct nic *nic:          NIC data structure
00818  *
00819  * Returns:   void.
00820  */
00821 
00822 static void
00823 sis900_check_mode(struct nic *nic)
00824 {
00825     int speed, duplex;
00826     u32 tx_flags = 0, rx_flags = 0;
00827 
00828     mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
00829 
00830     if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
00831         tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
00832         rx_flags = DMA_BURST_64 << RxMXDMA_shift;
00833     }
00834     else {
00835             tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
00836             rx_flags = DMA_BURST_512 << RxMXDMA_shift;
00837     }
00838 
00839     if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
00840         rx_flags |= (RxDRNT_10 << RxDRNT_shift);
00841         tx_flags |= (TxDRNT_10 << TxDRNT_shift);
00842     }
00843     else {
00844         rx_flags |= (RxDRNT_100 << RxDRNT_shift);
00845         tx_flags |= (TxDRNT_100 << TxDRNT_shift);
00846     }
00847 
00848     if (duplex == FDX_CAPABLE_FULL_SELECTED) {
00849         tx_flags |= (TxCSI | TxHBI);
00850         rx_flags |= RxATX;
00851     }
00852 
00853     outl (tx_flags, ioaddr + txcfg);
00854     outl (rx_flags, ioaddr + rxcfg);
00855 }
00856 
00857 
00858 /* Function: sis900_read_mode
00859  *
00860  * Description: retrieves and displays speed and duplex
00861  *    parameters from the NIC
00862  *    
00863  * Arguments: struct nic *nic:          NIC data structure
00864  *
00865  * Returns:   void.
00866  */
00867 
00868 static void
00869 sis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00870 {
00871     int i = 0;
00872     u32 status;
00873     u16 phy_id0, phy_id1;
00874         
00875     /* STSOUT register is Latched on Transition, read operation updates it */
00876     do {
00877         status = sis900_mdio_read(phy_addr, MII_STSOUT);
00878     } while (i++ < 2);
00879 
00880     *speed = HW_SPEED_10_MBPS;
00881     *duplex = FDX_CAPABLE_HALF_SELECTED;
00882     
00883     if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
00884         *speed = HW_SPEED_100_MBPS;
00885     if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
00886         *duplex = FDX_CAPABLE_FULL_SELECTED;
00887         
00888     /* Workaround for Realtek RTL8201 PHY issue */
00889     phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
00890     phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
00891     if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
00892         if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
00893             *duplex = FDX_CAPABLE_FULL_SELECTED;
00894         if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
00895             *speed = HW_SPEED_100_MBPS;
00896     }
00897 
00898     if (status & MII_STSOUT_LINK_FAIL)
00899         printf("sis900_read_mode: Media Link Off\n");
00900     else
00901         printf("sis900_read_mode: Media Link On %s %s-duplex \n", 
00902                *speed == HW_SPEED_100_MBPS ? 
00903                "100mbps" : "10mbps",
00904                *duplex == FDX_CAPABLE_FULL_SELECTED ?
00905                "full" : "half");
00906 }
00907 
00908 
00909 /* Function: amd79c901_read_mode
00910  *
00911  * Description: retrieves and displays speed and duplex
00912  *    parameters from the NIC
00913  *    
00914  * Arguments: struct nic *nic:          NIC data structure
00915  *
00916  * Returns:   void.
00917  */
00918 
00919 static void
00920 amd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00921 {
00922     int i;
00923     u16 status;
00924         
00925     for (i = 0; i < 2; i++)
00926         status = sis900_mdio_read(phy_addr, MII_STATUS);
00927 
00928     if (status & MII_STAT_CAN_AUTO) {
00929         /* 10BASE-T PHY */
00930         for (i = 0; i < 2; i++)
00931             status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
00932         if (status & MII_STSSUM_SPD)
00933             *speed = HW_SPEED_100_MBPS;
00934         else
00935             *speed = HW_SPEED_10_MBPS;
00936         if (status & MII_STSSUM_DPLX)
00937             *duplex = FDX_CAPABLE_FULL_SELECTED;
00938         else
00939             *duplex = FDX_CAPABLE_HALF_SELECTED;
00940 
00941         if (status & MII_STSSUM_LINK)
00942             printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", 
00943                    *speed == HW_SPEED_100_MBPS ? 
00944                    "100mbps" : "10mbps",
00945                    *duplex == FDX_CAPABLE_FULL_SELECTED ?
00946                    "full" : "half");
00947         else
00948             printf("amd79c901_read_mode: Media Link Off\n");
00949     }
00950     else {
00951         /* HomePNA */
00952         *speed = HW_SPEED_HOME;
00953         *duplex = FDX_CAPABLE_HALF_SELECTED;
00954         if (status & MII_STAT_LINK)
00955             printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
00956         else
00957             printf("amd79c901_read_mode: Media Link Off\n");
00958     }
00959 }
00960 
00961 
00962 /**
00963  *      ics1893_read_mode: - read media mode for ICS1893 PHY
00964  *      @net_dev: the net device to read mode for
00965  *      @phy_addr: mii phy address
00966  *      @speed: the transmit speed to be determined
00967  *      @duplex: the duplex mode to be determined
00968  *
00969  *      ICS1893 PHY use Quick Poll Detailed Status register
00970  *      to determine the speed and duplex mode for sis900
00971  */
00972 
00973 static void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00974 {
00975         int i = 0;
00976         u32 status;
00977 
00978         /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
00979         for (i = 0; i < 2; i++)
00980                 status = sis900_mdio_read(phy_addr, MII_QPDSTS);
00981 
00982         if (status & MII_STSICS_SPD)
00983                 *speed = HW_SPEED_100_MBPS;
00984         else
00985                 *speed = HW_SPEED_10_MBPS;
00986 
00987         if (status & MII_STSICS_DPLX)
00988                 *duplex = FDX_CAPABLE_FULL_SELECTED;
00989         else
00990                 *duplex = FDX_CAPABLE_HALF_SELECTED;
00991 
00992         if (status & MII_STSICS_LINKSTS)
00993                 printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
00994                        *speed == HW_SPEED_100_MBPS ?
00995                        "100mbps" : "10mbps",
00996                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
00997                        "full" : "half");
00998         else
00999                 printf("ics1893_read_mode: Media Link Off\n");
01000 }
01001 
01002 /**
01003  *      rtl8201_read_mode: - read media mode for rtl8201 phy
01004  *      @nic: the net device to read mode for
01005  *      @phy_addr: mii phy address
01006  *      @speed: the transmit speed to be determined
01007  *      @duplex: the duplex mode to be determined
01008  *
01009  *      read MII_STATUS register from rtl8201 phy
01010  *      to determine the speed and duplex mode for sis900
01011  */
01012 
01013 static void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
01014 {
01015         u32 status;
01016 
01017         status = sis900_mdio_read(phy_addr, MII_STATUS);
01018 
01019         if (status & MII_STAT_CAN_TX_FDX) {
01020                 *speed = HW_SPEED_100_MBPS;
01021                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01022         }
01023         else if (status & MII_STAT_CAN_TX) {
01024                 *speed = HW_SPEED_100_MBPS;
01025                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01026         }
01027         else if (status & MII_STAT_CAN_T_FDX) {
01028                 *speed = HW_SPEED_10_MBPS;
01029                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01030         }
01031         else if (status & MII_STAT_CAN_T) {
01032                 *speed = HW_SPEED_10_MBPS;
01033                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01034         }
01035 
01036         if (status & MII_STAT_LINK)
01037                 printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
01038                        *speed == HW_SPEED_100_MBPS ?
01039                        "100mbps" : "10mbps",
01040                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
01041                        "full" : "half");
01042         else
01043                 printf("rtl8201_read_config_mode: Media Link Off\n");
01044 }
01045 
01046 /**
01047  *      vt6103_read_mode: - read media mode for vt6103 phy
01048  *      @nic: the net device to read mode for
01049  *      @phy_addr: mii phy address
01050  *      @speed: the transmit speed to be determined
01051  *      @duplex: the duplex mode to be determined
01052  *
01053  *      read MII_STATUS register from rtl8201 phy
01054  *      to determine the speed and duplex mode for sis900
01055  */
01056 
01057 static void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
01058 {
01059         u32 status;
01060 
01061         status = sis900_mdio_read(phy_addr, MII_STATUS);
01062 
01063         if (status & MII_STAT_CAN_TX_FDX) {
01064                 *speed = HW_SPEED_100_MBPS;
01065                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01066         }
01067         else if (status & MII_STAT_CAN_TX) {
01068                 *speed = HW_SPEED_100_MBPS;
01069                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01070         }
01071         else if (status & MII_STAT_CAN_T_FDX) {
01072                 *speed = HW_SPEED_10_MBPS;
01073                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01074         }
01075         else if (status & MII_STAT_CAN_T) {
01076                 *speed = HW_SPEED_10_MBPS;
01077                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01078         }
01079 
01080         if (status & MII_STAT_LINK)
01081                 printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
01082                        *speed == HW_SPEED_100_MBPS ?
01083                        "100mbps" : "10mbps",
01084                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
01085                        "full" : "half");
01086         else
01087                 printf("vt6103_read_config_mode: Media Link Off\n");
01088 }
01089 
01090 /* Function: sis900_transmit
01091  *
01092  * Description: transmits a packet and waits for completion or timeout.
01093  *
01094  * Arguments: char d[6]:          destination ethernet address.
01095  *            unsigned short t:   ethernet protocol type.
01096  *            unsigned short s:   size of the data-part of the packet.
01097  *            char *p:            the data for the packet.
01098  *    
01099  * Returns:   void.
01100  */
01101 
01102 static void
01103 sis900_transmit(struct nic  *nic,
01104                 const char  *d,     /* Destination */
01105                 unsigned int t,     /* Type */
01106                 unsigned int s,     /* size */
01107                 const char  *p)     /* Packet */
01108 {
01109     u32 to, nstype;
01110     volatile u32 tx_status;
01111     
01112     /* Stop the transmitter */
01113     outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
01114 
01115     /* load Transmit Descriptor Register */
01116     outl(virt_to_bus(&txd), ioaddr + txdp); 
01117     if (sis900_debug > 1)
01118         printf("sis900_transmit: TX descriptor register loaded with: %X\n", 
01119                inl(ioaddr + txdp));
01120 
01121     memcpy(txb, d, ETH_ALEN);
01122     memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
01123     nstype = htons(t);
01124     memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
01125     memcpy(txb + ETH_HLEN, p, s);
01126 
01127     s += ETH_HLEN;
01128     s &= DSIZE;
01129 
01130     if (sis900_debug > 1)
01131         printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
01132 
01133     /* pad to minimum packet size */
01134     while (s < ETH_ZLEN)  
01135         txb[s++] = '\0';
01136 
01137     /* set the transmit buffer descriptor and enable Transmit State Machine */
01138     txd.bufptr = virt_to_bus(&txb[0]);
01139     txd.cmdsts = (u32) OWN | s;
01140 
01141     /* restart the transmitter */
01142     outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
01143 
01144     if (sis900_debug > 1)
01145         printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
01146 
01147     to = currticks() + TX_TIMEOUT;
01148 
01149     while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
01150         /* wait */ ;
01151 
01152     if (currticks() >= to) {
01153         printf("sis900_transmit: TX Timeout! Tx status %X.\n", 
01154                (unsigned int) tx_status);
01155     }
01156     
01157     if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
01158         /* packet unsuccessfully transmited */
01159         printf("sis900_transmit: Transmit error, Tx status %X.\n", 
01160                (unsigned int) tx_status);
01161     }
01162     /* Disable interrupts by clearing the interrupt mask. */
01163     outl(0, ioaddr + imr);
01164 }
01165 
01166 
01167 /* Function: sis900_poll
01168  *
01169  * Description: checks for a received packet and returns it if found.
01170  *
01171  * Arguments: struct nic *nic:          NIC data structure
01172  *
01173  * Returns:   1 if a packet was received.
01174  *            0 if no packet was received.
01175  *
01176  * Side effects:
01177  *            Returns (copies) the packet to the array nic->packet.
01178  *            Returns the length of the packet in nic->packetlen.
01179  */
01180 
01181 static int
01182 sis900_poll(struct nic *nic, int retrieve)
01183 {
01184     u32 rx_status = rxd[cur_rx].cmdsts;
01185     int retstat = 0;
01186 
01187      /* acknowledge interrupts by reading interrupt status register */
01188     inl(ioaddr + isr);
01189 
01190     if (sis900_debug > 2)
01191         printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, 
01192                (unsigned int) rx_status);
01193 
01194     if (!(rx_status & OWN))
01195         return retstat;
01196 
01197     if (sis900_debug > 1)
01198         printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
01199                cur_rx, (unsigned int) rx_status);
01200 
01201     if ( ! retrieve ) return 1;
01202     
01203     nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
01204 
01205     if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
01206         /* corrupted packet received */
01207         printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
01208                (unsigned int) rx_status);
01209         retstat = 0;
01210     } else {
01211         /* give packet to higher level routine */
01212         memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
01213         retstat = 1;
01214     }
01215 
01216     /* return the descriptor and buffer to receive ring */
01217     rxd[cur_rx].cmdsts = RX_BUF_SIZE;
01218     rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
01219         
01220     if (++cur_rx == NUM_RX_DESC)
01221         cur_rx = 0;
01222 
01223     /* re-enable the potentially idle receive state machine */
01224     outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
01225 
01226     return retstat;
01227 
01228 }
01229 
01230 
01231 /* Function: sis900_disable
01232  *
01233  * Description: Turns off interrupts and stops Tx and Rx engines
01234  *    
01235  * Arguments: struct nic *nic:          NIC data structure
01236  *
01237  * Returns:   void.
01238  */
01239 
01240 static void
01241 sis900_disable ( struct nic *nic ) {
01242 
01243     sis900_init(nic);
01244 
01245     /* Disable interrupts by clearing the interrupt mask. */
01246     outl(0, ioaddr + imr);
01247     outl(0, ioaddr + ier);
01248     
01249     /* Stop the chip's Tx and Rx Status Machine */
01250     outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
01251 }
01252 
01253 
01254 /* Function: sis900_irq
01255  *
01256  * Description: Enable, Disable, or Force, interrupts
01257  *    
01258  * Arguments: struct nic *nic:          NIC data structure
01259  *            irq_action_t action:      Requested action       
01260  *
01261  * Returns:   void.
01262  */
01263 
01264 static void
01265 sis900_irq(struct nic *nic __unused, irq_action_t action __unused)
01266 {
01267   switch ( action ) {
01268   case DISABLE :
01269     outl(0, ioaddr + imr);
01270     break;
01271   case ENABLE :
01272     outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
01273     break;
01274   case FORCE :
01275     break;
01276   }
01277 }
01278 
01279 static struct nic_operations sis900_operations = {
01280         .connect        = dummy_connect,
01281         .poll           = sis900_poll,
01282         .transmit       = sis900_transmit,
01283         .irq            = sis900_irq,
01284 };
01285 
01286 static struct pci_device_id sis900_nics[] = {
01287 PCI_ROM(0x1039, 0x0900, "sis900",  "SIS900", 0),
01288 PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016", 0),
01289 };
01290 
01291 PCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
01292 
01293 DRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
01294          sis900_probe, sis900_disable );
01295 
01296 /*
01297  * Local variables:
01298  *  c-basic-offset: 8
01299  *  c-indent-level: 8
01300  *  tab-width: 8
01301  * End:
01302  */