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