176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* -*- Mode:C; c-basic-offset:4; -*- */
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   sis900.c: An SiS 900/7016 PCI Fast Ethernet driver for Etherboot
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Copyright (C) 2001 Entity Cyber, Inc.
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Revision:	1.0	March 1, 2001
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Author: Marty Connor (mdc@etherboot.org)
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Adapted from a Linux driver which was written by Donald Becker
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   and modified by Ollie Lho and Chin-Shan Li of SiS Corporation.
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Rewritten for Etherboot by Marty Connor.
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   This software may be used and distributed according to the terms
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   of the GNU Public License (GPL), incorporated herein by reference.
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   References:
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   preliminary Rev. 1.0 Jan. 14, 1998
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   preliminary Rev. 1.0 Nov. 10, 1998
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   preliminary Rev. 1.0 Jan. 18, 1998
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   http://www.sis.com.tw/support/databook.htm */
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2776d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL_ANY );
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Revision History */
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  07 Dec 2003  timlegge - Enabled Multicast Support
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  06 Dec 2003  timlegge - Fixed relocation issue in 5.2
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  04 Jan 2002  Chien-Yu Chen, Doug Ambrisko, Marty Connor  Patch to Etherboot 5.0.5
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     Added support for the SiS 630ET plus various bug fixes from linux kernel
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     source 2.4.17.
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  01 March 2001  mdc     1.0
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     Initial Release.  Tested with PCI based sis900 card and ThinkNIC
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     computer.
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  20 March 2001 P.Koegel
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     added support for sis630e and PHY ICS1893 and RTL8201
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     Testet with SIS730S chipset + ICS1893
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman*/
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Includes */
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "etherboot.h"
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h>
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "nic.h"
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "sis900.h"
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Globals */
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct nic_operations sis900_operations;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis900_debug = 0;
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned short vendor, dev_id;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned long ioaddr;
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u8 pci_revision;
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int cur_phy;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic unsigned int cur_rx;
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct {
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    BufferDesc txd;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    BufferDesc rxd[NUM_RX_DESC];
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned char txb[TX_BUF_SIZE];
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} sis900_bufs __shared;
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define txd sis900_bufs.txd
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define rxd sis900_bufs.rxd
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define txb sis900_bufs.txb
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define rxb sis900_bufs.rxb
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct mac_chip_info {
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *name;
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 vendor_id, device_id, flags;
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int io_size;
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} mac_chip_table[] = {
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    { "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS900,
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    { "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SIS, PCI_DEVICE_ID_SIS7016,
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE},
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {0,0,0,0,0} /* 0 terminated list. */
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void amd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void vt6103_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex);
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct mii_chip_info {
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char * name;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 phy_id0;
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 phy_id1;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void (*read_mode) (struct nic *nic, int phy_addr, int *speed, int *duplex);
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} mii_chip_table[] = {
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"SiS 900 Internal MII PHY", 0x001d, 0x8000, sis900_read_mode},
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"SiS 900 on Foxconn 661 7MI", 0x0143, 0xBC70, sis900_read_mode},
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"AMD 79C901 10BASE-T PHY",  0x0000, 0x6B70, amd79c901_read_mode},
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"AMD 79C901 HomePNA PHY",   0x0000, 0x6B90, amd79c901_read_mode},
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf440,ics1893_read_mode},
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman//  {"NS 83851 PHY",0x2000, 0x5C20, MIX },
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8200,rtl8201_read_mode},
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode},
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {0,0,0,0}
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct mii_phy {
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct mii_phy * next;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct mii_chip_info * chip_info;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int phy_addr;
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 status;
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} mii;
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman// PCI to ISA bridge for SIS640E access
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id pci_isa_bridge_list[] = {
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{ .vendor = 0x1039, .device = 0x0008,
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		.name = "SIS 85C503/5513 PCI to ISA bridge"},
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_DRIVER( sis_bridge_pci_driver, pci_isa_bridge_list, PCI_NO_CLASS );
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct device_driver sis_bridge_driver = {
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    .name = "SIS ISA bridge",
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    .bus_driver = &pci_driver,
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    .bus_driver_info = ( struct bus_driver_info * ) &sis_bridge_pci_driver,
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function Prototypes */
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis900_probe(struct nic *nic,struct pci_device *pci);
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16  sis900_read_eeprom(int location);
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_reset(long mdio_addr);
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_idle(long mdio_addr);
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16  sis900_mdio_read(int phy_id, int location);
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_write(int phy_id, int location, int val);
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_init(struct nic *nic);
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_reset(struct nic *nic);
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_init_rxfilter(struct nic *nic);
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_init_txd(struct nic *nic);
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_init_rxd(struct nic *nic);
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_set_rx_mode(struct nic *nic);
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_check_mode(struct nic *nic);
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_transmit(struct nic *nic, const char *d,
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                            unsigned int t, unsigned int s, const char *p);
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int  sis900_poll(struct nic *nic, int retrieve);
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_disable(struct nic *nic);
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_irq(struct nic *nic, irq_action_t action);
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@pci_dev: the sis900 pci device
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@net_dev: the net device to get address for
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	Older SiS900 and friends, use EEPROM to store MAC address.
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	MAC address is read from read_eeprom() into @net_dev->dev_addr.
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis900_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 signature;
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* check to see if we have sane EEPROM */
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	signature = (u16) sis900_read_eeprom( EEPROMSignature);
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (signature == 0xffff || signature == 0x0000) {
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf ("sis900_probe: Error EERPOM read %hX\n", signature);
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return 0;
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* get MAC address from EEPROM */
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 3; i++)
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 1;
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@pci_dev: the sis900 pci device
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@net_dev: the net device to get address for
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	is shared by
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	by LAN, otherwise is not. After MAC address is read from EEPROM, send
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	EEDONE signal to refuse EEPROM access by LAN.
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	The EEPROM map of SiS962 or SiS963 is different to SiS900.
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	The signature field in SiS962 or SiS963 spec is meaningless.
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	MAC address is read into @net_dev->dev_addr.
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis96x_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 	long ioaddr = net_dev->base_addr; */
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	long ee_addr = ioaddr + mear;
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 waittime = 0;
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("Alternate function\n");
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outl(EEREQ, ee_addr);
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while(waittime < 2000) {
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if(inl(ee_addr) & EEGNT) {
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* get MAC address from EEPROM */
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			for (i = 0; i < 3; i++)
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			        ((u16 *)(nic->node_addr))[i] = sis900_read_eeprom(i+EEPROMMACAddr);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			outl(EEDONE, ee_addr);
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return 1;
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			udelay(1);
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			waittime ++;
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outl(EEDONE, ee_addr);
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	sis630e_get_mac_addr: - Get MAC address for SiS630E model
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@pci_dev: the sis900 pci device
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@net_dev: the net device to get address for
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	SiS630E model, use APC CMOS RAM to store MAC address.
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	APC CMOS RAM is accessed through ISA bridge.
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	MAC address is read into @net_dev->dev_addr.
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis630e_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 reg;
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct bus_loc bus_loc;
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	union {
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    struct bus_dev bus_dev;
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    struct pci_device isa_bridge;
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} u;
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* find PCI to ISA bridge */
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(&bus_loc, 0, sizeof(bus_loc));
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ( ! find_by_driver ( &bus_loc, &u.bus_dev, &sis_bridge_driver, 0 ) )
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return 0;
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_read_config_byte(&u.isa_bridge, 0x48, &reg);
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_write_config_byte(&u.isa_bridge, 0x48, reg | 0x40);
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < ETH_ALEN; i++)
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	{
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		outb(0x09 + i, 0x70);
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		((u8 *)(nic->node_addr))[i] = inb(0x71);
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_write_config_byte(&u.isa_bridge, 0x48, reg & ~0x40);
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 1;
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Does not work with current bus/device model */
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset ( nic->node_addr, 0, sizeof ( nic->node_addr ) );
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      sis630e_get_mac_addr: - Get MAC address for SiS630E model
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      @pci_dev: the sis900 pci device
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      @net_dev: the net device to get address for
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      SiS630E model, use APC CMOS RAM to store MAC address.
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      APC CMOS RAM is accessed through ISA bridge.
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *      MAC address is read into @net_dev->dev_addr.
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic *nic)
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u32 rfcrSave;
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u32 i;
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rfcrSave = inl(rfcr + ioaddr);
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(rfcrSave | RELOAD, ioaddr + cr);
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(0, ioaddr + cr);
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* disable packet filtering before setting filter */
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(rfcrSave & ~RFEN, rfcr + ioaddr);
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* load MAC addr to filter data register */
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        for (i = 0 ; i < 3 ; i++) {
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                outl((i << RFADDR_shift), ioaddr + rfcr);
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                *( ((u16 *)nic->node_addr) + i) = inw(ioaddr + rfdr);
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* enable packet filitering */
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(rfcrSave | RFEN, rfcr + ioaddr);
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return 1;
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Function: sis900_probe
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: initializes initializes the NIC, retrieves the
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    MAC address of the card, and sets up some globals required by
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    other routines.
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Side effects:
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            leaves the sis900 initialized, and ready to recieve packets.
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   struct nic *:          pointer to NIC data structure
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int found=0;
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int phy_addr;
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u8 revision;
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int ret;
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pci->ioaddr == 0)
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return 0;
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nic->irqno  = 0;
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nic->ioaddr = pci->ioaddr;
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ioaddr  = pci->ioaddr;
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    vendor  = pci->vendor;
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dev_id  = pci->device;
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* wakeup chip */
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pci_write_config_dword(pci, 0x40, 0x00000000);
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    adjust_pci_device(pci);
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* get MAC address */
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ret = 0;
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pci_read_config_byte(pci, PCI_REVISION, &revision);
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* save for use later in sis900_reset() */
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pci_revision = revision;
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (revision == SIS630E_900_REV)
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ret = sis630e_get_mac_addr(pci, nic);
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if ((revision > 0x81) && (revision <= 0x90))
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ret = sis635_get_mac_addr(pci, nic);
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (revision == SIS96x_900_REV)
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ret = sis96x_get_mac_addr(pci, nic);
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ret = sis900_get_mac_addr(pci, nic);
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (ret == 0)
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    {
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf ("sis900_probe: Error MAC address not found\n");
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return 0;
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* 630ET : set the mii access mode as software-mode */
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (revision == SIS630ET_900_REV)
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    DBG( "sis900_probe: Vendor:%#hX Device:%#hX\n", vendor, dev_id );
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* probe for mii transceiver */
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* search for total of 32 possible mii phy addresses */
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    found = 0;
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (phy_addr = 0; phy_addr < 32; phy_addr++) {
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u16 mii_status;
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u16 phy_id0, phy_id1;
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (mii_status == 0xffff || mii_status == 0x0000)
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            /* the mii is not accessable, try next one */
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            continue;
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* search our mii table for the current mii */
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        for (i = 0; mii_chip_table[i].phy_id1; i++) {
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            if ((phy_id0 == mii_chip_table[i].phy_id0) &&
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                ((phy_id1 & 0xFFF0) == mii_chip_table[i].phy_id1)){
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                printf("sis900_probe: %s transceiver found at address %d.\n",
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                       mii_chip_table[i].name, phy_addr);
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                mii.chip_info = &mii_chip_table[i];
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                mii.phy_addr  = phy_addr;
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                mii.status    = sis900_mdio_read(phy_addr, MII_STATUS);
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                mii.next      = NULL;
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                found=1;
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                break;
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            }
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (found == 0) {
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_probe: No MII transceivers found!\n");
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return 0;
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Arbitrarily select the last PHY found as current PHY */
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cur_phy = mii.phy_addr;
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("sis900_probe: Using %s as default\n",  mii.chip_info->name);
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* initialize device */
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_init(nic);
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nic->nic_op	= &sis900_operations;
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 1;
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * EEPROM Routines:  These functions read and write to EEPROM for
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    retrieving the MAC address and other configuration information about
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    the card.
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Delay between EEPROM clock transitions. */
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define eeprom_delay()  inl(ee_addr)
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_read_eeprom
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: reads and returns a given location from EEPROM
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: int location:       requested EEPROM location
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   u16:                contents of requested EEPROM location
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Read Serial EEPROM through EEPROM Access Register, Note that location is
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   in word (16 bits) unit */
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 sis900_read_eeprom(int location)
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 retval = 0;
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    long ee_addr = ioaddr + mear;
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 read_cmd = location | EEread;
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ee_addr);
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    eeprom_delay();
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(EECS, ee_addr);
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    eeprom_delay();
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Shift the read command (9) bits out. */
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 8; i >= 0; i--) {
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval, ee_addr);
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        eeprom_delay();
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval | EECLK, ee_addr);
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        eeprom_delay();
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(EECS, ee_addr);
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    eeprom_delay();
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* read the 16-bits data in */
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 16; i > 0; i--) {
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(EECS, ee_addr);
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        eeprom_delay();
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(EECS | EECLK, ee_addr);
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        eeprom_delay();
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        eeprom_delay();
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Terminate the EEPROM access. */
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ee_addr);
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    eeprom_delay();
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman//  outl(EECLK, ee_addr);
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (retval);
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define sis900_mdio_delay()    inl(mdio_addr)
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   Read and write the MII management registers using software-generated
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   serial MDIO protocol. Note that the command bits and data bits are
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   send out seperately
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman*/
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_idle(long mdio_addr)
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(MDIO | MDDIR, mdio_addr);
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_delay();
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(MDIO | MDDIR | MDC, mdio_addr);
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Syncronize the MII management interface by shifting 32 one bits out. */
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_reset(long mdio_addr)
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 31; i >= 0; i--) {
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(MDDIR | MDIO, mdio_addr);
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(MDDIR | MDIO | MDC, mdio_addr);
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 sis900_mdio_read(int phy_id, int location)
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    long mdio_addr = ioaddr + mear;
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 retval = 0;
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_reset(mdio_addr);
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_idle(mdio_addr);
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 15; i >= 0; i--) {
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval, mdio_addr);
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval | MDC, mdio_addr);
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Read the 16 data bits. */
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 16; i > 0; i--) {
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(0, mdio_addr);
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(MDC, mdio_addr);
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0x00, mdio_addr);
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return retval;
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if 0
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_mdio_write(int phy_id, int location, int value)
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    long mdio_addr = ioaddr + mear;
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_reset(mdio_addr);
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_idle(mdio_addr);
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Shift the command bits out. */
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 15; i >= 0; i--) {
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outb(dataval, mdio_addr);
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outb(dataval | MDC, mdio_addr);
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_delay();
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Shift the value bits out. */
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 15; i >= 0; i--) {
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval, mdio_addr);
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(dataval | MDC, mdio_addr);
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_mdio_delay();
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Clear out extra bits. */
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 2; i > 0; i--) {
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outb(0, mdio_addr);
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outb(MDC, mdio_addr);
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sis900_mdio_delay();
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0x00, mdio_addr);
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_init
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: resets the ethernet controller chip and various
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    data structures required for sending and receiving packets.
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * returns:   void.
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_init(struct nic *nic)
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Soft reset the chip. */
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_reset(nic);
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_init_rxfilter(nic);
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_init_txd(nic);
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_init_rxd(nic);
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_set_rx_mode(nic);
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_check_mode(nic);
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(RxENA| inl(ioaddr + cr), ioaddr + cr);
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Function: sis900_reset
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: disables interrupts and soft resets the controller chip
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_reset(struct nic *nic __unused)
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i = 0;
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 status = TxRCMP | RxRCMP;
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + ier);
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + imr);
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + rfcr);
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Check that the chip has finished the reset. */
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (status && (i++ < 1000)) {
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        status ^= (inl(isr + ioaddr) & status);
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if( (pci_revision >= SIS635A_900_REV) || (pci_revision == SIS900B_900_REV) )
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            outl(PESEL | RND_CNT, ioaddr + cfg);
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            outl(PESEL, ioaddr + cfg);
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis_init_rxfilter
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: sets receive filter address to our MAC address
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * returns:   void.
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_init_rxfilter(struct nic *nic)
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 rfcrSave;
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rfcrSave = inl(rfcr + ioaddr);
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* disable packet filtering before setting filter */
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(rfcrSave & ~RFEN, rfcr + ioaddr);
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* load MAC addr to filter data register */
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0 ; i < 3 ; i++) {
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        u32 w;
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        w = (u32) *((u16 *)(nic->node_addr)+i);
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl((i << RFADDR_shift), ioaddr + rfcr);
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(w, ioaddr + rfdr);
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (sis900_debug > 0)
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   i, inl(ioaddr + rfdr));
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* enable packet filitering */
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(rfcrSave | RFEN, rfcr + ioaddr);
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Function: sis_init_txd
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: initializes the Tx descriptor
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * returns:   void.
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_init_txd(struct nic *nic __unused)
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txd.link   = (u32) 0;
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txd.cmdsts = (u32) 0;
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txd.bufptr = virt_to_bus(&txb[0]);
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* load Transmit Descriptor Register */
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(virt_to_bus(&txd), ioaddr + txdp);
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 0)
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_init_txd: TX descriptor register loaded with: %X\n",
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               inl(ioaddr + txdp));
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis_init_rxd
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: initializes the Rx descriptor ring
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_init_rxd(struct nic *nic __unused)
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cur_rx = 0;
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* init RX descriptor */
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < NUM_RX_DESC; i++) {
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rxd[i].link   = virt_to_bus((i+1 < NUM_RX_DESC) ? &rxd[i+1] : &rxd[0]);
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rxd[i].cmdsts = (u32) RX_BUF_SIZE;
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rxd[i].bufptr = virt_to_bus(&rxb[i*RX_BUF_SIZE]);
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (sis900_debug > 0)
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("sis900_init_rxd: rxd[%d]=%p link=%X cmdsts=%X bufptr=%X\n",
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   i, &rxd[i], (unsigned int) rxd[i].link, (unsigned int) rxd[i].cmdsts,
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   (unsigned int) rxd[i].bufptr);
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* load Receive Descriptor Register */
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 0)
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_init_rxd: RX descriptor register loaded with: %X\n",
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               inl(ioaddr + rxdp));
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis_init_rxd
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description:
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    sets the receive mode to accept all broadcast packets and packets
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    with our MAC address, and reject all multicast packets.
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void sis900_set_rx_mode(struct nic *nic __unused)
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i, table_entries;
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 rx_mode;
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 mc_filter[16] = {0};	/* 256/128 bits multicast hash table */
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if((pci_revision == SIS635A_900_REV) || (pci_revision == SIS900B_900_REV))
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	table_entries = 16;
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	table_entries = 8;
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* accept all multicast packet */
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rx_mode = RFAAB | RFAAM;
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < table_entries; i++)
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		mc_filter[i] = 0xffff;
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* update Multicast Hash Table in Receive Filter */
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < table_entries; i++) {
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* why plus 0x04? That makes the correct value for hash table. */
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        outl(mc_filter[i], ioaddr + rfdr);
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Accept Broadcast and multicast packets, destination addresses that match
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       our MAC address */
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(RFEN | rx_mode, ioaddr + rfcr);
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_check_mode
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: checks the state of transmit and receive
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    parameters on the NIC, and updates NIC registers to match
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_check_mode(struct nic *nic)
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int speed, duplex;
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 tx_flags = 0, rx_flags = 0;
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex);
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if( inl(ioaddr + cfg) & EDB_MASTER_EN ) {
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        tx_flags = TxATP | (DMA_BURST_64 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rx_flags = DMA_BURST_64 << RxMXDMA_shift;
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else {
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            tx_flags = TxATP | (DMA_BURST_512 << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift);
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            rx_flags = DMA_BURST_512 << RxMXDMA_shift;
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) {
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rx_flags |= (RxDRNT_10 << RxDRNT_shift);
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        tx_flags |= (TxDRNT_10 << TxDRNT_shift);
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else {
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rx_flags |= (RxDRNT_100 << RxDRNT_shift);
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        tx_flags |= (TxDRNT_100 << TxDRNT_shift);
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (duplex == FDX_CAPABLE_FULL_SELECTED) {
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        tx_flags |= (TxCSI | TxHBI);
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        rx_flags |= RxATX;
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl (tx_flags, ioaddr + txcfg);
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl (rx_flags, ioaddr + rxcfg);
85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_read_mode
86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: retrieves and displays speed and duplex
86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    parameters from the NIC
86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i = 0;
87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 status;
87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 phy_id0, phy_id1;
87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* STSOUT register is Latched on Transition, read operation updates it */
87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    do {
87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        status = sis900_mdio_read(phy_addr, MII_STSOUT);
87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } while (i++ < 2);
88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *speed = HW_SPEED_10_MBPS;
88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *duplex = FDX_CAPABLE_HALF_SELECTED;
88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX))
88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*speed = HW_SPEED_100_MBPS;
88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*duplex = FDX_CAPABLE_FULL_SELECTED;
88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Workaround for Realtek RTL8201 PHY issue */
89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1);
89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){
89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX)
89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *duplex = FDX_CAPABLE_FULL_SELECTED;
89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if(sis900_mdio_read(phy_addr, 0x0019) & 0x01)
89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *speed = HW_SPEED_100_MBPS;
89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status & MII_STSOUT_LINK_FAIL)
90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_read_mode: Media Link Off\n");
90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_read_mode: Media Link On %s %s-duplex \n",
90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               *speed == HW_SPEED_100_MBPS ?
90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               "100mbps" : "10mbps",
90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               *duplex == FDX_CAPABLE_FULL_SELECTED ?
90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               "full" : "half");
90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: amd79c901_read_mode
91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: retrieves and displays speed and duplex
91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    parameters from the NIC
91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanamd79c901_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16 status;
92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (i = 0; i < 2; i++)
92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        status = sis900_mdio_read(phy_addr, MII_STATUS);
92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status & MII_STAT_CAN_AUTO) {
93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* 10BASE-T PHY */
93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        for (i = 0; i < 2; i++)
93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY);
93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (status & MII_STSSUM_SPD)
93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            *speed = HW_SPEED_100_MBPS;
93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        else
93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            *speed = HW_SPEED_10_MBPS;
93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (status & MII_STSSUM_DPLX)
93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            *duplex = FDX_CAPABLE_FULL_SELECTED;
93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        else
94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            *duplex = FDX_CAPABLE_HALF_SELECTED;
94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (status & MII_STSSUM_LINK)
94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("amd79c901_read_mode: Media Link On %s %s-duplex \n",
94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   *speed == HW_SPEED_100_MBPS ?
94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   "100mbps" : "10mbps",
94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   *duplex == FDX_CAPABLE_FULL_SELECTED ?
94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   "full" : "half");
94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        else
94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("amd79c901_read_mode: Media Link Off\n");
95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else {
95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* HomePNA */
95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        *speed = HW_SPEED_HOME;
95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        *duplex = FDX_CAPABLE_HALF_SELECTED;
95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (status & MII_STAT_LINK)
95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n");
95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        else
95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            printf("amd79c901_read_mode: Media Link Off\n");
95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	ics1893_read_mode: - read media mode for ICS1893 PHY
96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@net_dev: the net device to read mode for
96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@phy_addr: mii phy address
96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@speed: the transmit speed to be determined
96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@duplex: the duplex mode to be determined
96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	ICS1893 PHY use Quick Poll Detailed Status register
97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	to determine the speed and duplex mode for sis900
97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ics1893_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i = 0;
97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 status;
97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 2; i++)
98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		status = sis900_mdio_read(phy_addr, MII_QPDSTS);
98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STSICS_SPD)
98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_100_MBPS;
98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_10_MBPS;
98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STSICS_DPLX)
98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_FULL_SELECTED;
99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_HALF_SELECTED;
99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STSICS_LINKSTS)
99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("ics1893_read_mode: Media Link On %s %s-duplex \n",
99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *speed == HW_SPEED_100_MBPS ?
99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "100mbps" : "10mbps",
99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "full" : "half");
99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("ics1893_read_mode: Media Link Off\n");
100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	rtl8201_read_mode: - read media mode for rtl8201 phy
100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@nic: the net device to read mode for
100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@phy_addr: mii phy address
100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@speed: the transmit speed to be determined
100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@duplex: the duplex mode to be determined
100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	read MII_STATUS register from rtl8201 phy
101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	to determine the speed and duplex mode for sis900
101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl8201_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 status;
101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = sis900_mdio_read(phy_addr, MII_STATUS);
101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STAT_CAN_TX_FDX) {
102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_100_MBPS;
102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_FULL_SELECTED;
102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_TX) {
102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_100_MBPS;
102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_HALF_SELECTED;
102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_T_FDX) {
102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_10_MBPS;
103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_FULL_SELECTED;
103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_T) {
103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_10_MBPS;
103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_HALF_SELECTED;
103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STAT_LINK)
103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("rtl8201_read_mode: Media Link On %s %s-duplex \n",
103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *speed == HW_SPEED_100_MBPS ?
104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "100mbps" : "10mbps",
104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "full" : "half");
104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("rtl8201_read_config_mode: Media Link Off\n");
104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	vt6103_read_mode: - read media mode for vt6103 phy
104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@nic: the net device to read mode for
105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@phy_addr: mii phy address
105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@speed: the transmit speed to be determined
105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	@duplex: the duplex mode to be determined
105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	read MII_STATUS register from rtl8201 phy
105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *	to determine the speed and duplex mode for sis900
105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void vt6103_read_mode(struct nic *nic __unused, int phy_addr, int *speed, int *duplex)
105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 status;
106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = sis900_mdio_read(phy_addr, MII_STATUS);
106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STAT_CAN_TX_FDX) {
106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_100_MBPS;
106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_FULL_SELECTED;
106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_TX) {
106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_100_MBPS;
107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_HALF_SELECTED;
107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_T_FDX) {
107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_10_MBPS;
107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_FULL_SELECTED;
107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (status & MII_STAT_CAN_T) {
107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*speed = HW_SPEED_10_MBPS;
107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*duplex = FDX_CAPABLE_HALF_SELECTED;
107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status & MII_STAT_LINK)
108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("vt6103_read_mode: Media Link On %s %s-duplex \n",
108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *speed == HW_SPEED_100_MBPS ?
108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "100mbps" : "10mbps",
108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		       "full" : "half");
108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("vt6103_read_config_mode: Media Link Off\n");
108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_transmit
109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: transmits a packet and waits for completion or timeout.
109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: char d[6]:          destination ethernet address.
109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            unsigned short t:   ethernet protocol type.
109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            unsigned short s:   size of the data-part of the packet.
109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            char *p:            the data for the packet.
109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_transmit(struct nic  *nic,
110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                const char  *d,     /* Destination */
110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                unsigned int t,     /* Type */
110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                unsigned int s,     /* size */
110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                const char  *p)     /* Packet */
110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 to, nstype;
111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    volatile u32 tx_status;
111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Stop the transmitter */
111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* load Transmit Descriptor Register */
111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(virt_to_bus(&txd), ioaddr + txdp);
111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 1)
111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_transmit: TX descriptor register loaded with: %X\n",
112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               inl(ioaddr + txdp));
112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(txb, d, ETH_ALEN);
112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nstype = htons(t);
112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2);
112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(txb + ETH_HLEN, p, s);
112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    s += ETH_HLEN;
112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    s &= DSIZE;
113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 1)
113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t);
113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* pad to minimum packet size */
113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (s < ETH_ZLEN)
113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        txb[s++] = '\0';
113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* set the transmit buffer descriptor and enable Transmit State Machine */
113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txd.bufptr = virt_to_bus(&txb[0]);
114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txd.cmdsts = (u32) OWN | s;
114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* restart the transmitter */
114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 1)
114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s);
114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    to = currticks() + TX_TIMEOUT;
114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* wait */ ;
115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (currticks() >= to) {
115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_transmit: TX Timeout! Tx status %X.\n",
115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       (unsigned int) tx_status);
115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* packet unsuccessfully transmited */
116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_transmit: Transmit error, Tx status %X.\n",
116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       (unsigned int) tx_status);
116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Disable interrupts by clearing the interrupt mask. */
116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + imr);
116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_poll
116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: checks for a received packet and returns it if found.
117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   1 if a packet was recieved.
117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            0 if no pacet was recieved.
117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Side effects:
117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            Returns (copies) the packet to the array nic->packet.
117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            Returns the length of the packet in nic->packetlen.
118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int
118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_poll(struct nic *nic, int retrieve)
118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 rx_status = rxd[cur_rx].cmdsts;
118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32 intr_status;
118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int retstat = 0;
118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     /* acknowledge interrupts by reading interrupt status register */
119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    intr_status = inl(ioaddr + isr);
119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 2)
119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx,
119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       (unsigned int) rx_status);
119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!(rx_status & OWN))
119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return retstat;
119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (sis900_debug > 1)
120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n",
120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               cur_rx, (unsigned int) rx_status);
120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ( ! retrieve ) return 1;
120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    nic->packetlen = (rx_status & DSIZE) - CRC_SIZE;
120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* corrupted packet received */
120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        printf("sis900_poll: Corrupted packet received, buffer status = %X\n",
121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               (unsigned int) rx_status);
121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        retstat = 0;
121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* give packet to higher level routine */
121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen);
121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        retstat = 1;
121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* return the descriptor and buffer to receive ring */
121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rxd[cur_rx].cmdsts = RX_BUF_SIZE;
122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rxd[cur_rx].bufptr = virt_to_bus(&rxb[cur_rx*RX_BUF_SIZE]);
122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (++cur_rx == NUM_RX_DESC)
122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        cur_rx = 0;
122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* re-enable the potentially idle receive state machine */
122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(RxENA | inl(ioaddr + cr), ioaddr + cr);
122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return retstat;
122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_disable
123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: Turns off interrupts and stops Tx and Rx engines
123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_disable ( struct nic *nic ) {
124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sis900_init(nic);
124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Disable interrupts by clearing the interrupt mask. */
124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + imr);
124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + ier);
125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Stop the chip's Tx and Rx Status Machine */
125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(RxDIS | TxDIS | inl(ioaddr + cr), ioaddr + cr);
125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Function: sis900_irq
125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Description: Enable, Disable, or Force, interrupts
125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Arguments: struct nic *nic:          NIC data structure
126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *            irq_action_t action:      Requested action
126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Returns:   void.
126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmansis900_irq(struct nic *nic __unused, irq_action_t action __unused)
126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  switch ( action ) {
127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  case DISABLE :
127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl(0, ioaddr + imr);
127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  case ENABLE :
127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  case FORCE :
127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct nic_operations sis900_operations = {
128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.connect	= dummy_connect,
128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.poll		= sis900_poll,
128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.transmit	= sis900_transmit,
128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.irq		= sis900_irq,
128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id sis900_nics[] = {
128976d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x1039, 0x0900, "sis900",  "SIS900", 0),
129076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016", 0),
129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129376d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanPCI_DRIVER ( sis900_driver, sis900_nics, PCI_NO_CLASS );
129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129576d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanDRIVER ( "SIS900", nic_driver, pci_driver, sis900_driver,
129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	 sis900_probe, sis900_disable );
129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Local variables:
130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  c-basic-offset: 8
130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  c-indent-level: 8
130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  tab-width: 8
130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * End:
130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1305