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 <gpxe/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     {0,0,0,0}
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)
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         memset ( nic->node_addr, 0, sizeof ( nic->node_addr ) );
00283         return 0;
00284 }
00285 
00286 /**
00287  *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
00288  *      @pci_dev: the sis900 pci device
00289  *      @net_dev: the net device to get address for
00290  *
00291  *      SiS630E model, use APC CMOS RAM to store MAC address.
00292  *      APC CMOS RAM is accessed through ISA bridge.
00293  *      MAC address is read into @net_dev->dev_addr.
00294  */
00295 
00296 static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
00297 {
00298         u32 rfcrSave;
00299         u32 i;
00300         
00301         
00302         rfcrSave = inl(rfcr + ioaddr);
00303 
00304         outl(rfcrSave | RELOAD, ioaddr + cr);
00305         outl(0, ioaddr + cr);
00306 
00307         /* disable packet filtering before setting filter */
00308         outl(rfcrSave & ~RFEN, rfcr + ioaddr);
00309 
00310         /* load MAC addr to filter data register */
00311         for (i = 0 ; i < 3 ; i++) {
00312                 outl((i << RFADDR_shift), ioaddr + rfcr);
00313                 *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
00314         }
00315 
00316         /* enable packet filitering */
00317         outl(rfcrSave | RFEN, rfcr + ioaddr);
00318 
00319         return 1;
00320 }
00321 
00322 /* 
00323  * Function: sis900_probe
00324  *
00325  * Description: initializes initializes the NIC, retrieves the
00326  *    MAC address of the card, and sets up some globals required by 
00327  *    other routines.
00328  *
00329  * Side effects:
00330  *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
00331  *            leaves the sis900 initialized, and ready to recieve packets.
00332  *
00333  * Returns:   struct nic *:          pointer to NIC data structure
00334  */
00335 
00336 static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
00337 
00338     int i;
00339     int found=0;
00340     int phy_addr;
00341     u8 revision;
00342     int ret;
00343 
00344     if (pci->ioaddr == 0)
00345         return 0;
00346 
00347     nic->irqno  = 0;
00348     nic->ioaddr = pci->ioaddr;
00349 
00350     ioaddr  = pci->ioaddr;
00351     vendor  = pci->vendor;
00352     dev_id  = pci->device;
00353 
00354     /* wakeup chip */
00355     pci_write_config_dword(pci, 0x40, 0x00000000);
00356 
00357     adjust_pci_device(pci);
00358 
00359     /* get MAC address */
00360     ret = 0;
00361     pci_read_config_byte(pci, PCI_REVISION, &revision);
00362     
00363     /* save for use later in sis900_reset() */
00364     pci_revision = revision; 
00365 
00366     if (revision == SIS630E_900_REV)
00367         ret = sis630e_get_mac_addr(pci, nic);
00368     else if ((revision > 0x81) && (revision <= 0x90))
00369         ret = sis635_get_mac_addr(pci, nic);
00370     else if (revision == SIS96x_900_REV)
00371         ret = sis96x_get_mac_addr(pci, nic);
00372     else
00373         ret = sis900_get_mac_addr(pci, nic);
00374 
00375     if (ret == 0)
00376     {
00377         printf ("sis900_probe: Error MAC address not found\n");
00378         return 0;
00379     }
00380 
00381     /* 630ET : set the mii access mode as software-mode */
00382     if (revision == SIS630ET_900_REV)
00383         outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
00384 
00385     DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
00386 
00387     /* probe for mii transceiver */
00388     /* search for total of 32 possible mii phy addresses */
00389 
00390     found = 0;
00391     for (phy_addr = 0; phy_addr < 32; phy_addr++) {
00392         u16 mii_status;
00393         u16 phy_id0, phy_id1;
00394 
00395         mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
00396         if (mii_status == 0xffff || mii_status == 0x0000)
00397             /* the mii is not accessable, try next one */
00398             continue;
00399                 
00400         phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
00401         phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
00402 
00403         /* search our mii table for the current mii */ 
00404         for (i = 0; mii_chip_table[i].phy_id1; i++) {
00405 
00406             if ((phy_id0 == mii_chip_table[i].phy_id0) &&
00407                 ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
00408 
00409                 printf("sis900_probe: %s transceiver found at address %d.\n",
00410                        mii_chip_table[i].name, phy_addr);
00411 
00412                 mii.chip_info = &mii_chip_table[i];
00413                 mii.phy_addr  = phy_addr;
00414                 mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
00415                 mii.next      = NULL;
00416 
00417                 found=1;
00418                 break;
00419             }
00420         }
00421     }
00422         
00423     if (found == 0) {
00424         printf("sis900_probe: No MII transceivers found!\n");
00425         return 0;
00426     }
00427 
00428     /* Arbitrarily select the last PHY found as current PHY */
00429     cur_phy = mii.phy_addr;
00430     printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
00431 
00432     /* initialize device */
00433     sis900_init(nic);
00434     nic->nic_op = &sis900_operations;
00435 
00436     return 1;
00437 }
00438 
00439 
00440 
00441 
00442 /* 
00443  * EEPROM Routines:  These functions read and write to EEPROM for 
00444  *    retrieving the MAC address and other configuration information about 
00445  *    the card.
00446  */
00447 
00448 /* Delay between EEPROM clock transitions. */
00449 #define eeprom_delay()  inl(ee_addr)
00450 
00451 
00452 /* Function: sis900_read_eeprom
00453  *
00454  * Description: reads and returns a given location from EEPROM
00455  *
00456  * Arguments: int location:       requested EEPROM location
00457  *
00458  * Returns:   u16:                contents of requested EEPROM location
00459  *
00460  */
00461 
00462 /* Read Serial EEPROM through EEPROM Access Register, Note that location is 
00463    in word (16 bits) unit */
00464 static u16 sis900_read_eeprom(int location)
00465 {
00466     int i;
00467     u16 retval = 0;
00468     long ee_addr = ioaddr + mear;
00469     u32 read_cmd = location | EEread;
00470 
00471     outl(0, ee_addr);
00472     eeprom_delay();
00473     outl(EECS, ee_addr);
00474     eeprom_delay();
00475 
00476     /* Shift the read command (9) bits out. */
00477     for (i = 8; i >= 0; i--) {
00478         u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
00479         outl(dataval, ee_addr);
00480         eeprom_delay();
00481         outl(dataval | EECLK, ee_addr);
00482         eeprom_delay();
00483     }
00484     outl(EECS, ee_addr);
00485     eeprom_delay();
00486 
00487     /* read the 16-bits data in */
00488     for (i = 16; i > 0; i--) {
00489         outl(EECS, ee_addr);
00490         eeprom_delay();
00491         outl(EECS | EECLK, ee_addr);
00492         eeprom_delay();
00493         retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
00494         eeprom_delay();
00495     }
00496                 
00497     /* Terminate the EEPROM access. */
00498     outl(0, ee_addr);
00499     eeprom_delay();
00500 //  outl(EECLK, ee_addr);
00501 
00502     return (retval);
00503 }
00504 
00505 #define sis900_mdio_delay()    inl(mdio_addr)
00506 
00507 
00508 /* 
00509    Read and write the MII management registers using software-generated
00510    serial MDIO protocol. Note that the command bits and data bits are
00511    send out seperately 
00512 */
00513 
00514 static void sis900_mdio_idle(long mdio_addr)
00515 {
00516     outl(MDIO | MDDIR, mdio_addr);
00517     sis900_mdio_delay();
00518     outl(MDIO | MDDIR | MDC, mdio_addr);
00519 }
00520 
00521 /* Syncronize the MII management interface by shifting 32 one bits out. */
00522 static void sis900_mdio_reset(long mdio_addr)
00523 {
00524     int i;
00525 
00526     for (i = 31; i >= 0; i--) {
00527         outl(MDDIR | MDIO, mdio_addr);
00528         sis900_mdio_delay();
00529         outl(MDDIR | MDIO | MDC, mdio_addr);
00530         sis900_mdio_delay();
00531     }
00532     return;
00533 }
00534 
00535 static u16 sis900_mdio_read(int phy_id, int location)
00536 {
00537     long mdio_addr = ioaddr + mear;
00538     int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
00539     u16 retval = 0;
00540     int i;
00541 
00542     sis900_mdio_reset(mdio_addr);
00543     sis900_mdio_idle(mdio_addr);
00544 
00545     for (i = 15; i >= 0; i--) {
00546         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
00547         outl(dataval, mdio_addr);
00548         sis900_mdio_delay();
00549         outl(dataval | MDC, mdio_addr);
00550         sis900_mdio_delay();
00551     }
00552 
00553     /* Read the 16 data bits. */
00554     for (i = 16; i > 0; i--) {
00555         outl(0, mdio_addr);
00556         sis900_mdio_delay();
00557         retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
00558         outl(MDC, mdio_addr);
00559         sis900_mdio_delay();
00560     }
00561     outl(0x00, mdio_addr);
00562     return retval;
00563 }
00564 
00565 #if 0
00566 static void sis900_mdio_write(int phy_id, int location, int value)
00567 {
00568     long mdio_addr = ioaddr + mear;
00569     int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
00570     int i;
00571 
00572     sis900_mdio_reset(mdio_addr);
00573     sis900_mdio_idle(mdio_addr);
00574 
00575     /* Shift the command bits out. */
00576     for (i = 15; i >= 0; i--) {
00577         int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
00578         outb(dataval, mdio_addr);
00579         sis900_mdio_delay();
00580         outb(dataval | MDC, mdio_addr);
00581         sis900_mdio_delay();
00582     }
00583     sis900_mdio_delay();
00584 
00585     /* Shift the value bits out. */
00586     for (i = 15; i >= 0; i--) {
00587         int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
00588         outl(dataval, mdio_addr);
00589         sis900_mdio_delay();
00590         outl(dataval | MDC, mdio_addr);
00591         sis900_mdio_delay();
00592     }
00593     sis900_mdio_delay();
00594         
00595     /* Clear out extra bits. */
00596     for (i = 2; i > 0; i--) {
00597         outb(0, mdio_addr);
00598         sis900_mdio_delay();
00599         outb(MDC, mdio_addr);
00600         sis900_mdio_delay();
00601     }
00602     outl(0x00, mdio_addr);
00603     return;
00604 }
00605 #endif
00606 
00607 
00608 /* Function: sis900_init
00609  *
00610  * Description: resets the ethernet controller chip and various
00611  *    data structures required for sending and receiving packets.
00612  *    
00613  * Arguments: struct nic *nic:          NIC data structure
00614  *
00615  * returns:   void.
00616  */
00617 
00618 static void
00619 sis900_init(struct nic *nic)
00620 {
00621     /* Soft reset the chip. */
00622     sis900_reset(nic);
00623 
00624     sis900_init_rxfilter(nic);
00625 
00626     sis900_init_txd(nic);
00627     sis900_init_rxd(nic);
00628 
00629     sis900_set_rx_mode(nic);
00630 
00631     sis900_check_mode(nic);
00632 
00633     outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
00634 }
00635 
00636 
00637 /* 
00638  * Function: sis900_reset
00639  *
00640  * Description: disables interrupts and soft resets the controller chip
00641  *
00642  * Arguments: struct nic *nic:          NIC data structure
00643  *
00644  * Returns:   void.
00645  */
00646 
00647 static void 
00648 sis900_reset(struct nic *nic __unused)
00649 {
00650     int i = 0;
00651     u32 status = TxRCMP | RxRCMP;
00652 
00653     outl(0, ioaddr + ier);
00654     outl(0, ioaddr + imr);
00655     outl(0, ioaddr + rfcr);
00656 
00657     outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
00658 
00659     /* Check that the chip has finished the reset. */
00660     while (status && (i++ < 1000)) {
00661         status ^= (inl(isr + ioaddr) & status);
00662     }
00663 
00664     if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
00665             outl(PESEL | RND_CNT, ioaddr + cfg);
00666     else
00667             outl(PESEL, ioaddr + cfg);
00668 }
00669 
00670 
00671 /* Function: sis_init_rxfilter
00672  *
00673  * Description: sets receive filter address to our MAC address
00674  *
00675  * Arguments: struct nic *nic:          NIC data structure
00676  *
00677  * returns:   void.
00678  */
00679 
00680 static void
00681 sis900_init_rxfilter(struct nic *nic)
00682 {
00683     u32 rfcrSave;
00684     int i;
00685         
00686     rfcrSave = inl(rfcr + ioaddr);
00687 
00688     /* disable packet filtering before setting filter */
00689     outl(rfcrSave & ~RFEN, rfcr + ioaddr);
00690 
00691     /* load MAC addr to filter data register */
00692     for (i = 0 ; i < 3 ; i++) {
00693         u32 w;
00694 
00695         w = (u32) *((u16 *)(nic->node_addr)+i);
00696         outl((i << RFADDR_shift), ioaddr + rfcr);
00697         outl(w, ioaddr + rfdr);
00698 
00699         if (sis900_debug > 0)
00700             printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
00701                    i, inl(ioaddr + rfdr));
00702     }
00703 
00704     /* enable packet filitering */
00705     outl(rfcrSave | RFEN, rfcr + ioaddr);
00706 }
00707 
00708 
00709 /* 
00710  * Function: sis_init_txd
00711  *
00712  * Description: initializes the Tx descriptor
00713  *
00714  * Arguments: struct nic *nic:          NIC data structure
00715  *
00716  * returns:   void.
00717  */
00718 
00719 static void
00720 sis900_init_txd(struct nic *nic __unused)
00721 {
00722     txd.link   = (u32) 0;
00723     txd.cmdsts = (u32) 0;
00724     txd.bufptr = virt_to_bus(&txb[0]);
00725 
00726     /* load Transmit Descriptor Register */
00727     outl(virt_to_bus(&txd), ioaddr + txdp); 
00728     if (sis900_debug > 0)
00729         printf("sis900_init_txd: TX descriptor register loaded with: %X\n", 
00730                inl(ioaddr + txdp));
00731 }
00732 
00733 
00734 /* Function: sis_init_rxd
00735  *
00736  * Description: initializes the Rx descriptor ring
00737  *    
00738  * Arguments: struct nic *nic:          NIC data structure
00739  *
00740  * Returns:   void.
00741  */
00742 
00743 static void 
00744 sis900_init_rxd(struct nic *nic __unused) 
00745 { 
00746     int i;
00747 
00748     cur_rx = 0; 
00749 
00750     /* init RX descriptor */
00751     for (i = 0; i < NUM_RX_DESC; i++) {
00752         rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
00753         rxd[i].cmdsts = (u32) RX_BUF_SIZE;
00754         rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
00755         if (sis900_debug > 0)
00756             printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n", 
00757                    i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
00758                    (unsigned int) rxd[i].bufptr);
00759     }
00760 
00761     /* load Receive Descriptor Register */
00762     outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
00763 
00764     if (sis900_debug > 0)
00765         printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", 
00766                inl(ioaddr + rxdp));
00767 
00768 }
00769 
00770 
00771 /* Function: sis_init_rxd
00772  *
00773  * Description: 
00774  *    sets the receive mode to accept all broadcast packets and packets
00775  *    with our MAC address, and reject all multicast packets.      
00776  *    
00777  * Arguments: struct nic *nic:          NIC data structure
00778  *
00779  * Returns:   void.
00780  */
00781 
00782 static void sis900_set_rx_mode(struct nic *nic __unused)
00783 {
00784     int i, table_entries;
00785     u32 rx_mode; 
00786     u16 mc_filter[16] = {0};    /* 256/128 bits multicast hash table */
00787         
00788     if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
00789         table_entries = 16;
00790     else
00791         table_entries = 8;
00792 
00793     /* accept all multicast packet */
00794     rx_mode = RFAAB | RFAAM;
00795     for (i = 0; i < table_entries; i++)
00796                 mc_filter[i] = 0xffff;
00797                                         
00798     /* update Multicast Hash Table in Receive Filter */
00799     for (i = 0; i < table_entries; i++) {
00800         /* why plus 0x04? That makes the correct value for hash table. */
00801         outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
00802         outl(mc_filter[i], ioaddr + rfdr);
00803     }
00804 
00805     /* Accept Broadcast and multicast packets, destination addresses that match 
00806        our MAC address */
00807     outl(RFEN | rx_mode, ioaddr + rfcr);
00808 
00809     return;
00810 }
00811 
00812 
00813 /* Function: sis900_check_mode
00814  *
00815  * Description: checks the state of transmit and receive
00816  *    parameters on the NIC, and updates NIC registers to match
00817  *    
00818  * Arguments: struct nic *nic:          NIC data structure
00819  *
00820  * Returns:   void.
00821  */
00822 
00823 static void
00824 sis900_check_mode(struct nic *nic)
00825 {
00826     int speed, duplex;
00827     u32 tx_flags = 0, rx_flags = 0;
00828 
00829     mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
00830 
00831     if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
00832         tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
00833         rx_flags = DMA_BURST_64 << RxMXDMA_shift;
00834     }
00835     else {
00836             tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
00837             rx_flags = DMA_BURST_512 << RxMXDMA_shift;
00838     }
00839 
00840     if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
00841         rx_flags |= (RxDRNT_10 << RxDRNT_shift);
00842         tx_flags |= (TxDRNT_10 << TxDRNT_shift);
00843     }
00844     else {
00845         rx_flags |= (RxDRNT_100 << RxDRNT_shift);
00846         tx_flags |= (TxDRNT_100 << TxDRNT_shift);
00847     }
00848 
00849     if (duplex == FDX_CAPABLE_FULL_SELECTED) {
00850         tx_flags |= (TxCSI | TxHBI);
00851         rx_flags |= RxATX;
00852     }
00853 
00854     outl (tx_flags, ioaddr + txcfg);
00855     outl (rx_flags, ioaddr + rxcfg);
00856 }
00857 
00858 
00859 /* Function: sis900_read_mode
00860  *
00861  * Description: retrieves and displays speed and duplex
00862  *    parameters from the NIC
00863  *    
00864  * Arguments: struct nic *nic:          NIC data structure
00865  *
00866  * Returns:   void.
00867  */
00868 
00869 static void
00870 sis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00871 {
00872     int i = 0;
00873     u32 status;
00874     u16 phy_id0, phy_id1;
00875         
00876     /* STSOUT register is Latched on Transition, read operation updates it */
00877     do {
00878         status = sis900_mdio_read(phy_addr, MII_STSOUT);
00879     } while (i++ < 2);
00880 
00881     *speed = HW_SPEED_10_MBPS;
00882     *duplex = FDX_CAPABLE_HALF_SELECTED;
00883     
00884     if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
00885         *speed = HW_SPEED_100_MBPS;
00886     if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
00887         *duplex = FDX_CAPABLE_FULL_SELECTED;
00888         
00889     /* Workaround for Realtek RTL8201 PHY issue */
00890     phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
00891     phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
00892     if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
00893         if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
00894             *duplex = FDX_CAPABLE_FULL_SELECTED;
00895         if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
00896             *speed = HW_SPEED_100_MBPS;
00897     }
00898 
00899     if (status & MII_STSOUT_LINK_FAIL)
00900         printf("sis900_read_mode: Media Link Off\n");
00901     else
00902         printf("sis900_read_mode: Media Link On %s %s-duplex \n", 
00903                *speed == HW_SPEED_100_MBPS ? 
00904                "100mbps" : "10mbps",
00905                *duplex == FDX_CAPABLE_FULL_SELECTED ?
00906                "full" : "half");
00907 }
00908 
00909 
00910 /* Function: amd79c901_read_mode
00911  *
00912  * Description: retrieves and displays speed and duplex
00913  *    parameters from the NIC
00914  *    
00915  * Arguments: struct nic *nic:          NIC data structure
00916  *
00917  * Returns:   void.
00918  */
00919 
00920 static void
00921 amd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00922 {
00923     int i;
00924     u16 status;
00925         
00926     for (i = 0; i < 2; i++)
00927         status = sis900_mdio_read(phy_addr, MII_STATUS);
00928 
00929     if (status & MII_STAT_CAN_AUTO) {
00930         /* 10BASE-T PHY */
00931         for (i = 0; i < 2; i++)
00932             status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
00933         if (status & MII_STSSUM_SPD)
00934             *speed = HW_SPEED_100_MBPS;
00935         else
00936             *speed = HW_SPEED_10_MBPS;
00937         if (status & MII_STSSUM_DPLX)
00938             *duplex = FDX_CAPABLE_FULL_SELECTED;
00939         else
00940             *duplex = FDX_CAPABLE_HALF_SELECTED;
00941 
00942         if (status & MII_STSSUM_LINK)
00943             printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", 
00944                    *speed == HW_SPEED_100_MBPS ? 
00945                    "100mbps" : "10mbps",
00946                    *duplex == FDX_CAPABLE_FULL_SELECTED ?
00947                    "full" : "half");
00948         else
00949             printf("amd79c901_read_mode: Media Link Off\n");
00950     }
00951     else {
00952         /* HomePNA */
00953         *speed = HW_SPEED_HOME;
00954         *duplex = FDX_CAPABLE_HALF_SELECTED;
00955         if (status & MII_STAT_LINK)
00956             printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
00957         else
00958             printf("amd79c901_read_mode: Media Link Off\n");
00959     }
00960 }
00961 
00962 
00963 /**
00964  *      ics1893_read_mode: - read media mode for ICS1893 PHY
00965  *      @net_dev: the net device to read mode for
00966  *      @phy_addr: mii phy address
00967  *      @speed: the transmit speed to be determined
00968  *      @duplex: the duplex mode to be determined
00969  *
00970  *      ICS1893 PHY use Quick Poll Detailed Status register
00971  *      to determine the speed and duplex mode for sis900
00972  */
00973 
00974 static void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
00975 {
00976         int i = 0;
00977         u32 status;
00978 
00979         /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
00980         for (i = 0; i < 2; i++)
00981                 status = sis900_mdio_read(phy_addr, MII_QPDSTS);
00982 
00983         if (status & MII_STSICS_SPD)
00984                 *speed = HW_SPEED_100_MBPS;
00985         else
00986                 *speed = HW_SPEED_10_MBPS;
00987 
00988         if (status & MII_STSICS_DPLX)
00989                 *duplex = FDX_CAPABLE_FULL_SELECTED;
00990         else
00991                 *duplex = FDX_CAPABLE_HALF_SELECTED;
00992 
00993         if (status & MII_STSICS_LINKSTS)
00994                 printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
00995                        *speed == HW_SPEED_100_MBPS ?
00996                        "100mbps" : "10mbps",
00997                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
00998                        "full" : "half");
00999         else
01000                 printf("ics1893_read_mode: Media Link Off\n");
01001 }
01002 
01003 /**
01004  *      rtl8201_read_mode: - read media mode for rtl8201 phy
01005  *      @nic: the net device to read mode for
01006  *      @phy_addr: mii phy address
01007  *      @speed: the transmit speed to be determined
01008  *      @duplex: the duplex mode to be determined
01009  *
01010  *      read MII_STATUS register from rtl8201 phy
01011  *      to determine the speed and duplex mode for sis900
01012  */
01013 
01014 static void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
01015 {
01016         u32 status;
01017 
01018         status = sis900_mdio_read(phy_addr, MII_STATUS);
01019 
01020         if (status & MII_STAT_CAN_TX_FDX) {
01021                 *speed = HW_SPEED_100_MBPS;
01022                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01023         }
01024         else if (status & MII_STAT_CAN_TX) {
01025                 *speed = HW_SPEED_100_MBPS;
01026                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01027         }
01028         else if (status & MII_STAT_CAN_T_FDX) {
01029                 *speed = HW_SPEED_10_MBPS;
01030                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01031         }
01032         else if (status & MII_STAT_CAN_T) {
01033                 *speed = HW_SPEED_10_MBPS;
01034                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01035         }
01036 
01037         if (status & MII_STAT_LINK)
01038                 printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
01039                        *speed == HW_SPEED_100_MBPS ?
01040                        "100mbps" : "10mbps",
01041                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
01042                        "full" : "half");
01043         else
01044                 printf("rtl8201_read_config_mode: Media Link Off\n");
01045 }
01046 
01047 /**
01048  *      vt6103_read_mode: - read media mode for vt6103 phy
01049  *      @nic: the net device to read mode for
01050  *      @phy_addr: mii phy address
01051  *      @speed: the transmit speed to be determined
01052  *      @duplex: the duplex mode to be determined
01053  *
01054  *      read MII_STATUS register from rtl8201 phy
01055  *      to determine the speed and duplex mode for sis900
01056  */
01057 
01058 static void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
01059 {
01060         u32 status;
01061 
01062         status = sis900_mdio_read(phy_addr, MII_STATUS);
01063 
01064         if (status & MII_STAT_CAN_TX_FDX) {
01065                 *speed = HW_SPEED_100_MBPS;
01066                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01067         }
01068         else if (status & MII_STAT_CAN_TX) {
01069                 *speed = HW_SPEED_100_MBPS;
01070                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01071         }
01072         else if (status & MII_STAT_CAN_T_FDX) {
01073                 *speed = HW_SPEED_10_MBPS;
01074                 *duplex = FDX_CAPABLE_FULL_SELECTED;
01075         }
01076         else if (status & MII_STAT_CAN_T) {
01077                 *speed = HW_SPEED_10_MBPS;
01078                 *duplex = FDX_CAPABLE_HALF_SELECTED;
01079         }
01080 
01081         if (status & MII_STAT_LINK)
01082                 printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
01083                        *speed == HW_SPEED_100_MBPS ?
01084                        "100mbps" : "10mbps",
01085                        *duplex == FDX_CAPABLE_FULL_SELECTED ?
01086                        "full" : "half");
01087         else
01088                 printf("vt6103_read_config_mode: Media Link Off\n");
01089 }
01090 
01091 /* Function: sis900_transmit
01092  *
01093  * Description: transmits a packet and waits for completion or timeout.
01094  *
01095  * Arguments: char d[6]:          destination ethernet address.
01096  *            unsigned short t:   ethernet protocol type.
01097  *            unsigned short s:   size of the data-part of the packet.
01098  *            char *p:            the data for the packet.
01099  *    
01100  * Returns:   void.
01101  */
01102 
01103 static void
01104 sis900_transmit(struct nic  *nic,
01105                 const char  *d,     /* Destination */
01106                 unsigned int t,     /* Type */
01107                 unsigned int s,     /* size */
01108                 const char  *p)     /* Packet */
01109 {
01110     u32 to, nstype;
01111     volatile u32 tx_status;
01112     
01113     /* Stop the transmitter */
01114     outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
01115 
01116     /* load Transmit Descriptor Register */
01117     outl(virt_to_bus(&txd), ioaddr + txdp); 
01118     if (sis900_debug > 1)
01119         printf("sis900_transmit: TX descriptor register loaded with: %X\n", 
01120                inl(ioaddr + txdp));
01121 
01122     memcpy(txb, d, ETH_ALEN);
01123     memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
01124     nstype = htons(t);
01125     memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
01126     memcpy(txb + ETH_HLEN, p, s);
01127 
01128     s += ETH_HLEN;
01129     s &= DSIZE;
01130 
01131     if (sis900_debug > 1)
01132         printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
01133 
01134     /* pad to minimum packet size */
01135     while (s < ETH_ZLEN)  
01136         txb[s++] = '\0';
01137 
01138     /* set the transmit buffer descriptor and enable Transmit State Machine */
01139     txd.bufptr = virt_to_bus(&txb[0]);
01140     txd.cmdsts = (u32) OWN | s;
01141 
01142     /* restart the transmitter */
01143     outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
01144 
01145     if (sis900_debug > 1)
01146         printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
01147 
01148     to = currticks() + TX_TIMEOUT;
01149 
01150     while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
01151         /* wait */ ;
01152 
01153     if (currticks() >= to) {
01154         printf("sis900_transmit: TX Timeout! Tx status %X.\n", 
01155                (unsigned int) tx_status);
01156     }
01157     
01158     if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
01159         /* packet unsuccessfully transmited */
01160         printf("sis900_transmit: Transmit error, Tx status %X.\n", 
01161                (unsigned int) tx_status);
01162     }
01163     /* Disable interrupts by clearing the interrupt mask. */
01164     outl(0, ioaddr + imr);
01165 }
01166 
01167 
01168 /* Function: sis900_poll
01169  *
01170  * Description: checks for a received packet and returns it if found.
01171  *
01172  * Arguments: struct nic *nic:          NIC data structure
01173  *
01174  * Returns:   1 if a packet was recieved.
01175  *            0 if no pacet was recieved.
01176  *
01177  * Side effects:
01178  *            Returns (copies) the packet to the array nic->packet.
01179  *            Returns the length of the packet in nic->packetlen.
01180  */
01181 
01182 static int
01183 sis900_poll(struct nic *nic, int retrieve)
01184 {
01185     u32 rx_status = rxd[cur_rx].cmdsts;
01186     u32 intr_status;
01187     int retstat = 0;
01188 
01189      /* acknowledge interrupts by reading interrupt status register */
01190     intr_status = inl(ioaddr + isr);
01191 
01192     if (sis900_debug > 2)
01193         printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, 
01194                (unsigned int) rx_status);
01195 
01196     if (!(rx_status & OWN))
01197         return retstat;
01198 
01199     if (sis900_debug > 1)
01200         printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
01201                cur_rx, (unsigned int) rx_status);
01202 
01203     if ( ! retrieve ) return 1;
01204     
01205     nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
01206 
01207     if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
01208         /* corrupted packet received */
01209         printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
01210                (unsigned int) rx_status);
01211         retstat = 0;
01212     } else {
01213         /* give packet to higher level routine */
01214         memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
01215         retstat = 1;
01216     }
01217 
01218     /* return the descriptor and buffer to receive ring */
01219     rxd[cur_rx].cmdsts = RX_BUF_SIZE;
01220     rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
01221         
01222     if (++cur_rx == NUM_RX_DESC)
01223         cur_rx = 0;
01224 
01225     /* re-enable the potentially idle receive state machine */
01226     outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
01227 
01228     return retstat;
01229 
01230 }
01231 
01232 
01233 /* Function: sis900_disable
01234  *
01235  * Description: Turns off interrupts and stops Tx and Rx engines
01236  *    
01237  * Arguments: struct nic *nic:          NIC data structure
01238  *
01239  * Returns:   void.
01240  */
01241 
01242 static void
01243 sis900_disable ( struct nic *nic ) {
01244 
01245     sis900_init(nic);
01246 
01247     /* Disable interrupts by clearing the interrupt mask. */
01248     outl(0, ioaddr + imr);
01249     outl(0, ioaddr + ier);
01250     
01251     /* Stop the chip's Tx and Rx Status Machine */
01252     outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
01253 }
01254 
01255 
01256 /* Function: sis900_irq
01257  *
01258  * Description: Enable, Disable, or Force, interrupts
01259  *    
01260  * Arguments: struct nic *nic:          NIC data structure
01261  *            irq_action_t action:      Requested action       
01262  *
01263  * Returns:   void.
01264  */
01265 
01266 static void
01267 sis900_irq(struct nic *nic __unused, irq_action_t action __unused)
01268 {
01269   switch ( action ) {
01270   case DISABLE :
01271     outl(0, ioaddr + imr);
01272     break;
01273   case ENABLE :
01274     outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
01275     break;
01276   case FORCE :
01277     break;
01278   }
01279 }
01280 
01281 static struct nic_operations sis900_operations = {
01282         .connect        = dummy_connect,
01283         .poll           = sis900_poll,
01284         .transmit       = sis900_transmit,
01285         .irq            = sis900_irq,
01286 };
01287 
01288 static struct pci_device_id sis900_nics[] = {
01289 PCI_ROM(0x1039, 0x0900, "sis900",  "SIS900", 0),
01290 PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016", 0),
01291 };
01292 
01293 PCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
01294 
01295 DRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
01296          sis900_probe, sis900_disable );
01297 
01298 /*
01299  * Local variables:
01300  *  c-basic-offset: 8
01301  *  c-indent-level: 8
01302  *  tab-width: 8
01303  * End:
01304  */

Generated on Tue Apr 6 20:01:03 2010 for gPXE by  doxygen 1.5.7.1