etherrhine.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. /*
  2. Via Rhine driver, written for VT6102.
  3. Uses the ethermii to control PHY.
  4. Currently always copies on both, tx and rx.
  5. rx side could be copy-free, and tx-side might be made
  6. (almost) copy-free by using (possibly) two descriptors (if it allows
  7. arbitrary tx lengths, which it should..): first for alignment and
  8. second for rest of the frame. Rx-part should be worth doing.
  9. */
  10. #include "u.h"
  11. #include "lib.h"
  12. #include "mem.h"
  13. #include "dat.h"
  14. #include "fns.h"
  15. #include "io.h"
  16. typedef struct QLock { int r; } QLock;
  17. #define qlock(i) while(0)
  18. #define qunlock(i) while(0)
  19. #define coherence()
  20. #define iprint print
  21. #include "etherif.h"
  22. #include "ethermii.h"
  23. typedef struct Desc Desc;
  24. typedef struct Ctlr Ctlr;
  25. enum {
  26. Ntxd = 4,
  27. Nrxd = 4,
  28. Nwait = 50,
  29. Ntxstats = 9,
  30. Nrxstats = 8,
  31. BIGSTR = 8192,
  32. };
  33. struct Desc {
  34. ulong stat;
  35. ulong size;
  36. ulong addr;
  37. ulong next;
  38. char *buf;
  39. ulong pad[3];
  40. };
  41. struct Ctlr {
  42. Pcidev *pci;
  43. int attached;
  44. int txused;
  45. int txhead;
  46. int txtail;
  47. int rxtail;
  48. ulong port;
  49. Mii mii;
  50. ulong txstats[Ntxstats];
  51. ulong rxstats[Nrxstats];
  52. Desc *txd; /* wants to be aligned on 16-byte boundary */
  53. Desc *rxd;
  54. QLock attachlck;
  55. Lock tlock;
  56. };
  57. #define ior8(c, r) (inb((c)->port+(r)))
  58. #define ior16(c, r) (ins((c)->port+(r)))
  59. #define ior32(c, r) (inl((c)->port+(r)))
  60. #define iow8(c, r, b) (outb((c)->port+(r), (int)(b)))
  61. #define iow16(c, r, w) (outs((c)->port+(r), (ushort)(w)))
  62. #define iow32(c, r, l) (outl((c)->port+(r), (ulong)(l)))
  63. enum Regs {
  64. Eaddr = 0x0,
  65. Rcr = 0x6,
  66. Tcr = 0x7,
  67. Cr = 0x8,
  68. Isr = 0xc,
  69. Imr = 0xe,
  70. McastAddr = 0x10,
  71. RxdAddr = 0x18,
  72. TxdAddr = 0x1C,
  73. Bcr = 0x6e,
  74. RhineMiiPhy = 0x6C,
  75. RhineMiiSr = 0x6D,
  76. RhineMiiCr = 0x70,
  77. RhineMiiAddr = 0x71,
  78. RhineMiiData = 0x72,
  79. Eecsr = 0x74,
  80. ConfigB = 0x79,
  81. ConfigD = 0x7B,
  82. MiscCr = 0x80,
  83. HwSticky = 0x83,
  84. MiscIsr = 0x84,
  85. MiscImr = 0x86,
  86. WolCrSet = 0xA0,
  87. WolCfgSet = 0xA1,
  88. WolCgSet = 0xA3,
  89. WolCrClr = 0xA4,
  90. PwrCfgClr = 0xA5,
  91. WolCgClr = 0xA7,
  92. };
  93. enum Rcrbits {
  94. RxErrX = 1<<0,
  95. RxSmall = 1<<1,
  96. RxMcast = 1<<2,
  97. RxBcast = 1<<3,
  98. RxProm = 1<<4,
  99. RxFifo64 = 0<<5, RxFifo32 = 1<<5, RxFifo128 = 2<<5, RxFifo256 = 3<<5,
  100. RxFifo512 = 4<<5, RxFifo768 = 5<<5, RxFifo1024 = 6<<5,
  101. RxFifoStoreForward = 7<<5,
  102. };
  103. enum Tcrbits {
  104. TxLoopback0 = 1<<1,
  105. TxLoopback1 = 1<<2,
  106. TxBackoff = 1<<3,
  107. TxFifo128 = 0<<5, TxFifo256 = 1<<5, TxFifo512 = 2<<5, TxFifo1024 = 3<<5,
  108. TxFifoStoreForward = 7<<5,
  109. };
  110. enum Crbits {
  111. Init = 1<<0,
  112. Start = 1<<1,
  113. Stop = 1<<2,
  114. RxOn = 1<<3,
  115. TxOn = 1<<4,
  116. Tdmd = 1<<5,
  117. Rdmd = 1<<6,
  118. EarlyRx = 1<<8,
  119. Reserved0 = 1<<9,
  120. FullDuplex = 1<<10,
  121. NoAutoPoll = 1<<11,
  122. Reserved1 = 1<<12,
  123. Tdmd1 = 1<<13,
  124. Rdmd1 = 1<<14,
  125. Reset = 1<<15,
  126. };
  127. enum Isrbits {
  128. RxOk = 1<<0,
  129. TxOk = 1<<1,
  130. RxErr = 1<<2,
  131. TxErr = 1<<3,
  132. TxBufUdf = 1<<4,
  133. RxBufLinkErr = 1<<5,
  134. BusErr = 1<<6,
  135. CrcOvf = 1<<7,
  136. EarlyRxInt = 1<<8,
  137. TxFifoUdf = 1<<9,
  138. RxFifoOvf = 1<<10,
  139. TxPktRace = 1<<11,
  140. NoRxbuf = 1<<12,
  141. TxCollision = 1<<13,
  142. PortCh = 1<<14,
  143. GPInt = 1<<15
  144. };
  145. enum Bcrbits {
  146. Dma32 = 0<<0, Dma64 = 1<<0, Dma128 = 2<<0,
  147. Dma256 = 3<<0, Dma512 = 4<<0, Dma1024 = 5<<0,
  148. DmaStoreForward = 7<<0,
  149. DupRxFifo0 = 1<<3, DupRxFifo1 = 1<<4, DupRxFifo2 = 1<<5,
  150. ExtraLed = 1<<6,
  151. MediumSelect = 1<<7,
  152. PollTimer0 = 1<<8, PollTimer1 = 1<<9, PollTimer2 = 1<<10,
  153. DupTxFifo0 = 1<<11, DupTxFifo1 = 1<<12, DupTxFifo2 = 1<<13,
  154. };
  155. enum Eecsrbits {
  156. EeAutoLoad = 1<<5,
  157. };
  158. enum MiscCrbits {
  159. Timer0Enable= 1<<0,
  160. Timer0Suspend = 1<<1,
  161. HalfDuplexFlowControl = 1<<2,
  162. FullDuplexFlowControl = 1<<3,
  163. Timer1Enable = 1<<8,
  164. ForceSoftReset = 1<<14,
  165. };
  166. enum HwStickybits {
  167. StickyDS0 = 1<<0,
  168. StickyDS1 = 1<<1,
  169. WOLEna = 1<<2,
  170. WOLStat = 1<<3,
  171. };
  172. enum WolCgbits {
  173. PmeOvr = 1<<7,
  174. };
  175. enum Descbits {
  176. OwnNic = 1<<31, /* stat */
  177. TxAbort = 1<<8, /* stat */
  178. TxError = 1<<15, /* stat */
  179. RxChainbuf = 1<<10, /* stat */
  180. RxChainStart = 1<<9, /* stat */
  181. RxChainEnd = 1<<8, /* stat */
  182. Chainbuf = 1<<15, /* size rx & tx*/
  183. TxDisableCrc = 1<<16, /* size */
  184. TxChainStart = 1<<21, /* size */
  185. TxChainEnd = 1<<22, /* size */
  186. TxInt = 1<<23, /* size */
  187. };
  188. enum ConfigDbits {
  189. BackoffOptional = 1<<0,
  190. BackoffAMD = 1<<1,
  191. BackoffDEC = 1<<2,
  192. BackoffRandom = 1<<3,
  193. PmccTestMode = 1<<4,
  194. PciReadlineCap = 1<<5,
  195. DiagMode = 1<<6,
  196. MmioEnable = 1<<7,
  197. };
  198. enum ConfigBbits {
  199. LatencyTimer = 1<<0,
  200. WriteWaitState = 1<<1,
  201. ReadWaitState = 1<<2,
  202. RxArbit = 1<<3,
  203. TxArbit = 1<<4,
  204. NoMemReadline = 1<<5,
  205. NoParity = 1<<6,
  206. NoTxQueuing = 1<<7,
  207. };
  208. enum RhineMiiCrbits {
  209. Mdc = 1<<0,
  210. Mdi = 1<<1,
  211. Mdo = 1<<2,
  212. Mdout = 1<<3,
  213. Mdpm = 1<<4,
  214. Wcmd = 1<<5,
  215. Rcmd = 1<<6,
  216. Mauto = 1<<7,
  217. };
  218. enum RhineMiiSrbits {
  219. Speed10M = 1<<0,
  220. LinkFail = 1<<1,
  221. PhyError = 1<<3,
  222. DefaultPhy = 1<<4,
  223. ResetPhy = 1<<7,
  224. };
  225. enum RhineMiiAddrbits {
  226. Mdone = 1<<5,
  227. Msrcen = 1<<6,
  228. Midle = 1<<7,
  229. };
  230. static char *
  231. txstatnames[Ntxstats] = {
  232. "aborts (excess collisions)",
  233. "out of window collisions",
  234. "carrier sense losses",
  235. "fifo underflows",
  236. "invalid descriptor format or underflows",
  237. "system errors",
  238. "reserved",
  239. "transmit errors",
  240. "collisions",
  241. };
  242. static char *
  243. rxstatnames[Nrxstats] = {
  244. "receiver errors",
  245. "crc errors",
  246. "frame alignment errors",
  247. "fifo overflows",
  248. "long packets",
  249. "run packets",
  250. "system errors",
  251. "buffer underflows",
  252. };
  253. static void
  254. attach(Ether *edev)
  255. {
  256. Ctlr *ctlr;
  257. Desc *txd, *rxd, *td, *rd;
  258. Mii *mi;
  259. MiiPhy *phy;
  260. int i, s;
  261. ctlr = edev->ctlr;
  262. qlock(&ctlr->attachlck);
  263. if (ctlr->attached == 0) {
  264. txd = ctlr->txd;
  265. rxd = ctlr->rxd;
  266. for (i = 0; i < Ntxd; ++i) {
  267. td = &txd[i];
  268. td->next = PCIWADDR(&txd[(i+1) % Ntxd]);
  269. td->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
  270. td->addr = PCIWADDR(td->buf);
  271. td->size = 0;
  272. coherence();
  273. td->stat = 0;
  274. }
  275. for (i = 0; i < Nrxd; ++i) {
  276. rd = &rxd[i];
  277. rd->next = PCIWADDR(&rxd[(i+1) % Nrxd]);
  278. rd->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
  279. rd->addr = PCIWADDR(rd->buf);
  280. rd->size = sizeof(Etherpkt)+4;
  281. coherence();
  282. rd->stat = OwnNic;
  283. }
  284. ctlr->txhead = ctlr->txtail = ctlr->rxtail = 0;
  285. mi = &ctlr->mii;
  286. miistatus(mi);
  287. phy = mi->curphy;
  288. s = splhi();
  289. iow32(ctlr, TxdAddr, PCIWADDR(&txd[0]));
  290. iow32(ctlr, RxdAddr, PCIWADDR(&rxd[0]));
  291. iow16(ctlr, Cr, (phy->fd ? FullDuplex : 0) | NoAutoPoll | TxOn | RxOn | Start | Rdmd);
  292. iow16(ctlr, Isr, 0xFFFF);
  293. iow16(ctlr, Imr, 0xFFFF);
  294. iow8(ctlr, MiscIsr, 0xFF);
  295. iow8(ctlr, MiscImr, ~(3<<5));
  296. splx(s);
  297. }
  298. ctlr->attached++;
  299. qunlock(&ctlr->attachlck);
  300. }
  301. static void
  302. txstart(Ether *edev)
  303. {
  304. Ctlr *ctlr;
  305. Desc *txd, *td;
  306. int i, txused, n;
  307. RingBuf *tb;
  308. ctlr = edev->ctlr;
  309. txd = ctlr->txd;
  310. i = ctlr->txhead;
  311. txused = ctlr->txused;
  312. n = 0;
  313. while (txused < Ntxd) {
  314. tb = &edev->tb[edev->ti];
  315. if(tb->owner != Interface)
  316. break;
  317. td = &txd[i];
  318. memmove(td->buf, tb->pkt, tb->len);
  319. td->size = tb->len | TxChainStart | TxChainEnd | TxInt; /* could reduce number of ints here */
  320. coherence();
  321. td->stat = OwnNic;
  322. i = (i + 1) % Ntxd;
  323. txused++;
  324. n++;
  325. tb->owner = Host;
  326. edev->ti = NEXT(edev->ti, edev->ntb);
  327. }
  328. if (n)
  329. iow16(ctlr, Cr, ior16(ctlr, Cr) | Tdmd);
  330. ctlr->txhead = i;
  331. ctlr->txused = txused;
  332. }
  333. static void
  334. transmit(Ether *edev)
  335. {
  336. Ctlr *ctlr;
  337. ctlr = edev->ctlr;
  338. ilock(&ctlr->tlock);
  339. txstart(edev);
  340. iunlock(&ctlr->tlock);
  341. }
  342. static void
  343. txcomplete(Ether *edev)
  344. {
  345. Ctlr *ctlr;
  346. Desc *txd, *td;
  347. int i, txused, j;
  348. ulong stat;
  349. ctlr = edev->ctlr;
  350. txd = ctlr->txd;
  351. txused = ctlr->txused;
  352. i = ctlr->txtail;
  353. while (txused > 0) {
  354. td = &txd[i];
  355. stat = td->stat;
  356. if (stat & OwnNic)
  357. break;
  358. ctlr->txstats[Ntxstats-1] += stat & 0xF;
  359. for (j = 0; j < Ntxstats-1; ++j)
  360. if (stat & (1<<(j+8)))
  361. ctlr->txstats[j]++;
  362. i = (i + 1) % Ntxd;
  363. txused--;
  364. }
  365. ctlr->txused = txused;
  366. ctlr->txtail = i;
  367. if (txused <= Ntxd/2)
  368. txstart(edev);
  369. }
  370. static void
  371. interrupt(Ureg *, void *arg)
  372. {
  373. Ether *edev;
  374. Ctlr *ctlr;
  375. RingBuf *rb;
  376. ushort isr, misr;
  377. ulong stat;
  378. Desc *rxd, *rd;
  379. int i, n, j, size;
  380. edev = (Ether*)arg;
  381. ctlr = edev->ctlr;
  382. iow16(ctlr, Imr, 0);
  383. isr = ior16(ctlr, Isr);
  384. iow16(ctlr, Isr, 0xFFFF);
  385. misr = ior16(ctlr, MiscIsr) & ~(3<<5); /* don't care about used defined ints */
  386. if (isr & RxOk) {
  387. rxd = ctlr->rxd;
  388. i = ctlr->rxtail;
  389. n = 0;
  390. while ((rxd[i].stat & OwnNic) == 0) {
  391. rd = &rxd[i];
  392. stat = rd->stat;
  393. for (j = 0; j < Nrxstats; ++j)
  394. if (stat & (1<<j))
  395. ctlr->rxstats[j]++;
  396. if (stat & 0xFF)
  397. iprint("rx: %lux\n", stat & 0xFF);
  398. size = ((rd->stat>>16) & 2047) - 4;
  399. rb = &edev->rb[edev->ri];
  400. if(rb->owner == Interface){
  401. rb->owner = Host;
  402. rb->len = size;
  403. memmove(rb->pkt, rd->buf, size);
  404. edev->ri = NEXT(edev->ri, edev->nrb);
  405. }
  406. rd->size = sizeof(Etherpkt)+4;
  407. coherence();
  408. rd->stat = OwnNic;
  409. i = (i + 1) % Nrxd;
  410. n++;
  411. }
  412. if (n)
  413. iow16(ctlr, Cr, ior16(ctlr, Cr) | Rdmd);
  414. ctlr->rxtail = i;
  415. isr &= ~RxOk;
  416. }
  417. if (isr & TxOk) {
  418. txcomplete(edev);
  419. isr &= ~TxOk;
  420. }
  421. if (isr | misr)
  422. iprint("etherrhine: unhandled irq(s). isr:%x misr:%x\n", isr, misr);
  423. iow16(ctlr, Imr, 0xFFFF);
  424. }
  425. static void
  426. promiscuous(void *arg, int enable)
  427. {
  428. Ether *edev;
  429. Ctlr *ctlr;
  430. edev = arg;
  431. ctlr = edev->ctlr;
  432. ilock(&ctlr->tlock);
  433. iow8(ctlr, Rcr, ior8(ctlr, Rcr) | (enable ? RxProm : RxBcast));
  434. iunlock(&ctlr->tlock);
  435. }
  436. static int
  437. miiread(Mii *mii, int phy, int reg)
  438. {
  439. Ctlr *ctlr;
  440. int n;
  441. ctlr = mii->ctlr;
  442. n = Nwait;
  443. while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
  444. microdelay(1);
  445. if (n == Nwait)
  446. iprint("etherrhine: miiread: timeout\n");
  447. iow8(ctlr, RhineMiiCr, 0);
  448. iow8(ctlr, RhineMiiPhy, phy);
  449. iow8(ctlr, RhineMiiAddr, reg);
  450. iow8(ctlr, RhineMiiCr, Rcmd);
  451. n = Nwait;
  452. while (n-- && ior8(ctlr, RhineMiiCr) & Rcmd)
  453. microdelay(1);
  454. if (n == Nwait)
  455. iprint("etherrhine: miiread: timeout\n");
  456. n = ior16(ctlr, RhineMiiData);
  457. return n;
  458. }
  459. static int
  460. miiwrite(Mii *mii, int phy, int reg, int data)
  461. {
  462. int n;
  463. Ctlr *ctlr;
  464. ctlr = mii->ctlr;
  465. n = Nwait;
  466. while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
  467. microdelay(1);
  468. if (n == Nwait)
  469. iprint("etherrhine: miiwrite: timeout\n");
  470. iow8(ctlr, RhineMiiCr, 0);
  471. iow8(ctlr, RhineMiiPhy, phy);
  472. iow8(ctlr, RhineMiiAddr, reg);
  473. iow16(ctlr, RhineMiiData, data);
  474. iow8(ctlr, RhineMiiCr, Wcmd);
  475. n = Nwait;
  476. while (n-- && ior8(ctlr, RhineMiiCr) & Wcmd)
  477. microdelay(1);
  478. if (n == Nwait)
  479. iprint("etherrhine: miiwrite: timeout\n");
  480. return 0;
  481. }
  482. static void
  483. reset(Ctlr* ctlr)
  484. {
  485. int i;
  486. iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop);
  487. iow16(ctlr, Cr, ior16(ctlr, Cr) | Reset);
  488. for (i = 0; i < Nwait; ++i) {
  489. if ((ior16(ctlr, Cr) & Reset) == 0)
  490. return;
  491. delay(5);
  492. }
  493. iprint("etherrhine: reset timeout\n");
  494. }
  495. static void
  496. detach(Ether* edev)
  497. {
  498. reset(edev->ctlr);
  499. }
  500. static void
  501. init(Ether *edev)
  502. {
  503. Ctlr *ctlr;
  504. int i;
  505. ctlr = edev->ctlr;
  506. ilock(&ctlr->tlock);
  507. pcisetbme(ctlr->pci);
  508. reset(ctlr);
  509. iow8(ctlr, Eecsr, ior8(ctlr, Eecsr) | EeAutoLoad);
  510. for (i = 0; i < Nwait; ++i) {
  511. if ((ior8(ctlr, Eecsr) & EeAutoLoad) == 0)
  512. break;
  513. delay(5);
  514. }
  515. if (i == Nwait)
  516. iprint("etherrhine: eeprom autoload timeout\n");
  517. for (i = 0; i < Eaddrlen; ++i)
  518. edev->ea[i] = ior8(ctlr, Eaddr + i);
  519. ctlr->mii.mir = miiread;
  520. ctlr->mii.miw = miiwrite;
  521. ctlr->mii.ctlr = ctlr;
  522. if(mii(&ctlr->mii, ~0) == 0 || ctlr->mii.curphy == nil){
  523. iprint("etherrhine: init mii failure\n");
  524. return;
  525. }
  526. for (i = 0; i < NMiiPhy; ++i)
  527. if (ctlr->mii.phy[i])
  528. if (ctlr->mii.phy[i]->oui != 0xFFFFF)
  529. ctlr->mii.curphy = ctlr->mii.phy[i];
  530. miistatus(&ctlr->mii);
  531. iow16(ctlr, Imr, 0);
  532. iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop);
  533. iunlock(&ctlr->tlock);
  534. }
  535. static Pcidev *
  536. rhinematch(ulong)
  537. {
  538. static int nrhines = 0;
  539. int nfound = 0;
  540. Pcidev *p = nil;
  541. while (p = pcimatch(p, 0x1106, 0))
  542. if (p->did == 0x3065)
  543. if (++nfound > nrhines) {
  544. nrhines++;
  545. break;
  546. }
  547. return p;
  548. }
  549. int
  550. rhinepnp(Ether *edev)
  551. {
  552. Pcidev *p;
  553. Ctlr *ctlr;
  554. ulong port;
  555. p = rhinematch(edev->port);
  556. if (p == nil)
  557. return -1;
  558. port = p->mem[0].bar & ~1;
  559. if ((ctlr = malloc(sizeof(Ctlr))) == nil) {
  560. print("etherrhine: couldn't allocate memory for ctlr\n");
  561. return -1;
  562. }
  563. memset(ctlr, 0, sizeof(Ctlr));
  564. ctlr->txd = xspanalloc(sizeof(Desc) * Ntxd, 16, 0);
  565. ctlr->rxd = xspanalloc(sizeof(Desc) * Nrxd, 16, 0);
  566. ctlr->pci = p;
  567. ctlr->port = port;
  568. edev->ctlr = ctlr;
  569. edev->port = ctlr->port;
  570. edev->irq = p->intl;
  571. edev->tbdf = p->tbdf;
  572. init(edev);
  573. edev->attach = attach;
  574. edev->transmit = transmit;
  575. edev->interrupt = interrupt;
  576. edev->detach = detach;
  577. return 0;
  578. }