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
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #define XCVR_MAGIC (0x5A00)
00044
00048 #define XMIT_RETRIES 250
00049
00050 #undef virt_to_bus
00051 #define virt_to_bus(x) ((unsigned long)x)
00052
00053
00054 enum Registers
00055 {
00056 regPowerMgmtCtrl_w = 0x7c,
00057 regUpMaxBurst_w = 0x7a,
00058 regDnMaxBurst_w = 0x78,
00059 regDebugControl_w = 0x74,
00060 regDebugData_l = 0x70,
00061 regRealTimeCnt_l = 0x40,
00062 regUpBurstThresh_b = 0x3e,
00063 regUpPoll_b = 0x3d,
00064 regUpPriorityThresh_b = 0x3c,
00065 regUpListPtr_l = 0x38,
00066 regCountdown_w = 0x36,
00067 regFreeTimer_w = 0x34,
00068 regUpPktStatus_l = 0x30,
00069 regTxFreeThresh_b = 0x2f,
00070 regDnPoll_b = 0x2d,
00071 regDnPriorityThresh_b = 0x2c,
00072 regDnBurstThresh_b = 0x2a,
00073 regDnListPtr_l = 0x24,
00074 regDmaCtrl_l = 0x20,
00076 regIntStatusAuto_w = 0x1e,
00077 regTxStatus_b = 0x1b,
00078 regTimer_b = 0x1a,
00079 regTxPktId_b = 0x18,
00080 regCommandIntStatus_w = 0x0e,
00081 };
00082
00084 enum Registers7
00085 {
00086 regPowerMgmtEvent_7_w = 0x0c,
00087 regVlanEtherType_7_w = 0x04,
00088 regVlanMask_7_w = 0x00,
00089 };
00090
00091 enum Registers6
00092 {
00093 regBytesXmittedOk_6_w = 0x0c,
00094 regBytesRcvdOk_6_w = 0x0a,
00095 regUpperFramesOk_6_b = 0x09,
00096 regFramesDeferred_6_b = 0x08,
00097 regFramesRecdOk_6_b = 0x07,
00098 regFramesXmittedOk_6_b = 0x06,
00099 regRxOverruns_6_b = 0x05,
00100 regLateCollisions_6_b = 0x04,
00101 regSingleCollisions_6_b = 0x03,
00102 regMultipleCollisions_6_b = 0x02,
00103 regSqeErrors_6_b = 0x01,
00104 regCarrierLost_6_b = 0x00,
00105 };
00106
00107 enum Registers5
00108 {
00109 regIndicationEnable_5_w = 0x0c,
00110 regInterruptEnable_5_w = 0x0a,
00111 regTxReclaimThresh_5_b = 0x09,
00112 regRxFilter_5_b = 0x08,
00113 regRxEarlyThresh_5_w = 0x06,
00114 regTxStartThresh_5_w = 0x00,
00115 };
00116
00117 enum Registers4
00118 {
00119 regUpperBytesOk_4_b = 0x0d,
00120 regBadSSD_4_b = 0x0c,
00121 regMediaStatus_4_w = 0x0a,
00122 regPhysicalMgmt_4_w = 0x08,
00123 regNetworkDiagnostic_4_w = 0x06,
00124 regFifoDiagnostic_4_w = 0x04,
00125 regVcoDiagnostic_4_w = 0x02,
00126 };
00127
00128 enum Registers3
00129 {
00130 regTxFree_3_w = 0x0c,
00131 regRxFree_3_w = 0x0a,
00132 regResetMediaOptions_3_w = 0x08,
00134 regMacControl_3_w = 0x06,
00135 regMaxPktSize_3_w = 0x04,
00136 regInternalConfig_3_l = 0x00,
00138 };
00139
00140 enum Registers2
00141 {
00142 regResetOptions_2_w = 0x0c,
00143 regStationMask_2_3w = 0x06,
00144 regStationAddress_2_3w = 0x00,
00145 };
00146
00147 enum Registers1
00148 {
00149 regRxStatus_1_w = 0x0a,
00150 };
00151
00152 enum Registers0
00153 {
00154 regEepromData_0_w = 0x0c,
00155 regEepromCommand_0_w = 0x0a,
00156 regBiosRomData_0_b = 0x08,
00157 regBiosRomAddr_0_l = 0x04,
00158 };
00159
00160
00161
00162 enum Windows
00163 {
00164 winPowerVlan7 = 0x07,
00165 winStatistics6 = 0x06,
00166 winTxRxControl5 = 0x05,
00167 winDiagnostics4 = 0x04,
00168 winTxRxOptions3 = 0x03,
00169 winAddressing2 = 0x02,
00170 winUnused1 = 0x01,
00171 winEepromBios0 = 0x00,
00172 };
00173
00174
00175
00176 enum Commands
00177 {
00178 cmdGlobalReset = 0x00,
00179 cmdSelectRegisterWindow = 0x01,
00180 cmdEnableDcConverter = 0x02,
00181 cmdRxDisable = 0x03,
00182 cmdRxEnable = 0x04,
00183 cmdRxReset = 0x05,
00184 cmdStallCtl = 0x06,
00185 cmdTxEnable = 0x09,
00186 cmdTxDisable = 0x0A,
00187 cmdTxReset = 0x0B,
00188 cmdRequestInterrupt = 0x0C,
00189 cmdAcknowledgeInterrupt = 0x0D,
00190 cmdSetInterruptEnable = 0x0E,
00191 cmdSetIndicationEnable = 0x0F,
00192 cmdSetRxFilter = 0x10,
00193 cmdSetRxEarlyThresh = 0x11,
00194 cmdSetTxStartThresh = 0x13,
00195 cmdStatisticsEnable = 0x15,
00196 cmdStatisticsDisable = 0x16,
00197 cmdDisableDcConverter = 0x17,
00198 cmdSetTxReclaimThresh = 0x18,
00199 cmdSetHashFilterBit = 0x19,
00200 };
00201
00202
00203
00204 #define INT_INTERRUPTLATCH (1<<0)
00205 #define INT_HOSTERROR (1<<1)
00206 #define INT_TXCOMPLETE (1<<2)
00207 #define INT_RXCOMPLETE (1<<4)
00208 #define INT_RXEARLY (1<<5)
00209 #define INT_INTREQUESTED (1<<6)
00210 #define INT_UPDATESTATS (1<<7)
00211 #define INT_LINKEVENT (1<<8)
00212 #define INT_DNCOMPLETE (1<<9)
00213 #define INT_UPCOMPLETE (1<<10)
00214 #define INT_CMDINPROGRESS (1<<12)
00215 #define INT_WINDOWNUMBER (7<<13)
00216
00217
00218
00219 typedef struct
00220 {
00221 unsigned int DnNextPtr;
00222 unsigned int FrameStartHeader;
00223 unsigned int HdrAddr;
00224 unsigned int HdrLength;
00225 unsigned int DataAddr;
00226 unsigned int DataLength;
00227 }
00228 TXD;
00229
00230
00231 typedef struct
00232 {
00233 unsigned int UpNextPtr;
00234 unsigned int UpPktStatus;
00235 unsigned int DataAddr;
00236 unsigned int DataLength;
00237 }
00238 RXD;
00239
00240
00241 static struct
00242 {
00243 unsigned char isBrev;
00244 unsigned char CurrentWindow;
00245 unsigned int IOAddr;
00246 unsigned char HWAddr[ETH_ALEN];
00247 TXD TransmitDPD;
00248 RXD ReceiveUPD;
00249 }
00250 INF_3C90X;
00251
00252
00253
00254
00255 static int
00256 a3c90x_internal_IssueCommand(int ioaddr, int cmd, int param)
00257 {
00258 unsigned int val;
00259
00261 val = cmd;
00262 val <<= 11;
00263 val |= param;
00264
00266 outw(val, ioaddr + regCommandIntStatus_w);
00267
00269 while (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
00270
00271 return 0;
00272 }
00273
00274
00275
00276
00277 static int
00278 a3c90x_internal_SetWindow(int ioaddr, int window)
00279 {
00280
00282 if (INF_3C90X.CurrentWindow == window) return 0;
00283
00285 a3c90x_internal_IssueCommand(ioaddr, cmdSelectRegisterWindow, window);
00286 INF_3C90X.CurrentWindow = window;
00287
00288 return 0;
00289 }
00290
00291
00292
00293
00294 static unsigned short
00295 a3c90x_internal_ReadEeprom(int ioaddr, int address)
00296 {
00297 unsigned short val;
00298
00300 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winEepromBios0);
00301
00303 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00304
00306 outw(address + ((0x02)<<6), ioaddr + regEepromCommand_0_w);
00307 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00308 val = inw(ioaddr + regEepromData_0_w);
00309
00310 return val;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319 static int
00320 a3c90x_internal_WriteEepromWord(int ioaddr, int address, unsigned short value)
00321 {
00323 a3c90x_internal_SetWindow(ioaddr, winEepromBios0);
00324
00326 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00327
00329 outw(0x30, ioaddr + regEepromCommand_0_w);
00330 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00331
00333 outw(address + ((0x03)<<6), ioaddr + regEepromCommand_0_w);
00334 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00335
00337 outw(value, ioaddr + regEepromData_0_w);
00338 outw(0x30, ioaddr + regEepromCommand_0_w);
00339 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00340
00342 outw(address + ((0x01)<<6), ioaddr + regEepromCommand_0_w);
00343 while((1<<15) & inw(ioaddr + regEepromCommand_0_w));
00344
00345 return 0;
00346 }
00347
00348
00349
00350
00351
00352 static int
00353 a3c90x_internal_WriteEeprom(int ioaddr, int address, unsigned short value)
00354 {
00355 int cksum = 0,v;
00356 int i;
00357 int maxAddress, cksumAddress;
00358
00359 if (INF_3C90X.isBrev)
00360 {
00361 maxAddress=0x1f;
00362 cksumAddress=0x20;
00363 }
00364 else
00365 {
00366 maxAddress=0x16;
00367 cksumAddress=0x17;
00368 }
00369
00371 if (a3c90x_internal_WriteEepromWord(ioaddr, address, value) == -1)
00372 return -1;
00373
00375 for(i=0;i<=maxAddress;i++)
00376 {
00377 v = a3c90x_internal_ReadEeprom(ioaddr, i);
00378 cksum ^= (v & 0xFF);
00379 cksum ^= ((v>>8) & 0xFF);
00380 }
00382 if (a3c90x_internal_WriteEepromWord(ioaddr, cksumAddress, cksum) == -1)
00383 return -1;
00384
00385 return 0;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 static void
00397 a3c90x_reset(struct nic *nic)
00398 {
00399 int cfg;
00400
00401 #ifdef CFG_3C90X_PRESERVE_XCVR
00402
00403 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00404 cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l);
00405 #endif
00406
00408 printf("Issuing RESET:\n");
00409 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdGlobalReset, 0);
00410
00412 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
00413
00417 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
00418 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
00419 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
00420 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4);
00421
00422 #ifdef CFG_3C90X_PRESERVE_XCVR
00423
00424 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00425 outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
00426
00428 if ((cfg&0x0300) == 0x0300)
00429 {
00430 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
00431 }
00432 #endif
00433
00435 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0);
00436 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
00437 ;
00438 if (! INF_3C90X.isBrev)
00439 outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b);
00440 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
00441
00446 if (INF_3C90X.isBrev)
00447 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04);
00448 else
00449 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00);
00450 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
00451 ;
00452 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
00453
00454 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00455 cmdSetInterruptEnable, 0);
00457 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00458 cmdSetIndicationEnable, 0x0014);
00460 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00461 cmdAcknowledgeInterrupt, 0x661);
00462
00463 return;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 static void
00476 a3c90x_transmit(struct nic *nic, const char *d, unsigned int t,
00477 unsigned int s, const char *p)
00478 {
00479
00480 struct eth_hdr
00481 {
00482 unsigned char dst_addr[ETH_ALEN];
00483 unsigned char src_addr[ETH_ALEN];
00484 unsigned short type;
00485 } hdr;
00486
00487 unsigned char status;
00488 unsigned i, retries;
00489
00490 for (retries=0; retries < XMIT_RETRIES ; retries++)
00491 {
00493 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 2);
00494
00496 inw(INF_3C90X.IOAddr + regCommandIntStatus_w);
00497 inw(INF_3C90X.IOAddr + regCommandIntStatus_w);
00498
00499 while (inw(INF_3C90X.IOAddr+regCommandIntStatus_w) &
00500 INT_CMDINPROGRESS)
00501 ;
00502
00504 hdr.type = htons(t);
00505
00507 memcpy(hdr.dst_addr, d, ETH_ALEN);
00508
00510 memcpy(hdr.src_addr, INF_3C90X.HWAddr, ETH_ALEN);
00511
00513 INF_3C90X.TransmitDPD.DnNextPtr = 0;
00515 INF_3C90X.TransmitDPD.FrameStartHeader = (s + sizeof(hdr)) | 0x8000;
00516 INF_3C90X.TransmitDPD.HdrAddr = virt_to_bus(&hdr);
00517 INF_3C90X.TransmitDPD.HdrLength = sizeof(hdr);
00518 INF_3C90X.TransmitDPD.DataAddr = virt_to_bus(p);
00519 INF_3C90X.TransmitDPD.DataLength = s + (1<<31);
00520
00522 outl(virt_to_bus(&(INF_3C90X.TransmitDPD)),
00523 INF_3C90X.IOAddr + regDnListPtr_l);
00524
00526 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 3);
00527 while(inl(INF_3C90X.IOAddr + regDnListPtr_l) != 0)
00528 ;
00529
00531 load_timer2(10*TICKS_PER_MS);
00532 while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
00533 timer2_running())
00534 ;
00535
00536 if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
00537 {
00538 printf("3C90X: Tx Timeout\n");
00539 continue;
00540 }
00541
00542 status = inb(INF_3C90X.IOAddr + regTxStatus_b);
00543
00545 outb(0x00, INF_3C90X.IOAddr + regTxStatus_b);
00546
00548 if ((status & 0xbf) == 0x80)
00549 return;
00550
00551 printf("3C90X: Status (%hhX)\n", status);
00553 if (status & 0x02)
00554 {
00555 printf("3C90X: Tx Reclaim Error (%hhX)\n", status);
00556 a3c90x_reset(NULL);
00557 }
00558 else if (status & 0x04)
00559 {
00560 printf("3C90X: Tx Status Overflow (%hhX)\n", status);
00561 for (i=0; i<32; i++)
00562 outb(0x00, INF_3C90X.IOAddr + regTxStatus_b);
00564 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
00565 }
00566 else if (status & 0x08)
00567 {
00568 printf("3C90X: Tx Max Collisions (%hhX)\n", status);
00570 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
00571 }
00572 else if (status & 0x10)
00573 {
00574 printf("3C90X: Tx Underrun (%hhX)\n", status);
00575 a3c90x_reset(NULL);
00576 }
00577 else if (status & 0x20)
00578 {
00579 printf("3C90X: Tx Jabber (%hhX)\n", status);
00580 a3c90x_reset(NULL);
00581 }
00582 else if ((status & 0x80) != 0x80)
00583 {
00584 printf("3C90X: Internal Error - Incomplete Transmission (%hhX)\n",
00585 status);
00586 a3c90x_reset(NULL);
00587 }
00588 }
00589
00591 printf("Failed to send after %d retries\n", retries);
00592 return;
00593
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603 static int
00604 a3c90x_poll(struct nic *nic)
00605 {
00606 int i, errcode;
00607
00608 if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0010))
00609 {
00610 return 0;
00611 }
00612
00618 INF_3C90X.ReceiveUPD.UpNextPtr = 0;
00619 INF_3C90X.ReceiveUPD.UpPktStatus = 0;
00620 INF_3C90X.ReceiveUPD.DataAddr = virt_to_bus(nic->packet);
00621 INF_3C90X.ReceiveUPD.DataLength = 1536 + (1<<31);
00622
00624 outl(virt_to_bus(&(INF_3C90X.ReceiveUPD)),
00625 INF_3C90X.IOAddr + regUpListPtr_l);
00626
00628 for(i=0;i<40000;i++);
00629 while((INF_3C90X.ReceiveUPD.UpPktStatus & ((1<<14) | (1<<15))) == 0)
00630 for(i=0;i<40000;i++);
00631
00633 if (INF_3C90X.ReceiveUPD.UpPktStatus & (1<<14))
00634 {
00635 errcode = INF_3C90X.ReceiveUPD.UpPktStatus;
00636 if (errcode & (1<<16))
00637 printf("3C90X: Rx Overrun (%hX)\n",errcode>>16);
00638 else if (errcode & (1<<17))
00639 printf("3C90X: Runt Frame (%hX)\n",errcode>>16);
00640 else if (errcode & (1<<18))
00641 printf("3C90X: Alignment Error (%hX)\n",errcode>>16);
00642 else if (errcode & (1<<19))
00643 printf("3C90X: CRC Error (%hX)\n",errcode>>16);
00644 else if (errcode & (1<<20))
00645 printf("3C90X: Oversized Frame (%hX)\n",errcode>>16);
00646 else
00647 printf("3C90X: Packet error (%hX)\n",errcode>>16);
00648 return 0;
00649 }
00650
00652 nic->packetlen = (INF_3C90X.ReceiveUPD.UpPktStatus & 0x1FFF);
00653
00654 return 1;
00655 }
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 static void
00666 a3c90x_disable(struct nic *nic)
00667 {
00668
00669 outw(cmdRxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w);
00670 outw(cmdTxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w);
00671 }
00672
00673
00674
00675
00676
00677
00678
00679 struct nic*
00680 a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
00681 {
00682 int i, c;
00683 unsigned short eeprom[0x21];
00684 unsigned int cfg;
00685 unsigned int mopt;
00686 unsigned short linktype;
00687
00688 if (probeaddrs == 0 || probeaddrs[0] == 0)
00689 return 0;
00690
00691 adjust_pci_device(pci);
00692
00693 INF_3C90X.IOAddr = probeaddrs[0] & ~3;
00694 INF_3C90X.CurrentWindow = 255;
00695 switch (a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, 0x03))
00696 {
00697 case 0x9000:
00698 case 0x9001:
00699 case 0x9050:
00700 case 0x9051:
00701 INF_3C90X.isBrev = 0;
00702 break;
00703
00704 case 0x9004:
00705 case 0x9005:
00706 case 0x9006:
00707 case 0x900A:
00708 case 0x9055:
00709 case 0x9056:
00710 case 0x905A:
00711 default:
00712 INF_3C90X.isBrev = 1;
00713 break;
00714 }
00715
00717 if (INF_3C90X.isBrev)
00718 {
00719 for(i=0;i<=0x20;i++)
00720 {
00721 eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i);
00722 }
00723
00724 #ifdef CFG_3C90X_BOOTROM_FIX
00725
00726
00727 a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x13, 0x0160);
00728 #endif
00729
00730 #ifdef CFG_3C90X_XCVR
00731 if (CFG_3C90X_XCVR == 255)
00732 {
00734 a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16, 0);
00735 }
00736 else
00737 {
00741 a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16,
00742 XCVR_MAGIC + ((CFG_3C90X_XCVR) & 0x000F));
00743 }
00744 #endif
00745 }
00746 else
00747 {
00748 for(i=0;i<=0x17;i++)
00749 {
00750 eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i);
00751 }
00752 }
00753
00755 printf("\n\n3C90X Driver 2.00 "
00756 "Copyright 1999 LightSys Technology Services, Inc.\n"
00757 "Portions Copyright 1999 Steve Smith\n");
00758 printf("Provided with ABSOLUTELY NO WARRANTY.\n");
00759 printf("-------------------------------------------------------"
00760 "------------------------\n");
00761
00763 INF_3C90X.HWAddr[0] = eeprom[0]>>8;
00764 INF_3C90X.HWAddr[1] = eeprom[0]&0xFF;
00765 INF_3C90X.HWAddr[2] = eeprom[1]>>8;
00766 INF_3C90X.HWAddr[3] = eeprom[1]&0xFF;
00767 INF_3C90X.HWAddr[4] = eeprom[2]>>8;
00768 INF_3C90X.HWAddr[5] = eeprom[2]&0xFF;
00769 printf("MAC Address = %!\n", INF_3C90X.HWAddr);
00770
00772 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
00773 outw(htons(eeprom[0]), INF_3C90X.IOAddr + regStationAddress_2_3w);
00774 outw(htons(eeprom[1]), INF_3C90X.IOAddr + regStationAddress_2_3w+2);
00775 outw(htons(eeprom[2]), INF_3C90X.IOAddr + regStationAddress_2_3w+4);
00776 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
00777 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
00778 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4);
00779
00781 for(i=0;i<ETH_ALEN;i++)
00782 nic->node_addr[i] = (eeprom[i/2] >> (8*((i&1)^1))) & 0xff;
00783
00790 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00791 mopt = inw(INF_3C90X.IOAddr + regResetMediaOptions_3_w);
00792
00794 if (! INF_3C90X.isBrev)
00795 {
00796 mopt &= 0x7F;
00797 }
00798
00799 printf("Connectors present: ");
00800 c = 0;
00801 linktype = 0x0008;
00802 if (mopt & 0x01)
00803 {
00804 printf("%s100Base-T4",(c++)?", ":"");
00805 linktype = 0x0006;
00806 }
00807 if (mopt & 0x04)
00808 {
00809 printf("%s100Base-FX",(c++)?", ":"");
00810 linktype = 0x0005;
00811 }
00812 if (mopt & 0x10)
00813 {
00814 printf("%s10Base-2",(c++)?", ":"");
00815 linktype = 0x0003;
00816 }
00817 if (mopt & 0x20)
00818 {
00819 printf("%sAUI",(c++)?", ":"");
00820 linktype = 0x0001;
00821 }
00822 if (mopt & 0x40)
00823 {
00824 printf("%sMII",(c++)?", ":"");
00825 linktype = 0x0006;
00826 }
00827 if ((mopt & 0xA) == 0xA)
00828 {
00829 printf("%s10Base-T / 100Base-TX",(c++)?", ":"");
00830 linktype = 0x0008;
00831 }
00832 else if ((mopt & 0xA) == 0x2)
00833 {
00834 printf("%s100Base-TX",(c++)?", ":"");
00835 linktype = 0x0008;
00836 }
00837 else if ((mopt & 0xA) == 0x8)
00838 {
00839 printf("%s10Base-T",(c++)?", ":"");
00840 linktype = 0x0008;
00841 }
00842 printf(".\n");
00843
00847 if (INF_3C90X.isBrev)
00848 {
00849 if ((eeprom[0x16] & 0xFF00) == XCVR_MAGIC)
00850 {
00852 linktype = eeprom[0x16] & 0x000F;
00853 }
00854 }
00855 else
00856 {
00857 #ifdef CFG_3C90X_XCVR
00858 if (CFG_3C90X_XCVR != 255)
00859 linktype = CFG_3C90X_XCVR;
00860 #endif
00861
00863 if (linktype == 0x0009)
00864 {
00865 if (INF_3C90X.isBrev)
00866 printf("WARNING: MII External MAC Mode only supported on B-revision "
00867 "cards!!!!\nFalling Back to MII Mode\n");
00868 linktype = 0x0006;
00869 }
00870 }
00871
00873 if (linktype == 0x0003)
00874 {
00875 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
00876 }
00877
00879 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00880 cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l);
00881 cfg &= ~(0xF<<20);
00882 cfg |= (linktype<<20);
00883 outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
00884
00886 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0x00);
00887 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
00888 ;
00889
00890 if (!INF_3C90X.isBrev)
00891 outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b);
00892
00893 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
00894
00899 if (INF_3C90X.isBrev)
00900 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04);
00901 else
00902 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00);
00903 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
00904 ;
00905
00907 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetRxFilter, 0x01 + 0x04);
00908 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
00909
00910
00914 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetInterruptEnable, 0);
00915 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00916 cmdSetIndicationEnable, 0x0014);
00917 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00918 cmdAcknowledgeInterrupt, 0x661);
00919
00921 nic->reset = a3c90x_reset;
00922 nic->poll = a3c90x_poll;
00923 nic->transmit = a3c90x_transmit;
00924 nic->disable = a3c90x_disable;
00925
00926 return nic;
00927 }
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 #include "etherboot.h"
00951 #include "pci.h"
00952
00953
00954 #define DEBUG 0
00955
00956 #ifdef CONFIG_PCI_DIRECT
00957 #define PCIBIOS_SUCCESSFUL 0x00
00958
00959
00960
00961
00962
00963 #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
00964
00965 int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
00966 unsigned int where, unsigned char *value)
00967 {
00968 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
00969 *value = inb(0xCFC + (where&3));
00970 return PCIBIOS_SUCCESSFUL;
00971 }
00972
00973 int pcibios_read_config_word (unsigned int bus,
00974 unsigned int device_fn, unsigned int where, unsigned short *value)
00975 {
00976 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
00977 *value = inw(0xCFC + (where&2));
00978 return PCIBIOS_SUCCESSFUL;
00979 }
00980
00981 int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
00982 unsigned int where, unsigned int *value)
00983 {
00984 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
00985 *value = inl(0xCFC);
00986 return PCIBIOS_SUCCESSFUL;
00987 }
00988
00989 int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
00990 unsigned int where, unsigned char value)
00991 {
00992 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
00993 outb(value, 0xCFC + (where&3));
00994 return PCIBIOS_SUCCESSFUL;
00995 }
00996
00997 int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
00998 unsigned int where, unsigned short value)
00999 {
01000 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
01001 outw(value, 0xCFC + (where&2));
01002 return PCIBIOS_SUCCESSFUL;
01003 }
01004
01005 int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value)
01006 {
01007 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
01008 outl(value, 0xCFC);
01009 return PCIBIOS_SUCCESSFUL;
01010 }
01011
01012 #undef CONFIG_CMD
01013
01014 #else
01015
01016 static struct {
01017 unsigned long address;
01018 unsigned short segment;
01019 } bios32_indirect = { 0, KERN_CODE_SEG };
01020
01021 static long pcibios_entry;
01022 static struct {
01023 unsigned long address;
01024 unsigned short segment;
01025 } pci_indirect = { 0, KERN_CODE_SEG };
01026
01027 static unsigned long bios32_service(unsigned long service)
01028 {
01029 unsigned char return_code;
01030 unsigned long address;
01031 unsigned long length;
01032 unsigned long entry;
01033 unsigned long flags;
01034
01035 save_flags(flags);
01036 __asm__(
01037 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01038 "lcall (%%edi)"
01039 #else
01040 "lcall *(%%edi)"
01041 #endif
01042 : "=a" (return_code),
01043 "=b" (address),
01044 "=c" (length),
01045 "=d" (entry)
01046 : "0" (service),
01047 "1" (0),
01048 "D" (&bios32_indirect));
01049 restore_flags(flags);
01050
01051 switch (return_code) {
01052 case 0:
01053 return address + entry;
01054 case 0x80:
01055 printf("bios32_service(%d) : not present\n", service);
01056 return 0;
01057 default:
01058 printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",
01059 service, return_code);
01060 return 0;
01061 }
01062 }
01063
01064 int pcibios_read_config_byte(unsigned int bus,
01065 unsigned int device_fn, unsigned int where, unsigned char *value)
01066 {
01067 unsigned long ret;
01068 unsigned long bx = (bus << 8) | device_fn;
01069 unsigned long flags;
01070
01071 save_flags(flags);
01072 __asm__(
01073 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01074 "lcall (%%esi)\n\t"
01075 #else
01076 "lcall *(%%esi)\n\t"
01077 #endif
01078 "jc 1f\n\t"
01079 "xor %%ah, %%ah\n"
01080 "1:"
01081 : "=c" (*value),
01082 "=a" (ret)
01083 : "1" (PCIBIOS_READ_CONFIG_BYTE),
01084 "b" (bx),
01085 "D" ((long) where),
01086 "S" (&pci_indirect));
01087 restore_flags(flags);
01088 return (int) (ret & 0xff00) >> 8;
01089 }
01090
01091 int pcibios_read_config_word(unsigned int bus,
01092 unsigned int device_fn, unsigned int where, unsigned short *value)
01093 {
01094 unsigned long ret;
01095 unsigned long bx = (bus << 8) | device_fn;
01096 unsigned long flags;
01097
01098 save_flags(flags);
01099 __asm__(
01100 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01101 "lcall (%%esi)\n\t"
01102 #else
01103 "lcall *(%%esi)\n\t"
01104 #endif
01105 "jc 1f\n\t"
01106 "xor %%ah, %%ah\n"
01107 "1:"
01108 : "=c" (*value),
01109 "=a" (ret)
01110 : "1" (PCIBIOS_READ_CONFIG_WORD),
01111 "b" (bx),
01112 "D" ((long) where),
01113 "S" (&pci_indirect));
01114 restore_flags(flags);
01115 return (int) (ret & 0xff00) >> 8;
01116 }
01117
01118 int pcibios_read_config_dword(unsigned int bus,
01119 unsigned int device_fn, unsigned int where, unsigned int *value)
01120 {
01121 unsigned long ret;
01122 unsigned long bx = (bus << 8) | device_fn;
01123 unsigned long flags;
01124
01125 save_flags(flags);
01126 __asm__(
01127 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01128 "lcall (%%esi)\n\t"
01129 #else
01130 "lcall *(%%esi)\n\t"
01131 #endif
01132 "jc 1f\n\t"
01133 "xor %%ah, %%ah\n"
01134 "1:"
01135 : "=c" (*value),
01136 "=a" (ret)
01137 : "1" (PCIBIOS_READ_CONFIG_DWORD),
01138 "b" (bx),
01139 "D" ((long) where),
01140 "S" (&pci_indirect));
01141 restore_flags(flags);
01142 return (int) (ret & 0xff00) >> 8;
01143 }
01144
01145 int pcibios_write_config_byte (unsigned int bus,
01146 unsigned int device_fn, unsigned int where, unsigned char value)
01147 {
01148 unsigned long ret;
01149 unsigned long bx = (bus << 8) | device_fn;
01150 unsigned long flags;
01151
01152 save_flags(flags); cli();
01153 __asm__(
01154 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01155 "lcall (%%esi)\n\t"
01156 #else
01157 "lcall *(%%esi)\n\t"
01158 #endif
01159 "jc 1f\n\t"
01160 "xor %%ah, %%ah\n"
01161 "1:"
01162 : "=a" (ret)
01163 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
01164 "c" (value),
01165 "b" (bx),
01166 "D" ((long) where),
01167 "S" (&pci_indirect));
01168 restore_flags(flags);
01169 return (int) (ret & 0xff00) >> 8;
01170 }
01171
01172 int pcibios_write_config_word (unsigned int bus,
01173 unsigned int device_fn, unsigned int where, unsigned short value)
01174 {
01175 unsigned long ret;
01176 unsigned long bx = (bus << 8) | device_fn;
01177 unsigned long flags;
01178
01179 save_flags(flags); cli();
01180 __asm__(
01181 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01182 "lcall (%%esi)\n\t"
01183 #else
01184 "lcall *(%%esi)\n\t"
01185 #endif
01186 "jc 1f\n\t"
01187 "xor %%ah, %%ah\n"
01188 "1:"
01189 : "=a" (ret)
01190 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
01191 "c" (value),
01192 "b" (bx),
01193 "D" ((long) where),
01194 "S" (&pci_indirect));
01195 restore_flags(flags);
01196 return (int) (ret & 0xff00) >> 8;
01197 }
01198
01199 int pcibios_write_config_dword (unsigned int bus,
01200 unsigned int device_fn, unsigned int where, unsigned int value)
01201 {
01202 unsigned long ret;
01203 unsigned long bx = (bus << 8) | device_fn;
01204 unsigned long flags;
01205
01206 save_flags(flags); cli();
01207 __asm__(
01208 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01209 "lcall (%%esi)\n\t"
01210 #else
01211 "lcall *(%%esi)\n\t"
01212 #endif
01213 "jc 1f\n\t"
01214 "xor %%ah, %%ah\n"
01215 "1:"
01216 : "=a" (ret)
01217 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
01218 "c" (value),
01219 "b" (bx),
01220 "D" ((long) where),
01221 "S" (&pci_indirect));
01222 restore_flags(flags);
01223 return (int) (ret & 0xff00) >> 8;
01224 }
01225
01226 static void check_pcibios(void)
01227 {
01228 unsigned long signature;
01229 unsigned char present_status;
01230 unsigned char major_revision;
01231 unsigned char minor_revision;
01232 unsigned long flags;
01233 int pack;
01234
01235 if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
01236 pci_indirect.address = pcibios_entry;
01237
01238 save_flags(flags);
01239 __asm__(
01240 #ifdef ABSOLUTE_WITHOUT_ASTERISK
01241 "lcall (%%edi)\n\t"
01242 #else
01243 "lcall *(%%edi)\n\t"
01244 #endif
01245 "jc 1f\n\t"
01246 "xor %%ah, %%ah\n"
01247 "1:\tshl $8, %%eax\n\t"
01248 "movw %%bx, %%ax"
01249 : "=d" (signature),
01250 "=a" (pack)
01251 : "1" (PCIBIOS_PCI_BIOS_PRESENT),
01252 "D" (&pci_indirect)
01253 : "bx", "cx");
01254 restore_flags(flags);
01255
01256 present_status = (pack >> 16) & 0xff;
01257 major_revision = (pack >> 8) & 0xff;
01258 minor_revision = pack & 0xff;
01259 if (present_status || (signature != PCI_SIGNATURE)) {
01260 printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
01261 "BIOS????\n");
01262 pcibios_entry = 0;
01263 }
01264 #if DEBUG
01265 if (pcibios_entry) {
01266 printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
01267 " entry at %#X\n", major_revision,
01268 minor_revision, pcibios_entry);
01269 }
01270 #endif
01271 }
01272 }
01273
01274 static void pcibios_init(void)
01275 {
01276 union bios32 *check;
01277 unsigned char sum;
01278 int i, length;
01279 unsigned long bios32_entry = 0;
01280
01281
01282
01283
01284
01285
01286
01287
01288 for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
01289 if (check->fields.signature != BIOS32_SIGNATURE)
01290 continue;
01291 length = check->fields.length * 16;
01292 if (!length)
01293 continue;
01294 sum = 0;
01295 for (i = 0; i < length ; ++i)
01296 sum += check->chars[i];
01297 if (sum != 0)
01298 continue;
01299 if (check->fields.revision != 0) {
01300 printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
01301 check->fields.revision, check);
01302 continue;
01303 }
01304 #if DEBUG
01305 printf("pcibios_init : BIOS32 Service Directory "
01306 "structure at %#X\n", check);
01307 #endif
01308 if (!bios32_entry) {
01309 if (check->fields.entry >= 0x100000) {
01310 printf("pcibios_init: entry in high "
01311 "memory, giving up\n");
01312 return;
01313 } else {
01314 bios32_entry = check->fields.entry;
01315 #if DEBUG
01316 printf("pcibios_init : BIOS32 Service Directory"
01317 " entry at %#X\n", bios32_entry);
01318 #endif
01319 bios32_indirect.address = bios32_entry;
01320 }
01321 }
01322 }
01323 if (bios32_entry)
01324 check_pcibios();
01325 }
01326 #endif
01327
01328 static void scan_bus(struct pci_device *pcidev)
01329 {
01330 unsigned int devfn, l, bus, buses;
01331 unsigned char hdr_type = 0;
01332 unsigned short vendor, device;
01333 unsigned int membase, ioaddr, romaddr;
01334 int i, reg;
01335 unsigned int pci_ioaddr = 0;
01336
01337
01338
01339
01340
01341
01342
01343 buses=256;
01344 for (bus = 0; bus < buses; ++bus) {
01345 for (devfn = 0; devfn < 0xff; ++devfn) {
01346 if (PCI_FUNC (devfn) == 0)
01347 pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
01348 else if (!(hdr_type & 0x80))
01349 continue;
01350 pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l);
01351
01352 if (l == 0xffffffff || l == 0x00000000) {
01353 hdr_type = 0;
01354 continue;
01355 }
01356 vendor = l & 0xffff;
01357 device = (l >> 16) & 0xffff;
01358
01359 #if DEBUG
01360 printf("bus %hhX, function %hhX, vendor %hX, device %hX\n",
01361 bus, devfn, vendor, device);
01362 #endif
01363 for (i = 0; pcidev[i].vendor != 0; i++) {
01364 if (vendor != pcidev[i].vendor
01365 || device != pcidev[i].dev_id)
01366 continue;
01367 pcidev[i].devfn = devfn;
01368 pcidev[i].bus = bus;
01369 for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
01370 pcibios_read_config_dword(bus, devfn, reg, &ioaddr);
01371
01372 if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)
01373 continue;
01374
01375 ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
01376
01377 pcibios_read_config_dword(bus, devfn,
01378 PCI_BASE_ADDRESS_1, &membase);
01379
01380 pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
01381 romaddr >>= 10;
01382 printf("Found %s at %#hx, ROM address %#hx\n",
01383 pcidev[i].name, ioaddr, romaddr);
01384
01385 if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) {
01386 pcidev[i].membase = membase;
01387 pcidev[i].ioaddr = ioaddr;
01388 return;
01389 }
01390 }
01391 }
01392 }
01393 }
01394 }
01395
01396 void eth_pci_init(struct pci_device *pcidev)
01397 {
01398 #ifndef CONFIG_PCI_DIRECT
01399 pcibios_init();
01400 if (!pcibios_entry) {
01401 printf("pci_init: no BIOS32 detected\n");
01402 return;
01403 }
01404 #endif
01405 scan_bus(pcidev);
01406
01407 }
01408
01409
01410
01411
01412
01413 void adjust_pci_device(struct pci_device *p)
01414 {
01415 unsigned short new_command, pci_command;
01416 unsigned char pci_latency;
01417
01418 pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command);
01419 new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
01420 if (pci_command != new_command) {
01421 printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",
01422 pci_command, new_command, p->bus, p->devfn);
01423 pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command);
01424 }
01425 pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency);
01426 if (pci_latency < 32) {
01427 printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
01428 pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32);
01429 }
01430 }