00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 FILE_LICENCE ( BSD2 );
00027
00028
00029
00030 #include "etherboot.h"
00031 #include "nic.h"
00032 #include <gpxe/pci.h>
00033 #include <gpxe/ethernet.h>
00034 #include "3c595.h"
00035
00036 static struct nic_operations t595_operations;
00037
00038 static unsigned short eth_nic_base;
00039 static unsigned short vx_connector, vx_connectors;
00040
00041 static struct connector_entry {
00042 int bit;
00043 char *name;
00044 } conn_tab[VX_CONNECTORS] = {
00045 #define CONNECTOR_UTP 0
00046 { 0x08, "utp"},
00047 #define CONNECTOR_AUI 1
00048 { 0x20, "aui"},
00049
00050 { 0, "???"},
00051 #define CONNECTOR_BNC 3
00052 { 0x10, "bnc"},
00053 #define CONNECTOR_TX 4
00054 { 0x02, "tx"},
00055 #define CONNECTOR_FX 5
00056 { 0x04, "fx"},
00057 #define CONNECTOR_MII 6
00058 { 0x40, "mii"},
00059 { 0, "???"}
00060 };
00061
00062 static void vxgetlink(void);
00063 static void vxsetlink(void);
00064
00065
00066
00067
00068 static void t595_reset(struct nic *nic)
00069 {
00070 int i;
00071
00072
00073
00074
00075
00076
00077 outw(RX_DISABLE, BASE + VX_COMMAND);
00078 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
00079 VX_BUSY_WAIT;
00080 outw(TX_DISABLE, BASE + VX_COMMAND);
00081 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
00082 udelay(8000);
00083 outw(RX_RESET, BASE + VX_COMMAND);
00084 VX_BUSY_WAIT;
00085 outw(TX_RESET, BASE + VX_COMMAND);
00086 VX_BUSY_WAIT;
00087 outw(C_INTR_LATCH, BASE + VX_COMMAND);
00088 outw(SET_RD_0_MASK, BASE + VX_COMMAND);
00089 outw(SET_INTR_MASK, BASE + VX_COMMAND);
00090 outw(SET_RX_FILTER, BASE + VX_COMMAND);
00091
00092
00093
00094
00095 VX_BUSY_WAIT;
00096
00097 GO_WINDOW(0);
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 GO_WINDOW(2);
00109
00110
00111 for (i = 0; i < ETH_ALEN; i++)
00112 outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
00113
00114 outw(RX_RESET, BASE + VX_COMMAND);
00115 VX_BUSY_WAIT;
00116 outw(TX_RESET, BASE + VX_COMMAND);
00117 VX_BUSY_WAIT;
00118
00119
00120 GO_WINDOW(1);
00121 for (i = 0; i < 31; i++)
00122 inb(BASE + VX_W1_TX_STATUS);
00123
00124 outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
00125 S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
00126 outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
00127 S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
00128
00129
00130
00131
00132
00133
00134
00135
00136 outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
00137
00138 outw(SET_RX_FILTER | FIL_INDIVIDUAL |
00139 FIL_BRDCST|FIL_MULTICAST, BASE + VX_COMMAND);
00140
00141 vxsetlink();
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 outw(RX_ENABLE, BASE + VX_COMMAND);
00155 outw(TX_ENABLE, BASE + VX_COMMAND);
00156
00157 }
00158
00159
00160
00161
00162 static char padmap[] = {
00163 0, 3, 2, 1};
00164
00165 static void t595_transmit(
00166 struct nic *nic,
00167 const char *d,
00168 unsigned int t,
00169 unsigned int s,
00170 const char *p)
00171 {
00172 register int len;
00173 int pad;
00174 int status;
00175
00176 #ifdef EDEBUG
00177 printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
00178 #endif
00179
00180
00181 t= htons(t);
00182
00183 len=s+ETH_HLEN;
00184 pad = padmap[len & 3];
00185
00186
00187
00188
00189
00190
00191 if (len + pad > ETH_FRAME_LEN) {
00192 return;
00193 }
00194
00195
00196 while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
00197 if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
00198 outw(TX_RESET, BASE + VX_COMMAND);
00199 outw(TX_ENABLE, BASE + VX_COMMAND);
00200 }
00201
00202 outb(0x0, BASE + VX_W1_TX_STATUS);
00203 }
00204
00205 while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
00206
00207 }
00208
00209 outw(len, BASE + VX_W1_TX_PIO_WR_1);
00210 outw(0x0, BASE + VX_W1_TX_PIO_WR_1);
00211
00212
00213 outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
00214 outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
00215 outw(t, BASE + VX_W1_TX_PIO_WR_1);
00216 outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
00217 if (s & 1)
00218 outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
00219
00220 while (pad--)
00221 outb(0, BASE + VX_W1_TX_PIO_WR_1);
00222
00223
00224 while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
00225 ;
00226 }
00227
00228
00229
00230
00231 static int t595_poll(struct nic *nic, int retrieve)
00232 {
00233
00234
00235 short status, cst;
00236 register short rx_fifo;
00237
00238 cst=inw(BASE + VX_STATUS);
00239
00240 #ifdef EDEBUG
00241 if(cst & 0x1FFF)
00242 printf("-%hX-",cst);
00243 #endif
00244
00245 if( (cst & S_RX_COMPLETE)==0 ) {
00246
00247 outw(ACK_INTR | cst, BASE + VX_COMMAND);
00248 outw(C_INTR_LATCH, BASE + VX_COMMAND);
00249
00250 return 0;
00251 }
00252
00253 status = inw(BASE + VX_W1_RX_STATUS);
00254 #ifdef EDEBUG
00255 printf("*%hX*",status);
00256 #endif
00257
00258 if (status & ERR_RX) {
00259 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
00260 return 0;
00261 }
00262
00263 rx_fifo = status & RX_BYTES_MASK;
00264 if (rx_fifo==0)
00265 return 0;
00266
00267 if ( ! retrieve ) return 1;
00268
00269
00270 #ifdef EDEBUG
00271 printf("[l=%d",rx_fifo);
00272 #endif
00273 insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
00274 if(rx_fifo & 1)
00275 nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
00276 nic->packetlen=rx_fifo;
00277
00278 while(1) {
00279 status = inw(BASE + VX_W1_RX_STATUS);
00280 #ifdef EDEBUG
00281 printf("*%hX*",status);
00282 #endif
00283 rx_fifo = status & RX_BYTES_MASK;
00284
00285 if(rx_fifo>0) {
00286 insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
00287 if(rx_fifo & 1)
00288 nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
00289 nic->packetlen+=rx_fifo;
00290 #ifdef EDEBUG
00291 printf("+%d",rx_fifo);
00292 #endif
00293 }
00294 if(( status & RX_INCOMPLETE )==0) {
00295 #ifdef EDEBUG
00296 printf("=%d",nic->packetlen);
00297 #endif
00298 break;
00299 }
00300 udelay(1000);
00301 }
00302
00303
00304 outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
00305 while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
00306 #ifdef EDEBUG
00307 {
00308 unsigned short type = 0;
00309 type = (nic->packet[12]<<8) | nic->packet[13];
00310 if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
00311 nic->packet[5] == 0xFF*ETH_ALEN)
00312 printf(",t=%hX,b]",type);
00313 else
00314 printf(",t=%hX]",type);
00315 }
00316 #endif
00317 return 1;
00318 }
00319
00320
00321
00322
00323
00324
00325 static int
00326 eeprom_rdy()
00327 {
00328 int i;
00329
00330 for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
00331 udelay(1000);
00332 if (i >= MAX_EEPROMBUSY) {
00333
00334 printf("3c595: eeprom is busy.\n");
00335 return (0);
00336 }
00337 return (1);
00338 }
00339
00340
00341
00342
00343
00344 static int
00345 get_e(offset)
00346 int offset;
00347 {
00348 if (!eeprom_rdy())
00349 return (0xffff);
00350 outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
00351 if (!eeprom_rdy())
00352 return (0xffff);
00353 return (inw(BASE + VX_W0_EEPROM_DATA));
00354 }
00355
00356 static void
00357 vxgetlink(void)
00358 {
00359 int n, k;
00360
00361 GO_WINDOW(3);
00362 vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
00363 for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
00364 if (vx_connectors & conn_tab[k].bit) {
00365 if (n > 0) {
00366 printf("/");
00367 }
00368 printf("%s", conn_tab[k].name );
00369 n++;
00370 }
00371 }
00372 if (vx_connectors == 0) {
00373 printf("no connectors!");
00374 return;
00375 }
00376 GO_WINDOW(3);
00377 vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
00378 & INTERNAL_CONNECTOR_MASK)
00379 >> INTERNAL_CONNECTOR_BITS;
00380 if (vx_connector & 0x10) {
00381 vx_connector &= 0x0f;
00382 printf("[*%s*]", conn_tab[vx_connector].name);
00383 printf(": disable 'auto select' with DOS util!");
00384 } else {
00385 printf("[*%s*]", conn_tab[vx_connector].name);
00386 }
00387 }
00388
00389 static void
00390 vxsetlink(void)
00391 {
00392 int i, j;
00393 char *reason, *warning;
00394 static char prev_conn = -1;
00395
00396 if (prev_conn == -1) {
00397 prev_conn = vx_connector;
00398 }
00399
00400 i = vx_connector;
00401 reason = "default";
00402 warning = 0;
00403
00404 if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
00405 warning = "strange connector type in EEPROM.";
00406 reason = "forced";
00407 i = CONNECTOR_UTP;
00408 }
00409
00410 if (warning != 0) {
00411 printf("warning: %s\n", warning);
00412 }
00413 printf("selected %s. (%s)\n", conn_tab[i].name, reason);
00414
00415
00416 GO_WINDOW(3);
00417 j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
00418 outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
00419
00420
00421 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
00422 udelay(8000);
00423 GO_WINDOW(4);
00424 outw(0, BASE + VX_W4_MEDIA_TYPE);
00425
00426
00427 switch(i) {
00428 case CONNECTOR_UTP:
00429 GO_WINDOW(4);
00430 outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
00431 break;
00432 case CONNECTOR_BNC:
00433 outw(START_TRANSCEIVER,BASE + VX_COMMAND);
00434 udelay(8000);
00435 break;
00436 case CONNECTOR_TX:
00437 case CONNECTOR_FX:
00438 GO_WINDOW(4);
00439 outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
00440 break;
00441 default:
00442 break;
00443 }
00444 GO_WINDOW(1);
00445 }
00446
00447 static void t595_disable ( struct nic *nic ) {
00448
00449 t595_reset(nic);
00450
00451 outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
00452 udelay(8000);
00453 GO_WINDOW(4);
00454 outw(0, BASE + VX_W4_MEDIA_TYPE);
00455 GO_WINDOW(1);
00456 }
00457
00458 static void t595_irq(struct nic *nic __unused, irq_action_t action __unused)
00459 {
00460 switch ( action ) {
00461 case DISABLE :
00462 break;
00463 case ENABLE :
00464 break;
00465 case FORCE :
00466 break;
00467 }
00468 }
00469
00470
00471
00472
00473 static int t595_probe ( struct nic *nic, struct pci_device *pci ) {
00474
00475 int i;
00476 unsigned short *p;
00477
00478 if (pci->ioaddr == 0)
00479 return 0;
00480 eth_nic_base = pci->ioaddr;
00481
00482 nic->irqno = 0;
00483 nic->ioaddr = pci->ioaddr;
00484
00485 GO_WINDOW(0);
00486 outw(GLOBAL_RESET, BASE + VX_COMMAND);
00487 VX_BUSY_WAIT;
00488
00489 vxgetlink();
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 p = (unsigned short *) nic->node_addr;
00502 for (i = 0; i < 3; i++) {
00503 GO_WINDOW(0);
00504 p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
00505 GO_WINDOW(2);
00506 outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
00507 }
00508
00509 DBG ( "Ethernet address: %s\n", eth_ntoa (nic->node_addr) );
00510
00511 t595_reset(nic);
00512 nic->nic_op = &t595_operations;
00513 return 1;
00514
00515 }
00516
00517 static struct nic_operations t595_operations = {
00518 .connect = dummy_connect,
00519 .poll = t595_poll,
00520 .transmit = t595_transmit,
00521 .irq = t595_irq,
00522
00523 };
00524
00525 static struct pci_device_id t595_nics[] = {
00526 PCI_ROM(0x10b7, 0x5900, "3c590", "3Com590", 0),
00527 PCI_ROM(0x10b7, 0x5950, "3c595", "3Com595", 0),
00528 PCI_ROM(0x10b7, 0x5951, "3c595-1", "3Com595", 0),
00529 PCI_ROM(0x10b7, 0x5952, "3c595-2", "3Com595", 0),
00530 PCI_ROM(0x10b7, 0x9000, "3c900-tpo", "3Com900-TPO", 0),
00531 PCI_ROM(0x10b7, 0x9001, "3c900-t4", "3Com900-Combo", 0),
00532 PCI_ROM(0x10b7, 0x9004, "3c900b-tpo", "3Com900B-TPO", 0),
00533 PCI_ROM(0x10b7, 0x9005, "3c900b-combo", "3Com900B-Combo", 0),
00534 PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2", "3Com900B-2/T", 0),
00535 PCI_ROM(0x10b7, 0x900a, "3c900b-fl", "3Com900B-FL", 0),
00536 PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone", 0),
00537 PCI_ROM(0x10b7, 0x9805, "3c9805-1", "3Com9805", 0),
00538 PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1", "3CSOHO100-TX", 0),
00539 PCI_ROM(0x10b7, 0x4500, "3c450-1", "3Com450 HomePNA Tornado", 0),
00540 };
00541
00542 PCI_DRIVER ( t595_driver, t595_nics, PCI_NO_CLASS );
00543
00544 DRIVER ( "3C595", nic_driver, pci_driver, t595_driver,
00545 t595_probe, t595_disable );
00546
00547
00548
00549
00550
00551
00552
00553