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