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