ether79c970.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff);
  178. len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc);
  179. len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo);
  180. len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram);
  181. len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry);
  182. len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar);
  183. len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol);
  184. len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo);
  185. len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff);
  186. len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr);
  187. len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss);
  188. snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl);
  189. n = readstr(offset, a, n, p);
  190. free(p);
  191. return n;
  192. }
  193. static void
  194. ringinit(Ctlr* ctlr)
  195. {
  196. Dre *dre;
  197. /*
  198. * Initialise the receive and transmit buffer rings.
  199. * The ring entries must be aligned on 16-byte boundaries.
  200. *
  201. * This routine is protected by ctlr->init.
  202. */
  203. if(ctlr->rdr == 0){
  204. ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0);
  205. for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){
  206. dre->bp = iallocb(Rbsize);
  207. if(dre->bp == nil)
  208. panic("can't allocate ethernet receive ring\n");
  209. dre->addr = PADDR(dre->bp->rp);
  210. dre->md2 = 0;
  211. dre->md1 = Own|(-Rbsize & 0xFFFF);
  212. }
  213. }
  214. ctlr->rdrx = 0;
  215. if(ctlr->tdr == 0)
  216. ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0);
  217. memset(ctlr->tdr, 0, Ntdre*sizeof(Dre));
  218. ctlr->tdrh = ctlr->tdri = 0;
  219. }
  220. static void
  221. promiscuous(void* arg, int on)
  222. {
  223. Ether *ether;
  224. int x;
  225. Ctlr *ctlr;
  226. ether = arg;
  227. ctlr = ether->ctlr;
  228. /*
  229. * Put the chip into promiscuous mode. First must wait until
  230. * anyone transmitting is done, then stop the chip and put
  231. * it in promiscuous mode. Restarting is made harder by the chip
  232. * reloading the transmit and receive descriptor pointers with their
  233. * base addresses when Strt is set (unlike the older Lance chip),
  234. * so the rings must be re-initialised.
  235. */
  236. ilock(ctlr);
  237. if(ctlr->init){
  238. iunlock(ctlr);
  239. return;
  240. }
  241. ctlr->init = 1;
  242. iunlock(ctlr);
  243. while(ctlr->ntq)
  244. ;
  245. ctlr->iow(ctlr, Rdp, Stop);
  246. ctlr->iow(ctlr, Rap, 15);
  247. x = ctlr->ior(ctlr, Rdp) & ~Prom;
  248. if(on)
  249. x |= Prom;
  250. ctlr->iow(ctlr, Rdp, x);
  251. ctlr->iow(ctlr, Rap, 0);
  252. ringinit(ctlr);
  253. ilock(ctlr);
  254. ctlr->init = 0;
  255. ctlr->iow(ctlr, Rdp, Iena|Strt);
  256. iunlock(ctlr);
  257. }
  258. static void
  259. txstart(Ether* ether)
  260. {
  261. Ctlr *ctlr;
  262. Block *bp;
  263. Dre *dre;
  264. ctlr = ether->ctlr;
  265. if(ctlr->init)
  266. return;
  267. while(ctlr->ntq < (Ntdre-1)){
  268. bp = qget(ether->oq);
  269. if(bp == nil)
  270. break;
  271. /*
  272. * Give ownership of the descriptor to the chip,
  273. * increment the software ring descriptor pointer
  274. * and tell the chip to poll.
  275. * There's no need to pad to ETHERMINTU
  276. * here as ApadXmt is set in CSR4.
  277. */
  278. dre = &ctlr->tdr[ctlr->tdrh];
  279. dre->bp = bp;
  280. dre->addr = PADDR(bp->rp);
  281. dre->md2 = 0;
  282. dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF);
  283. ctlr->ntq++;
  284. ctlr->iow(ctlr, Rdp, Iena|Tdmd);
  285. ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
  286. }
  287. }
  288. static void
  289. transmit(Ether* ether)
  290. {
  291. Ctlr *ctlr;
  292. ctlr = ether->ctlr;
  293. ilock(ctlr);
  294. txstart(ether);
  295. iunlock(ctlr);
  296. }
  297. static void
  298. interrupt(Ureg*, void* arg)
  299. {
  300. Ctlr *ctlr;
  301. Ether *ether;
  302. int csr0, len;
  303. Dre *dre;
  304. Block *bp;
  305. ether = arg;
  306. ctlr = ether->ctlr;
  307. /*
  308. * Acknowledge all interrupts and whine about those that shouldn't
  309. * happen.
  310. */
  311. intrloop:
  312. csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  313. ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena);
  314. if(csr0 & Merr)
  315. ctlr->merr++;
  316. if(csr0 & Miss)
  317. ctlr->miss++;
  318. if(csr0 & Babl)
  319. ctlr->babl++;
  320. //if(csr0 & (Babl|Miss|Merr))
  321. // print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0);
  322. if(!(csr0 & (Rint|Tint)))
  323. return;
  324. /*
  325. * Receiver interrupt: run round the descriptor ring logging
  326. * errors and passing valid receive data up to the higher levels
  327. * until a descriptor is encountered still owned by the chip.
  328. */
  329. if(csr0 & Rint){
  330. dre = &ctlr->rdr[ctlr->rdrx];
  331. while(!(dre->md1 & Own)){
  332. if(dre->md1 & RxErr){
  333. if(dre->md1 & RxBuff)
  334. ctlr->rxbuff++;
  335. if(dre->md1 & Crc)
  336. ctlr->crc++;
  337. if(dre->md1 & Oflo)
  338. ctlr->oflo++;
  339. if(dre->md1 & Fram)
  340. ctlr->fram++;
  341. }
  342. else if(bp = iallocb(Rbsize)){
  343. len = (dre->md2 & 0x0FFF)-4;
  344. dre->bp->wp = dre->bp->rp+len;
  345. etheriq(ether, dre->bp, 1);
  346. dre->bp = bp;
  347. dre->addr = PADDR(bp->rp);
  348. }
  349. /*
  350. * Finished with this descriptor, reinitialise it,
  351. * give it back to the chip, then on to the next...
  352. */
  353. dre->md2 = 0;
  354. dre->md1 = Own|(-Rbsize & 0xFFFF);
  355. ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
  356. dre = &ctlr->rdr[ctlr->rdrx];
  357. }
  358. }
  359. /*
  360. * Transmitter interrupt: wakeup anyone waiting for a free descriptor.
  361. */
  362. if(csr0 & Tint){
  363. lock(ctlr);
  364. while(ctlr->ntq){
  365. dre = &ctlr->tdr[ctlr->tdri];
  366. if(dre->md1 & Own)
  367. break;
  368. if(dre->md1 & TxErr){
  369. if(dre->md2 & Rtry)
  370. ctlr->rtry++;
  371. if(dre->md2 & Lcar)
  372. ctlr->lcar++;
  373. if(dre->md2 & Lcol)
  374. ctlr->lcol++;
  375. if(dre->md2 & Uflo)
  376. ctlr->uflo++;
  377. if(dre->md2 & TxBuff)
  378. ctlr->txbuff++;
  379. ether->oerrs++;
  380. }
  381. freeb(dre->bp);
  382. ctlr->ntq--;
  383. ctlr->tdri = NEXT(ctlr->tdri, Ntdre);
  384. }
  385. txstart(ether);
  386. unlock(ctlr);
  387. }
  388. goto intrloop;
  389. }
  390. static void
  391. amd79c970pci(void)
  392. {
  393. int port;
  394. Ctlr *ctlr;
  395. Pcidev *p;
  396. p = nil;
  397. while(p = pcimatch(p, 0x1022, 0x2000)){
  398. port = p->mem[0].bar & ~0x01;
  399. if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){
  400. print("amd79c970: port 0x%uX in use\n", port);
  401. continue;
  402. }
  403. ctlr = malloc(sizeof(Ctlr));
  404. ctlr->port = p->mem[0].bar & ~0x01;
  405. ctlr->pcidev = p;
  406. if(ctlrhead != nil)
  407. ctlrtail->next = ctlr;
  408. else
  409. ctlrhead = ctlr;
  410. ctlrtail = ctlr;
  411. }
  412. }
  413. static int
  414. reset(Ether* ether)
  415. {
  416. int x;
  417. uchar ea[Eaddrlen];
  418. Ctlr *ctlr;
  419. if(ctlrhead == nil)
  420. amd79c970pci();
  421. /*
  422. * Any adapter matches if no port is supplied,
  423. * otherwise the ports must match.
  424. */
  425. for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
  426. if(ctlr->active)
  427. continue;
  428. if(ether->port == 0 || ether->port == ctlr->port){
  429. ctlr->active = 1;
  430. break;
  431. }
  432. }
  433. if(ctlr == nil)
  434. return -1;
  435. /*
  436. * Allocate a controller structure and start to initialise it.
  437. */
  438. ether->ctlr = ctlr;
  439. ether->port = ctlr->port;
  440. ether->irq = ctlr->pcidev->intl;
  441. ether->tbdf = ctlr->pcidev->tbdf;
  442. pcisetbme(ctlr->pcidev);
  443. ilock(ctlr);
  444. ctlr->init = 1;
  445. io32r(ctlr, Sreset);
  446. io16r(ctlr, Sreset);
  447. if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){
  448. ctlr->ior = io16r;
  449. ctlr->iow = io16w;
  450. }else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){
  451. ctlr->ior = io32r;
  452. ctlr->iow = io32w;
  453. }else{
  454. print("#l%d: card doesn't talk right\n", ether->ctlrno);
  455. iunlock(ctlr);
  456. return -1;
  457. }
  458. ctlr->iow(ctlr, Rap, 88);
  459. x = ctlr->ior(ctlr, Rdp);
  460. ctlr->iow(ctlr, Rap, 89);
  461. x |= ctlr->ior(ctlr, Rdp)<<16;
  462. switch(x&0xFFFFFFF){
  463. case 0x2420003: /* PCnet/PCI 79C970 */
  464. case 0x2621003: /* PCnet/PCI II 79C970A */
  465. break;
  466. default:
  467. print("#l%d: unknown PCnet card version %.7ux\n",
  468. ether->ctlrno, x&0xFFFFFFF);
  469. iunlock(ctlr);
  470. return -1;
  471. }
  472. /*
  473. * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access.
  474. * Set the auto pad transmit in CSR4.
  475. */
  476. ctlr->iow(ctlr, Rap, 20);
  477. ctlr->iow(ctlr, Bdp, 0x0002);
  478. ctlr->iow(ctlr, Rap, 4);
  479. x = ctlr->ior(ctlr, Rdp) & 0xFFFF;
  480. ctlr->iow(ctlr, Rdp, ApadXmt|x);
  481. ctlr->iow(ctlr, Rap, 0);
  482. /*
  483. * Check if the adapter's station address is to be overridden.
  484. * If not, read it from the I/O-space and set in ether->ea prior to
  485. * loading the station address in the initialisation block.
  486. */
  487. memset(ea, 0, Eaddrlen);
  488. if(!memcmp(ea, ether->ea, Eaddrlen)){
  489. x = ctlr->ior(ctlr, Aprom);
  490. ether->ea[0] = x;
  491. ether->ea[1] = x>>8;
  492. if(ctlr->ior == io16r)
  493. x = ctlr->ior(ctlr, Aprom+2);
  494. else
  495. x >>= 16;
  496. ether->ea[2] = x;
  497. ether->ea[3] = x>>8;
  498. x = ctlr->ior(ctlr, Aprom+4);
  499. ether->ea[4] = x;
  500. ether->ea[5] = x>>8;
  501. }
  502. /*
  503. * Start to fill in the initialisation block
  504. * (must be DWORD aligned).
  505. */
  506. ctlr->iblock.rlen = Lognrdre<<4;
  507. ctlr->iblock.tlen = Logntdre<<4;
  508. memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr));
  509. ringinit(ctlr);
  510. ctlr->iblock.rdra = PADDR(ctlr->rdr);
  511. ctlr->iblock.tdra = PADDR(ctlr->tdr);
  512. /*
  513. * Point the chip at the initialisation block and tell it to go.
  514. * Mask the Idon interrupt and poll for completion. Strt and interrupt
  515. * enables will be set later when attaching to the network.
  516. */
  517. x = PADDR(&ctlr->iblock);
  518. ctlr->iow(ctlr, Rap, 1);
  519. ctlr->iow(ctlr, Rdp, x & 0xFFFF);
  520. ctlr->iow(ctlr, Rap, 2);
  521. ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF);
  522. ctlr->iow(ctlr, Rap, 3);
  523. ctlr->iow(ctlr, Rdp, Idon);
  524. ctlr->iow(ctlr, Rap, 0);
  525. ctlr->iow(ctlr, Rdp, Init);
  526. while(!(ctlr->ior(ctlr, Rdp) & Idon))
  527. ;
  528. /*
  529. * We used to set CSR0 to Idon|Stop here, and then
  530. * in attach change it to Iena|Strt. Apparently the simulated
  531. * 79C970 in VMware never enables after a write of Idon|Stop,
  532. * so we enable the device here now.
  533. */
  534. ctlr->iow(ctlr, Rdp, Iena|Strt);
  535. ctlr->init = 0;
  536. iunlock(ctlr);
  537. /*
  538. * Linkage to the generic ethernet driver.
  539. */
  540. ether->attach = attach;
  541. ether->transmit = transmit;
  542. ether->interrupt = interrupt;
  543. ether->ifstat = ifstat;
  544. ether->arg = ether;
  545. ether->promiscuous = promiscuous;
  546. return 0;
  547. }
  548. void
  549. ether79c970link(void)
  550. {
  551. addethercard("AMD79C970", reset);
  552. }