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