17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
57c478bd9Sstevel@tonic-gate * All rights reserved.
67c478bd9Sstevel@tonic-gate * Mar. 14, 2000
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate *  This software may be used, modified, copied, distributed, and sold, in
97c478bd9Sstevel@tonic-gate *  both source and binary form provided that the above copyright and these
107c478bd9Sstevel@tonic-gate *  terms are retained. Under no circumstances are the authors responsible for
117c478bd9Sstevel@tonic-gate *  the proper functioning of this software, nor do the authors assume any
127c478bd9Sstevel@tonic-gate *  responsibility for damages incurred with its use.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * This code is based on Martin Renters' etherboot-4.4.3 3c509.c and
157c478bd9Sstevel@tonic-gate * Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
167c478bd9Sstevel@tonic-gate *
177c478bd9Sstevel@tonic-gate *  Copyright (C) 1993-1994, David Greenman, Martin Renters.
187c478bd9Sstevel@tonic-gate *  Copyright (C) 1993-1995, Andres Vega Garcia.
197c478bd9Sstevel@tonic-gate *  Copyright (C) 1995, Serge Babkin.
207c478bd9Sstevel@tonic-gate *
217c478bd9Sstevel@tonic-gate *  Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
227c478bd9Sstevel@tonic-gate *
237c478bd9Sstevel@tonic-gate * timlegge	08-24-2003	Add Multicast Support
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /* #define EDEBUG */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "etherboot.h"
297c478bd9Sstevel@tonic-gate #include "nic.h"
307c478bd9Sstevel@tonic-gate #include "pci.h"
317c478bd9Sstevel@tonic-gate #include "3c595.h"
327c478bd9Sstevel@tonic-gate #include "timer.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate static unsigned short	eth_nic_base;
357c478bd9Sstevel@tonic-gate static unsigned short	vx_connector, vx_connectors;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static struct connector_entry {
387c478bd9Sstevel@tonic-gate   int bit;
397c478bd9Sstevel@tonic-gate   char *name;
407c478bd9Sstevel@tonic-gate } conn_tab[VX_CONNECTORS] = {
417c478bd9Sstevel@tonic-gate #define CONNECTOR_UTP   0
427c478bd9Sstevel@tonic-gate   { 0x08, "utp"},
437c478bd9Sstevel@tonic-gate #define CONNECTOR_AUI   1
447c478bd9Sstevel@tonic-gate   { 0x20, "aui"},
457c478bd9Sstevel@tonic-gate /* dummy */
467c478bd9Sstevel@tonic-gate   { 0, "???"},
477c478bd9Sstevel@tonic-gate #define CONNECTOR_BNC   3
487c478bd9Sstevel@tonic-gate   { 0x10, "bnc"},
497c478bd9Sstevel@tonic-gate #define CONNECTOR_TX    4
507c478bd9Sstevel@tonic-gate   { 0x02, "tx"},
517c478bd9Sstevel@tonic-gate #define CONNECTOR_FX    5
527c478bd9Sstevel@tonic-gate   { 0x04, "fx"},
537c478bd9Sstevel@tonic-gate #define CONNECTOR_MII   6
547c478bd9Sstevel@tonic-gate   { 0x40, "mii"},
557c478bd9Sstevel@tonic-gate   { 0, "???"}
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static void vxgetlink(void);
597c478bd9Sstevel@tonic-gate static void vxsetlink(void);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /**************************************************************************
627c478bd9Sstevel@tonic-gate ETH_RESET - Reset adapter
637c478bd9Sstevel@tonic-gate ***************************************************************************/
t595_reset(struct nic * nic)647c478bd9Sstevel@tonic-gate static void t595_reset(struct nic *nic)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	int i;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	/***********************************************************
697c478bd9Sstevel@tonic-gate 			Reset 3Com 595 card
707c478bd9Sstevel@tonic-gate 	*************************************************************/
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/* stop card */
737c478bd9Sstevel@tonic-gate 	outw(RX_DISABLE, BASE + VX_COMMAND);
747c478bd9Sstevel@tonic-gate 	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
757c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
767c478bd9Sstevel@tonic-gate 	outw(TX_DISABLE, BASE + VX_COMMAND);
777c478bd9Sstevel@tonic-gate 	outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
787c478bd9Sstevel@tonic-gate 	udelay(8000);
797c478bd9Sstevel@tonic-gate 	outw(RX_RESET, BASE + VX_COMMAND);
807c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
817c478bd9Sstevel@tonic-gate 	outw(TX_RESET, BASE + VX_COMMAND);
827c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
837c478bd9Sstevel@tonic-gate 	outw(C_INTR_LATCH, BASE + VX_COMMAND);
847c478bd9Sstevel@tonic-gate 	outw(SET_RD_0_MASK, BASE + VX_COMMAND);
857c478bd9Sstevel@tonic-gate 	outw(SET_INTR_MASK, BASE + VX_COMMAND);
867c478bd9Sstevel@tonic-gate 	outw(SET_RX_FILTER, BASE + VX_COMMAND);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	/*
897c478bd9Sstevel@tonic-gate 	* initialize card
907c478bd9Sstevel@tonic-gate 	*/
917c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	GO_WINDOW(0);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/* Disable the card */
967c478bd9Sstevel@tonic-gate /*	outw(0, BASE + VX_W0_CONFIG_CTRL); */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/* Configure IRQ to none */
997c478bd9Sstevel@tonic-gate /*	outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/* Enable the card */
1027c478bd9Sstevel@tonic-gate /*	outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	GO_WINDOW(2);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/* Reload the ether_addr. */
1077c478bd9Sstevel@tonic-gate 	for (i = 0; i < ETH_ALEN; i++)
1087c478bd9Sstevel@tonic-gate 		outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	outw(RX_RESET, BASE + VX_COMMAND);
1117c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
1127c478bd9Sstevel@tonic-gate 	outw(TX_RESET, BASE + VX_COMMAND);
1137c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/* Window 1 is operating window */
1167c478bd9Sstevel@tonic-gate 	GO_WINDOW(1);
1177c478bd9Sstevel@tonic-gate 	for (i = 0; i < 31; i++)
1187c478bd9Sstevel@tonic-gate 		inb(BASE + VX_W1_TX_STATUS);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
1217c478bd9Sstevel@tonic-gate 		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
1227c478bd9Sstevel@tonic-gate 	outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
1237c478bd9Sstevel@tonic-gate 		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Attempt to get rid of any stray interrupts that occured during
1277c478bd9Sstevel@tonic-gate  * configuration.  On the i386 this isn't possible because one may
1287c478bd9Sstevel@tonic-gate  * already be queued.  However, a single stray interrupt is
1297c478bd9Sstevel@tonic-gate  * unimportant.
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	outw(SET_RX_FILTER | FIL_INDIVIDUAL |
1357c478bd9Sstevel@tonic-gate 	    FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	vxsetlink();
1387c478bd9Sstevel@tonic-gate /*{
1397c478bd9Sstevel@tonic-gate 	int i,j;
1407c478bd9Sstevel@tonic-gate 	i = CONNECTOR_TX;
1417c478bd9Sstevel@tonic-gate 	GO_WINDOW(3);
1427c478bd9Sstevel@tonic-gate 	j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
1437c478bd9Sstevel@tonic-gate 	outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
1447c478bd9Sstevel@tonic-gate         GO_WINDOW(4);
1457c478bd9Sstevel@tonic-gate         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
1467c478bd9Sstevel@tonic-gate         GO_WINDOW(1);
1477c478bd9Sstevel@tonic-gate }*/
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* start tranciever and receiver */
1507c478bd9Sstevel@tonic-gate 	outw(RX_ENABLE, BASE + VX_COMMAND);
1517c478bd9Sstevel@tonic-gate 	outw(TX_ENABLE, BASE + VX_COMMAND);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /**************************************************************************
1567c478bd9Sstevel@tonic-gate ETH_TRANSMIT - Transmit a frame
1577c478bd9Sstevel@tonic-gate ***************************************************************************/
1587c478bd9Sstevel@tonic-gate static char padmap[] = {
1597c478bd9Sstevel@tonic-gate 	0, 3, 2, 1};
1607c478bd9Sstevel@tonic-gate 
t595_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)1617c478bd9Sstevel@tonic-gate static void t595_transmit(
1627c478bd9Sstevel@tonic-gate struct nic *nic,
1637c478bd9Sstevel@tonic-gate const char *d,			/* Destination */
1647c478bd9Sstevel@tonic-gate unsigned int t,			/* Type */
1657c478bd9Sstevel@tonic-gate unsigned int s,			/* size */
1667c478bd9Sstevel@tonic-gate const char *p)			/* Packet */
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	register int len;
1697c478bd9Sstevel@tonic-gate 	int pad;
1707c478bd9Sstevel@tonic-gate 	int status;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate #ifdef EDEBUG
1737c478bd9Sstevel@tonic-gate 	printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
1747c478bd9Sstevel@tonic-gate #endif
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* swap bytes of type */
1777c478bd9Sstevel@tonic-gate 	t= htons(t);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	len=s+ETH_HLEN; /* actual length of packet */
1807c478bd9Sstevel@tonic-gate 	pad = padmap[len & 3];
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	* The 3c595 automatically pads short packets to minimum ethernet length,
1847c478bd9Sstevel@tonic-gate 	* but we drop packets that are too large. Perhaps we should truncate
1857c478bd9Sstevel@tonic-gate 	* them instead?
1867c478bd9Sstevel@tonic-gate 	*/
1877c478bd9Sstevel@tonic-gate 	if (len + pad > ETH_FRAME_LEN) {
1887c478bd9Sstevel@tonic-gate 		return;
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/* drop acknowledgements */
1927c478bd9Sstevel@tonic-gate 	while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
1937c478bd9Sstevel@tonic-gate 		if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
1947c478bd9Sstevel@tonic-gate 			outw(TX_RESET, BASE + VX_COMMAND);
1957c478bd9Sstevel@tonic-gate 			outw(TX_ENABLE, BASE + VX_COMMAND);
1967c478bd9Sstevel@tonic-gate 		}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		outb(0x0, BASE + VX_W1_TX_STATUS);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
2027c478bd9Sstevel@tonic-gate 		/* no room in FIFO */
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	outw(len, BASE + VX_W1_TX_PIO_WR_1);
2067c478bd9Sstevel@tonic-gate 	outw(0x0, BASE + VX_W1_TX_PIO_WR_1);	/* Second dword meaningless */
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* write packet */
2097c478bd9Sstevel@tonic-gate 	outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
2107c478bd9Sstevel@tonic-gate 	outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
2117c478bd9Sstevel@tonic-gate 	outw(t, BASE + VX_W1_TX_PIO_WR_1);
2127c478bd9Sstevel@tonic-gate 	outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
2137c478bd9Sstevel@tonic-gate 	if (s & 1)
2147c478bd9Sstevel@tonic-gate 		outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	while (pad--)
2177c478bd9Sstevel@tonic-gate 		outb(0, BASE + VX_W1_TX_PIO_WR_1);	/* Padding */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate         /* wait for Tx complete */
2207c478bd9Sstevel@tonic-gate         while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
2217c478bd9Sstevel@tonic-gate                 ;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /**************************************************************************
2257c478bd9Sstevel@tonic-gate ETH_POLL - Wait for a frame
2267c478bd9Sstevel@tonic-gate ***************************************************************************/
t595_poll(struct nic * nic,int retrieve)2277c478bd9Sstevel@tonic-gate static int t595_poll(struct nic *nic, int retrieve)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	/* common variables */
2307c478bd9Sstevel@tonic-gate 	/* variables for 3C595 */
2317c478bd9Sstevel@tonic-gate 	short status, cst;
2327c478bd9Sstevel@tonic-gate 	register short rx_fifo;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	cst=inw(BASE + VX_STATUS);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2377c478bd9Sstevel@tonic-gate 	if(cst & 0x1FFF)
2387c478bd9Sstevel@tonic-gate 		printf("-%hX-",cst);
2397c478bd9Sstevel@tonic-gate #endif
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if( (cst & S_RX_COMPLETE)==0 ) {
2427c478bd9Sstevel@tonic-gate 		/* acknowledge  everything */
2437c478bd9Sstevel@tonic-gate 		outw(ACK_INTR | cst, BASE + VX_COMMAND);
2447c478bd9Sstevel@tonic-gate 		outw(C_INTR_LATCH, BASE + VX_COMMAND);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 		return 0;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	status = inw(BASE + VX_W1_RX_STATUS);
2507c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2517c478bd9Sstevel@tonic-gate 	printf("*%hX*",status);
2527c478bd9Sstevel@tonic-gate #endif
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if (status & ERR_RX) {
2557c478bd9Sstevel@tonic-gate 		outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
2567c478bd9Sstevel@tonic-gate 		return 0;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	rx_fifo = status & RX_BYTES_MASK;
2607c478bd9Sstevel@tonic-gate 	if (rx_fifo==0)
2617c478bd9Sstevel@tonic-gate 		return 0;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if ( ! retrieve ) return 1;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		/* read packet */
2667c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2677c478bd9Sstevel@tonic-gate 	printf("[l=%d",rx_fifo);
2687c478bd9Sstevel@tonic-gate #endif
2697c478bd9Sstevel@tonic-gate 	insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
2707c478bd9Sstevel@tonic-gate 	if(rx_fifo & 1)
2717c478bd9Sstevel@tonic-gate 		nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
2727c478bd9Sstevel@tonic-gate 	nic->packetlen=rx_fifo;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	while(1) {
2757c478bd9Sstevel@tonic-gate 		status = inw(BASE + VX_W1_RX_STATUS);
2767c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2777c478bd9Sstevel@tonic-gate 		printf("*%hX*",status);
2787c478bd9Sstevel@tonic-gate #endif
2797c478bd9Sstevel@tonic-gate 		rx_fifo = status & RX_BYTES_MASK;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		if(rx_fifo>0) {
2827c478bd9Sstevel@tonic-gate 			insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
2837c478bd9Sstevel@tonic-gate 			if(rx_fifo & 1)
2847c478bd9Sstevel@tonic-gate 				nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
2857c478bd9Sstevel@tonic-gate 			nic->packetlen+=rx_fifo;
2867c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2877c478bd9Sstevel@tonic-gate 			printf("+%d",rx_fifo);
2887c478bd9Sstevel@tonic-gate #endif
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 		if(( status & RX_INCOMPLETE )==0) {
2917c478bd9Sstevel@tonic-gate #ifdef EDEBUG
2927c478bd9Sstevel@tonic-gate 			printf("=%d",nic->packetlen);
2937c478bd9Sstevel@tonic-gate #endif
2947c478bd9Sstevel@tonic-gate 			break;
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 		udelay(1000);
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* acknowledge reception of packet */
3007c478bd9Sstevel@tonic-gate 	outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
3017c478bd9Sstevel@tonic-gate 	while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
3027c478bd9Sstevel@tonic-gate #ifdef EDEBUG
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	unsigned short type = 0;	/* used by EDEBUG */
3057c478bd9Sstevel@tonic-gate 	type = (nic->packet[12]<<8) | nic->packet[13];
3067c478bd9Sstevel@tonic-gate 	if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
3077c478bd9Sstevel@tonic-gate 	    nic->packet[5] == 0xFF*ETH_ALEN)
3087c478bd9Sstevel@tonic-gate 		printf(",t=%hX,b]",type);
3097c478bd9Sstevel@tonic-gate 	else
3107c478bd9Sstevel@tonic-gate 		printf(",t=%hX]",type);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate 	return 1;
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*************************************************************************
3187c478bd9Sstevel@tonic-gate 	3Com 595 - specific routines
3197c478bd9Sstevel@tonic-gate **************************************************************************/
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static int
eeprom_rdy()3227c478bd9Sstevel@tonic-gate eeprom_rdy()
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	int i;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
3277c478bd9Sstevel@tonic-gate 		udelay(1000);
3287c478bd9Sstevel@tonic-gate 	if (i >= MAX_EEPROMBUSY) {
3297c478bd9Sstevel@tonic-gate 	        /* printf("3c595: eeprom failed to come ready.\n"); */
3307c478bd9Sstevel@tonic-gate 		printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
3317c478bd9Sstevel@tonic-gate 		return (0);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 	return (1);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
3387c478bd9Sstevel@tonic-gate  * before
3397c478bd9Sstevel@tonic-gate  */
3407c478bd9Sstevel@tonic-gate static int
get_e(offset)3417c478bd9Sstevel@tonic-gate get_e(offset)
3427c478bd9Sstevel@tonic-gate int offset;
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	if (!eeprom_rdy())
3457c478bd9Sstevel@tonic-gate 		return (0xffff);
3467c478bd9Sstevel@tonic-gate 	outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
3477c478bd9Sstevel@tonic-gate 	if (!eeprom_rdy())
3487c478bd9Sstevel@tonic-gate 		return (0xffff);
3497c478bd9Sstevel@tonic-gate 	return (inw(BASE + VX_W0_EEPROM_DATA));
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate static void
vxgetlink(void)3537c478bd9Sstevel@tonic-gate vxgetlink(void)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate     int n, k;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate     GO_WINDOW(3);
3587c478bd9Sstevel@tonic-gate     vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
3597c478bd9Sstevel@tonic-gate     for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
3607c478bd9Sstevel@tonic-gate       if (vx_connectors & conn_tab[k].bit) {
3617c478bd9Sstevel@tonic-gate         if (n > 0) {
3627c478bd9Sstevel@tonic-gate           printf("/");
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate         printf(conn_tab[k].name);
3657c478bd9Sstevel@tonic-gate         n++;
3667c478bd9Sstevel@tonic-gate       }
3677c478bd9Sstevel@tonic-gate     }
3687c478bd9Sstevel@tonic-gate     if (vx_connectors == 0) {
3697c478bd9Sstevel@tonic-gate         printf("no connectors!");
3707c478bd9Sstevel@tonic-gate         return;
3717c478bd9Sstevel@tonic-gate     }
3727c478bd9Sstevel@tonic-gate     GO_WINDOW(3);
3737c478bd9Sstevel@tonic-gate     vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
3747c478bd9Sstevel@tonic-gate                         & INTERNAL_CONNECTOR_MASK)
3757c478bd9Sstevel@tonic-gate                         >> INTERNAL_CONNECTOR_BITS;
3767c478bd9Sstevel@tonic-gate     if (vx_connector & 0x10) {
3777c478bd9Sstevel@tonic-gate         vx_connector &= 0x0f;
3787c478bd9Sstevel@tonic-gate         printf("[*%s*]", conn_tab[vx_connector].name);
3797c478bd9Sstevel@tonic-gate         printf(": disable 'auto select' with DOS util!");
3807c478bd9Sstevel@tonic-gate     } else {
3817c478bd9Sstevel@tonic-gate         printf("[*%s*]", conn_tab[vx_connector].name);
3827c478bd9Sstevel@tonic-gate     }
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate static void
vxsetlink(void)3867c478bd9Sstevel@tonic-gate vxsetlink(void)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate     int i, j;
3897c478bd9Sstevel@tonic-gate     char *reason, *warning;
3907c478bd9Sstevel@tonic-gate     static char prev_conn = -1;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate     if (prev_conn == -1) {
3937c478bd9Sstevel@tonic-gate         prev_conn = vx_connector;
3947c478bd9Sstevel@tonic-gate     }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate     i = vx_connector;       /* default in EEPROM */
3977c478bd9Sstevel@tonic-gate     reason = "default";
3987c478bd9Sstevel@tonic-gate     warning = 0;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate     if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
4017c478bd9Sstevel@tonic-gate         warning = "strange connector type in EEPROM.";
4027c478bd9Sstevel@tonic-gate         reason = "forced";
4037c478bd9Sstevel@tonic-gate         i = CONNECTOR_UTP;
4047c478bd9Sstevel@tonic-gate     }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate         if (warning != 0) {
4077c478bd9Sstevel@tonic-gate             printf("warning: %s\n", warning);
4087c478bd9Sstevel@tonic-gate         }
4097c478bd9Sstevel@tonic-gate         printf("selected %s. (%s)\n", conn_tab[i].name, reason);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate     /* Set the selected connector. */
4127c478bd9Sstevel@tonic-gate     GO_WINDOW(3);
4137c478bd9Sstevel@tonic-gate     j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
4147c478bd9Sstevel@tonic-gate     outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate     /* First, disable all. */
4177c478bd9Sstevel@tonic-gate     outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
4187c478bd9Sstevel@tonic-gate     udelay(8000);
4197c478bd9Sstevel@tonic-gate     GO_WINDOW(4);
4207c478bd9Sstevel@tonic-gate     outw(0, BASE + VX_W4_MEDIA_TYPE);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate     /* Second, enable the selected one. */
4237c478bd9Sstevel@tonic-gate     switch(i) {
4247c478bd9Sstevel@tonic-gate       case CONNECTOR_UTP:
4257c478bd9Sstevel@tonic-gate         GO_WINDOW(4);
4267c478bd9Sstevel@tonic-gate         outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
4277c478bd9Sstevel@tonic-gate         break;
4287c478bd9Sstevel@tonic-gate       case CONNECTOR_BNC:
4297c478bd9Sstevel@tonic-gate         outw(START_TRANSCEIVER,BASE + VX_COMMAND);
4307c478bd9Sstevel@tonic-gate         udelay(8000);
4317c478bd9Sstevel@tonic-gate         break;
4327c478bd9Sstevel@tonic-gate       case CONNECTOR_TX:
4337c478bd9Sstevel@tonic-gate       case CONNECTOR_FX:
4347c478bd9Sstevel@tonic-gate         GO_WINDOW(4);
4357c478bd9Sstevel@tonic-gate         outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
4367c478bd9Sstevel@tonic-gate         break;
4377c478bd9Sstevel@tonic-gate       default:  /* AUI and MII fall here */
4387c478bd9Sstevel@tonic-gate         break;
4397c478bd9Sstevel@tonic-gate     }
4407c478bd9Sstevel@tonic-gate     GO_WINDOW(1);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
t595_disable(struct dev * dev)4437c478bd9Sstevel@tonic-gate static void t595_disable(struct dev *dev)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	struct nic *nic = (struct nic *)dev;
4467c478bd9Sstevel@tonic-gate 	t595_reset(nic);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
4497c478bd9Sstevel@tonic-gate 	udelay(8000);
4507c478bd9Sstevel@tonic-gate 	GO_WINDOW(4);
4517c478bd9Sstevel@tonic-gate 	outw(0, BASE + VX_W4_MEDIA_TYPE);
4527c478bd9Sstevel@tonic-gate 	GO_WINDOW(1);
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate 
t595_irq(struct nic * nic __unused,irq_action_t action __unused)4557c478bd9Sstevel@tonic-gate static void t595_irq(struct nic *nic __unused, irq_action_t action __unused)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate   switch ( action ) {
4587c478bd9Sstevel@tonic-gate   case DISABLE :
4597c478bd9Sstevel@tonic-gate     break;
4607c478bd9Sstevel@tonic-gate   case ENABLE :
4617c478bd9Sstevel@tonic-gate     break;
4627c478bd9Sstevel@tonic-gate   case FORCE :
4637c478bd9Sstevel@tonic-gate     break;
4647c478bd9Sstevel@tonic-gate   }
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /**************************************************************************
4687c478bd9Sstevel@tonic-gate ETH_PROBE - Look for an adapter
4697c478bd9Sstevel@tonic-gate ***************************************************************************/
t595_probe(struct dev * dev,struct pci_device * pci)4707c478bd9Sstevel@tonic-gate static int t595_probe(struct dev *dev, struct pci_device *pci)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	struct nic *nic = (struct nic *)dev;
4737c478bd9Sstevel@tonic-gate 	int i;
4747c478bd9Sstevel@tonic-gate 	unsigned short *p;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (pci->ioaddr == 0)
4777c478bd9Sstevel@tonic-gate 		return 0;
4787c478bd9Sstevel@tonic-gate /*	eth_nic_base = probeaddrs[0] & ~3; */
4797c478bd9Sstevel@tonic-gate 	eth_nic_base = pci->ioaddr;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	nic->irqno  = 0;
4827c478bd9Sstevel@tonic-gate 	nic->ioaddr = pci->ioaddr & ~3;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	GO_WINDOW(0);
4857c478bd9Sstevel@tonic-gate 	outw(GLOBAL_RESET, BASE + VX_COMMAND);
4867c478bd9Sstevel@tonic-gate 	VX_BUSY_WAIT;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	vxgetlink();
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate 	printf("\nEEPROM:");
4927c478bd9Sstevel@tonic-gate 	for (i = 0; i < (EEPROMSIZE/2); i++) {
4937c478bd9Sstevel@tonic-gate 	  printf("%hX:", get_e(i));
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	printf("\n");
4967c478bd9Sstevel@tonic-gate */
4977c478bd9Sstevel@tonic-gate 	/*
4987c478bd9Sstevel@tonic-gate 	* Read the station address from the eeprom
4997c478bd9Sstevel@tonic-gate 	*/
5007c478bd9Sstevel@tonic-gate 	p = (unsigned short *) nic->node_addr;
5017c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++) {
5027c478bd9Sstevel@tonic-gate 		GO_WINDOW(0);
5037c478bd9Sstevel@tonic-gate 		p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
5047c478bd9Sstevel@tonic-gate 		GO_WINDOW(2);
5057c478bd9Sstevel@tonic-gate 		outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	printf("Ethernet address: %!\n", nic->node_addr);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	t595_reset(nic);
5117c478bd9Sstevel@tonic-gate 	dev->disable  = t595_disable;
5127c478bd9Sstevel@tonic-gate 	nic->poll     = t595_poll;
5137c478bd9Sstevel@tonic-gate 	nic->transmit = t595_transmit;
5147c478bd9Sstevel@tonic-gate 	nic->irq      = t595_irq;
5157c478bd9Sstevel@tonic-gate 	return 1;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate static struct pci_id t595_nics[] = {
5207c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x5900, "3c590",           "3Com590"),		/* Vortex 10Mbps */
5217c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x5950, "3c595",           "3Com595"),		/* Vortex 100baseTx */
5227c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x5951, "3c595-1",         "3Com595"),		/* Vortex 100baseT4 */
5237c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x5952, "3c595-2",         "3Com595"),		/* Vortex 100base-MII */
5247c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9000, "3c900-tpo",       "3Com900-TPO"),	/* 10 Base TPO */
5257c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9001, "3c900-t4",        "3Com900-Combo"),	/* 10/100 T4 */
5267c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9004, "3c900b-tpo",      "3Com900B-TPO"),	/* 10 Base TPO */
5277c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9005, "3c900b-combo",    "3Com900B-Combo"),	/* 10 Base Combo */
5287c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2",     "3Com900B-2/T"),	/* 10 Base TP and Base2 */
5297c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x900a, "3c900b-fl",       "3Com900B-FL"),	/* 10 Base F */
5307c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone"),	/* Cyclone */
5317c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x9805, "3c9805-1",        "3Com9805"),		/* Dual Port Server Cyclone */
5327c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1",  "3CSOHO100-TX"),	/* Hurricane */
5337c478bd9Sstevel@tonic-gate PCI_ROM(0x10b7, 0x4500, "3c450-1",         "3Com450 HomePNA Tornado"),
5347c478bd9Sstevel@tonic-gate };
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate struct pci_driver t595_driver = {
5377c478bd9Sstevel@tonic-gate 	.type     = NIC_DRIVER,
5387c478bd9Sstevel@tonic-gate 	.name     = "3C595",
5397c478bd9Sstevel@tonic-gate 	.probe    = t595_probe,
5407c478bd9Sstevel@tonic-gate 	.ids      = t595_nics,
5417c478bd9Sstevel@tonic-gate 	.id_count = sizeof(t595_nics)/sizeof(t595_nics[0]),
5427c478bd9Sstevel@tonic-gate 	.class    = 0,
5437c478bd9Sstevel@tonic-gate };
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate  * Local variables:
5477c478bd9Sstevel@tonic-gate  *  c-basic-offset: 8
5487c478bd9Sstevel@tonic-gate  * End:
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate 
551