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