ether79c970.c 14 KB

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