3c595.c revision 5b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4
1/* 2* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot 3* 4* Copyright (C) 2000 Shusuke Nisiyama <shu@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@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 33static unsigned short eth_nic_base, eth_asic_base; 34static unsigned short vx_connector, vx_connectors; 35 36static 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 57static void vxgetlink(void); 58static void vxsetlink(void); 59 60#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000) 61 62/************************************************************************** 63ETH_RESET - Reset adapter 64***************************************************************************/ 65static 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/************************************************************************** 157ETH_TRANSMIT - Transmit a frame 158***************************************************************************/ 159static char padmap[] = { 160 0, 3, 2, 1}; 161 162static void t595_transmit( 163struct nic *nic, 164const char *d, /* Destination */ 165unsigned int t, /* Type */ 166unsigned int s, /* size */ 167const 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/************************************************************************** 226ETH_POLL - Wait for a frame 227***************************************************************************/ 228static 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 318static int 319eeprom_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 */ 337static int 338get_e(offset) 339int 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 349static void 350vxgetlink(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 382static void 383vxsetlink(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 441static 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/************************************************************************** 451ETH_PROBE - Look for an adapter 452***************************************************************************/ 453struct 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