00001 #ifdef ALLMULTI
00002 #error multicast support is not yet implemented
00003 #endif
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 FILE_LICENCE ( GPL2_ONLY );
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 #include <errno.h>
00091 #include <gpxe/ethernet.h>
00092 #include "etherboot.h"
00093 #include "nic.h"
00094 #include <gpxe/isa.h>
00095 #include "console.h"
00096 #include "cs89x0.h"
00097
00098 static unsigned short eth_nic_base;
00099 static unsigned long eth_mem_start;
00100 static unsigned short eth_irqno;
00101 static unsigned short eth_cs_type;
00102 static unsigned short eth_auto_neg_cnf;
00103 static unsigned short eth_adapter_cnf;
00104 static unsigned short eth_linectl;
00105
00106
00107
00108
00109
00110 static inline int readreg(int portno)
00111 {
00112 outw(portno, eth_nic_base + ADD_PORT);
00113 return inw(eth_nic_base + DATA_PORT);
00114 }
00115
00116 static inline void writereg(int portno, int value)
00117 {
00118 outw(portno, eth_nic_base + ADD_PORT);
00119 outw(value, eth_nic_base + DATA_PORT);
00120 return;
00121 }
00122
00123
00124
00125
00126
00127 static int wait_eeprom_ready(void)
00128 {
00129 unsigned long tmo = currticks() + 4*TICKS_PER_SEC;
00130
00131
00132
00133
00134 while(readreg(PP_SelfST) & SI_BUSY) {
00135 if (currticks() >= tmo)
00136 return -1; }
00137 return 0;
00138 }
00139
00140 static int get_eeprom_data(int off, int len, unsigned short *buffer)
00141 {
00142 int i;
00143
00144 #ifdef EDEBUG
00145 printf("\ncs: EEPROM data from %hX for %hX:",off,len);
00146 #endif
00147 for (i = 0; i < len; i++) {
00148 if (wait_eeprom_ready() < 0)
00149 return -1;
00150
00151
00152 writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD);
00153 if (wait_eeprom_ready() < 0)
00154 return -1;
00155 buffer[i] = readreg(PP_EEData);
00156 #ifdef EDEBUG
00157 if (!(i%10))
00158 printf("\ncs: ");
00159 printf("%hX ", buffer[i]);
00160 #endif
00161 }
00162 #ifdef EDEBUG
00163 putchar('\n');
00164 #endif
00165
00166 return(0);
00167 }
00168
00169 static int get_eeprom_chksum(int off __unused, int len, unsigned short *buffer)
00170 {
00171 int i, cksum;
00172
00173 cksum = 0;
00174 for (i = 0; i < len; i++)
00175 cksum += buffer[i];
00176 cksum &= 0xffff;
00177 if (cksum == 0)
00178 return 0;
00179 return -1;
00180 }
00181
00182
00183
00184
00185
00186 static void clrline(void)
00187 {
00188 int i;
00189
00190 putchar('\r');
00191 for (i = 79; i--; ) putchar(' ');
00192 printf("\rcs: ");
00193 return;
00194 }
00195
00196 static void control_dc_dc(int on_not_off)
00197 {
00198 unsigned int selfcontrol;
00199 unsigned long tmo = currticks() + TICKS_PER_SEC;
00200
00201
00202 selfcontrol = HCB1_ENBL;
00203 if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
00204 selfcontrol |= HCB1;
00205 else
00206 selfcontrol &= ~HCB1;
00207 writereg(PP_SelfCTL, selfcontrol);
00208
00209
00210 while (currticks() < tmo);
00211
00212 return;
00213 }
00214
00215 static int detect_tp(void)
00216 {
00217 unsigned long tmo;
00218
00219
00220
00221 clrline(); printf("attempting %s:","TP");
00222
00223
00224
00225
00226
00227
00228
00229 writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY);
00230 control_dc_dc(0);
00231
00232
00233
00234 for (tmo = currticks() + 4; currticks() < tmo; );
00235
00236 if ((readreg(PP_LineST) & LINK_OK) == 0)
00237 return 0;
00238
00239 if (eth_cs_type != CS8900) {
00240
00241 writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK);
00242
00243 if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
00244 printf(" negotiating duplex... ");
00245 while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) {
00246 if (currticks() - tmo > 40*TICKS_PER_SEC) {
00247 printf("time out ");
00248 break;
00249 }
00250 }
00251 }
00252 if (readreg(PP_AutoNegST) & FDX_ACTIVE)
00253 printf("using full duplex");
00254 else
00255 printf("using half duplex");
00256 }
00257
00258 return A_CNF_MEDIA_10B_T;
00259 }
00260
00261
00262 static int send_test_pkt(struct nic *nic)
00263 {
00264 static unsigned char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,
00265 0, 46,
00266 0, 0,
00267 0xf3,0 };
00268 unsigned long tmo;
00269
00270 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON);
00271
00272 memcpy(testpacket, nic->node_addr, ETH_ALEN);
00273 memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN);
00274
00275 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
00276 outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT);
00277
00278
00279 for (tmo = currticks() + 2;
00280 (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; )
00281 if (currticks() >= tmo)
00282 return(0);
00283
00284
00285 outsw(eth_nic_base + TX_FRAME_PORT, testpacket,
00286 (ETH_ZLEN+1)>>1);
00287
00288 printf(" sending test packet ");
00289
00290 for (tmo = currticks() + 2; currticks() < tmo; );
00291
00292 if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
00293 printf("succeeded");
00294 return 1;
00295 }
00296 printf("failed");
00297 return 0;
00298 }
00299
00300
00301 static int detect_aui(struct nic *nic)
00302 {
00303 clrline(); printf("attempting %s:","AUI");
00304 control_dc_dc(0);
00305
00306 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
00307
00308 if (send_test_pkt(nic)) {
00309 return A_CNF_MEDIA_AUI; }
00310 else
00311 return 0;
00312 }
00313
00314 static int detect_bnc(struct nic *nic)
00315 {
00316 clrline(); printf("attempting %s:","BNC");
00317 control_dc_dc(1);
00318
00319 writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
00320
00321 if (send_test_pkt(nic)) {
00322 return A_CNF_MEDIA_10B_2; }
00323 else
00324 return 0;
00325 }
00326
00327
00328
00329
00330
00331 static void cs89x0_reset(struct nic *nic)
00332 {
00333 int i;
00334 unsigned long reset_tmo;
00335
00336 writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET);
00337
00338
00339 for (reset_tmo = currticks() + 2; currticks() < reset_tmo; );
00340
00341 if (eth_cs_type != CS8900) {
00342
00343
00344 if (eth_irqno != 0xFFFF) {
00345 outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT);
00346 outb(eth_irqno, eth_nic_base + DATA_PORT);
00347 outb(0, eth_nic_base + DATA_PORT + 1); }
00348
00349 if (eth_mem_start) {
00350 outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT);
00351 outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT);
00352 outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } }
00353
00354
00355 for (reset_tmo = currticks() + 2;
00356 (readreg(PP_SelfST) & INIT_DONE) == 0 &&
00357 currticks() < reset_tmo; );
00358
00359
00360 writereg(PP_BusCTL, 0);
00361
00362
00363 for (i=0; i < ETH_ALEN/2; i++)
00364 writereg(PP_IA+i*2,
00365 nic->node_addr[i*2] |
00366 (nic->node_addr[i*2+1] << 8));
00367
00368
00369 writereg(PP_RxCTL, DEF_RX_ACCEPT);
00370
00371
00372 writereg(PP_RxCFG, 0);
00373
00374
00375 writereg(PP_TxCFG, 0);
00376
00377
00378 writereg(PP_BufCFG, 0);
00379
00380
00381 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00382
00383 return;
00384 }
00385
00386
00387
00388
00389
00390 static void cs89x0_transmit(
00391 struct nic *nic,
00392 const char *d,
00393 unsigned int t,
00394 unsigned int s,
00395 const char *p)
00396 {
00397 unsigned long tmo;
00398 int sr;
00399
00400
00401
00402 if ((sr = ((s + ETH_HLEN + 1)&~1)) < ETH_ZLEN)
00403 sr = ETH_ZLEN;
00404
00405 retry:
00406
00407 outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT);
00408 outw(sr, eth_nic_base + TX_LEN_PORT);
00409
00410
00411 if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) {
00412
00413 printf("cs: unable to send packet; retrying...\n");
00414 for (tmo = currticks() + 5*TICKS_PER_SEC; currticks() < tmo; );
00415 cs89x0_reset(nic);
00416 goto retry; }
00417
00418
00419 outsw(eth_nic_base + TX_FRAME_PORT, d, ETH_ALEN/2);
00420 outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr,
00421 ETH_ALEN/2);
00422 outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
00423 outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
00424 for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
00425 outw(0, eth_nic_base + TX_FRAME_PORT);
00426
00427
00428 for (tmo = currticks()+5*TICKS_PER_SEC;
00429 (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() < tmo;)
00430 ;
00431 if ((s & TX_SEND_OK_BITS) != TX_OK) {
00432 printf("\ntransmission error %#hX\n", s);
00433 }
00434
00435 return;
00436 }
00437
00438
00439
00440
00441
00442 static int cs89x0_poll(struct nic *nic, int retrieve)
00443 {
00444 int status;
00445
00446 status = readreg(PP_RxEvent);
00447
00448 if ((status & RX_OK) == 0)
00449 return(0);
00450
00451 if ( ! retrieve ) return 1;
00452
00453 status = inw(eth_nic_base + RX_FRAME_PORT);
00454 nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT);
00455 insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1);
00456 if (nic->packetlen & 1)
00457 nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT);
00458 return 1;
00459 }
00460
00461 static void cs89x0_irq(struct nic *nic __unused, irq_action_t action __unused)
00462 {
00463 switch ( action ) {
00464 case DISABLE :
00465 break;
00466 case ENABLE :
00467 break;
00468 case FORCE :
00469 break;
00470 }
00471 }
00472
00473 static struct nic_operations cs89x0_operations = {
00474 .connect = dummy_connect,
00475 .poll = cs89x0_poll,
00476 .transmit = cs89x0_transmit,
00477 .irq = cs89x0_irq,
00478 };
00479
00480
00481
00482
00483
00484 static int cs89x0_probe_addr ( isa_probe_addr_t ioaddr ) {
00485
00486
00487
00488 if (ioaddr & 1) {
00489 ioaddr &= ~1;
00490 if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
00491 return 0;
00492 outw(PP_ChipID, ioaddr + ADD_PORT);
00493 }
00494
00495 if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
00496 return 0;
00497
00498 return 1;
00499 }
00500
00501 static int cs89x0_probe ( struct nic *nic, struct isa_device *isa __unused ) {
00502 int i, result = -1;
00503 unsigned rev_type = 0, isa_cnf, cs_revision;
00504 unsigned short eeprom_buff[CHKSUM_LEN];
00505
00506 nic->ioaddr &= ~1;
00507 eth_nic_base = nic->ioaddr;
00508
00509
00510 rev_type = readreg(PRODUCT_ID_ADD);
00511 eth_cs_type = rev_type &~ REVISON_BITS;
00512 cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
00513
00514 printf("\ncs: cs89%c0%s rev %c, base %#hX",
00515 eth_cs_type==CS8900?'0':'2',
00516 eth_cs_type==CS8920M?"M":"",
00517 cs_revision,
00518 eth_nic_base);
00519 #ifndef EMBEDDED
00520
00521 if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) {
00522 printf("\ncs: no EEPROM...\n");
00523 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00524 return 0;
00525 } else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN,
00526 eeprom_buff) < 0) {
00527 printf("\ncs: EEPROM read failed...\n");
00528 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00529 return 0;
00530 } else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN,
00531 eeprom_buff) < 0) {
00532 printf("\ncs: EEPROM checksum bad...\n");
00533 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00534 return 0;
00535 }
00536
00537
00538
00539 eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
00540
00541 eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
00542
00543 isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2];
00544
00545
00546 eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8;
00547
00548 printf("%s%s%s, addr ",
00549 (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"",
00550 (eth_adapter_cnf & A_CNF_AUI)?", AUI":"",
00551 (eth_adapter_cnf & A_CNF_10B_2)?", BNC":"");
00552
00553
00554 if (eth_cs_type != CS8900 &&
00555
00556 (i = readreg(PP_CS8920_ISAINT) & 0xff,
00557 (i != 0 && i < CS8920_NO_INTS)))
00558 eth_irqno = i;
00559 else {
00560 i = isa_cnf & INT_NO_MASK;
00561 if (eth_cs_type == CS8900) {
00562
00563
00564
00565
00566
00567
00568
00569
00570 if (i < 4) i = "\012\013\014\005"[i];
00571 else printf("\ncs: BUG: isa_config is %d\n", i); }
00572 eth_irqno = i; }
00573
00574 nic->irqno = eth_irqno;
00575
00576
00577 for (i=0; i<ETH_ALEN; i++) {
00578 nic->node_addr[i] = ((unsigned char *)eeprom_buff)[i];
00579 }
00580
00581 DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
00582
00583 #endif
00584 #ifdef EMBEDDED
00585
00586 {
00587 unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
00588 memcpy(nic->node_addr, MAC_HW_ADDR, 6);
00589 }
00590
00591 DBG ( "%s\n", eth_ntoa ( nic->node_addr ) );
00592
00593 eth_adapter_cnf = A_CNF_10B_T | A_CNF_MEDIA_10B_T;
00594 eth_auto_neg_cnf = EE_AUTO_NEG_ENABLE | IMM_BIT;
00595 #endif
00596 #ifndef EMBEDDED
00597
00598
00599 if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) &&
00600 (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH))
00601 eth_linectl = LOW_RX_SQUELCH;
00602 else
00603 eth_linectl = 0;
00604
00605
00606
00607 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
00608 case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T;
00609 break;
00610 case A_CNF_MEDIA_AUI: result = eth_adapter_cnf & A_CNF_AUI;
00611 break;
00612 case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2;
00613 break;
00614 default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI |
00615 A_CNF_10B_2);
00616 }
00617 if (!result) {
00618 printf("cs: EEPROM is configured for unavailable media\n");
00619 error:
00620 writereg(PP_LineCTL, readreg(PP_LineCTL) &
00621 ~(SERIAL_TX_ON | SERIAL_RX_ON));
00622 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00623 return 0;
00624 }
00625 #endif
00626
00627 cs89x0_reset(nic);
00628
00629
00630 switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) {
00631 case A_CNF_MEDIA_10B_T:
00632 result = detect_tp();
00633 if (!result) {
00634 clrline();
00635 printf("10Base-T (RJ-45%s",
00636 ") has no cable\n"); }
00637
00638 if (eth_auto_neg_cnf & IMM_BIT)
00639
00640 result = A_CNF_MEDIA_10B_T;
00641 break;
00642 case A_CNF_MEDIA_AUI:
00643 result = detect_aui(nic);
00644 if (!result) {
00645 clrline();
00646 printf("10Base-5 (AUI%s",
00647 ") has no cable\n"); }
00648
00649 if (eth_auto_neg_cnf & IMM_BIT)
00650
00651 result = A_CNF_MEDIA_AUI;
00652 break;
00653 case A_CNF_MEDIA_10B_2:
00654 result = detect_bnc(nic);
00655 if (!result) {
00656 clrline();
00657 printf("10Base-2 (BNC%s",
00658 ") has no cable\n"); }
00659
00660 if (eth_auto_neg_cnf & IMM_BIT)
00661
00662 result = A_CNF_MEDIA_10B_2;
00663 break;
00664 case A_CNF_MEDIA_AUTO:
00665 writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET);
00666 if (eth_adapter_cnf & A_CNF_10B_T)
00667 if ((result = detect_tp()) != 0)
00668 break;
00669 if (eth_adapter_cnf & A_CNF_AUI)
00670 if ((result = detect_aui(nic)) != 0)
00671 break;
00672 if (eth_adapter_cnf & A_CNF_10B_2)
00673 if ((result = detect_bnc(nic)) != 0)
00674 break;
00675 clrline(); printf("no media detected\n");
00676 goto error;
00677 }
00678 clrline();
00679 switch(result) {
00680 case 0: printf("no network cable attached to configured media\n");
00681 goto error;
00682 case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\n");
00683 break;
00684 case A_CNF_MEDIA_AUI: printf("using 10Base-5 (AUI)\n");
00685 break;
00686 case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\n");
00687 break;
00688 }
00689
00690
00691 writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON |
00692 SERIAL_TX_ON);
00693
00694 return 0;
00695 #ifdef EMBEDDED
00696 error:
00697 writereg(PP_LineCTL, readreg(PP_LineCTL) &
00698 ~(SERIAL_TX_ON | SERIAL_RX_ON));
00699 outw(PP_ChipID, eth_nic_base + ADD_PORT);
00700 return 0;
00701 #endif
00702
00703 nic->nic_op = &cs89x0_operations;
00704 return 1;
00705 }
00706
00707 static void cs89x0_disable ( struct nic *nic,
00708 struct isa_device *isa __unused ) {
00709 cs89x0_reset(nic);
00710 }
00711
00712 static isa_probe_addr_t cs89x0_probe_addrs[] = {
00713 #ifndef EMBEDDED
00714
00715 0x300, 0x320, 0x340, 0x200, 0x220, 0x240,
00716 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
00717
00718 0x301, 0x321, 0x341, 0x201, 0x221, 0x241,
00719 0x261, 0x281, 0x2a1, 0x2c1, 0x2e1,
00720 #else
00721 0x01000300,
00722 #endif
00723 };
00724
00725 ISA_DRIVER ( cs89x0_driver, cs89x0_probe_addrs, cs89x0_probe_addr,
00726 ISAPNP_VENDOR('C','S','C'), 0x0007 );
00727
00728 DRIVER ( "cs89x0", nic_driver, isa_driver, cs89x0_driver,
00729 cs89x0_probe, cs89x0_disable );
00730
00731 ISA_ROM ( "cs89x0", "Crystal Semiconductor CS89x0" );
00732
00733
00734
00735
00736
00737
00738
00739