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