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