etherelnk3x.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. /*
  2. * Etherlink III and Fast EtherLink adapters.
  3. * To do:
  4. * autoSelect;
  5. * busmaster channel;
  6. * PCMCIA;
  7. * PCI latency timer and master enable;
  8. * errata list.
  9. *
  10. * Product ID:
  11. * 9150 ISA 3C509[B]
  12. * 9050 ISA 3C509[B]-TP
  13. * 9450 ISA 3C509[B]-COMBO
  14. * 9550 ISA 3C509[B]-TPO
  15. *
  16. * 9350 EISA 3C579
  17. * 9250 EISA 3C579-TP
  18. *
  19. * 5920 EISA 3C592-[TP|COMBO|TPO]
  20. * 5970 EISA 3C597-TX Fast Etherlink 10BASE-T/100BASE-TX
  21. * 5971 EISA 3C597-T4 Fast Etherlink 10BASE-T/100BASE-T4
  22. * 5972 EISA 3C597-MII Fast Etherlink 10BASE-T/MII
  23. *
  24. * 5900 PCI 3C590-[TP|COMBO|TPO]
  25. * 5950 PCI 3C595-TX Fast Etherlink Shared 10BASE-T/100BASE-TX
  26. * 5951 PCI 3C595-T4 Fast Etherlink Shared 10BASE-T/100BASE-T4
  27. * 5952 PCI 3C595-MII Fast Etherlink 10BASE-T/MII
  28. *
  29. * 9058 PCMCIA 3C589[B]-[TP|COMBO]
  30. *
  31. * 627C MCA 3C529
  32. * 627D MCA 3C529-TP
  33. */
  34. #include "u.h"
  35. #include "lib.h"
  36. #include "mem.h"
  37. #include "dat.h"
  38. #include "fns.h"
  39. #include "io.h"
  40. #include "etherif.h"
  41. enum {
  42. IDport = 0x0110, /* anywhere between 0x0100 and 0x01F0 */
  43. };
  44. enum { /* all windows */
  45. Command = 0x000E,
  46. IntStatus = 0x000E,
  47. };
  48. enum { /* Commands */
  49. GlobalReset = 0x0000,
  50. SelectRegisterWindow = 0x0001,
  51. EnableDcConverter = 0x0002,
  52. RxDisable = 0x0003,
  53. RxEnable = 0x0004,
  54. RxReset = 0x0005,
  55. TxDone = 0x0007,
  56. RxDiscard = 0x0008,
  57. TxEnable = 0x0009,
  58. TxDisable = 0x000A,
  59. TxReset = 0x000B,
  60. RequestInterrupt = 0x000C,
  61. AcknowledgeInterrupt = 0x000D,
  62. SetInterruptEnable = 0x000E,
  63. SetIndicationEnable = 0x000F, /* SetReadZeroMask */
  64. SetRxFilter = 0x0010,
  65. SetRxEarlyThresh = 0x0011,
  66. SetTxAvailableThresh = 0x0012,
  67. SetTxStartThresh = 0x0013,
  68. StartDma = 0x0014, /* initiate busmaster operation */
  69. StatisticsEnable = 0x0015,
  70. StatisticsDisable = 0x0016,
  71. DisableDcConverter = 0x0017,
  72. SetTxReclaimThresh = 0x0018, /* PIO-only adapters */
  73. PowerUp = 0x001B, /* not all adapters */
  74. PowerDownFull = 0x001C, /* not all adapters */
  75. PowerAuto = 0x001D, /* not all adapters */
  76. };
  77. enum { /* (Global|Rx|Tx)Reset command bits */
  78. tpAuiReset = 0x0001, /* 10BaseT and AUI transceivers */
  79. endecReset = 0x0002, /* internal Ethernet encoder/decoder */
  80. networkReset = 0x0004, /* network interface logic */
  81. fifoReset = 0x0008, /* FIFO control logic */
  82. aismReset = 0x0010, /* autoinitialise state-machine logic */
  83. hostReset = 0x0020, /* bus interface logic */
  84. dmaReset = 0x0040, /* bus master logic */
  85. vcoReset = 0x0080, /* on-board 10Mbps VCO */
  86. resetMask = 0x00FF,
  87. };
  88. enum { /* SetRxFilter command bits */
  89. receiveIndividual = 0x0001, /* match station address */
  90. receiveMulticast = 0x0002,
  91. receiveBroadcast = 0x0004,
  92. receiveAllFrames = 0x0008, /* promiscuous */
  93. };
  94. enum { /* StartDma command bits */
  95. Upload = 0x0000, /* transfer data from adapter to memory */
  96. Download = 0x0001, /* transfer data from memory to adapter */
  97. };
  98. enum { /* IntStatus bits */
  99. interruptLatch = 0x0001,
  100. hostError = 0x0002, /* Adapter Failure */
  101. txComplete = 0x0004,
  102. txAvailable = 0x0008,
  103. rxComplete = 0x0010,
  104. rxEarly = 0x0020,
  105. intRequested = 0x0040,
  106. updateStats = 0x0080,
  107. transferInt = 0x0100, /* Bus Master Transfer Complete */
  108. busMasterInProgress = 0x0800,
  109. commandInProgress = 0x1000,
  110. interruptMask = 0x01FE,
  111. };
  112. #define COMMAND(port, cmd, a) outs((port)+Command, ((cmd)<<11)|(a))
  113. #define STATUS(port) ins((port)+IntStatus)
  114. enum { /* Window 0 - setup */
  115. Wsetup = 0x0000,
  116. /* registers */
  117. ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */
  118. ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */
  119. ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */
  120. AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */
  121. ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */
  122. EepromCommand = 0x000A,
  123. EepromData = 0x000C,
  124. /* AddressConfig Bits */
  125. autoSelect9 = 0x0080,
  126. xcvrMask9 = 0xC000,
  127. /* ConfigControl bits */
  128. Ena = 0x0001,
  129. /* EepromCommand bits */
  130. EepromReadRegister = 0x0080,
  131. EepromBusy = 0x8000,
  132. };
  133. #define EEPROMCMD(port, cmd, a) outs((port)+EepromCommand, (cmd)|(a))
  134. #define EEPROMBUSY(port) (ins((port)+EepromCommand) & EepromBusy)
  135. #define EEPROMDATA(port) ins((port)+EepromData)
  136. enum { /* Window 1 - operating set */
  137. Wop = 0x0001,
  138. /* registers */
  139. Fifo = 0x0000,
  140. RxError = 0x0004, /* 3C59[0257] only */
  141. RxStatus = 0x0008,
  142. Timer = 0x000A,
  143. TxStatus = 0x000B,
  144. TxFree = 0x000C,
  145. /* RxError bits */
  146. rxOverrun = 0x0001,
  147. runtFrame = 0x0002,
  148. alignmentError = 0x0004, /* Framing */
  149. crcError = 0x0008,
  150. oversizedFrame = 0x0010,
  151. dribbleBits = 0x0080,
  152. /* RxStatus bits */
  153. rxBytes = 0x1FFF, /* 3C59[0257] mask */
  154. rxBytes9 = 0x07FF, /* 3C5[078]9 mask */
  155. rxError9 = 0x3800, /* 3C5[078]9 error mask */
  156. rxOverrun9 = 0x0000,
  157. oversizedFrame9 = 0x0800,
  158. dribbleBits9 = 0x1000,
  159. runtFrame9 = 0x1800,
  160. alignmentError9 = 0x2000, /* Framing */
  161. crcError9 = 0x2800,
  162. rxError = 0x4000,
  163. rxIncomplete = 0x8000,
  164. /* TxStatus Bits */
  165. txStatusOverflow = 0x0004,
  166. maxCollisions = 0x0008,
  167. txUnderrun = 0x0010,
  168. txJabber = 0x0020,
  169. interruptRequested = 0x0040,
  170. txStatusComplete = 0x0080,
  171. };
  172. enum { /* Window 2 - station address */
  173. Wstation = 0x0002,
  174. };
  175. enum { /* Window 3 - FIFO management */
  176. Wfifo = 0x0003,
  177. /* registers */
  178. InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */
  179. OtherInt = 0x0004, /* 3C59[0257] */
  180. RomControl = 0x0006, /* 3C509B, 3C59[27] */
  181. MacControl = 0x0006, /* 3C59[0257] */
  182. ResetOptions = 0x0008, /* 3C59[0257] */
  183. RxFree = 0x000A,
  184. /* InternalConfig bits */
  185. disableBadSsdDetect = 0x00000100,
  186. ramLocation = 0x00000200, /* 0 external, 1 internal */
  187. ramPartition5to3 = 0x00000000,
  188. ramPartition3to1 = 0x00010000,
  189. ramPartition1to1 = 0x00020000,
  190. ramPartition3to5 = 0x00030000,
  191. ramPartitionMask = 0x00030000,
  192. xcvr10BaseT = 0x00000000,
  193. xcvrAui = 0x00100000, /* 10BASE5 */
  194. xcvr10Base2 = 0x00300000,
  195. xcvr100BaseTX = 0x00400000,
  196. xcvr100BaseFX = 0x00500000,
  197. xcvrMii = 0x00600000,
  198. xcvrMask = 0x00700000,
  199. autoSelect = 0x01000000,
  200. /* MacControl bits */
  201. deferExtendEnable = 0x0001,
  202. deferTimerSelect = 0x001E, /* mask */
  203. fullDuplexEnable = 0x0020,
  204. allowLargePackets = 0x0040,
  205. /* ResetOptions bits */
  206. baseT4Available = 0x0001,
  207. baseTXAvailable = 0x0002,
  208. baseFXAvailable = 0x0004,
  209. base10TAvailable = 0x0008,
  210. coaxAvailable = 0x0010,
  211. auiAvailable = 0x0020,
  212. miiConnector = 0x0040,
  213. };
  214. enum { /* Window 4 - diagnostic */
  215. Wdiagnostic = 0x0004,
  216. /* registers */
  217. VcoDiagnostic = 0x0002,
  218. FifoDiagnostic = 0x0004,
  219. NetworkDiagnostic = 0x0006,
  220. PhysicalMgmt = 0x0008,
  221. MediaStatus = 0x000A,
  222. BadSSD = 0x000C,
  223. /* FifoDiagnostic bits */
  224. txOverrun = 0x0400,
  225. rxUnderrun = 0x2000,
  226. receiving = 0x8000,
  227. /* MediaStatus bits */
  228. dataRate100 = 0x0002,
  229. crcStripDisable = 0x0004,
  230. enableSqeStats = 0x0008,
  231. collisionDetect = 0x0010,
  232. carrierSense = 0x0020,
  233. jabberGuardEnable = 0x0040,
  234. linkBeatEnable = 0x0080,
  235. jabberDetect = 0x0200,
  236. polarityReversed = 0x0400,
  237. linkBeatDetect = 0x0800,
  238. txInProg = 0x1000,
  239. dcConverterEnabled = 0x4000,
  240. auiDisable = 0x8000,
  241. };
  242. enum { /* Window 5 - internal state */
  243. Wstate = 0x0005,
  244. /* registers */
  245. TxStartThresh = 0x0000,
  246. TxAvalableThresh = 0x0002,
  247. RxEarlyThresh = 0x0006,
  248. RxFilter = 0x0008,
  249. InterruptEnable = 0x000A,
  250. IndicationEnable = 0x000C,
  251. };
  252. enum { /* Window 6 - statistics */
  253. Wstatistics = 0x0006,
  254. /* registers */
  255. CarrierLost = 0x0000,
  256. SqeErrors = 0x0001,
  257. MultipleColls = 0x0002,
  258. SingleCollFrames = 0x0003,
  259. LateCollisions = 0x0004,
  260. RxOverruns = 0x0005,
  261. FramesXmittedOk = 0x0006,
  262. FramesRcvdOk = 0x0007,
  263. FramesDeferred = 0x0008,
  264. UpperFramesOk = 0x0009,
  265. BytesRcvdOk = 0x000A,
  266. BytesXmittedOk = 0x000C,
  267. };
  268. enum { /* Window 7 - bus master operations */
  269. Wmaster = 0x0007,
  270. /* registers */
  271. MasterAddress = 0x0000,
  272. MasterLen = 0x0006,
  273. MasterStatus = 0x000C,
  274. /* MasterStatus bits */
  275. masterAbort = 0x0001,
  276. targetAbort = 0x0002,
  277. targetRetry = 0x0004,
  278. targetDisc = 0x0008,
  279. masterDownload = 0x1000,
  280. masterUpload = 0x4000,
  281. masterInProgress = 0x8000,
  282. masterMask = 0xD00F,
  283. };
  284. typedef struct {
  285. int txthreshold;
  286. } Ctlr;
  287. static void
  288. attach(Ether* ether)
  289. {
  290. int port, x;
  291. port = ether->port;
  292. /*
  293. * Set the receiver packet filter for this and broadcast addresses,
  294. * set the interrupt masks for all interrupts, enable the receiver
  295. * and transmitter.
  296. */
  297. x = receiveBroadcast|receiveIndividual;
  298. COMMAND(port, SetRxFilter, x);
  299. x = interruptMask|interruptLatch;
  300. COMMAND(port, SetIndicationEnable, x);
  301. COMMAND(port, SetInterruptEnable, x);
  302. COMMAND(port, RxEnable, 0);
  303. COMMAND(port, TxEnable, 0);
  304. }
  305. static void
  306. transmit(Ether* ether)
  307. {
  308. int port, len;
  309. RingBuf *tb;
  310. /*
  311. * Attempt to top-up the transmit FIFO. If there's room simply
  312. * stuff in the packet length (unpadded to a dword boundary), the
  313. * packet data (padded) and remove the packet from the queue.
  314. * If there's no room post an interrupt for when there is.
  315. * This routine is called both from the top level and from interrupt
  316. * level.
  317. */
  318. port = ether->port;
  319. for(tb = &ether->tb[ether->ti]; tb->owner == Interface; tb = &ether->tb[ether->ti]){
  320. len = ROUNDUP(tb->len, 4);
  321. if(len+4 <= ins(port+TxFree)){
  322. outl(port+Fifo, tb->len);
  323. outsl(port+Fifo, tb->pkt, len/4);
  324. tb->owner = Host;
  325. ether->ti = NEXT(ether->ti, ether->ntb);
  326. }
  327. else{
  328. COMMAND(port, SetTxAvailableThresh, len);
  329. break;
  330. }
  331. }
  332. }
  333. static void
  334. receive(Ether* ether)
  335. {
  336. int len, port, rxstatus;
  337. RingBuf *rb;
  338. port = ether->port;
  339. while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){
  340. /*
  341. * If there was an error, throw it away and continue.
  342. * The 3C5[078]9 has the error info in the status register
  343. * and the 3C59[0257] implement a separate RxError register.
  344. */
  345. if((rxstatus & rxError) == 0){
  346. /*
  347. * Packet received. Read it into the next free
  348. * ring buffer, if any. Must read len bytes padded
  349. * to a doubleword, can be picked out 32-bits at
  350. * a time. The CRC is already stripped off.
  351. */
  352. rb = &ether->rb[ether->ri];
  353. if(rb->owner == Interface){
  354. len = (rxstatus & rxBytes9);
  355. rb->len = len;
  356. insl(port+Fifo, rb->pkt, HOWMANY(len, 4));
  357. rb->owner = Host;
  358. ether->ri = NEXT(ether->ri, ether->nrb);
  359. }
  360. }
  361. /*
  362. * All done, discard the packet.
  363. */
  364. COMMAND(port, RxDiscard, 0);
  365. while(STATUS(port) & commandInProgress)
  366. ;
  367. }
  368. }
  369. static void
  370. statistics(Ether* ether)
  371. {
  372. int i, port, w;
  373. port = ether->port;
  374. w = (STATUS(port)>>13) & 0x07;
  375. COMMAND(port, SelectRegisterWindow, Wop);
  376. COMMAND(port, SelectRegisterWindow, Wstatistics);
  377. for(i = 0; i < 0x0A; i++)
  378. inb(port+i);
  379. ins(port+BytesRcvdOk);
  380. ins(port+BytesXmittedOk);
  381. COMMAND(port, SelectRegisterWindow, w);
  382. }
  383. static void
  384. interrupt(Ureg*, void* arg)
  385. {
  386. Ether *ether;
  387. int port, status, txstatus, w, x;
  388. Ctlr *ctlr;
  389. ether = arg;
  390. port = ether->port;
  391. ctlr = ether->ctlr;
  392. w = (STATUS(port)>>13) & 0x07;
  393. COMMAND(port, SelectRegisterWindow, Wop);
  394. for(;;){
  395. /*
  396. * Clear the interrupt latch.
  397. * It's possible to receive a packet and for another
  398. * to become complete before exiting the interrupt
  399. * handler so this must be done first to ensure another
  400. * interrupt will occur.
  401. */
  402. COMMAND(port, AcknowledgeInterrupt, interruptLatch);
  403. status = STATUS(port);
  404. if((status & interruptMask) == 0)
  405. break;
  406. if(status & hostError){
  407. /*
  408. * Adapter failure, try to find out why, reset if
  409. * necessary. What happens if Tx is active and a reset
  410. * occurs, need to retransmit? This probably isn't right.
  411. */
  412. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  413. x = ins(port+FifoDiagnostic);
  414. COMMAND(port, SelectRegisterWindow, Wop);
  415. print("elnk3#%d: status 0x%uX, diag 0x%uX\n",
  416. ether->ctlrno, status, x);
  417. if(x & txOverrun){
  418. COMMAND(port, TxReset, 0);
  419. COMMAND(port, TxEnable, 0);
  420. }
  421. if(x & rxUnderrun){
  422. /*
  423. * This shouldn't happen...
  424. * Need to restart any busmastering?
  425. */
  426. COMMAND(port, RxReset, 0);
  427. while(STATUS(port) & commandInProgress)
  428. ;
  429. COMMAND(port, RxEnable, 0);
  430. }
  431. status &= ~hostError;
  432. }
  433. if(status & (transferInt|rxComplete)){
  434. receive(ether);
  435. status &= ~(transferInt|rxComplete);
  436. }
  437. if(status & txComplete){
  438. /*
  439. * Pop the TxStatus stack, accumulating errors.
  440. * Adjust the TX start threshold if there was an underrun.
  441. * If there was a Jabber or Underrun error, reset
  442. * the transmitter.
  443. * For all conditions enable the transmitter.
  444. */
  445. txstatus = 0;
  446. do{
  447. if(x = inb(port+TxStatus))
  448. outb(port+TxStatus, 0);
  449. txstatus |= x;
  450. }while(STATUS(port) & txComplete);
  451. if(txstatus & txUnderrun){
  452. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  453. while(ins(port+MediaStatus) & txInProg)
  454. ;
  455. COMMAND(port, SelectRegisterWindow, Wop);
  456. if(ctlr->txthreshold < ETHERMAXTU)
  457. ctlr->txthreshold += ETHERMINTU;
  458. }
  459. if(txstatus & (txJabber|txUnderrun)){
  460. COMMAND(port, TxReset, 0);
  461. while(STATUS(port) & commandInProgress)
  462. ;
  463. COMMAND(port, SetTxStartThresh, ctlr->txthreshold);
  464. }
  465. COMMAND(port, TxEnable, 0);
  466. status &= ~txComplete;
  467. status |= txAvailable;
  468. }
  469. if(status & txAvailable){
  470. COMMAND(port, AcknowledgeInterrupt, txAvailable);
  471. transmit(ether);
  472. status &= ~txAvailable;
  473. }
  474. if(status & updateStats){
  475. statistics(ether);
  476. status &= ~updateStats;
  477. }
  478. /*
  479. * Panic if there are any interrupts not dealt with.
  480. */
  481. if(status & interruptMask)
  482. panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status);
  483. }
  484. COMMAND(port, SelectRegisterWindow, w);
  485. }
  486. typedef struct Adapter {
  487. int port;
  488. int irq;
  489. int tbdf;
  490. } Adapter;
  491. static Block* adapter;
  492. static void
  493. tcmadapter(int port, int irq, int tbdf)
  494. {
  495. Block *bp;
  496. Adapter *ap;
  497. bp = allocb(sizeof(Adapter));
  498. ap = (Adapter*)bp->rp;
  499. ap->port = port;
  500. ap->irq = irq;
  501. ap->tbdf = tbdf;
  502. bp->next = adapter;
  503. adapter = bp;
  504. }
  505. /*
  506. * Write two 0 bytes to identify the IDport and then reset the
  507. * ID sequence. Then send the ID sequence to the card to get
  508. * the card into command state.
  509. */
  510. static void
  511. idseq(void)
  512. {
  513. int i;
  514. uchar al;
  515. static int reset, untag;
  516. /*
  517. * One time only:
  518. * reset any adapters listening
  519. */
  520. if(reset == 0){
  521. outb(IDport, 0);
  522. outb(IDport, 0);
  523. outb(IDport, 0xC0);
  524. delay(20);
  525. reset = 1;
  526. }
  527. outb(IDport, 0);
  528. outb(IDport, 0);
  529. for(al = 0xFF, i = 0; i < 255; i++){
  530. outb(IDport, al);
  531. if(al & 0x80){
  532. al <<= 1;
  533. al ^= 0xCF;
  534. }
  535. else
  536. al <<= 1;
  537. }
  538. /*
  539. * One time only:
  540. * write ID sequence to get the attention of all adapters;
  541. * untag all adapters.
  542. * If we do a global reset here on all adapters we'll confuse any
  543. * ISA cards configured for EISA mode.
  544. */
  545. if(untag == 0){
  546. outb(IDport, 0xD0);
  547. untag = 1;
  548. }
  549. }
  550. static ulong
  551. activate(void)
  552. {
  553. int i;
  554. ushort x, acr;
  555. /*
  556. * Do the little configuration dance:
  557. *
  558. * 2. write the ID sequence to get to command state.
  559. */
  560. idseq();
  561. /*
  562. * 3. Read the Manufacturer ID from the EEPROM.
  563. * This is done by writing the IDPort with 0x87 (0x80
  564. * is the 'read EEPROM' command, 0x07 is the offset of
  565. * the Manufacturer ID field in the EEPROM).
  566. * The data comes back 1 bit at a time.
  567. * We seem to need a delay here between reading the bits.
  568. *
  569. * If the ID doesn't match, there are no more adapters.
  570. */
  571. outb(IDport, 0x87);
  572. delay(20);
  573. for(x = 0, i = 0; i < 16; i++){
  574. delay(20);
  575. x <<= 1;
  576. x |= inb(IDport) & 0x01;
  577. }
  578. if(x != 0x6D50)
  579. return 0;
  580. /*
  581. * 3. Read the Address Configuration from the EEPROM.
  582. * The Address Configuration field is at offset 0x08 in the EEPROM).
  583. */
  584. outb(IDport, 0x88);
  585. for(acr = 0, i = 0; i < 16; i++){
  586. delay(20);
  587. acr <<= 1;
  588. acr |= inb(IDport) & 0x01;
  589. }
  590. return (acr & 0x1F)*0x10 + 0x200;
  591. }
  592. #ifdef notjustpcmcia
  593. static void
  594. tcm509isa(void)
  595. {
  596. int irq, port;
  597. /*
  598. * Attempt to activate all adapters. If adapter is set for
  599. * EISA mode (0x3F0), tag it and ignore. Otherwise, activate
  600. * it fully.
  601. */
  602. while(port = activate()){
  603. /*
  604. * 6. Tag the adapter so it won't respond in future.
  605. */
  606. outb(IDport, 0xD1);
  607. if(port == 0x3F0)
  608. continue;
  609. /*
  610. * 6. Activate the adapter by writing the Activate command
  611. * (0xFF).
  612. */
  613. outb(IDport, 0xFF);
  614. delay(20);
  615. /*
  616. * 8. Can now talk to the adapter's I/O base addresses.
  617. * Use the I/O base address from the acr just read.
  618. *
  619. * Enable the adapter and clear out any lingering status
  620. * and interrupts.
  621. */
  622. while(STATUS(port) & commandInProgress)
  623. ;
  624. COMMAND(port, SelectRegisterWindow, Wsetup);
  625. outs(port+ConfigControl, Ena);
  626. COMMAND(port, TxReset, 0);
  627. COMMAND(port, RxReset, 0);
  628. COMMAND(port, AcknowledgeInterrupt, 0xFF);
  629. irq = (ins(port+ResourceConfig)>>12) & 0x0F;
  630. tcmadapter(port, irq, BUSUNKNOWN);
  631. }
  632. }
  633. static void
  634. tcm5XXeisa(void)
  635. {
  636. ushort x;
  637. int irq, port, slot;
  638. /*
  639. * Check if this is an EISA machine.
  640. * If not, nothing to do.
  641. */
  642. if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4))
  643. return;
  644. /*
  645. * Continue through the EISA slots looking for a match on both
  646. * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product.
  647. * If an adapter is found, select window 0, enable it and clear
  648. * out any lingering status and interrupts.
  649. */
  650. for(slot = 1; slot < MaxEISA; slot++){
  651. port = slot*0x1000;
  652. if(ins(port+0xC80+ManufacturerID) != 0x6D50)
  653. continue;
  654. x = ins(port+0xC80+ProductID);
  655. if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900)
  656. continue;
  657. COMMAND(port, SelectRegisterWindow, Wsetup);
  658. outs(port+ConfigControl, Ena);
  659. COMMAND(port, TxReset, 0);
  660. COMMAND(port, RxReset, 0);
  661. COMMAND(port, AcknowledgeInterrupt, 0xFF);
  662. irq = (ins(port+ResourceConfig)>>12) & 0x0F;
  663. tcmadapter(port, irq, BUSUNKNOWN);
  664. }
  665. }
  666. static void
  667. tcm59Xpci(void)
  668. {
  669. Pcidev *p;
  670. int irq, port;
  671. p = nil;
  672. while(p = pcimatch(p, 0x10B7, 0)){
  673. port = p->mem[0].bar & ~0x01;
  674. irq = p->intl;
  675. COMMAND(port, GlobalReset, 0);
  676. while(STATUS(port) & commandInProgress)
  677. ;
  678. tcmadapter(port, irq, p->tbdf);
  679. }
  680. }
  681. #endif /* notjustpcmcia */
  682. static char* tcmpcmcia[] = {
  683. "3C589", /* 3COM 589[ABCD] */
  684. "3C562", /* 3COM 562 */
  685. "589E", /* 3COM Megahertz 589E */
  686. nil,
  687. };
  688. static int
  689. tcm5XXpcmcia(Ether* ether)
  690. {
  691. int i;
  692. for(i = 0; tcmpcmcia[i] != nil; i++){
  693. if(!cistrcmp(ether->type, tcmpcmcia[i]))
  694. return ether->port;
  695. }
  696. return 0;
  697. }
  698. static int
  699. autoselect(int port, int rxstatus9)
  700. {
  701. int media, x;
  702. /*
  703. * Pathetic attempt at automatic media selection.
  704. * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX
  705. * cards operational.
  706. */
  707. media = auiAvailable|coaxAvailable|base10TAvailable;
  708. if(rxstatus9 == 0){
  709. COMMAND(port, SelectRegisterWindow, Wfifo);
  710. media = ins(port+ResetOptions);
  711. }
  712. if(media & miiConnector)
  713. return xcvrMii;
  714. if(media & baseTXAvailable){
  715. /*
  716. * Must have InternalConfig register.
  717. */
  718. COMMAND(port, SelectRegisterWindow, Wfifo);
  719. x = inl(port+InternalConfig) & ~xcvrMask;
  720. x |= xcvr100BaseTX;
  721. outl(port+InternalConfig, x);
  722. COMMAND(port, TxReset, 0);
  723. while(STATUS(port) & commandInProgress)
  724. ;
  725. COMMAND(port, RxReset, 0);
  726. while(STATUS(port) & commandInProgress)
  727. ;
  728. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  729. x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
  730. outs(port+MediaStatus, linkBeatEnable|x);
  731. delay(10);
  732. { int i, v;
  733. for(i = 0; i < 10000; i++){
  734. v = ins(port+MediaStatus);
  735. if(v & linkBeatDetect){
  736. print("count %d v %uX\n", i, v);
  737. return xcvr100BaseTX;
  738. }
  739. delay(1);
  740. }
  741. print("count %d v %uX\n", i, ins(port+MediaStatus));
  742. }
  743. if(ins(port+MediaStatus) & linkBeatDetect)
  744. return xcvr100BaseTX;
  745. outs(port+MediaStatus, x);
  746. }
  747. if(media & base10TAvailable){
  748. if(rxstatus9 == 0){
  749. COMMAND(port, SelectRegisterWindow, Wfifo);
  750. x = inl(port+InternalConfig) & ~xcvrMask;
  751. x |= xcvr10BaseT;
  752. outl(port+InternalConfig, x);
  753. }
  754. else{
  755. COMMAND(port, SelectRegisterWindow, Wsetup);
  756. x = ins(port+AddressConfig) & ~xcvrMask9;
  757. x |= (xcvr10BaseT>>20)<<14;
  758. outs(port+AddressConfig, x);
  759. }
  760. COMMAND(port, TxReset, 0);
  761. while(STATUS(port) & commandInProgress)
  762. ;
  763. COMMAND(port, RxReset, 0);
  764. while(STATUS(port) & commandInProgress)
  765. ;
  766. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  767. x = ins(port+MediaStatus) & ~dcConverterEnabled;
  768. outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);
  769. delay(10);
  770. if(ins(port+MediaStatus) & linkBeatDetect)
  771. return xcvr10BaseT;
  772. outs(port+MediaStatus, x);
  773. }
  774. /*
  775. * Botch.
  776. */
  777. return autoSelect;
  778. }
  779. static int
  780. eepromdata(int port, int offset)
  781. {
  782. COMMAND(port, SelectRegisterWindow, Wsetup);
  783. while(EEPROMBUSY(port))
  784. ;
  785. EEPROMCMD(port, EepromReadRegister, offset);
  786. while(EEPROMBUSY(port))
  787. ;
  788. return EEPROMDATA(port);
  789. }
  790. int
  791. elnk3reset(Ether* ether)
  792. {
  793. int did, i, port, rxstatus9, x, xcvr;
  794. Block *bp, **bpp;
  795. Adapter *ap;
  796. uchar ea[Eaddrlen];
  797. Ctlr *ctlr;
  798. #ifdef notjustpcmcia
  799. static int scandone;
  800. /*
  801. * Scan for adapter on PCI, EISA and finally
  802. * using the little ISA configuration dance.
  803. */
  804. if(scandone == 0){
  805. tcm59Xpci();
  806. tcm5XXeisa();
  807. tcm509isa();
  808. scandone = 1;
  809. }
  810. #endif /* notjustpcmcia */
  811. /*
  812. * Any adapter matches if no ether->port is supplied,
  813. * otherwise the ports must match.
  814. */
  815. port = 0;
  816. bpp = &adapter;
  817. for(bp = *bpp; bp; bp = bp->next){
  818. ap = (Adapter*)bp->rp;
  819. if(ether->port == 0 || ether->port == ap->port){
  820. port = ap->port;
  821. ether->irq = ap->irq;
  822. ether->tbdf = ap->tbdf;
  823. *bpp = bp->next;
  824. freeb(bp);
  825. break;
  826. }
  827. bpp = &bp->next;
  828. }
  829. if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0)
  830. return -1;
  831. /*
  832. * Read the DeviceID from the EEPROM, it's at offset 0x03,
  833. * and do something depending on capabilities.
  834. */
  835. switch(did = eepromdata(port, 0x03)){
  836. case 0x9000:
  837. case 0x9001:
  838. case 0x9050:
  839. case 0x9051:
  840. if(BUSTYPE(ether->tbdf) != BusPCI)
  841. goto buggery;
  842. goto vortex;
  843. case 0x5900:
  844. case 0x5920:
  845. case 0x5950:
  846. case 0x5951:
  847. case 0x5952:
  848. case 0x5970:
  849. case 0x5971:
  850. case 0x5972:
  851. vortex:
  852. COMMAND(port, SelectRegisterWindow, Wfifo);
  853. xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);
  854. rxstatus9 = 0;
  855. break;
  856. buggery:
  857. default:
  858. COMMAND(port, SelectRegisterWindow, Wsetup);
  859. x = ins(port+AddressConfig);
  860. xcvr = ((x & xcvrMask9)>>14)<<20;
  861. if(x & autoSelect9)
  862. xcvr |= autoSelect;
  863. rxstatus9 = 1;
  864. break;
  865. }
  866. USED(did);
  867. /*
  868. * Check if the adapter's station address is to be overridden.
  869. * If not, read it from the EEPROM and set in ether->ea prior to loading the
  870. * station address in Wstation. The EEPROM returns 16-bits at a time.
  871. */
  872. memset(ea, 0, Eaddrlen);
  873. if(memcmp(ea, ether->ea, Eaddrlen) == 0){
  874. for(i = 0; i < Eaddrlen/2; i++){
  875. x = eepromdata(port, i);
  876. ether->ea[2*i] = x>>8;
  877. ether->ea[2*i+1] = x;
  878. }
  879. }
  880. COMMAND(port, SelectRegisterWindow, Wstation);
  881. for(i = 0; i < Eaddrlen; i++)
  882. outb(port+i, ether->ea[i]);
  883. /*
  884. * Enable the transceiver if necessary.
  885. */
  886. if(xcvr & autoSelect)
  887. xcvr = autoselect(port, rxstatus9);
  888. switch(xcvr){
  889. case xcvrMii:
  890. break;
  891. case xcvr100BaseTX:
  892. case xcvr100BaseFX:
  893. COMMAND(port, SelectRegisterWindow, Wfifo);
  894. x = inl(port+InternalConfig) & ~ramPartitionMask;
  895. outl(port+InternalConfig, x|ramPartition1to1);
  896. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  897. x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);
  898. x |= linkBeatEnable;
  899. outs(port+MediaStatus, x);
  900. break;
  901. case xcvr10BaseT:
  902. /*
  903. * Enable Link Beat and Jabber to start the
  904. * transceiver.
  905. */
  906. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  907. x = ins(port+MediaStatus) & ~dcConverterEnabled;
  908. x |= linkBeatEnable|jabberGuardEnable;
  909. outs(port+MediaStatus, x);
  910. break;
  911. case xcvr10Base2:
  912. COMMAND(port, SelectRegisterWindow, Wdiagnostic);
  913. x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);
  914. outs(port+MediaStatus, x);
  915. /*
  916. * Start the DC-DC converter.
  917. * Wait > 800 microseconds.
  918. */
  919. COMMAND(port, EnableDcConverter, 0);
  920. delay(1);
  921. break;
  922. }
  923. /*
  924. * Wop is the normal operating register set.
  925. * The 3C59[0257] adapters allow access to more than one register window
  926. * at a time, but there are situations where switching still needs to be
  927. * done, so just do it.
  928. * Clear out any lingering Tx status.
  929. */
  930. COMMAND(port, SelectRegisterWindow, Wop);
  931. while(inb(port+TxStatus))
  932. outb(port+TxStatus, 0);
  933. /*
  934. * Allocate a controller structure and start
  935. * to initialise it.
  936. */
  937. ether->ctlr = malloc(sizeof(Ctlr));
  938. ctlr = ether->ctlr;
  939. memset(ctlr, 0, sizeof(Ctlr));
  940. /*
  941. * Set a base TxStartThresh which will be incremented
  942. * if any txUnderrun errors occur and ensure no RxEarly
  943. * interrupts happen.
  944. */
  945. ctlr->txthreshold = ETHERMINTU;
  946. COMMAND(port, SetTxStartThresh, ETHERMINTU);
  947. COMMAND(port, SetRxEarlyThresh, ETHERMAXTU);
  948. /*
  949. * Set up the software configuration.
  950. */
  951. ether->port = port;
  952. ether->attach = attach;
  953. ether->transmit = transmit;
  954. ether->interrupt = interrupt;
  955. return 0;
  956. }