ether79c970.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * AMD79C970
  3. * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus
  4. * To do:
  5. * finish this rewrite
  6. */
  7. #include "u.h"
  8. #include "../port/lib.h"
  9. #include "mem.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "io.h"
  13. #include "../port/error.h"
  14. #include "../port/netif.h"
  15. #include "etherif.h"
  16. enum {
  17. Lognrdre = 6,
  18. Nrdre = (1<<Lognrdre),/* receive descriptor ring entries */
  19. Logntdre = 4,
  20. Ntdre = (1<<Logntdre),/* transmit descriptor ring entries */
  21. Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */
  22. };
  23. enum { /* DWIO I/O resource map */
  24. Aprom = 0x0000, /* physical address */
  25. Rdp = 0x0010, /* register data port */
  26. Rap = 0x0014, /* register address port */
  27. Sreset = 0x0018, /* software reset */
  28. Bdp = 0x001C, /* bus configuration register data port */
  29. };
  30. enum { /* CSR0 */
  31. Init = 0x0001, /* begin initialisation */
  32. Strt = 0x0002, /* enable chip */
  33. Stop = 0x0004, /* disable chip */
  34. Tdmd = 0x0008, /* transmit demand */
  35. Txon = 0x0010, /* transmitter on */
  36. Rxon = 0x0020, /* receiver on */
  37. Iena = 0x0040, /* interrupt enable */
  38. Intr = 0x0080, /* interrupt flag */
  39. Idon = 0x0100, /* initialisation done */
  40. Tint = 0x0200, /* transmit interrupt */
  41. Rint = 0x0400, /* receive interrupt */
  42. Merr = 0x0800, /* memory error */
  43. Miss = 0x1000, /* missed frame */
  44. Cerr = 0x2000, /* collision */
  45. Babl = 0x4000, /* transmitter timeout */
  46. Err = 0x8000, /* Babl|Cerr|Miss|Merr */
  47. };
  48. enum { /* CSR3 */
  49. Bswp = 0x0004, /* byte swap */
  50. Emba = 0x0008, /* enable modified back-off algorithm */
  51. Dxmt2pd = 0x0010, /* disable transmit two part deferral */
  52. Lappen = 0x0020, /* look-ahead packet processing enable */
  53. };
  54. enum { /* CSR4 */
  55. ApadXmt = 0x0800, /* auto pad transmit */
  56. };
  57. enum { /* CSR15 */
  58. Prom = 0x8000, /* promiscuous mode */
  59. };
  60. typedef struct Iblock Iblock;
  61. struct Iblock { /* Initialisation Block */
  62. ushort mode;
  63. uchar rlen; /* upper 4 bits */
  64. uchar tlen; /* upper 4 bits */
  65. uchar padr[6];
  66. uchar res[2];
  67. uchar ladr[8];
  68. ulong rdra;
  69. ulong tdra;
  70. };
  71. typedef struct Dre Dre;
  72. struct Dre { /* descriptor ring entry */
  73. ulong addr;
  74. ulong md1; /* status|bcnt */
  75. ulong md2; /* rcc|rpc|mcnt */
  76. Block* bp;
  77. };
  78. enum { /* md1 */
  79. Enp = 0x01000000, /* end of packet */
  80. Stp = 0x02000000, /* start of packet */
  81. RxBuff = 0x04000000, /* buffer error */
  82. Def = 0x04000000, /* deferred */
  83. Crc = 0x08000000, /* CRC error */
  84. One = 0x08000000, /* one retry needed */
  85. Oflo = 0x10000000, /* overflow error */
  86. More = 0x10000000, /* more than one retry needed */
  87. Fram = 0x20000000, /* framing error */
  88. RxErr = 0x40000000, /* Fram|Oflo|Crc|RxBuff */
  89. TxErr = 0x40000000, /* Uflo|Lcol|Lcar|Rtry */
  90. Own = 0x80000000,
  91. };
  92. enum { /* md2 */
  93. Rtry = 0x04000000, /* failed after repeated retries */
  94. Lcar = 0x08000000, /* loss of carrier */
  95. Lcol = 0x10000000, /* late collision */
  96. Uflo = 0x40000000, /* underflow error */
  97. TxBuff = 0x80000000, /* buffer error */
  98. };
  99. typedef struct Ctlr Ctlr;
  100. struct Ctlr {
  101. Lock;
  102. int port;
  103. Pcidev* pcidev;
  104. Ctlr* next;
  105. int active;
  106. int init; /* initialisation in progress */
  107. Iblock iblock;
  108. Dre* rdr; /* receive descriptor ring */
  109. int rdrx;
  110. Dre* tdr; /* transmit descriptor ring */
  111. int tdrh; /* host index into tdr */
  112. int tdri; /* interface index into tdr */
  113. int ntq; /* descriptors active */
  114. ulong rxbuff; /* receive statistics */
  115. ulong crc;
  116. ulong oflo;
  117. ulong fram;
  118. ulong rtry; /* transmit statistics */
  119. ulong lcar;
  120. ulong lcol;
  121. ulong uflo;
  122. ulong txbuff;
  123. ulong merr; /* bobf is such a whiner */
  124. ulong miss;
  125. ulong babl;
  126. int (*ior)(Ctlr*, int);
  127. void (*iow)(Ctlr*, int, int);
  128. };
  129. static Ctlr* ctlrhead;
  130. static Ctlr* ctlrtail;
  131. /*
  132. * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above.
  133. * To get to 16-bit offsets, scale down with 0x10 staying the same.
  134. */
  135. static int
  136. io16r(Ctlr *c, int r)
  137. {
  138. if(r >= Rdp)
  139. r = (r-Rdp)/2+Rdp;
  140. return ins(c->port+r);
  141. }
  142. static void
  143. io16w(Ctlr *c, int r, int v)
  144. {
  145. if(r >= Rdp)
  146. r = (r-Rdp)/2+Rdp;
  147. outs(c->port+r, v);
  148. }
  149. static int
  150. io32r(Ctlr *c, int r)
  151. {
  152. return inl(c->port+r);
  153. }
  154. static void
  155. io32w(Ctlr *c, int r, int v)
  156. {
  157. outl(c->port+r, v);
  158. }
  159. static void
  160. attach(Ether*)
  161. {
  162. }
  163. static long
  164. ifstat(Ether* ether, void* a, long n, ulong offset)
  165. {
  166. char *p;
  167. int len;
  168. Ctlr *ctlr;
  169. ctlr = ether->ctlr;
  170. ether->crcs = ctlr->crc;
  171. ether->frames = ctlr->fram;
  172. ether->buffs = ctlr->rxbuff+ctlr->txbuff;
  173. ether->overflows = ctlr->oflo;
  174. if(n == 0)
  175. return 0;
  176. p = malloc(READSTR);
  177. if(p == nil)
  178. error(Enomem);
  179. len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
  180. len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
  181. len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
  182. len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
  183. len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
  184. len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
  185. len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
  186. len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
  187. len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
  188. len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
  189. len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
  190. snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
  191. n = readstr(offset, a, n, p);
  192. free(p);
  193. return n;
  194. }
  195. static void
  196. ringinit(Ctlr* ctlr)
  197. {
  198. Dre *dre;
  199. /*
  200. * Initialise the receive and transmit buffer rings.
  201. * The ring entries must be aligned on 16-byte boundaries.
  202. *
  203. * This routine is protected by ctlr->init.
  204. */
  205. if(ctlr->rdr == 0){
  206. ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
  207. for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
  208. dre->bp = iallocb(Rbsize);
  209. if(dre->bp == nil)
  210. panic("can't allocate ethernet receive ring\n");
  211. dre->addr = PADDR(dre->bp->rp);
  212. dre->md2 = 0;
  213. dre->md1 = Own|(-Rbsize & 0xFFFF);
  214. }
  215. }
  216. ctlr->rdrx = 0;
  217. if(ctlr->tdr == 0)
  218. ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
  219. memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
  220. ctlr->tdrh = ctlr->tdri = 0;
  221. }
  222. static void
  223. promiscuous(void* arg, int on)
  224. {
  225. Ether *ether;
  226. int x;
  227. Ctlr *ctlr;
  228. ether = arg;
  229. ctlr = ether->ctlr;
  230. /*
  231. * Put the chip into promiscuous mode. First must wait until
  232. * anyone transmitting is done, then stop the chip and put
  233. * it in promiscuous mode. Restarting is made harder by the chip
  234. * reloading the transmit and receive descriptor pointers with their
  235. * base addresses when Strt is set (unlike the older Lance chip),
  236. * so the rings must be re-initialised.
  237. */
  238. ilock(ctlr);
  239. if(ctlr->init){
  240. iunlock(ctlr);
  241. return;
  242. }
  243. ctlr->init = 1;
  244. iunlock(ctlr);
  245. while(ctlr->ntq)
  246. ;
  247. ctlr->iow(ctlr, Rdp, Stop);
  248. ctlr->iow(ctlr, Rap, 15);
  249. x = ctlr->ior(ctlr, Rdp) & ~Prom;
  250. if(on)
  251. x |= Prom;
  252. ctlr->iow(ctlr, Rdp, x);
  253. ctlr->iow(ctlr, Rap, 0);
  254. ringinit(ctlr);
  255. ilock(ctlr);
  256. ctlr->init = 0;
  257. ctlr->iow(ctlr, Rdp, Iena|Strt);
  258. iunlock(ctlr);
  259. }
  260. static void
  261. multicast(void* arg, uchar*, int)
  262. {
  263. promiscuous(arg, 1);
  264. }
  265. static void
  266. shutdown(Ether *ether)
  267. {
  268. Ctlr *ctlr;
  269. ctlr = ether->ctlr;
  270. ilock(ctlr);
  271. io32r(ctlr, Sreset);
  272. io16r(ctlr, Sreset);
  273. iunlock(ctlr);
  274. }
  275. static void
  276. txstart(Ether* ether)
  277. {
  278. Ctlr *ctlr;
  279. Block *bp;
  280. Dre *dre;
  281. ctlr = ether->ctlr;
  282. if(ctlr->init)
  283. return;
  284. while(ctlr->ntq < (Ntdre-1)){
  285. bp = qget(ether->oq);
  286. if(bp == nil)
  287. break;
  288. /*
  289. * Give ownership of the descriptor to the chip,
  290. * increment the software ring descriptor pointer
  291. * and tell the chip to poll.
  292. * There's no need to pad to ETHERMINTU
  293. * here as ApadXmt is set in CSR4.
  294. */
  295. dre = &ctlr->tdr[ctlr->tdrh];
  296. dre->bp = bp;
  297. dre->addr = PADDR(bp->rp);
  298. dre->md2 = 0;
  299. dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
  300. ctlr->ntq++;
  301. ctlr->iow(ctlr, Rdp, Iena|Tdmd);
  302. ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
  303. }
  304. }
  305. static void
  306. transmit(Ether* ether)
  307. {
  308. Ctlr *ctlr;
  309. ctlr = ether->ctlr;
  310. ilock(ctlr);
  311. txstart(ether);
  312. iunlock(ctlr);
  313. }
  314. static void
  315. interrupt(Ureg*, void* arg)
  316. {
  317. Ctlr *ctlr;
  318. Ether *ether;
  319. int csr0, len;
  320. Dre *dre;
  321. Block *bp;
  322. ether = arg;
  323. ctlr = ether->ctlr;
  324. /*
  325. * Acknowledge all interrupts and whine about those that shouldn't
  326. * happen.
  327. */
  328. intrloop:
  329. csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  330. ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
  331. if(csr0 & Merr)
  332. ctlr->merr++;
  333. if(csr0 & Miss)
  334. ctlr->miss++;
  335. if(csr0 & Babl)
  336. ctlr->babl++;
  337. //if(csr0 & (Babl|Miss|Merr))
  338. // print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
  339. if(!(csr0 & (Rint|Tint)))
  340. return;
  341. /*
  342. * Receiver interrupt: run round the descriptor ring logging
  343. * errors and passing valid receive data up to the higher levels
  344. * until a descriptor is encountered still owned by the chip.
  345. */
  346. if(csr0 & Rint){
  347. dre = &ctlr->rdr[ctlr->rdrx];
  348. while(!(dre->md1 & Own)){
  349. if(dre->md1 & RxErr){
  350. if(dre->md1 & RxBuff)
  351. ctlr->rxbuff++;
  352. if(dre->md1 & Crc)
  353. ctlr->crc++;
  354. if(dre->md1 & Oflo)
  355. ctlr->oflo++;
  356. if(dre->md1 & Fram)
  357. ctlr->fram++;
  358. }
  359. else if(bp = iallocb(Rbsize)){
  360. len = (dre->md2 & 0x0FFF)-4;
  361. dre->bp->wp = dre->bp->rp+len;
  362. etheriq(ether, dre->bp, 1);
  363. dre->bp = bp;
  364. dre->addr = PADDR(bp->rp);
  365. }
  366. /*
  367. * Finished with this descriptor, reinitialise it,
  368. * give it back to the chip, then on to the next...
  369. */
  370. dre->md2 = 0;
  371. dre->md1 = Own|(-Rbsize & 0xFFFF);
  372. ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
  373. dre = &ctlr->rdr[ctlr->rdrx];
  374. }
  375. }
  376. /*
  377. * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
  378. */
  379. if(csr0 & Tint){
  380. lock(ctlr);
  381. while(ctlr->ntq){
  382. dre = &ctlr->tdr[ctlr->tdri];
  383. if(dre->md1 & Own)
  384. break;
  385. if(dre->md1 & TxErr){
  386. if(dre->md2 & Rtry)
  387. ctlr->rtry++;
  388. if(dre->md2 & Lcar)
  389. ctlr->lcar++;
  390. if(dre->md2 & Lcol)
  391. ctlr->lcol++;
  392. if(dre->md2 & Uflo)
  393. ctlr->uflo++;
  394. if(dre->md2 & TxBuff)
  395. ctlr->txbuff++;
  396. ether->oerrs++;
  397. }
  398. freeb(dre->bp);
  399. ctlr->ntq--;
  400. ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
  401. }
  402. txstart(ether);
  403. unlock(ctlr);
  404. }
  405. goto intrloop;
  406. }
  407. static void
  408. amd79c970pci(void)
  409. {
  410. int port;
  411. Ctlr *ctlr;
  412. Pcidev *p;
  413. p = nil;
  414. while(p = pcimatch(p, 0x1022, 0x2000)){
  415. port = p->mem[0].bar & ~0x01;
  416. if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
  417. print("amd79c970: port 0x%uX in use\n", port);
  418. continue;
  419. }
  420. ctlr = malloc(sizeof(Ctlr));
  421. if(ctlr == nil)
  422. error(Enomem);
  423. ctlr->port = p->mem[0].bar & ~0x01;
  424. ctlr->pcidev = p;
  425. if(ctlrhead != nil)
  426. ctlrtail->next = ctlr;
  427. else
  428. ctlrhead = ctlr;
  429. ctlrtail = ctlr;
  430. }
  431. }
  432. static int
  433. reset(Ether* ether)
  434. {
  435. int x;
  436. uchar ea[Eaddrlen];
  437. Ctlr *ctlr;
  438. if(ctlrhead == nil)
  439. amd79c970pci();
  440. /*
  441. * Any adapter matches if no port is supplied,
  442. * otherwise the ports must match.
  443. */
  444. for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
  445. if(ctlr->active)
  446. continue;
  447. if(ether->port == 0 || ether->port == ctlr->port){
  448. ctlr->active = 1;
  449. break;
  450. }
  451. }
  452. if(ctlr == nil)
  453. return -1;
  454. /*
  455. * Allocate a controller structure and start to initialise it.
  456. */
  457. ether->ctlr = ctlr;
  458. ether->port = ctlr->port;
  459. ether->irq = ctlr->pcidev->intl;
  460. ether->tbdf = ctlr->pcidev->tbdf;
  461. pcisetbme(ctlr->pcidev);
  462. shutdown(ether);
  463. ilock(ctlr);
  464. ctlr->init = 1;
  465. if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
  466. ctlr->ior = io16r;
  467. ctlr->iow = io16w;
  468. }else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
  469. ctlr->ior = io32r;
  470. ctlr->iow = io32w;
  471. }else{
  472. print("#l%d: card doesn't talk right\n", ether->ctlrno);
  473. iunlock(ctlr);
  474. return -1;
  475. }
  476. ctlr->iow(ctlr, Rap, 88);
  477. x = ctlr->ior(ctlr, Rdp);
  478. ctlr->iow(ctlr, Rap, 89);
  479. x |= ctlr->ior(ctlr, Rdp)<<16;
  480. switch(x&0xFFFFFFF){
  481. case 0x2420003: /* PCnet/PCI 79C970 */
  482. case 0x2621003: /* PCnet/PCI II 79C970A */
  483. case 0x2625003: /* PCnet-FAST III 79C973 */
  484. break;
  485. default:
  486. print("#l%d: unknown PCnet card version 0x%.7ux\n",
  487. ether->ctlrno, x&0xFFFFFFF);
  488. iunlock(ctlr);
  489. return -1;
  490. }
  491. /*
  492. * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
  493. * Set the auto pad transmit in CSR4.
  494. */
  495. ctlr->iow(ctlr, Rap, 20);
  496. ctlr->iow(ctlr, Bdp, 0x0002);
  497. ctlr->iow(ctlr, Rap, 4);
  498. x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  499. ctlr->iow(ctlr, Rdp, ApadXmt|x);
  500. ctlr->iow(ctlr, Rap, 0);
  501. /*
  502. * Check if the adapter's station address is to be overridden.
  503. * If not, read it from the I/O-space and set in ether->ea prior to
  504. * loading the station address in the initialisation block.
  505. */
  506. memset(ea, 0, Eaddrlen);
  507. if(!memcmp(ea, ether->ea, Eaddrlen)){
  508. x = ctlr->ior(ctlr, Aprom);
  509. ether->ea[0] = x;
  510. ether->ea[1] = x>>8;
  511. if(ctlr->ior == io16r)
  512. x = ctlr->ior(ctlr, Aprom+2);
  513. else
  514. x >>= 16;
  515. ether->ea[2] = x;
  516. ether->ea[3] = x>>8;
  517. x = ctlr->ior(ctlr, Aprom+4);
  518. ether->ea[4] = x;
  519. ether->ea[5] = x>>8;
  520. }
  521. /*
  522. * Start to fill in the initialisation block
  523. * (must be DWORD aligned).
  524. */
  525. ctlr->iblock.rlen = Lognrdre<<4;
  526. ctlr->iblock.tlen = Logntdre<<4;
  527. memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
  528. ringinit(ctlr);
  529. ctlr->iblock.rdra = PADDR(ctlr->rdr);
  530. ctlr->iblock.tdra = PADDR(ctlr->tdr);
  531. /*
  532. * Point the chip at the initialisation block and tell it to go.
  533. * Mask the Idon interrupt and poll for completion. Strt and interrupt
  534. * enables will be set later when attaching to the network.
  535. */
  536. x = PADDR(&ctlr->iblock);
  537. ctlr->iow(ctlr, Rap, 1);
  538. ctlr->iow(ctlr, Rdp, x & 0xFFFF);
  539. ctlr->iow(ctlr, Rap, 2);
  540. ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
  541. ctlr->iow(ctlr, Rap, 3);
  542. ctlr->iow(ctlr, Rdp, Idon);
  543. ctlr->iow(ctlr, Rap, 0);
  544. ctlr->iow(ctlr, Rdp, Init);
  545. while(!(ctlr->ior(ctlr, Rdp) & Idon))
  546. ;
  547. /*
  548. * We used to set CSR0 to Idon|Stop here, and then
  549. * in attach change it to Iena|Strt. Apparently the simulated
  550. * 79C970 in VMware never enables after a write of Idon|Stop,
  551. * so we enable the device here now.
  552. */
  553. ctlr->iow(ctlr, Rdp, Iena|Strt);
  554. ctlr->init = 0;
  555. iunlock(ctlr);
  556. /*
  557. * Linkage to the generic ethernet driver.
  558. */
  559. ether->attach = attach;
  560. ether->transmit = transmit;
  561. ether->interrupt = interrupt;
  562. ether->ifstat = ifstat;
  563. ether->arg = ether;
  564. ether->promiscuous = promiscuous;
  565. ether->multicast = multicast;
  566. ether->shutdown = shutdown;
  567. return 0;
  568. }
  569. void
  570. ether79c970link(void)
  571. {
  572. addethercard("AMD79C970", reset);
  573. }