1*8044SWilliam.Kucharski@Sun.COM #ifdef ALLMULTI
2*8044SWilliam.Kucharski@Sun.COM #error multicast support is not yet implemented
3*8044SWilliam.Kucharski@Sun.COM #endif
4*8044SWilliam.Kucharski@Sun.COM /*
5*8044SWilliam.Kucharski@Sun.COM DAVICOM DM9009/DM9102/DM9102A Etherboot Driver V1.00
6*8044SWilliam.Kucharski@Sun.COM
7*8044SWilliam.Kucharski@Sun.COM This driver was ported from Marty Connor's Tulip Etherboot driver.
8*8044SWilliam.Kucharski@Sun.COM Thanks Marty Connor (mdc@etherboot.org)
9*8044SWilliam.Kucharski@Sun.COM
10*8044SWilliam.Kucharski@Sun.COM This davicom etherboot driver supports DM9009/DM9102/DM9102A/
11*8044SWilliam.Kucharski@Sun.COM DM9102A+DM9801/DM9102A+DM9802 NICs.
12*8044SWilliam.Kucharski@Sun.COM
13*8044SWilliam.Kucharski@Sun.COM This software may be used and distributed according to the terms
14*8044SWilliam.Kucharski@Sun.COM of the GNU Public License, incorporated herein by reference.
15*8044SWilliam.Kucharski@Sun.COM
16*8044SWilliam.Kucharski@Sun.COM */
17*8044SWilliam.Kucharski@Sun.COM
18*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
19*8044SWilliam.Kucharski@Sun.COM /* Revision History */
20*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
21*8044SWilliam.Kucharski@Sun.COM
22*8044SWilliam.Kucharski@Sun.COM /*
23*8044SWilliam.Kucharski@Sun.COM 19 OCT 2000 Sten 1.00
24*8044SWilliam.Kucharski@Sun.COM Different half and full duplex mode
25*8044SWilliam.Kucharski@Sun.COM Do the different programming for DM9801/DM9802
26*8044SWilliam.Kucharski@Sun.COM
27*8044SWilliam.Kucharski@Sun.COM 12 OCT 2000 Sten 0.90
28*8044SWilliam.Kucharski@Sun.COM This driver was ported from tulip driver and it
29*8044SWilliam.Kucharski@Sun.COM has the following difference.
30*8044SWilliam.Kucharski@Sun.COM Changed symbol tulip/TULIP to davicom/DAVICOM
31*8044SWilliam.Kucharski@Sun.COM Deleted some code that did not use in this driver.
32*8044SWilliam.Kucharski@Sun.COM Used chain-strcture to replace ring structure
33*8044SWilliam.Kucharski@Sun.COM for both TX/RX descriptor.
34*8044SWilliam.Kucharski@Sun.COM Allocated two tx descriptor.
35*8044SWilliam.Kucharski@Sun.COM According current media mode to set operating
36*8044SWilliam.Kucharski@Sun.COM register(CR6)
37*8044SWilliam.Kucharski@Sun.COM */
38*8044SWilliam.Kucharski@Sun.COM
39*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
40*8044SWilliam.Kucharski@Sun.COM /* Declarations */
41*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
42*8044SWilliam.Kucharski@Sun.COM
43*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
44*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
45*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
46*8044SWilliam.Kucharski@Sun.COM
47*8044SWilliam.Kucharski@Sun.COM #undef DAVICOM_DEBUG
48*8044SWilliam.Kucharski@Sun.COM #undef DAVICOM_DEBUG_WHERE
49*8044SWilliam.Kucharski@Sun.COM
50*8044SWilliam.Kucharski@Sun.COM #define TX_TIME_OUT 2*TICKS_PER_SEC
51*8044SWilliam.Kucharski@Sun.COM
52*8044SWilliam.Kucharski@Sun.COM typedef unsigned char u8;
53*8044SWilliam.Kucharski@Sun.COM typedef signed char s8;
54*8044SWilliam.Kucharski@Sun.COM typedef unsigned short u16;
55*8044SWilliam.Kucharski@Sun.COM typedef signed short s16;
56*8044SWilliam.Kucharski@Sun.COM typedef unsigned int u32;
57*8044SWilliam.Kucharski@Sun.COM typedef signed int s32;
58*8044SWilliam.Kucharski@Sun.COM
59*8044SWilliam.Kucharski@Sun.COM /* Register offsets for davicom device */
60*8044SWilliam.Kucharski@Sun.COM enum davicom_offsets {
61*8044SWilliam.Kucharski@Sun.COM CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
62*8044SWilliam.Kucharski@Sun.COM CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
63*8044SWilliam.Kucharski@Sun.COM CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0
64*8044SWilliam.Kucharski@Sun.COM };
65*8044SWilliam.Kucharski@Sun.COM
66*8044SWilliam.Kucharski@Sun.COM /* EEPROM Address width definitions */
67*8044SWilliam.Kucharski@Sun.COM #define EEPROM_ADDRLEN 6
68*8044SWilliam.Kucharski@Sun.COM #define EEPROM_SIZE 32 /* 1 << EEPROM_ADDRLEN */
69*8044SWilliam.Kucharski@Sun.COM /* Used to be 128, but we only need to read enough to get the MAC
70*8044SWilliam.Kucharski@Sun.COM address at bytes 20..25 */
71*8044SWilliam.Kucharski@Sun.COM
72*8044SWilliam.Kucharski@Sun.COM /* Data Read from the EEPROM */
73*8044SWilliam.Kucharski@Sun.COM static unsigned char ee_data[EEPROM_SIZE];
74*8044SWilliam.Kucharski@Sun.COM
75*8044SWilliam.Kucharski@Sun.COM /* The EEPROM commands include the alway-set leading bit. */
76*8044SWilliam.Kucharski@Sun.COM #define EE_WRITE_CMD (5 << addr_len)
77*8044SWilliam.Kucharski@Sun.COM #define EE_READ_CMD (6 << addr_len)
78*8044SWilliam.Kucharski@Sun.COM #define EE_ERASE_CMD (7 << addr_len)
79*8044SWilliam.Kucharski@Sun.COM
80*8044SWilliam.Kucharski@Sun.COM /* EEPROM_Ctrl bits. */
81*8044SWilliam.Kucharski@Sun.COM #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
82*8044SWilliam.Kucharski@Sun.COM #define EE_CS 0x01 /* EEPROM chip select. */
83*8044SWilliam.Kucharski@Sun.COM #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
84*8044SWilliam.Kucharski@Sun.COM #define EE_WRITE_0 0x01
85*8044SWilliam.Kucharski@Sun.COM #define EE_WRITE_1 0x05
86*8044SWilliam.Kucharski@Sun.COM #define EE_DATA_READ 0x08 /* EEPROM chip data out. */
87*8044SWilliam.Kucharski@Sun.COM #define EE_ENB (0x4800 | EE_CS)
88*8044SWilliam.Kucharski@Sun.COM
89*8044SWilliam.Kucharski@Sun.COM /* Sten 10/11 for phyxcer */
90*8044SWilliam.Kucharski@Sun.COM #define PHY_DATA_0 0x0
91*8044SWilliam.Kucharski@Sun.COM #define PHY_DATA_1 0x20000
92*8044SWilliam.Kucharski@Sun.COM #define MDCLKH 0x10000
93*8044SWilliam.Kucharski@Sun.COM
94*8044SWilliam.Kucharski@Sun.COM /* Delay between EEPROM clock transitions. Even at 33Mhz current PCI
95*8044SWilliam.Kucharski@Sun.COM implementations don't overrun the EEPROM clock. We add a bus
96*8044SWilliam.Kucharski@Sun.COM turn-around to insure that this remains true. */
97*8044SWilliam.Kucharski@Sun.COM #define eeprom_delay() inl(ee_addr)
98*8044SWilliam.Kucharski@Sun.COM
99*8044SWilliam.Kucharski@Sun.COM /* helpful macro if on a big_endian machine for changing byte order.
100*8044SWilliam.Kucharski@Sun.COM not strictly needed on Intel
101*8044SWilliam.Kucharski@Sun.COM Already defined in Etherboot includes
102*8044SWilliam.Kucharski@Sun.COM #define le16_to_cpu(val) (val)
103*8044SWilliam.Kucharski@Sun.COM */
104*8044SWilliam.Kucharski@Sun.COM
105*8044SWilliam.Kucharski@Sun.COM /* transmit and receive descriptor format */
106*8044SWilliam.Kucharski@Sun.COM struct txdesc {
107*8044SWilliam.Kucharski@Sun.COM volatile unsigned long status; /* owner, status */
108*8044SWilliam.Kucharski@Sun.COM unsigned long buf1sz:11, /* size of buffer 1 */
109*8044SWilliam.Kucharski@Sun.COM buf2sz:11, /* size of buffer 2 */
110*8044SWilliam.Kucharski@Sun.COM control:10; /* control bits */
111*8044SWilliam.Kucharski@Sun.COM const unsigned char *buf1addr; /* buffer 1 address */
112*8044SWilliam.Kucharski@Sun.COM const unsigned char *buf2addr; /* buffer 2 address */
113*8044SWilliam.Kucharski@Sun.COM };
114*8044SWilliam.Kucharski@Sun.COM
115*8044SWilliam.Kucharski@Sun.COM struct rxdesc {
116*8044SWilliam.Kucharski@Sun.COM volatile unsigned long status; /* owner, status */
117*8044SWilliam.Kucharski@Sun.COM unsigned long buf1sz:11, /* size of buffer 1 */
118*8044SWilliam.Kucharski@Sun.COM buf2sz:11, /* size of buffer 2 */
119*8044SWilliam.Kucharski@Sun.COM control:10; /* control bits */
120*8044SWilliam.Kucharski@Sun.COM unsigned char *buf1addr; /* buffer 1 address */
121*8044SWilliam.Kucharski@Sun.COM unsigned char *buf2addr; /* buffer 2 address */
122*8044SWilliam.Kucharski@Sun.COM };
123*8044SWilliam.Kucharski@Sun.COM
124*8044SWilliam.Kucharski@Sun.COM /* Size of transmit and receive buffers */
125*8044SWilliam.Kucharski@Sun.COM #define BUFLEN 1536
126*8044SWilliam.Kucharski@Sun.COM
127*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
128*8044SWilliam.Kucharski@Sun.COM /* Global Storage */
129*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
130*8044SWilliam.Kucharski@Sun.COM
131*8044SWilliam.Kucharski@Sun.COM /* PCI Bus parameters */
132*8044SWilliam.Kucharski@Sun.COM static unsigned short vendor, dev_id;
133*8044SWilliam.Kucharski@Sun.COM static unsigned long ioaddr;
134*8044SWilliam.Kucharski@Sun.COM
135*8044SWilliam.Kucharski@Sun.COM /* Note: transmit and receive buffers must be longword aligned and
136*8044SWilliam.Kucharski@Sun.COM longword divisable */
137*8044SWilliam.Kucharski@Sun.COM
138*8044SWilliam.Kucharski@Sun.COM /* transmit descriptor and buffer */
139*8044SWilliam.Kucharski@Sun.COM #define NTXD 2
140*8044SWilliam.Kucharski@Sun.COM static struct txdesc txd[NTXD] __attribute__ ((aligned(4)));
141*8044SWilliam.Kucharski@Sun.COM static unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));
142*8044SWilliam.Kucharski@Sun.COM
143*8044SWilliam.Kucharski@Sun.COM /* receive descriptor(s) and buffer(s) */
144*8044SWilliam.Kucharski@Sun.COM #define NRXD 4
145*8044SWilliam.Kucharski@Sun.COM static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4)));
146*8044SWilliam.Kucharski@Sun.COM static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4)));
147*8044SWilliam.Kucharski@Sun.COM static int rxd_tail;
148*8044SWilliam.Kucharski@Sun.COM static int TxPtr;
149*8044SWilliam.Kucharski@Sun.COM
150*8044SWilliam.Kucharski@Sun.COM
151*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
152*8044SWilliam.Kucharski@Sun.COM /* Function Prototypes */
153*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
154*8044SWilliam.Kucharski@Sun.COM static void whereami(const char *str);
155*8044SWilliam.Kucharski@Sun.COM static int read_eeprom(unsigned long ioaddr, int location, int addr_len);
156*8044SWilliam.Kucharski@Sun.COM static int davicom_probe(struct dev *dev, struct pci_device *pci);
157*8044SWilliam.Kucharski@Sun.COM static void davicom_init_chain(struct nic *nic); /* Sten 10/9 */
158*8044SWilliam.Kucharski@Sun.COM static void davicom_reset(struct nic *nic);
159*8044SWilliam.Kucharski@Sun.COM static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
160*8044SWilliam.Kucharski@Sun.COM unsigned int s, const char *p);
161*8044SWilliam.Kucharski@Sun.COM static int davicom_poll(struct nic *nic, int retrieve);
162*8044SWilliam.Kucharski@Sun.COM static void davicom_disable(struct dev *dev);
163*8044SWilliam.Kucharski@Sun.COM #ifdef DAVICOM_DEBUG
164*8044SWilliam.Kucharski@Sun.COM static void davicom_more(void);
165*8044SWilliam.Kucharski@Sun.COM #endif /* DAVICOM_DEBUG */
166*8044SWilliam.Kucharski@Sun.COM static void davicom_wait(unsigned int nticks);
167*8044SWilliam.Kucharski@Sun.COM static int phy_read(int);
168*8044SWilliam.Kucharski@Sun.COM static void phy_write(int, u16);
169*8044SWilliam.Kucharski@Sun.COM static void phy_write_1bit(u32, u32);
170*8044SWilliam.Kucharski@Sun.COM static int phy_read_1bit(u32);
171*8044SWilliam.Kucharski@Sun.COM static void davicom_media_chk(struct nic *);
172*8044SWilliam.Kucharski@Sun.COM
173*8044SWilliam.Kucharski@Sun.COM
174*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
175*8044SWilliam.Kucharski@Sun.COM /* Utility Routines */
176*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
whereami(const char * str)177*8044SWilliam.Kucharski@Sun.COM static inline void whereami(const char *str)
178*8044SWilliam.Kucharski@Sun.COM {
179*8044SWilliam.Kucharski@Sun.COM printf("%s\n", str);
180*8044SWilliam.Kucharski@Sun.COM /* sleep(2); */
181*8044SWilliam.Kucharski@Sun.COM }
182*8044SWilliam.Kucharski@Sun.COM
183*8044SWilliam.Kucharski@Sun.COM #ifdef DAVICOM_DEBUG
davicom_more()184*8044SWilliam.Kucharski@Sun.COM static void davicom_more()
185*8044SWilliam.Kucharski@Sun.COM {
186*8044SWilliam.Kucharski@Sun.COM printf("\n\n-- more --");
187*8044SWilliam.Kucharski@Sun.COM while (!iskey())
188*8044SWilliam.Kucharski@Sun.COM /* wait */;
189*8044SWilliam.Kucharski@Sun.COM getchar();
190*8044SWilliam.Kucharski@Sun.COM printf("\n\n");
191*8044SWilliam.Kucharski@Sun.COM }
192*8044SWilliam.Kucharski@Sun.COM #endif /* DAVICOM_DEBUG */
193*8044SWilliam.Kucharski@Sun.COM
davicom_wait(unsigned int nticks)194*8044SWilliam.Kucharski@Sun.COM static void davicom_wait(unsigned int nticks)
195*8044SWilliam.Kucharski@Sun.COM {
196*8044SWilliam.Kucharski@Sun.COM unsigned int to = currticks() + nticks;
197*8044SWilliam.Kucharski@Sun.COM while (currticks() < to)
198*8044SWilliam.Kucharski@Sun.COM /* wait */ ;
199*8044SWilliam.Kucharski@Sun.COM }
200*8044SWilliam.Kucharski@Sun.COM
201*8044SWilliam.Kucharski@Sun.COM
202*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
203*8044SWilliam.Kucharski@Sun.COM /* For DAVICOM phyxcer register by MII interface */
204*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
205*8044SWilliam.Kucharski@Sun.COM /*
206*8044SWilliam.Kucharski@Sun.COM Read a word data from phy register
207*8044SWilliam.Kucharski@Sun.COM */
phy_read(int location)208*8044SWilliam.Kucharski@Sun.COM static int phy_read(int location)
209*8044SWilliam.Kucharski@Sun.COM {
210*8044SWilliam.Kucharski@Sun.COM int i, phy_addr=1;
211*8044SWilliam.Kucharski@Sun.COM u16 phy_data;
212*8044SWilliam.Kucharski@Sun.COM u32 io_dcr9;
213*8044SWilliam.Kucharski@Sun.COM
214*8044SWilliam.Kucharski@Sun.COM whereami("phy_read\n");
215*8044SWilliam.Kucharski@Sun.COM
216*8044SWilliam.Kucharski@Sun.COM io_dcr9 = ioaddr + CSR9;
217*8044SWilliam.Kucharski@Sun.COM
218*8044SWilliam.Kucharski@Sun.COM /* Send 33 synchronization clock to Phy controller */
219*8044SWilliam.Kucharski@Sun.COM for (i=0; i<34; i++)
220*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
221*8044SWilliam.Kucharski@Sun.COM
222*8044SWilliam.Kucharski@Sun.COM /* Send start command(01) to Phy */
223*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_0);
224*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
225*8044SWilliam.Kucharski@Sun.COM
226*8044SWilliam.Kucharski@Sun.COM /* Send read command(10) to Phy */
227*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
228*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_0);
229*8044SWilliam.Kucharski@Sun.COM
230*8044SWilliam.Kucharski@Sun.COM /* Send Phy addres */
231*8044SWilliam.Kucharski@Sun.COM for (i=0x10; i>0; i=i>>1)
232*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
233*8044SWilliam.Kucharski@Sun.COM
234*8044SWilliam.Kucharski@Sun.COM /* Send register addres */
235*8044SWilliam.Kucharski@Sun.COM for (i=0x10; i>0; i=i>>1)
236*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
237*8044SWilliam.Kucharski@Sun.COM
238*8044SWilliam.Kucharski@Sun.COM /* Skip transition state */
239*8044SWilliam.Kucharski@Sun.COM phy_read_1bit(io_dcr9);
240*8044SWilliam.Kucharski@Sun.COM
241*8044SWilliam.Kucharski@Sun.COM /* read 16bit data */
242*8044SWilliam.Kucharski@Sun.COM for (phy_data=0, i=0; i<16; i++) {
243*8044SWilliam.Kucharski@Sun.COM phy_data<<=1;
244*8044SWilliam.Kucharski@Sun.COM phy_data|=phy_read_1bit(io_dcr9);
245*8044SWilliam.Kucharski@Sun.COM }
246*8044SWilliam.Kucharski@Sun.COM
247*8044SWilliam.Kucharski@Sun.COM return phy_data;
248*8044SWilliam.Kucharski@Sun.COM }
249*8044SWilliam.Kucharski@Sun.COM
250*8044SWilliam.Kucharski@Sun.COM /*
251*8044SWilliam.Kucharski@Sun.COM Write a word to Phy register
252*8044SWilliam.Kucharski@Sun.COM */
phy_write(int location,u16 phy_data)253*8044SWilliam.Kucharski@Sun.COM static void phy_write(int location, u16 phy_data)
254*8044SWilliam.Kucharski@Sun.COM {
255*8044SWilliam.Kucharski@Sun.COM u16 i, phy_addr=1;
256*8044SWilliam.Kucharski@Sun.COM u32 io_dcr9;
257*8044SWilliam.Kucharski@Sun.COM
258*8044SWilliam.Kucharski@Sun.COM whereami("phy_write\n");
259*8044SWilliam.Kucharski@Sun.COM
260*8044SWilliam.Kucharski@Sun.COM io_dcr9 = ioaddr + CSR9;
261*8044SWilliam.Kucharski@Sun.COM
262*8044SWilliam.Kucharski@Sun.COM /* Send 33 synchronization clock to Phy controller */
263*8044SWilliam.Kucharski@Sun.COM for (i=0; i<34; i++)
264*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
265*8044SWilliam.Kucharski@Sun.COM
266*8044SWilliam.Kucharski@Sun.COM /* Send start command(01) to Phy */
267*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_0);
268*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
269*8044SWilliam.Kucharski@Sun.COM
270*8044SWilliam.Kucharski@Sun.COM /* Send write command(01) to Phy */
271*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_0);
272*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
273*8044SWilliam.Kucharski@Sun.COM
274*8044SWilliam.Kucharski@Sun.COM /* Send Phy addres */
275*8044SWilliam.Kucharski@Sun.COM for (i=0x10; i>0; i=i>>1)
276*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
277*8044SWilliam.Kucharski@Sun.COM
278*8044SWilliam.Kucharski@Sun.COM /* Send register addres */
279*8044SWilliam.Kucharski@Sun.COM for (i=0x10; i>0; i=i>>1)
280*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
281*8044SWilliam.Kucharski@Sun.COM
282*8044SWilliam.Kucharski@Sun.COM /* written trasnition */
283*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_1);
284*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, PHY_DATA_0);
285*8044SWilliam.Kucharski@Sun.COM
286*8044SWilliam.Kucharski@Sun.COM /* Write a word data to PHY controller */
287*8044SWilliam.Kucharski@Sun.COM for (i=0x8000; i>0; i>>=1)
288*8044SWilliam.Kucharski@Sun.COM phy_write_1bit(io_dcr9, phy_data&i ? PHY_DATA_1: PHY_DATA_0);
289*8044SWilliam.Kucharski@Sun.COM }
290*8044SWilliam.Kucharski@Sun.COM
291*8044SWilliam.Kucharski@Sun.COM /*
292*8044SWilliam.Kucharski@Sun.COM Write one bit data to Phy Controller
293*8044SWilliam.Kucharski@Sun.COM */
phy_write_1bit(u32 ee_addr,u32 phy_data)294*8044SWilliam.Kucharski@Sun.COM static void phy_write_1bit(u32 ee_addr, u32 phy_data)
295*8044SWilliam.Kucharski@Sun.COM {
296*8044SWilliam.Kucharski@Sun.COM whereami("phy_write_1bit\n");
297*8044SWilliam.Kucharski@Sun.COM outl(phy_data, ee_addr); /* MII Clock Low */
298*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
299*8044SWilliam.Kucharski@Sun.COM outl(phy_data|MDCLKH, ee_addr); /* MII Clock High */
300*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
301*8044SWilliam.Kucharski@Sun.COM outl(phy_data, ee_addr); /* MII Clock Low */
302*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
303*8044SWilliam.Kucharski@Sun.COM }
304*8044SWilliam.Kucharski@Sun.COM
305*8044SWilliam.Kucharski@Sun.COM /*
306*8044SWilliam.Kucharski@Sun.COM Read one bit phy data from PHY controller
307*8044SWilliam.Kucharski@Sun.COM */
phy_read_1bit(u32 ee_addr)308*8044SWilliam.Kucharski@Sun.COM static int phy_read_1bit(u32 ee_addr)
309*8044SWilliam.Kucharski@Sun.COM {
310*8044SWilliam.Kucharski@Sun.COM int phy_data;
311*8044SWilliam.Kucharski@Sun.COM
312*8044SWilliam.Kucharski@Sun.COM whereami("phy_read_1bit\n");
313*8044SWilliam.Kucharski@Sun.COM
314*8044SWilliam.Kucharski@Sun.COM outl(0x50000, ee_addr);
315*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
316*8044SWilliam.Kucharski@Sun.COM
317*8044SWilliam.Kucharski@Sun.COM phy_data=(inl(ee_addr)>>19) & 0x1;
318*8044SWilliam.Kucharski@Sun.COM
319*8044SWilliam.Kucharski@Sun.COM outl(0x40000, ee_addr);
320*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
321*8044SWilliam.Kucharski@Sun.COM
322*8044SWilliam.Kucharski@Sun.COM return phy_data;
323*8044SWilliam.Kucharski@Sun.COM }
324*8044SWilliam.Kucharski@Sun.COM
325*8044SWilliam.Kucharski@Sun.COM /*
326*8044SWilliam.Kucharski@Sun.COM DM9801/DM9802 present check and program
327*8044SWilliam.Kucharski@Sun.COM */
HPNA_process(void)328*8044SWilliam.Kucharski@Sun.COM static void HPNA_process(void)
329*8044SWilliam.Kucharski@Sun.COM {
330*8044SWilliam.Kucharski@Sun.COM
331*8044SWilliam.Kucharski@Sun.COM if ( (phy_read(3) & 0xfff0) == 0xb900 ) {
332*8044SWilliam.Kucharski@Sun.COM if ( phy_read(31) == 0x4404 ) {
333*8044SWilliam.Kucharski@Sun.COM /* DM9801 present */
334*8044SWilliam.Kucharski@Sun.COM if (phy_read(3) == 0xb901)
335*8044SWilliam.Kucharski@Sun.COM phy_write(16, 0x5); /* DM9801 E4 */
336*8044SWilliam.Kucharski@Sun.COM else
337*8044SWilliam.Kucharski@Sun.COM phy_write(16, 0x1005); /* DM9801 E3 and others */
338*8044SWilliam.Kucharski@Sun.COM phy_write(25, ((phy_read(24) + 3) & 0xff) | 0xf000);
339*8044SWilliam.Kucharski@Sun.COM } else {
340*8044SWilliam.Kucharski@Sun.COM /* DM9802 present */
341*8044SWilliam.Kucharski@Sun.COM phy_write(16, 0x5);
342*8044SWilliam.Kucharski@Sun.COM phy_write(25, (phy_read(25) & 0xff00) + 2);
343*8044SWilliam.Kucharski@Sun.COM }
344*8044SWilliam.Kucharski@Sun.COM }
345*8044SWilliam.Kucharski@Sun.COM }
346*8044SWilliam.Kucharski@Sun.COM
347*8044SWilliam.Kucharski@Sun.COM /*
348*8044SWilliam.Kucharski@Sun.COM Sense media mode and set CR6
349*8044SWilliam.Kucharski@Sun.COM */
davicom_media_chk(struct nic * nic __unused)350*8044SWilliam.Kucharski@Sun.COM static void davicom_media_chk(struct nic * nic __unused)
351*8044SWilliam.Kucharski@Sun.COM {
352*8044SWilliam.Kucharski@Sun.COM unsigned long to, csr6;
353*8044SWilliam.Kucharski@Sun.COM
354*8044SWilliam.Kucharski@Sun.COM csr6 = 0x00200000; /* SF */
355*8044SWilliam.Kucharski@Sun.COM outl(csr6, ioaddr + CSR6);
356*8044SWilliam.Kucharski@Sun.COM
357*8044SWilliam.Kucharski@Sun.COM if (vendor == PCI_VENDOR_ID_DAVICOM && dev_id == PCI_DEVICE_ID_DM9009) {
358*8044SWilliam.Kucharski@Sun.COM /* Set to 10BaseT mode for DM9009 */
359*8044SWilliam.Kucharski@Sun.COM phy_write(0, 0);
360*8044SWilliam.Kucharski@Sun.COM } else {
361*8044SWilliam.Kucharski@Sun.COM /* For DM9102/DM9102A */
362*8044SWilliam.Kucharski@Sun.COM to = currticks() + 2 * TICKS_PER_SEC;
363*8044SWilliam.Kucharski@Sun.COM while ( ((phy_read(1) & 0x24)!=0x24) && (currticks() < to))
364*8044SWilliam.Kucharski@Sun.COM /* wait */ ;
365*8044SWilliam.Kucharski@Sun.COM
366*8044SWilliam.Kucharski@Sun.COM if ( (phy_read(1) & 0x24) == 0x24 ) {
367*8044SWilliam.Kucharski@Sun.COM if (phy_read(17) & 0xa000)
368*8044SWilliam.Kucharski@Sun.COM csr6 |= 0x00000200; /* Full Duplex mode */
369*8044SWilliam.Kucharski@Sun.COM } else
370*8044SWilliam.Kucharski@Sun.COM csr6 |= 0x00040000; /* Select DM9801/DM9802 when Ethernet link failed */
371*8044SWilliam.Kucharski@Sun.COM }
372*8044SWilliam.Kucharski@Sun.COM
373*8044SWilliam.Kucharski@Sun.COM /* set the chip's operating mode */
374*8044SWilliam.Kucharski@Sun.COM outl(csr6, ioaddr + CSR6);
375*8044SWilliam.Kucharski@Sun.COM
376*8044SWilliam.Kucharski@Sun.COM /* DM9801/DM9802 present check & program */
377*8044SWilliam.Kucharski@Sun.COM if (csr6 & 0x40000)
378*8044SWilliam.Kucharski@Sun.COM HPNA_process();
379*8044SWilliam.Kucharski@Sun.COM }
380*8044SWilliam.Kucharski@Sun.COM
381*8044SWilliam.Kucharski@Sun.COM
382*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
383*8044SWilliam.Kucharski@Sun.COM /* EEPROM Reading Code */
384*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
385*8044SWilliam.Kucharski@Sun.COM /* EEPROM routines adapted from the Linux Tulip Code */
386*8044SWilliam.Kucharski@Sun.COM /* Reading a serial EEPROM is a "bit" grungy, but we work our way
387*8044SWilliam.Kucharski@Sun.COM through:->.
388*8044SWilliam.Kucharski@Sun.COM */
read_eeprom(unsigned long ioaddr,int location,int addr_len)389*8044SWilliam.Kucharski@Sun.COM static int read_eeprom(unsigned long ioaddr, int location, int addr_len)
390*8044SWilliam.Kucharski@Sun.COM {
391*8044SWilliam.Kucharski@Sun.COM int i;
392*8044SWilliam.Kucharski@Sun.COM unsigned short retval = 0;
393*8044SWilliam.Kucharski@Sun.COM long ee_addr = ioaddr + CSR9;
394*8044SWilliam.Kucharski@Sun.COM int read_cmd = location | EE_READ_CMD;
395*8044SWilliam.Kucharski@Sun.COM
396*8044SWilliam.Kucharski@Sun.COM whereami("read_eeprom\n");
397*8044SWilliam.Kucharski@Sun.COM
398*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB & ~EE_CS, ee_addr);
399*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB, ee_addr);
400*8044SWilliam.Kucharski@Sun.COM
401*8044SWilliam.Kucharski@Sun.COM /* Shift the read command bits out. */
402*8044SWilliam.Kucharski@Sun.COM for (i = 4 + addr_len; i >= 0; i--) {
403*8044SWilliam.Kucharski@Sun.COM short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
404*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB | dataval, ee_addr);
405*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
406*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
407*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
408*8044SWilliam.Kucharski@Sun.COM }
409*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB, ee_addr);
410*8044SWilliam.Kucharski@Sun.COM
411*8044SWilliam.Kucharski@Sun.COM for (i = 16; i > 0; i--) {
412*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
413*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
414*8044SWilliam.Kucharski@Sun.COM retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
415*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB, ee_addr);
416*8044SWilliam.Kucharski@Sun.COM eeprom_delay();
417*8044SWilliam.Kucharski@Sun.COM }
418*8044SWilliam.Kucharski@Sun.COM
419*8044SWilliam.Kucharski@Sun.COM /* Terminate the EEPROM access. */
420*8044SWilliam.Kucharski@Sun.COM outl(EE_ENB & ~EE_CS, ee_addr);
421*8044SWilliam.Kucharski@Sun.COM return retval;
422*8044SWilliam.Kucharski@Sun.COM }
423*8044SWilliam.Kucharski@Sun.COM
424*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
425*8044SWilliam.Kucharski@Sun.COM /* davicom_init_chain - setup the tx and rx descriptors */
426*8044SWilliam.Kucharski@Sun.COM /* Sten 10/9 */
427*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_init_chain(struct nic * nic)428*8044SWilliam.Kucharski@Sun.COM static void davicom_init_chain(struct nic *nic)
429*8044SWilliam.Kucharski@Sun.COM {
430*8044SWilliam.Kucharski@Sun.COM int i;
431*8044SWilliam.Kucharski@Sun.COM
432*8044SWilliam.Kucharski@Sun.COM /* setup the transmit descriptor */
433*8044SWilliam.Kucharski@Sun.COM /* Sten: Set 2 TX descriptor but use one TX buffer because
434*8044SWilliam.Kucharski@Sun.COM it transmit a packet and wait complete every time. */
435*8044SWilliam.Kucharski@Sun.COM for (i=0; i<NTXD; i++) {
436*8044SWilliam.Kucharski@Sun.COM txd[i].buf1addr = (void *)virt_to_bus(&txb[0]); /* Used same TX buffer */
437*8044SWilliam.Kucharski@Sun.COM txd[i].buf2addr = (void *)virt_to_bus(&txd[i+1]); /* Point to Next TX desc */
438*8044SWilliam.Kucharski@Sun.COM txd[i].buf1sz = 0;
439*8044SWilliam.Kucharski@Sun.COM txd[i].buf2sz = 0;
440*8044SWilliam.Kucharski@Sun.COM txd[i].control = 0x184; /* Begin/End/Chain */
441*8044SWilliam.Kucharski@Sun.COM txd[i].status = 0x00000000; /* give ownership to Host */
442*8044SWilliam.Kucharski@Sun.COM }
443*8044SWilliam.Kucharski@Sun.COM
444*8044SWilliam.Kucharski@Sun.COM /* construct perfect filter frame with mac address as first match
445*8044SWilliam.Kucharski@Sun.COM and broadcast address for all others */
446*8044SWilliam.Kucharski@Sun.COM for (i=0; i<192; i++) txb[i] = 0xFF;
447*8044SWilliam.Kucharski@Sun.COM txb[0] = nic->node_addr[0];
448*8044SWilliam.Kucharski@Sun.COM txb[1] = nic->node_addr[1];
449*8044SWilliam.Kucharski@Sun.COM txb[4] = nic->node_addr[2];
450*8044SWilliam.Kucharski@Sun.COM txb[5] = nic->node_addr[3];
451*8044SWilliam.Kucharski@Sun.COM txb[8] = nic->node_addr[4];
452*8044SWilliam.Kucharski@Sun.COM txb[9] = nic->node_addr[5];
453*8044SWilliam.Kucharski@Sun.COM
454*8044SWilliam.Kucharski@Sun.COM /* setup receive descriptor */
455*8044SWilliam.Kucharski@Sun.COM for (i=0; i<NRXD; i++) {
456*8044SWilliam.Kucharski@Sun.COM rxd[i].buf1addr = (void *)virt_to_bus(&rxb[i * BUFLEN]);
457*8044SWilliam.Kucharski@Sun.COM rxd[i].buf2addr = (void *)virt_to_bus(&rxd[i+1]); /* Point to Next RX desc */
458*8044SWilliam.Kucharski@Sun.COM rxd[i].buf1sz = BUFLEN;
459*8044SWilliam.Kucharski@Sun.COM rxd[i].buf2sz = 0; /* not used */
460*8044SWilliam.Kucharski@Sun.COM rxd[i].control = 0x4; /* Chain Structure */
461*8044SWilliam.Kucharski@Sun.COM rxd[i].status = 0x80000000; /* give ownership to device */
462*8044SWilliam.Kucharski@Sun.COM }
463*8044SWilliam.Kucharski@Sun.COM
464*8044SWilliam.Kucharski@Sun.COM /* Chain the last descriptor to first */
465*8044SWilliam.Kucharski@Sun.COM txd[NTXD - 1].buf2addr = (void *)virt_to_bus(&txd[0]);
466*8044SWilliam.Kucharski@Sun.COM rxd[NRXD - 1].buf2addr = (void *)virt_to_bus(&rxd[0]);
467*8044SWilliam.Kucharski@Sun.COM TxPtr = 0;
468*8044SWilliam.Kucharski@Sun.COM rxd_tail = 0;
469*8044SWilliam.Kucharski@Sun.COM }
470*8044SWilliam.Kucharski@Sun.COM
471*8044SWilliam.Kucharski@Sun.COM
472*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
473*8044SWilliam.Kucharski@Sun.COM /* davicom_reset - Reset adapter */
474*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_reset(struct nic * nic)475*8044SWilliam.Kucharski@Sun.COM static void davicom_reset(struct nic *nic)
476*8044SWilliam.Kucharski@Sun.COM {
477*8044SWilliam.Kucharski@Sun.COM unsigned long to;
478*8044SWilliam.Kucharski@Sun.COM
479*8044SWilliam.Kucharski@Sun.COM whereami("davicom_reset\n");
480*8044SWilliam.Kucharski@Sun.COM
481*8044SWilliam.Kucharski@Sun.COM /* Stop Tx and RX */
482*8044SWilliam.Kucharski@Sun.COM outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
483*8044SWilliam.Kucharski@Sun.COM
484*8044SWilliam.Kucharski@Sun.COM /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
485*8044SWilliam.Kucharski@Sun.COM outl(0x00000001, ioaddr + CSR0);
486*8044SWilliam.Kucharski@Sun.COM
487*8044SWilliam.Kucharski@Sun.COM davicom_wait(TICKS_PER_SEC);
488*8044SWilliam.Kucharski@Sun.COM
489*8044SWilliam.Kucharski@Sun.COM /* TX/RX descriptor burst */
490*8044SWilliam.Kucharski@Sun.COM outl(0x0C00000, ioaddr + CSR0); /* Sten 10/9 */
491*8044SWilliam.Kucharski@Sun.COM
492*8044SWilliam.Kucharski@Sun.COM /* set up transmit and receive descriptors */
493*8044SWilliam.Kucharski@Sun.COM davicom_init_chain(nic); /* Sten 10/9 */
494*8044SWilliam.Kucharski@Sun.COM
495*8044SWilliam.Kucharski@Sun.COM /* Point to receive descriptor */
496*8044SWilliam.Kucharski@Sun.COM outl(virt_to_bus(&rxd[0]), ioaddr + CSR3);
497*8044SWilliam.Kucharski@Sun.COM outl(virt_to_bus(&txd[0]), ioaddr + CSR4); /* Sten 10/9 */
498*8044SWilliam.Kucharski@Sun.COM
499*8044SWilliam.Kucharski@Sun.COM /* According phyxcer media mode to set CR6,
500*8044SWilliam.Kucharski@Sun.COM DM9102/A phyxcer can auto-detect media mode */
501*8044SWilliam.Kucharski@Sun.COM davicom_media_chk(nic);
502*8044SWilliam.Kucharski@Sun.COM
503*8044SWilliam.Kucharski@Sun.COM /* Prepare Setup Frame Sten 10/9 */
504*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].buf1sz = 192;
505*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].control = 0x024; /* SF/CE */
506*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].status = 0x80000000; /* Give ownership to device */
507*8044SWilliam.Kucharski@Sun.COM
508*8044SWilliam.Kucharski@Sun.COM /* Start Tx */
509*8044SWilliam.Kucharski@Sun.COM outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6);
510*8044SWilliam.Kucharski@Sun.COM /* immediate transmit demand */
511*8044SWilliam.Kucharski@Sun.COM outl(0, ioaddr + CSR1);
512*8044SWilliam.Kucharski@Sun.COM
513*8044SWilliam.Kucharski@Sun.COM to = currticks() + TX_TIME_OUT;
514*8044SWilliam.Kucharski@Sun.COM while ((txd[TxPtr].status & 0x80000000) && (currticks() < to)) /* Sten 10/9 */
515*8044SWilliam.Kucharski@Sun.COM /* wait */ ;
516*8044SWilliam.Kucharski@Sun.COM
517*8044SWilliam.Kucharski@Sun.COM if (currticks() >= to) {
518*8044SWilliam.Kucharski@Sun.COM printf ("TX Setup Timeout!\n");
519*8044SWilliam.Kucharski@Sun.COM }
520*8044SWilliam.Kucharski@Sun.COM /* Point to next TX descriptor */
521*8044SWilliam.Kucharski@Sun.COM TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */
522*8044SWilliam.Kucharski@Sun.COM
523*8044SWilliam.Kucharski@Sun.COM #ifdef DAVICOM_DEBUG
524*8044SWilliam.Kucharski@Sun.COM printf("txd.status = %X\n", txd.status);
525*8044SWilliam.Kucharski@Sun.COM printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT));
526*8044SWilliam.Kucharski@Sun.COM davicom_more();
527*8044SWilliam.Kucharski@Sun.COM #endif
528*8044SWilliam.Kucharski@Sun.COM
529*8044SWilliam.Kucharski@Sun.COM /* enable RX */
530*8044SWilliam.Kucharski@Sun.COM outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6);
531*8044SWilliam.Kucharski@Sun.COM /* immediate poll demand */
532*8044SWilliam.Kucharski@Sun.COM outl(0, ioaddr + CSR2);
533*8044SWilliam.Kucharski@Sun.COM }
534*8044SWilliam.Kucharski@Sun.COM
535*8044SWilliam.Kucharski@Sun.COM
536*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
537*8044SWilliam.Kucharski@Sun.COM /* eth_transmit - Transmit a frame */
538*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)539*8044SWilliam.Kucharski@Sun.COM static void davicom_transmit(struct nic *nic, const char *d, unsigned int t,
540*8044SWilliam.Kucharski@Sun.COM unsigned int s, const char *p)
541*8044SWilliam.Kucharski@Sun.COM {
542*8044SWilliam.Kucharski@Sun.COM unsigned long to;
543*8044SWilliam.Kucharski@Sun.COM
544*8044SWilliam.Kucharski@Sun.COM whereami("davicom_transmit\n");
545*8044SWilliam.Kucharski@Sun.COM
546*8044SWilliam.Kucharski@Sun.COM /* Stop Tx */
547*8044SWilliam.Kucharski@Sun.COM /* outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6); */
548*8044SWilliam.Kucharski@Sun.COM
549*8044SWilliam.Kucharski@Sun.COM /* setup ethernet header */
550*8044SWilliam.Kucharski@Sun.COM memcpy(&txb[0], d, ETH_ALEN); /* DA 6byte */
551*8044SWilliam.Kucharski@Sun.COM memcpy(&txb[ETH_ALEN], nic->node_addr, ETH_ALEN); /* SA 6byte*/
552*8044SWilliam.Kucharski@Sun.COM txb[ETH_ALEN*2] = (t >> 8) & 0xFF; /* Frame type: 2byte */
553*8044SWilliam.Kucharski@Sun.COM txb[ETH_ALEN*2+1] = t & 0xFF;
554*8044SWilliam.Kucharski@Sun.COM memcpy(&txb[ETH_HLEN], p, s); /* Frame data */
555*8044SWilliam.Kucharski@Sun.COM
556*8044SWilliam.Kucharski@Sun.COM /* setup the transmit descriptor */
557*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].buf1sz = ETH_HLEN+s;
558*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].control = 0x00000184; /* LS+FS+CE */
559*8044SWilliam.Kucharski@Sun.COM txd[TxPtr].status = 0x80000000; /* give ownership to device */
560*8044SWilliam.Kucharski@Sun.COM
561*8044SWilliam.Kucharski@Sun.COM /* immediate transmit demand */
562*8044SWilliam.Kucharski@Sun.COM outl(0, ioaddr + CSR1);
563*8044SWilliam.Kucharski@Sun.COM
564*8044SWilliam.Kucharski@Sun.COM to = currticks() + TX_TIME_OUT;
565*8044SWilliam.Kucharski@Sun.COM while ((txd[TxPtr].status & 0x80000000) && (currticks() < to))
566*8044SWilliam.Kucharski@Sun.COM /* wait */ ;
567*8044SWilliam.Kucharski@Sun.COM
568*8044SWilliam.Kucharski@Sun.COM if (currticks() >= to) {
569*8044SWilliam.Kucharski@Sun.COM printf ("TX Timeout!\n");
570*8044SWilliam.Kucharski@Sun.COM }
571*8044SWilliam.Kucharski@Sun.COM
572*8044SWilliam.Kucharski@Sun.COM /* Point to next TX descriptor */
573*8044SWilliam.Kucharski@Sun.COM TxPtr = (++TxPtr >= NTXD) ? 0:TxPtr; /* Sten 10/9 */
574*8044SWilliam.Kucharski@Sun.COM
575*8044SWilliam.Kucharski@Sun.COM }
576*8044SWilliam.Kucharski@Sun.COM
577*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
578*8044SWilliam.Kucharski@Sun.COM /* eth_poll - Wait for a frame */
579*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_poll(struct nic * nic,int retrieve)580*8044SWilliam.Kucharski@Sun.COM static int davicom_poll(struct nic *nic, int retrieve)
581*8044SWilliam.Kucharski@Sun.COM {
582*8044SWilliam.Kucharski@Sun.COM whereami("davicom_poll\n");
583*8044SWilliam.Kucharski@Sun.COM
584*8044SWilliam.Kucharski@Sun.COM if (rxd[rxd_tail].status & 0x80000000)
585*8044SWilliam.Kucharski@Sun.COM return 0;
586*8044SWilliam.Kucharski@Sun.COM
587*8044SWilliam.Kucharski@Sun.COM if ( ! retrieve ) return 1;
588*8044SWilliam.Kucharski@Sun.COM
589*8044SWilliam.Kucharski@Sun.COM whereami("davicom_poll got one\n");
590*8044SWilliam.Kucharski@Sun.COM
591*8044SWilliam.Kucharski@Sun.COM nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
592*8044SWilliam.Kucharski@Sun.COM
593*8044SWilliam.Kucharski@Sun.COM if( rxd[rxd_tail].status & 0x00008000){
594*8044SWilliam.Kucharski@Sun.COM rxd[rxd_tail].status = 0x80000000;
595*8044SWilliam.Kucharski@Sun.COM rxd_tail++;
596*8044SWilliam.Kucharski@Sun.COM if (rxd_tail == NRXD) rxd_tail = 0;
597*8044SWilliam.Kucharski@Sun.COM return 0;
598*8044SWilliam.Kucharski@Sun.COM }
599*8044SWilliam.Kucharski@Sun.COM
600*8044SWilliam.Kucharski@Sun.COM /* copy packet to working buffer */
601*8044SWilliam.Kucharski@Sun.COM /* XXX - this copy could be avoided with a little more work
602*8044SWilliam.Kucharski@Sun.COM but for now we are content with it because the optimised
603*8044SWilliam.Kucharski@Sun.COM memcpy is quite fast */
604*8044SWilliam.Kucharski@Sun.COM
605*8044SWilliam.Kucharski@Sun.COM memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
606*8044SWilliam.Kucharski@Sun.COM
607*8044SWilliam.Kucharski@Sun.COM /* return the descriptor and buffer to receive ring */
608*8044SWilliam.Kucharski@Sun.COM rxd[rxd_tail].status = 0x80000000;
609*8044SWilliam.Kucharski@Sun.COM rxd_tail++;
610*8044SWilliam.Kucharski@Sun.COM if (rxd_tail == NRXD) rxd_tail = 0;
611*8044SWilliam.Kucharski@Sun.COM
612*8044SWilliam.Kucharski@Sun.COM return 1;
613*8044SWilliam.Kucharski@Sun.COM }
614*8044SWilliam.Kucharski@Sun.COM
615*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
616*8044SWilliam.Kucharski@Sun.COM /* eth_disable - Disable the interface */
617*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_disable(struct dev * dev)618*8044SWilliam.Kucharski@Sun.COM static void davicom_disable(struct dev *dev)
619*8044SWilliam.Kucharski@Sun.COM {
620*8044SWilliam.Kucharski@Sun.COM struct nic *nic = (struct nic *)dev;
621*8044SWilliam.Kucharski@Sun.COM whereami("davicom_disable\n");
622*8044SWilliam.Kucharski@Sun.COM
623*8044SWilliam.Kucharski@Sun.COM davicom_reset(nic);
624*8044SWilliam.Kucharski@Sun.COM
625*8044SWilliam.Kucharski@Sun.COM /* disable interrupts */
626*8044SWilliam.Kucharski@Sun.COM outl(0x00000000, ioaddr + CSR7);
627*8044SWilliam.Kucharski@Sun.COM
628*8044SWilliam.Kucharski@Sun.COM /* Stop the chip's Tx and Rx processes. */
629*8044SWilliam.Kucharski@Sun.COM outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
630*8044SWilliam.Kucharski@Sun.COM
631*8044SWilliam.Kucharski@Sun.COM /* Clear the missed-packet counter. */
632*8044SWilliam.Kucharski@Sun.COM (volatile unsigned long)inl(ioaddr + CSR8);
633*8044SWilliam.Kucharski@Sun.COM }
634*8044SWilliam.Kucharski@Sun.COM
635*8044SWilliam.Kucharski@Sun.COM
636*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
637*8044SWilliam.Kucharski@Sun.COM /* eth_irq - enable, disable and force interrupts */
638*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_irq(struct nic * nic __unused,irq_action_t action __unused)639*8044SWilliam.Kucharski@Sun.COM static void davicom_irq(struct nic *nic __unused, irq_action_t action __unused)
640*8044SWilliam.Kucharski@Sun.COM {
641*8044SWilliam.Kucharski@Sun.COM switch ( action ) {
642*8044SWilliam.Kucharski@Sun.COM case DISABLE :
643*8044SWilliam.Kucharski@Sun.COM break;
644*8044SWilliam.Kucharski@Sun.COM case ENABLE :
645*8044SWilliam.Kucharski@Sun.COM break;
646*8044SWilliam.Kucharski@Sun.COM case FORCE :
647*8044SWilliam.Kucharski@Sun.COM break;
648*8044SWilliam.Kucharski@Sun.COM }
649*8044SWilliam.Kucharski@Sun.COM }
650*8044SWilliam.Kucharski@Sun.COM
651*8044SWilliam.Kucharski@Sun.COM
652*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
653*8044SWilliam.Kucharski@Sun.COM /* eth_probe - Look for an adapter */
654*8044SWilliam.Kucharski@Sun.COM /*********************************************************************/
davicom_probe(struct dev * dev,struct pci_device * pci)655*8044SWilliam.Kucharski@Sun.COM static int davicom_probe(struct dev *dev, struct pci_device *pci)
656*8044SWilliam.Kucharski@Sun.COM {
657*8044SWilliam.Kucharski@Sun.COM struct nic *nic = (struct nic *)dev;
658*8044SWilliam.Kucharski@Sun.COM unsigned int i;
659*8044SWilliam.Kucharski@Sun.COM
660*8044SWilliam.Kucharski@Sun.COM whereami("davicom_probe\n");
661*8044SWilliam.Kucharski@Sun.COM
662*8044SWilliam.Kucharski@Sun.COM if (pci->ioaddr == 0)
663*8044SWilliam.Kucharski@Sun.COM return 0;
664*8044SWilliam.Kucharski@Sun.COM
665*8044SWilliam.Kucharski@Sun.COM vendor = pci->vendor;
666*8044SWilliam.Kucharski@Sun.COM dev_id = pci->dev_id;
667*8044SWilliam.Kucharski@Sun.COM ioaddr = pci->ioaddr & ~3;
668*8044SWilliam.Kucharski@Sun.COM
669*8044SWilliam.Kucharski@Sun.COM nic->irqno = 0;
670*8044SWilliam.Kucharski@Sun.COM nic->ioaddr = pci->ioaddr & ~3;
671*8044SWilliam.Kucharski@Sun.COM
672*8044SWilliam.Kucharski@Sun.COM /* wakeup chip */
673*8044SWilliam.Kucharski@Sun.COM pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000);
674*8044SWilliam.Kucharski@Sun.COM
675*8044SWilliam.Kucharski@Sun.COM /* Stop the chip's Tx and Rx processes. */
676*8044SWilliam.Kucharski@Sun.COM outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
677*8044SWilliam.Kucharski@Sun.COM
678*8044SWilliam.Kucharski@Sun.COM /* Clear the missed-packet counter. */
679*8044SWilliam.Kucharski@Sun.COM (volatile unsigned long)inl(ioaddr + CSR8);
680*8044SWilliam.Kucharski@Sun.COM
681*8044SWilliam.Kucharski@Sun.COM /* Get MAC Address */
682*8044SWilliam.Kucharski@Sun.COM /* read EEPROM data */
683*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < sizeof(ee_data)/2; i++)
684*8044SWilliam.Kucharski@Sun.COM ((unsigned short *)ee_data)[i] =
685*8044SWilliam.Kucharski@Sun.COM le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
686*8044SWilliam.Kucharski@Sun.COM
687*8044SWilliam.Kucharski@Sun.COM /* extract MAC address from EEPROM buffer */
688*8044SWilliam.Kucharski@Sun.COM for (i=0; i<ETH_ALEN; i++)
689*8044SWilliam.Kucharski@Sun.COM nic->node_addr[i] = ee_data[20+i];
690*8044SWilliam.Kucharski@Sun.COM
691*8044SWilliam.Kucharski@Sun.COM printf("Davicom %! at ioaddr %#hX\n", nic->node_addr, ioaddr);
692*8044SWilliam.Kucharski@Sun.COM
693*8044SWilliam.Kucharski@Sun.COM /* initialize device */
694*8044SWilliam.Kucharski@Sun.COM davicom_reset(nic);
695*8044SWilliam.Kucharski@Sun.COM
696*8044SWilliam.Kucharski@Sun.COM dev->disable = davicom_disable;
697*8044SWilliam.Kucharski@Sun.COM nic->poll = davicom_poll;
698*8044SWilliam.Kucharski@Sun.COM nic->transmit = davicom_transmit;
699*8044SWilliam.Kucharski@Sun.COM nic->irq = davicom_irq;
700*8044SWilliam.Kucharski@Sun.COM
701*8044SWilliam.Kucharski@Sun.COM return 1;
702*8044SWilliam.Kucharski@Sun.COM }
703*8044SWilliam.Kucharski@Sun.COM
704*8044SWilliam.Kucharski@Sun.COM static struct pci_id davicom_nics[] = {
705*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1282, 0x9100, "davicom9100", "Davicom 9100"),
706*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1282, 0x9102, "davicom9102", "Davicom 9102"),
707*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1282, 0x9009, "davicom9009", "Davicom 9009"),
708*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x1282, 0x9132, "davicom9132", "Davicom 9132"), /* Needs probably some fixing */
709*8044SWilliam.Kucharski@Sun.COM };
710*8044SWilliam.Kucharski@Sun.COM
711*8044SWilliam.Kucharski@Sun.COM struct pci_driver davicom_driver = {
712*8044SWilliam.Kucharski@Sun.COM .type = NIC_DRIVER,
713*8044SWilliam.Kucharski@Sun.COM .name = "DAVICOM",
714*8044SWilliam.Kucharski@Sun.COM .probe = davicom_probe,
715*8044SWilliam.Kucharski@Sun.COM .ids = davicom_nics,
716*8044SWilliam.Kucharski@Sun.COM .id_count = sizeof(davicom_nics)/sizeof(davicom_nics[0]),
717*8044SWilliam.Kucharski@Sun.COM .class = 0,
718*8044SWilliam.Kucharski@Sun.COM };
719