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