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