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