1*8044SWilliam.Kucharski@Sun.COM /*
2*8044SWilliam.Kucharski@Sun.COM * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
3*8044SWilliam.Kucharski@Sun.COM *
4*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
5*8044SWilliam.Kucharski@Sun.COM * All rights reserved.
6*8044SWilliam.Kucharski@Sun.COM * Mar. 14, 2000
7*8044SWilliam.Kucharski@Sun.COM *
8*8044SWilliam.Kucharski@Sun.COM * This software may be used, modified, copied, distributed, and sold, in
9*8044SWilliam.Kucharski@Sun.COM * both source and binary form provided that the above copyright and these
10*8044SWilliam.Kucharski@Sun.COM * terms are retained. Under no circumstances are the authors responsible for
11*8044SWilliam.Kucharski@Sun.COM * the proper functioning of this software, nor do the authors assume any
12*8044SWilliam.Kucharski@Sun.COM * responsibility for damages incurred with its use.
13*8044SWilliam.Kucharski@Sun.COM *
14*8044SWilliam.Kucharski@Sun.COM * This code is based on Martin Renters' etherboot-4.4.3 3c509.c and
15*8044SWilliam.Kucharski@Sun.COM * Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
16*8044SWilliam.Kucharski@Sun.COM *
17*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 1993-1994, David Greenman, Martin Renters.
18*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 1993-1995, Andres Vega Garcia.
19*8044SWilliam.Kucharski@Sun.COM * Copyright (C) 1995, Serge Babkin.
20*8044SWilliam.Kucharski@Sun.COM *
21*8044SWilliam.Kucharski@Sun.COM * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
22*8044SWilliam.Kucharski@Sun.COM *
23*8044SWilliam.Kucharski@Sun.COM * timlegge 08-24-2003 Add Multicast Support
24*8044SWilliam.Kucharski@Sun.COM */
25*8044SWilliam.Kucharski@Sun.COM
26*8044SWilliam.Kucharski@Sun.COM /* #define EDEBUG */
27*8044SWilliam.Kucharski@Sun.COM
28*8044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
29*8044SWilliam.Kucharski@Sun.COM #include "nic.h"
30*8044SWilliam.Kucharski@Sun.COM #include "pci.h"
31*8044SWilliam.Kucharski@Sun.COM #include "3c595.h"
32*8044SWilliam.Kucharski@Sun.COM #include "timer.h"
33*8044SWilliam.Kucharski@Sun.COM
34*8044SWilliam.Kucharski@Sun.COM static unsigned short eth_nic_base;
35*8044SWilliam.Kucharski@Sun.COM static unsigned short vx_connector, vx_connectors;
36*8044SWilliam.Kucharski@Sun.COM
37*8044SWilliam.Kucharski@Sun.COM static struct connector_entry {
38*8044SWilliam.Kucharski@Sun.COM int bit;
39*8044SWilliam.Kucharski@Sun.COM char *name;
40*8044SWilliam.Kucharski@Sun.COM } conn_tab[VX_CONNECTORS] = {
41*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_UTP 0
42*8044SWilliam.Kucharski@Sun.COM { 0x08, "utp"},
43*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_AUI 1
44*8044SWilliam.Kucharski@Sun.COM { 0x20, "aui"},
45*8044SWilliam.Kucharski@Sun.COM /* dummy */
46*8044SWilliam.Kucharski@Sun.COM { 0, "???"},
47*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_BNC 3
48*8044SWilliam.Kucharski@Sun.COM { 0x10, "bnc"},
49*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_TX 4
50*8044SWilliam.Kucharski@Sun.COM { 0x02, "tx"},
51*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_FX 5
52*8044SWilliam.Kucharski@Sun.COM { 0x04, "fx"},
53*8044SWilliam.Kucharski@Sun.COM #define CONNECTOR_MII 6
54*8044SWilliam.Kucharski@Sun.COM { 0x40, "mii"},
55*8044SWilliam.Kucharski@Sun.COM { 0, "???"}
56*8044SWilliam.Kucharski@Sun.COM };
57*8044SWilliam.Kucharski@Sun.COM
58*8044SWilliam.Kucharski@Sun.COM static void vxgetlink(void);
59*8044SWilliam.Kucharski@Sun.COM static void vxsetlink(void);
60*8044SWilliam.Kucharski@Sun.COM
61*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
62*8044SWilliam.Kucharski@Sun.COM ETH_RESET - Reset adapter
63*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
t595_reset(struct nic * nic)64*8044SWilliam.Kucharski@Sun.COM static void t595_reset(struct nic *nic)
65*8044SWilliam.Kucharski@Sun.COM {
66*8044SWilliam.Kucharski@Sun.COM int i;
67*8044SWilliam.Kucharski@Sun.COM
68*8044SWilliam.Kucharski@Sun.COM /***********************************************************
69*8044SWilliam.Kucharski@Sun.COM Reset 3Com 595 card
70*8044SWilliam.Kucharski@Sun.COM *************************************************************/
71*8044SWilliam.Kucharski@Sun.COM
72*8044SWilliam.Kucharski@Sun.COM /* stop card */
73*8044SWilliam.Kucharski@Sun.COM outw(RX_DISABLE, BASE + VX_COMMAND);
74*8044SWilliam.Kucharski@Sun.COM outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
75*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
76*8044SWilliam.Kucharski@Sun.COM outw(TX_DISABLE, BASE + VX_COMMAND);
77*8044SWilliam.Kucharski@Sun.COM outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
78*8044SWilliam.Kucharski@Sun.COM udelay(8000);
79*8044SWilliam.Kucharski@Sun.COM outw(RX_RESET, BASE + VX_COMMAND);
80*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
81*8044SWilliam.Kucharski@Sun.COM outw(TX_RESET, BASE + VX_COMMAND);
82*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
83*8044SWilliam.Kucharski@Sun.COM outw(C_INTR_LATCH, BASE + VX_COMMAND);
84*8044SWilliam.Kucharski@Sun.COM outw(SET_RD_0_MASK, BASE + VX_COMMAND);
85*8044SWilliam.Kucharski@Sun.COM outw(SET_INTR_MASK, BASE + VX_COMMAND);
86*8044SWilliam.Kucharski@Sun.COM outw(SET_RX_FILTER, BASE + VX_COMMAND);
87*8044SWilliam.Kucharski@Sun.COM
88*8044SWilliam.Kucharski@Sun.COM /*
89*8044SWilliam.Kucharski@Sun.COM * initialize card
90*8044SWilliam.Kucharski@Sun.COM */
91*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
92*8044SWilliam.Kucharski@Sun.COM
93*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(0);
94*8044SWilliam.Kucharski@Sun.COM
95*8044SWilliam.Kucharski@Sun.COM /* Disable the card */
96*8044SWilliam.Kucharski@Sun.COM /* outw(0, BASE + VX_W0_CONFIG_CTRL); */
97*8044SWilliam.Kucharski@Sun.COM
98*8044SWilliam.Kucharski@Sun.COM /* Configure IRQ to none */
99*8044SWilliam.Kucharski@Sun.COM /* outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
100*8044SWilliam.Kucharski@Sun.COM
101*8044SWilliam.Kucharski@Sun.COM /* Enable the card */
102*8044SWilliam.Kucharski@Sun.COM /* outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
103*8044SWilliam.Kucharski@Sun.COM
104*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(2);
105*8044SWilliam.Kucharski@Sun.COM
106*8044SWilliam.Kucharski@Sun.COM /* Reload the ether_addr. */
107*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < ETH_ALEN; i++)
108*8044SWilliam.Kucharski@Sun.COM outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
109*8044SWilliam.Kucharski@Sun.COM
110*8044SWilliam.Kucharski@Sun.COM outw(RX_RESET, BASE + VX_COMMAND);
111*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
112*8044SWilliam.Kucharski@Sun.COM outw(TX_RESET, BASE + VX_COMMAND);
113*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
114*8044SWilliam.Kucharski@Sun.COM
115*8044SWilliam.Kucharski@Sun.COM /* Window 1 is operating window */
116*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(1);
117*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 31; i++)
118*8044SWilliam.Kucharski@Sun.COM inb(BASE + VX_W1_TX_STATUS);
119*8044SWilliam.Kucharski@Sun.COM
120*8044SWilliam.Kucharski@Sun.COM outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
121*8044SWilliam.Kucharski@Sun.COM S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
122*8044SWilliam.Kucharski@Sun.COM outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
123*8044SWilliam.Kucharski@Sun.COM S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
124*8044SWilliam.Kucharski@Sun.COM
125*8044SWilliam.Kucharski@Sun.COM /*
126*8044SWilliam.Kucharski@Sun.COM * Attempt to get rid of any stray interrupts that occured during
127*8044SWilliam.Kucharski@Sun.COM * configuration. On the i386 this isn't possible because one may
128*8044SWilliam.Kucharski@Sun.COM * already be queued. However, a single stray interrupt is
129*8044SWilliam.Kucharski@Sun.COM * unimportant.
130*8044SWilliam.Kucharski@Sun.COM */
131*8044SWilliam.Kucharski@Sun.COM
132*8044SWilliam.Kucharski@Sun.COM outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
133*8044SWilliam.Kucharski@Sun.COM
134*8044SWilliam.Kucharski@Sun.COM outw(SET_RX_FILTER | FIL_INDIVIDUAL |
135*8044SWilliam.Kucharski@Sun.COM FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND);
136*8044SWilliam.Kucharski@Sun.COM
137*8044SWilliam.Kucharski@Sun.COM vxsetlink();
138*8044SWilliam.Kucharski@Sun.COM /*{
139*8044SWilliam.Kucharski@Sun.COM int i,j;
140*8044SWilliam.Kucharski@Sun.COM i = CONNECTOR_TX;
141*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(3);
142*8044SWilliam.Kucharski@Sun.COM j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
143*8044SWilliam.Kucharski@Sun.COM outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
144*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(4);
145*8044SWilliam.Kucharski@Sun.COM outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
146*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(1);
147*8044SWilliam.Kucharski@Sun.COM }*/
148*8044SWilliam.Kucharski@Sun.COM
149*8044SWilliam.Kucharski@Sun.COM /* start tranciever and receiver */
150*8044SWilliam.Kucharski@Sun.COM outw(RX_ENABLE, BASE + VX_COMMAND);
151*8044SWilliam.Kucharski@Sun.COM outw(TX_ENABLE, BASE + VX_COMMAND);
152*8044SWilliam.Kucharski@Sun.COM
153*8044SWilliam.Kucharski@Sun.COM }
154*8044SWilliam.Kucharski@Sun.COM
155*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
156*8044SWilliam.Kucharski@Sun.COM ETH_TRANSMIT - Transmit a frame
157*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
158*8044SWilliam.Kucharski@Sun.COM static char padmap[] = {
159*8044SWilliam.Kucharski@Sun.COM 0, 3, 2, 1};
160*8044SWilliam.Kucharski@Sun.COM
t595_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)161*8044SWilliam.Kucharski@Sun.COM static void t595_transmit(
162*8044SWilliam.Kucharski@Sun.COM struct nic *nic,
163*8044SWilliam.Kucharski@Sun.COM const char *d, /* Destination */
164*8044SWilliam.Kucharski@Sun.COM unsigned int t, /* Type */
165*8044SWilliam.Kucharski@Sun.COM unsigned int s, /* size */
166*8044SWilliam.Kucharski@Sun.COM const char *p) /* Packet */
167*8044SWilliam.Kucharski@Sun.COM {
168*8044SWilliam.Kucharski@Sun.COM register int len;
169*8044SWilliam.Kucharski@Sun.COM int pad;
170*8044SWilliam.Kucharski@Sun.COM int status;
171*8044SWilliam.Kucharski@Sun.COM
172*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
173*8044SWilliam.Kucharski@Sun.COM printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
174*8044SWilliam.Kucharski@Sun.COM #endif
175*8044SWilliam.Kucharski@Sun.COM
176*8044SWilliam.Kucharski@Sun.COM /* swap bytes of type */
177*8044SWilliam.Kucharski@Sun.COM t= htons(t);
178*8044SWilliam.Kucharski@Sun.COM
179*8044SWilliam.Kucharski@Sun.COM len=s+ETH_HLEN; /* actual length of packet */
180*8044SWilliam.Kucharski@Sun.COM pad = padmap[len & 3];
181*8044SWilliam.Kucharski@Sun.COM
182*8044SWilliam.Kucharski@Sun.COM /*
183*8044SWilliam.Kucharski@Sun.COM * The 3c595 automatically pads short packets to minimum ethernet length,
184*8044SWilliam.Kucharski@Sun.COM * but we drop packets that are too large. Perhaps we should truncate
185*8044SWilliam.Kucharski@Sun.COM * them instead?
186*8044SWilliam.Kucharski@Sun.COM */
187*8044SWilliam.Kucharski@Sun.COM if (len + pad > ETH_FRAME_LEN) {
188*8044SWilliam.Kucharski@Sun.COM return;
189*8044SWilliam.Kucharski@Sun.COM }
190*8044SWilliam.Kucharski@Sun.COM
191*8044SWilliam.Kucharski@Sun.COM /* drop acknowledgements */
192*8044SWilliam.Kucharski@Sun.COM while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
193*8044SWilliam.Kucharski@Sun.COM if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
194*8044SWilliam.Kucharski@Sun.COM outw(TX_RESET, BASE + VX_COMMAND);
195*8044SWilliam.Kucharski@Sun.COM outw(TX_ENABLE, BASE + VX_COMMAND);
196*8044SWilliam.Kucharski@Sun.COM }
197*8044SWilliam.Kucharski@Sun.COM
198*8044SWilliam.Kucharski@Sun.COM outb(0x0, BASE + VX_W1_TX_STATUS);
199*8044SWilliam.Kucharski@Sun.COM }
200*8044SWilliam.Kucharski@Sun.COM
201*8044SWilliam.Kucharski@Sun.COM while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
202*8044SWilliam.Kucharski@Sun.COM /* no room in FIFO */
203*8044SWilliam.Kucharski@Sun.COM }
204*8044SWilliam.Kucharski@Sun.COM
205*8044SWilliam.Kucharski@Sun.COM outw(len, BASE + VX_W1_TX_PIO_WR_1);
206*8044SWilliam.Kucharski@Sun.COM outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */
207*8044SWilliam.Kucharski@Sun.COM
208*8044SWilliam.Kucharski@Sun.COM /* write packet */
209*8044SWilliam.Kucharski@Sun.COM outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
210*8044SWilliam.Kucharski@Sun.COM outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
211*8044SWilliam.Kucharski@Sun.COM outw(t, BASE + VX_W1_TX_PIO_WR_1);
212*8044SWilliam.Kucharski@Sun.COM outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
213*8044SWilliam.Kucharski@Sun.COM if (s & 1)
214*8044SWilliam.Kucharski@Sun.COM outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
215*8044SWilliam.Kucharski@Sun.COM
216*8044SWilliam.Kucharski@Sun.COM while (pad--)
217*8044SWilliam.Kucharski@Sun.COM outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */
218*8044SWilliam.Kucharski@Sun.COM
219*8044SWilliam.Kucharski@Sun.COM /* wait for Tx complete */
220*8044SWilliam.Kucharski@Sun.COM while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
221*8044SWilliam.Kucharski@Sun.COM ;
222*8044SWilliam.Kucharski@Sun.COM }
223*8044SWilliam.Kucharski@Sun.COM
224*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
225*8044SWilliam.Kucharski@Sun.COM ETH_POLL - Wait for a frame
226*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
t595_poll(struct nic * nic,int retrieve)227*8044SWilliam.Kucharski@Sun.COM static int t595_poll(struct nic *nic, int retrieve)
228*8044SWilliam.Kucharski@Sun.COM {
229*8044SWilliam.Kucharski@Sun.COM /* common variables */
230*8044SWilliam.Kucharski@Sun.COM /* variables for 3C595 */
231*8044SWilliam.Kucharski@Sun.COM short status, cst;
232*8044SWilliam.Kucharski@Sun.COM register short rx_fifo;
233*8044SWilliam.Kucharski@Sun.COM
234*8044SWilliam.Kucharski@Sun.COM cst=inw(BASE + VX_STATUS);
235*8044SWilliam.Kucharski@Sun.COM
236*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
237*8044SWilliam.Kucharski@Sun.COM if(cst & 0x1FFF)
238*8044SWilliam.Kucharski@Sun.COM printf("-%hX-",cst);
239*8044SWilliam.Kucharski@Sun.COM #endif
240*8044SWilliam.Kucharski@Sun.COM
241*8044SWilliam.Kucharski@Sun.COM if( (cst & S_RX_COMPLETE)==0 ) {
242*8044SWilliam.Kucharski@Sun.COM /* acknowledge everything */
243*8044SWilliam.Kucharski@Sun.COM outw(ACK_INTR | cst, BASE + VX_COMMAND);
244*8044SWilliam.Kucharski@Sun.COM outw(C_INTR_LATCH, BASE + VX_COMMAND);
245*8044SWilliam.Kucharski@Sun.COM
246*8044SWilliam.Kucharski@Sun.COM return 0;
247*8044SWilliam.Kucharski@Sun.COM }
248*8044SWilliam.Kucharski@Sun.COM
249*8044SWilliam.Kucharski@Sun.COM status = inw(BASE + VX_W1_RX_STATUS);
250*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
251*8044SWilliam.Kucharski@Sun.COM printf("*%hX*",status);
252*8044SWilliam.Kucharski@Sun.COM #endif
253*8044SWilliam.Kucharski@Sun.COM
254*8044SWilliam.Kucharski@Sun.COM if (status & ERR_RX) {
255*8044SWilliam.Kucharski@Sun.COM outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
256*8044SWilliam.Kucharski@Sun.COM return 0;
257*8044SWilliam.Kucharski@Sun.COM }
258*8044SWilliam.Kucharski@Sun.COM
259*8044SWilliam.Kucharski@Sun.COM rx_fifo = status & RX_BYTES_MASK;
260*8044SWilliam.Kucharski@Sun.COM if (rx_fifo==0)
261*8044SWilliam.Kucharski@Sun.COM return 0;
262*8044SWilliam.Kucharski@Sun.COM
263*8044SWilliam.Kucharski@Sun.COM if ( ! retrieve ) return 1;
264*8044SWilliam.Kucharski@Sun.COM
265*8044SWilliam.Kucharski@Sun.COM /* read packet */
266*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
267*8044SWilliam.Kucharski@Sun.COM printf("[l=%d",rx_fifo);
268*8044SWilliam.Kucharski@Sun.COM #endif
269*8044SWilliam.Kucharski@Sun.COM insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
270*8044SWilliam.Kucharski@Sun.COM if(rx_fifo & 1)
271*8044SWilliam.Kucharski@Sun.COM nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
272*8044SWilliam.Kucharski@Sun.COM nic->packetlen=rx_fifo;
273*8044SWilliam.Kucharski@Sun.COM
274*8044SWilliam.Kucharski@Sun.COM while(1) {
275*8044SWilliam.Kucharski@Sun.COM status = inw(BASE + VX_W1_RX_STATUS);
276*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
277*8044SWilliam.Kucharski@Sun.COM printf("*%hX*",status);
278*8044SWilliam.Kucharski@Sun.COM #endif
279*8044SWilliam.Kucharski@Sun.COM rx_fifo = status & RX_BYTES_MASK;
280*8044SWilliam.Kucharski@Sun.COM
281*8044SWilliam.Kucharski@Sun.COM if(rx_fifo>0) {
282*8044SWilliam.Kucharski@Sun.COM insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
283*8044SWilliam.Kucharski@Sun.COM if(rx_fifo & 1)
284*8044SWilliam.Kucharski@Sun.COM nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
285*8044SWilliam.Kucharski@Sun.COM nic->packetlen+=rx_fifo;
286*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
287*8044SWilliam.Kucharski@Sun.COM printf("+%d",rx_fifo);
288*8044SWilliam.Kucharski@Sun.COM #endif
289*8044SWilliam.Kucharski@Sun.COM }
290*8044SWilliam.Kucharski@Sun.COM if(( status & RX_INCOMPLETE )==0) {
291*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
292*8044SWilliam.Kucharski@Sun.COM printf("=%d",nic->packetlen);
293*8044SWilliam.Kucharski@Sun.COM #endif
294*8044SWilliam.Kucharski@Sun.COM break;
295*8044SWilliam.Kucharski@Sun.COM }
296*8044SWilliam.Kucharski@Sun.COM udelay(1000);
297*8044SWilliam.Kucharski@Sun.COM }
298*8044SWilliam.Kucharski@Sun.COM
299*8044SWilliam.Kucharski@Sun.COM /* acknowledge reception of packet */
300*8044SWilliam.Kucharski@Sun.COM outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
301*8044SWilliam.Kucharski@Sun.COM while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
302*8044SWilliam.Kucharski@Sun.COM #ifdef EDEBUG
303*8044SWilliam.Kucharski@Sun.COM {
304*8044SWilliam.Kucharski@Sun.COM unsigned short type = 0; /* used by EDEBUG */
305*8044SWilliam.Kucharski@Sun.COM type = (nic->packet[12]<<8) | nic->packet[13];
306*8044SWilliam.Kucharski@Sun.COM if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
307*8044SWilliam.Kucharski@Sun.COM nic->packet[5] == 0xFF*ETH_ALEN)
308*8044SWilliam.Kucharski@Sun.COM printf(",t=%hX,b]",type);
309*8044SWilliam.Kucharski@Sun.COM else
310*8044SWilliam.Kucharski@Sun.COM printf(",t=%hX]",type);
311*8044SWilliam.Kucharski@Sun.COM }
312*8044SWilliam.Kucharski@Sun.COM #endif
313*8044SWilliam.Kucharski@Sun.COM return 1;
314*8044SWilliam.Kucharski@Sun.COM }
315*8044SWilliam.Kucharski@Sun.COM
316*8044SWilliam.Kucharski@Sun.COM
317*8044SWilliam.Kucharski@Sun.COM /*************************************************************************
318*8044SWilliam.Kucharski@Sun.COM 3Com 595 - specific routines
319*8044SWilliam.Kucharski@Sun.COM **************************************************************************/
320*8044SWilliam.Kucharski@Sun.COM
321*8044SWilliam.Kucharski@Sun.COM static int
eeprom_rdy()322*8044SWilliam.Kucharski@Sun.COM eeprom_rdy()
323*8044SWilliam.Kucharski@Sun.COM {
324*8044SWilliam.Kucharski@Sun.COM int i;
325*8044SWilliam.Kucharski@Sun.COM
326*8044SWilliam.Kucharski@Sun.COM for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
327*8044SWilliam.Kucharski@Sun.COM udelay(1000);
328*8044SWilliam.Kucharski@Sun.COM if (i >= MAX_EEPROMBUSY) {
329*8044SWilliam.Kucharski@Sun.COM /* printf("3c595: eeprom failed to come ready.\n"); */
330*8044SWilliam.Kucharski@Sun.COM printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
331*8044SWilliam.Kucharski@Sun.COM return (0);
332*8044SWilliam.Kucharski@Sun.COM }
333*8044SWilliam.Kucharski@Sun.COM return (1);
334*8044SWilliam.Kucharski@Sun.COM }
335*8044SWilliam.Kucharski@Sun.COM
336*8044SWilliam.Kucharski@Sun.COM /*
337*8044SWilliam.Kucharski@Sun.COM * get_e: gets a 16 bits word from the EEPROM. we must have set the window
338*8044SWilliam.Kucharski@Sun.COM * before
339*8044SWilliam.Kucharski@Sun.COM */
340*8044SWilliam.Kucharski@Sun.COM static int
get_e(offset)341*8044SWilliam.Kucharski@Sun.COM get_e(offset)
342*8044SWilliam.Kucharski@Sun.COM int offset;
343*8044SWilliam.Kucharski@Sun.COM {
344*8044SWilliam.Kucharski@Sun.COM if (!eeprom_rdy())
345*8044SWilliam.Kucharski@Sun.COM return (0xffff);
346*8044SWilliam.Kucharski@Sun.COM outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
347*8044SWilliam.Kucharski@Sun.COM if (!eeprom_rdy())
348*8044SWilliam.Kucharski@Sun.COM return (0xffff);
349*8044SWilliam.Kucharski@Sun.COM return (inw(BASE + VX_W0_EEPROM_DATA));
350*8044SWilliam.Kucharski@Sun.COM }
351*8044SWilliam.Kucharski@Sun.COM
352*8044SWilliam.Kucharski@Sun.COM static void
vxgetlink(void)353*8044SWilliam.Kucharski@Sun.COM vxgetlink(void)
354*8044SWilliam.Kucharski@Sun.COM {
355*8044SWilliam.Kucharski@Sun.COM int n, k;
356*8044SWilliam.Kucharski@Sun.COM
357*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(3);
358*8044SWilliam.Kucharski@Sun.COM vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
359*8044SWilliam.Kucharski@Sun.COM for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
360*8044SWilliam.Kucharski@Sun.COM if (vx_connectors & conn_tab[k].bit) {
361*8044SWilliam.Kucharski@Sun.COM if (n > 0) {
362*8044SWilliam.Kucharski@Sun.COM printf("/");
363*8044SWilliam.Kucharski@Sun.COM }
364*8044SWilliam.Kucharski@Sun.COM printf(conn_tab[k].name);
365*8044SWilliam.Kucharski@Sun.COM n++;
366*8044SWilliam.Kucharski@Sun.COM }
367*8044SWilliam.Kucharski@Sun.COM }
368*8044SWilliam.Kucharski@Sun.COM if (vx_connectors == 0) {
369*8044SWilliam.Kucharski@Sun.COM printf("no connectors!");
370*8044SWilliam.Kucharski@Sun.COM return;
371*8044SWilliam.Kucharski@Sun.COM }
372*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(3);
373*8044SWilliam.Kucharski@Sun.COM vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
374*8044SWilliam.Kucharski@Sun.COM & INTERNAL_CONNECTOR_MASK)
375*8044SWilliam.Kucharski@Sun.COM >> INTERNAL_CONNECTOR_BITS;
376*8044SWilliam.Kucharski@Sun.COM if (vx_connector & 0x10) {
377*8044SWilliam.Kucharski@Sun.COM vx_connector &= 0x0f;
378*8044SWilliam.Kucharski@Sun.COM printf("[*%s*]", conn_tab[vx_connector].name);
379*8044SWilliam.Kucharski@Sun.COM printf(": disable 'auto select' with DOS util!");
380*8044SWilliam.Kucharski@Sun.COM } else {
381*8044SWilliam.Kucharski@Sun.COM printf("[*%s*]", conn_tab[vx_connector].name);
382*8044SWilliam.Kucharski@Sun.COM }
383*8044SWilliam.Kucharski@Sun.COM }
384*8044SWilliam.Kucharski@Sun.COM
385*8044SWilliam.Kucharski@Sun.COM static void
vxsetlink(void)386*8044SWilliam.Kucharski@Sun.COM vxsetlink(void)
387*8044SWilliam.Kucharski@Sun.COM {
388*8044SWilliam.Kucharski@Sun.COM int i, j;
389*8044SWilliam.Kucharski@Sun.COM char *reason, *warning;
390*8044SWilliam.Kucharski@Sun.COM static char prev_conn = -1;
391*8044SWilliam.Kucharski@Sun.COM
392*8044SWilliam.Kucharski@Sun.COM if (prev_conn == -1) {
393*8044SWilliam.Kucharski@Sun.COM prev_conn = vx_connector;
394*8044SWilliam.Kucharski@Sun.COM }
395*8044SWilliam.Kucharski@Sun.COM
396*8044SWilliam.Kucharski@Sun.COM i = vx_connector; /* default in EEPROM */
397*8044SWilliam.Kucharski@Sun.COM reason = "default";
398*8044SWilliam.Kucharski@Sun.COM warning = 0;
399*8044SWilliam.Kucharski@Sun.COM
400*8044SWilliam.Kucharski@Sun.COM if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
401*8044SWilliam.Kucharski@Sun.COM warning = "strange connector type in EEPROM.";
402*8044SWilliam.Kucharski@Sun.COM reason = "forced";
403*8044SWilliam.Kucharski@Sun.COM i = CONNECTOR_UTP;
404*8044SWilliam.Kucharski@Sun.COM }
405*8044SWilliam.Kucharski@Sun.COM
406*8044SWilliam.Kucharski@Sun.COM if (warning != 0) {
407*8044SWilliam.Kucharski@Sun.COM printf("warning: %s\n", warning);
408*8044SWilliam.Kucharski@Sun.COM }
409*8044SWilliam.Kucharski@Sun.COM printf("selected %s. (%s)\n", conn_tab[i].name, reason);
410*8044SWilliam.Kucharski@Sun.COM
411*8044SWilliam.Kucharski@Sun.COM /* Set the selected connector. */
412*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(3);
413*8044SWilliam.Kucharski@Sun.COM j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
414*8044SWilliam.Kucharski@Sun.COM outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
415*8044SWilliam.Kucharski@Sun.COM
416*8044SWilliam.Kucharski@Sun.COM /* First, disable all. */
417*8044SWilliam.Kucharski@Sun.COM outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
418*8044SWilliam.Kucharski@Sun.COM udelay(8000);
419*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(4);
420*8044SWilliam.Kucharski@Sun.COM outw(0, BASE + VX_W4_MEDIA_TYPE);
421*8044SWilliam.Kucharski@Sun.COM
422*8044SWilliam.Kucharski@Sun.COM /* Second, enable the selected one. */
423*8044SWilliam.Kucharski@Sun.COM switch(i) {
424*8044SWilliam.Kucharski@Sun.COM case CONNECTOR_UTP:
425*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(4);
426*8044SWilliam.Kucharski@Sun.COM outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
427*8044SWilliam.Kucharski@Sun.COM break;
428*8044SWilliam.Kucharski@Sun.COM case CONNECTOR_BNC:
429*8044SWilliam.Kucharski@Sun.COM outw(START_TRANSCEIVER,BASE + VX_COMMAND);
430*8044SWilliam.Kucharski@Sun.COM udelay(8000);
431*8044SWilliam.Kucharski@Sun.COM break;
432*8044SWilliam.Kucharski@Sun.COM case CONNECTOR_TX:
433*8044SWilliam.Kucharski@Sun.COM case CONNECTOR_FX:
434*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(4);
435*8044SWilliam.Kucharski@Sun.COM outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
436*8044SWilliam.Kucharski@Sun.COM break;
437*8044SWilliam.Kucharski@Sun.COM default: /* AUI and MII fall here */
438*8044SWilliam.Kucharski@Sun.COM break;
439*8044SWilliam.Kucharski@Sun.COM }
440*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(1);
441*8044SWilliam.Kucharski@Sun.COM }
442*8044SWilliam.Kucharski@Sun.COM
t595_disable(struct dev * dev)443*8044SWilliam.Kucharski@Sun.COM static void t595_disable(struct dev *dev)
444*8044SWilliam.Kucharski@Sun.COM {
445*8044SWilliam.Kucharski@Sun.COM struct nic *nic = (struct nic *)dev;
446*8044SWilliam.Kucharski@Sun.COM t595_reset(nic);
447*8044SWilliam.Kucharski@Sun.COM
448*8044SWilliam.Kucharski@Sun.COM outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
449*8044SWilliam.Kucharski@Sun.COM udelay(8000);
450*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(4);
451*8044SWilliam.Kucharski@Sun.COM outw(0, BASE + VX_W4_MEDIA_TYPE);
452*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(1);
453*8044SWilliam.Kucharski@Sun.COM }
454*8044SWilliam.Kucharski@Sun.COM
t595_irq(struct nic * nic __unused,irq_action_t action __unused)455*8044SWilliam.Kucharski@Sun.COM static void t595_irq(struct nic *nic __unused, irq_action_t action __unused)
456*8044SWilliam.Kucharski@Sun.COM {
457*8044SWilliam.Kucharski@Sun.COM switch ( action ) {
458*8044SWilliam.Kucharski@Sun.COM case DISABLE :
459*8044SWilliam.Kucharski@Sun.COM break;
460*8044SWilliam.Kucharski@Sun.COM case ENABLE :
461*8044SWilliam.Kucharski@Sun.COM break;
462*8044SWilliam.Kucharski@Sun.COM case FORCE :
463*8044SWilliam.Kucharski@Sun.COM break;
464*8044SWilliam.Kucharski@Sun.COM }
465*8044SWilliam.Kucharski@Sun.COM }
466*8044SWilliam.Kucharski@Sun.COM
467*8044SWilliam.Kucharski@Sun.COM /**************************************************************************
468*8044SWilliam.Kucharski@Sun.COM ETH_PROBE - Look for an adapter
469*8044SWilliam.Kucharski@Sun.COM ***************************************************************************/
t595_probe(struct dev * dev,struct pci_device * pci)470*8044SWilliam.Kucharski@Sun.COM static int t595_probe(struct dev *dev, struct pci_device *pci)
471*8044SWilliam.Kucharski@Sun.COM {
472*8044SWilliam.Kucharski@Sun.COM struct nic *nic = (struct nic *)dev;
473*8044SWilliam.Kucharski@Sun.COM int i;
474*8044SWilliam.Kucharski@Sun.COM unsigned short *p;
475*8044SWilliam.Kucharski@Sun.COM
476*8044SWilliam.Kucharski@Sun.COM if (pci->ioaddr == 0)
477*8044SWilliam.Kucharski@Sun.COM return 0;
478*8044SWilliam.Kucharski@Sun.COM /* eth_nic_base = probeaddrs[0] & ~3; */
479*8044SWilliam.Kucharski@Sun.COM eth_nic_base = pci->ioaddr;
480*8044SWilliam.Kucharski@Sun.COM
481*8044SWilliam.Kucharski@Sun.COM nic->irqno = 0;
482*8044SWilliam.Kucharski@Sun.COM nic->ioaddr = pci->ioaddr & ~3;
483*8044SWilliam.Kucharski@Sun.COM
484*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(0);
485*8044SWilliam.Kucharski@Sun.COM outw(GLOBAL_RESET, BASE + VX_COMMAND);
486*8044SWilliam.Kucharski@Sun.COM VX_BUSY_WAIT;
487*8044SWilliam.Kucharski@Sun.COM
488*8044SWilliam.Kucharski@Sun.COM vxgetlink();
489*8044SWilliam.Kucharski@Sun.COM
490*8044SWilliam.Kucharski@Sun.COM /*
491*8044SWilliam.Kucharski@Sun.COM printf("\nEEPROM:");
492*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < (EEPROMSIZE/2); i++) {
493*8044SWilliam.Kucharski@Sun.COM printf("%hX:", get_e(i));
494*8044SWilliam.Kucharski@Sun.COM }
495*8044SWilliam.Kucharski@Sun.COM printf("\n");
496*8044SWilliam.Kucharski@Sun.COM */
497*8044SWilliam.Kucharski@Sun.COM /*
498*8044SWilliam.Kucharski@Sun.COM * Read the station address from the eeprom
499*8044SWilliam.Kucharski@Sun.COM */
500*8044SWilliam.Kucharski@Sun.COM p = (unsigned short *) nic->node_addr;
501*8044SWilliam.Kucharski@Sun.COM for (i = 0; i < 3; i++) {
502*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(0);
503*8044SWilliam.Kucharski@Sun.COM p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
504*8044SWilliam.Kucharski@Sun.COM GO_WINDOW(2);
505*8044SWilliam.Kucharski@Sun.COM outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
506*8044SWilliam.Kucharski@Sun.COM }
507*8044SWilliam.Kucharski@Sun.COM
508*8044SWilliam.Kucharski@Sun.COM printf("Ethernet address: %!\n", nic->node_addr);
509*8044SWilliam.Kucharski@Sun.COM
510*8044SWilliam.Kucharski@Sun.COM t595_reset(nic);
511*8044SWilliam.Kucharski@Sun.COM dev->disable = t595_disable;
512*8044SWilliam.Kucharski@Sun.COM nic->poll = t595_poll;
513*8044SWilliam.Kucharski@Sun.COM nic->transmit = t595_transmit;
514*8044SWilliam.Kucharski@Sun.COM nic->irq = t595_irq;
515*8044SWilliam.Kucharski@Sun.COM return 1;
516*8044SWilliam.Kucharski@Sun.COM
517*8044SWilliam.Kucharski@Sun.COM }
518*8044SWilliam.Kucharski@Sun.COM
519*8044SWilliam.Kucharski@Sun.COM static struct pci_id t595_nics[] = {
520*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x5900, "3c590", "3Com590"), /* Vortex 10Mbps */
521*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x5950, "3c595", "3Com595"), /* Vortex 100baseTx */
522*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x5951, "3c595-1", "3Com595"), /* Vortex 100baseT4 */
523*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x5952, "3c595-2", "3Com595"), /* Vortex 100base-MII */
524*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9000, "3c900-tpo", "3Com900-TPO"), /* 10 Base TPO */
525*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9001, "3c900-t4", "3Com900-Combo"), /* 10/100 T4 */
526*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9004, "3c900b-tpo", "3Com900B-TPO"), /* 10 Base TPO */
527*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9005, "3c900b-combo", "3Com900B-Combo"), /* 10 Base Combo */
528*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2", "3Com900B-2/T"), /* 10 Base TP and Base2 */
529*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x900a, "3c900b-fl", "3Com900B-FL"), /* 10 Base F */
530*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone"), /* Cyclone */
531*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x9805, "3c9805-1", "3Com9805"), /* Dual Port Server Cyclone */
532*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1", "3CSOHO100-TX"), /* Hurricane */
533*8044SWilliam.Kucharski@Sun.COM PCI_ROM(0x10b7, 0x4500, "3c450-1", "3Com450 HomePNA Tornado"),
534*8044SWilliam.Kucharski@Sun.COM };
535*8044SWilliam.Kucharski@Sun.COM
536*8044SWilliam.Kucharski@Sun.COM struct pci_driver t595_driver = {
537*8044SWilliam.Kucharski@Sun.COM .type = NIC_DRIVER,
538*8044SWilliam.Kucharski@Sun.COM .name = "3C595",
539*8044SWilliam.Kucharski@Sun.COM .probe = t595_probe,
540*8044SWilliam.Kucharski@Sun.COM .ids = t595_nics,
541*8044SWilliam.Kucharski@Sun.COM .id_count = sizeof(t595_nics)/sizeof(t595_nics[0]),
542*8044SWilliam.Kucharski@Sun.COM .class = 0,
543*8044SWilliam.Kucharski@Sun.COM };
544*8044SWilliam.Kucharski@Sun.COM
545*8044SWilliam.Kucharski@Sun.COM /*
546*8044SWilliam.Kucharski@Sun.COM * Local variables:
547*8044SWilliam.Kucharski@Sun.COM * c-basic-offset: 8
548*8044SWilliam.Kucharski@Sun.COM * End:
549*8044SWilliam.Kucharski@Sun.COM */
550*8044SWilliam.Kucharski@Sun.COM
551