xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/davicom.c (revision 8044:b3af80bbf173)
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