1 /*
2 * Xilinx XPS LL Temac Ethernet v1.00b + XPS LL Local Link FIFOs v1.00a driver.
3 *
4 * It uses the Central DMA controller.
5 * There are two interfaces per Temac controller.
6 * Each Temac interface is connected to a pair of FIFOs (tx and rx).
7 * Half-duplex is not supported by hardware.
8 *
9 * NB: The LL FIFO requires that we copy the data for a single packet
10 * into the FIFO, then write the frp->tlr register before writing any
11 * more data into the FIFO. It forbids copying the data for multiple
12 * packets into the FIFO and then writing frp->tlr with the length of each.
13 */
14 #include "u.h"
15 #include "../port/lib.h"
16 #include "mem.h"
17 #include "dat.h"
18 #include "fns.h"
19 #include "../ip/ip.h" /* to declare ethermedium */
20
21 #include "ethermii.h"
22 #include "../port/netif.h"
23
24 #include "etherif.h"
25 #include "io.h"
26
27 enum { /* directly-addressible registers' bits */
28 /* raf register */
29 Htrst = 1<<0, /* hard temac reset (both ifcs) */
30 Mcstrej = 1<<1, /* reject received multicast dest addr */
31 Bcstrej = 1<<2, /* reject received broadcast dest addr */
32
33 /* is, ip, ie register */
34 Hardacscmplt = 1<<0, /* hard register access complete */
35 Autoneg = 1<<1, /* auto-negotiation complete */
36 Rxcmplt = 1<<2, /* receive complete */
37 Rxrject = 1<<3, /* receive frame rejected (unknown m'cast?) */
38 Rxfifoovr = 1<<4, /* receive fifo overrun */
39 Txcmplt = 1<<5, /* transmit complete */
40 Rxdcmlock = 1<<6, /* receive DCM lock (ready for use) */
41
42 /* ctl register */
43 Wen = 1<<15, /* write instead of read */
44
45 /* ctl register address codes; select other registers */
46 Rcw0 = 0x200, /* receive configuration: pause addr low */
47 Rcw1 = 0x240, /* ": misc bits + pause addr high */
48 Tc = 0x280, /* tx config */
49 Fcc = 0x2c0, /* flow control */
50 Emmc = 0x300, /* ethernet mac mode config */
51 Phyc = 0x320, /* rgmii/sgmii config */
52 Mc = 0x340, /* mgmt config */
53 Uaw0 = 0x380, /* unicast addr word 0 (low-order) */
54 Uaw1 = 0x384, /* unicast addr word 1 (high-order) */
55 Maw0 = 0x388, /* multicast addr word 0 (low) */
56 Maw1 = 0x38c, /* multicast addr word 1 (high + more) */
57 Afm = 0x390, /* addr filter mode */
58 Tis = 0x3a0, /* intr status */
59 Tie = 0x3a4, /* intr enable */
60 Miimwd = 0x3b0, /* mii mgmt write data */
61 Miimai = 0x3b4, /* mii mgmt access initiate */
62
63 /* rdy register */
64 Fabrrr = 1<<0, /* fabric read ready */
65 Miimrr = 1<<1, /* mii mgmt read ready */
66 Miimwr = 1<<2, /* mii mgmt write ready */
67 Afrr = 1<<3, /* addr filter read ready */
68 Afwr = 1<<4, /* addr filter write ready */
69 Cfgrr = 1<<5, /* config reg read ready */
70 Cfgwr = 1<<6, /* config reg write ready */
71 Hardacsrdy = 1<<16, /* hard reg access ready */
72 };
73 enum { /* indirectly-addressible registers' bits */
74 /* Rcw1 register */
75 Rst = 1<<31, /* reset */
76 Jum = 1<<30, /* jumbo frame enable */
77 Fcs = 1<<29, /* in-band fcs enable */
78 Rx = 1<<28, /* rx enable */
79 Vlan = 1<<27, /* vlan frame enable */
80 Hd = 1<<26, /* half-duplex mode (must be 0) */
81 Ltdis = 1<<25, /* length/type field valid check disable */
82
83 /* Tc register. same as Rcw1 but Rx->Tx, Ltdis->Ifg */
84 Tx = Rx, /* tx enable */
85 Ifg = Ltdis, /* inter-frame gap adjustment enable */
86
87 /* Fcc register */
88 Fctx = 1<<30, /* tx flow control enable */
89 Fcrx = 1<<29, /* rx flow control enable */
90
91 /* Emmc register */
92 Linkspeed = 3<<30, /* field */
93 Ls1000 = 2<<30, /* Gb */
94 Ls100 = 1<<30, /* 100Mb */
95 Ls10 = 0<<30, /* 10Mb */
96 Rgmii = 1<<29, /* rgmii mode enable */
97 Sgmii = 1<<28, /* sgmii mode enable */
98 Gpcs = 1<<27, /* 1000base-x mode enable */
99 Hostifen= 1<<26, /* host interface enable */
100 Tx16 = 1<<25, /* tx 16-bit (vs 8-bit) data ifc enable (0) */
101 Rx16 = 1<<24, /* rx 16-bit (vs 8-bit) data ifc enable (0) */
102
103 /* Phyc register. sgmii link speed is Emmc's Linkspeed. */
104 Rgmiills = 3<<2, /* field */
105 Rls1000 = 2<<2, /* Gb */
106 Rls100 = 1<<2, /* 100Mb */
107 Rls10 = 0<<2, /* 10Mb */
108 Rgmiihd = 1<<1, /* half-duplex */
109 Rgmiilink = 1<<0, /* rgmii link (is up) */
110
111 /* Mc register */
112 Mdioen = 1<<6, /* mdio (mii mgmt) enable */
113
114 /* Maw1 register */
115 Rnw = 1<<23, /* multicast addr table reg read (vs write) */
116 Addr = 3<<16, /* field */
117
118 /* Afm register */
119 Pm = 1<<31, /* promiscuous mode */
120
121 /* Tis, Tie register (*rst->*en) */
122 Fabrrst = 1<<0, /* fabric read intr sts (read done) */
123 Miimrst = 1<<1, /* mii mgmt read intr sts (read done) */
124 Miimwst = 1<<2, /* mii mgmt write intr sts (write done) */
125 Afrst = 1<<3, /* addr filter read intr sts (read done) */
126 Afwst = 1<<4, /* addr filter write intr sts (write done) */
127 Cfgrst = 1<<5, /* config read intr sts (read done) */
128 Cfgwst = 1<<6, /* config write intr sts (write done) */
129 };
130
131 enum {
132 /* tunable parameters */
133 Defmbps = 1000, /* default Mb/s */
134 Defls = Ls1000, /* must match Defmbps */
135 };
136
137 enum { /* fifo's registers' bits */
138 /* isr, ier registers (*?e -> *ee) */
139 Rpure = 1<<31, /* rx packet underrun read error */
140 Rpore = 1<<30, /* rx packet overrun read error */
141 Rpue = 1<<29, /* rx packet underrun error */
142 Tpoe = 1<<28, /* tx packet overrun error */
143 FifoTc = 1<<27, /* tx complete */
144 Rc = 1<<26, /* rx complete */
145 Tse = 1<<25, /* tx size error */
146 Trc = 1<<24, /* tx reset complete */
147 Rrc = 1<<23, /* rx reset complete */
148
149 Errors = Rpure | Rpore | Rpue | Tpoe | Tse,
150 };
151 enum { /* fifo constants */
152 Chan0, /* dedicated to input */
153 Chan1, /* dedicated to output */
154
155 Reset = 0xa5, /* magic [tr]dfr & llr value */
156
157 /* dmacr; copied from dma.c */
158 Sinc = 1<<31, /* source increment */
159 Dinc = 1<<30, /* dest increment */
160
161 /* field masks */
162 Bytecnt = (1<<11) - 1,
163 Wordcnt = (1<<9) - 1,
164 };
165
166 typedef struct Temacctlr Temacctlr;
167 typedef struct Temacregs Temacregs;
168 typedef struct Llfiforegs Llfiforegs;
169
170 struct Temacregs {
171 ulong raf; /* reset & addr filter */
172 ulong tpf; /* tx pause frame */
173 ulong ifgp; /* tx inter-frame gap adjustment */
174 ulong is; /* intr status */
175 ulong ip; /* intr pending */
176 ulong ie; /* intr enable */
177 ulong pad[2];
178
179 ulong msw; /* msw data; shared by ifcs */
180 ulong lsw; /* lsw data; shared */
181 ulong ctl; /* control; shared */
182 ulong rdy; /* ready status */
183 ulong pad2[4];
184 };
185 struct Temacctlr { /* software state */
186 Temacregs *regs;
187 Lock;
188 ushort active;
189
190 /* tx state, for Block being sent */
191 int txdma;
192 Block *tbp; /* non-nil if dma to fifo in progress */
193
194 /* rx state, for packet being read */
195 int rxdma;
196 long rlf; /* read from frp->rlf iff non-negative */
197 ulong fifoier;
198 Block *rbp; /* non-nil if dma from fifo in progress */
199 };
200
201 struct Llfiforegs {
202 ulong isr; /* intr status */
203 ulong ier; /* intr enable */
204
205 ulong tdfr; /* tx data fifo reset */
206 ulong tdfv; /* tx data fifo vacancy (words free) */
207 ulong tdfd; /* tx data fifo write port */
208 ulong tlf; /* tx length fifo */
209
210 ulong rdfr; /* rx data fifo reset */
211 ulong rdfo; /* rx data fifo occupancy */
212 ulong rdfd; /* rx data fifo read port */
213 ulong rlf; /* rx length fifo */
214
215 ulong llr; /* locallink reset */
216 };
217
218 typedef struct {
219 ulong bit;
220 char *msg;
221 } Error;
222
223 extern int dmaready; /* flag: ready for general use? */
224 extern uchar mymac[Eaddrlen];
225
226 static Error errs[] = {
227 Rpure, "rx pkt underrun read",
228 Rpore, "rx pkt overrun read",
229 Rpue, "rx pkt underrun",
230 Tpoe, "tx pkt overrun",
231 Tse, "tx size",
232 };
233
234 static Ether *ethers[1]; /* only first ether is connected to a fifo */
235 static Llfiforegs *frp = (Llfiforegs *)Llfifo;
236
237 int fifointr(ulong bit);
238
239 static void fiforeset(Ether *ether);
240 static int dmatxstart(Ether *);
241
242 static void
getready(Temacregs * trp)243 getready(Temacregs *trp)
244 {
245 while ((trp->rdy & Hardacsrdy) == 0)
246 ;
247 }
248
249 static ulong
rdindir(Temacregs * trp,unsigned code)250 rdindir(Temacregs *trp, unsigned code)
251 {
252 ulong val;
253
254 getready(trp);
255 trp->ctl = code;
256 barriers();
257
258 getready(trp);
259 val = trp->lsw;
260 return val;
261 }
262
263 static int
wrindir(Temacregs * trp,unsigned code,ulong val)264 wrindir(Temacregs *trp, unsigned code, ulong val)
265 {
266 getready(trp);
267 trp->lsw = val;
268 barriers();
269 trp->ctl = Wen | code;
270 barriers();
271
272 getready(trp);
273 return 0;
274 }
275
276 /*
277 * we're only interested in temac errors; completion interrupts come
278 * from the fifo.
279 */
280 static int
temacintr(ulong bit)281 temacintr(ulong bit)
282 {
283 int e, forme, sts;
284 Ether *ether;
285 Temacctlr *ctlr;
286 Temacregs *trp;
287
288 forme = 0;
289 for (e = 0; e < nelem(ethers); e++) {
290 ether = ethers[e];
291 if (ether == nil)
292 continue;
293 ether->interrupts++;
294 ctlr = ether->ctlr;
295 trp = ctlr->regs;
296 while ((sts = trp->is) & (Autoneg | Rxfifoovr)) {
297 forme = 1;
298 if (sts & Rxfifoovr) {
299 iprint("temac: receive fifo overrun. ");
300 whackether(ether);
301 }
302 if (sts & Autoneg) {
303 iprint("temac: autoneg done\n");
304 trp->is = Autoneg; /* extinguish intr source */
305 barriers();
306 }
307 }
308 }
309 if (forme)
310 intrack(bit);
311 return forme;
312 }
313
314 static void
resetsw(Ether * ether)315 resetsw(Ether *ether) /* reset software state */
316 {
317 Temacctlr *ctlr;
318
319 ctlr = ether->ctlr;
320
321 delay(20); /* let any dma in progress complete */
322 ctlr->active = ctlr->txdma = ctlr->rxdma = 0;
323 ctlr->rlf = -1;
324 ctlr->rbp = ctlr->tbp = nil;
325 barriers();
326 }
327
328 static void
reset(Ether * ether)329 reset(Ether *ether)
330 {
331 Temacctlr *ctlr;
332 Temacregs *trp;
333
334 ctlr = ether->ctlr;
335 trp = ctlr->regs;
336 assert(trp);
337
338 trp->raf = Htrst; /* resets both ether interfaces */
339 barriers();
340 while (trp->raf & Htrst)
341 ;
342
343 fiforeset(ether);
344 barriers();
345
346 resetsw(ether);
347 }
348
349 static void
attach(Ether *)350 attach(Ether *)
351 {
352 }
353
354 static void
closed(Ether * ether)355 closed(Ether *ether)
356 {
357 Temacctlr *ctlr;
358
359 ctlr = ether->ctlr;
360 if(ctlr->active){
361 reset(ether);
362 ctlr->active = 0;
363 }
364 }
365
366 static void
temacshutdown(Ether * ether)367 temacshutdown(Ether* ether)
368 {
369 reset(ether); /* stop dma at the very least */
370 }
371
372 static int promon, multion;
373
374 static void
promiscuous(void * arg,int on)375 promiscuous(void* arg, int on)
376 {
377 Ether *ether;
378 Temacctlr *ctlr;
379
380 ether = (Ether*)arg;
381 ctlr = ether->ctlr;
382 ilock(ctlr);
383 promon = on;
384 if(on) {
385 ether->promisc = 1;
386 wrindir(ctlr->regs, Afm, Pm);
387 } else if (!multion) {
388 ether->promisc = 0;
389 wrindir(ctlr->regs, Afm, 0);
390 }
391 iunlock(ctlr);
392 }
393
394 static void
multicast(void * arg,uchar * addr,int on)395 multicast(void* arg, uchar *addr, int on)
396 {
397 Ether *ether;
398 Temacctlr *ctlr;
399
400 ether = (Ether*)arg;
401 ctlr = ether->ctlr;
402 multion = on;
403 ilock(ctlr);
404 /*
405 * could do better: set Maw[01] & Rnw since ipv6 needs multicast;
406 * see netmulti() in netif.c.
407 */
408 USED(addr);
409 if(on) {
410 ether->promisc = 1;
411 wrindir(ctlr->regs, Afm, Pm); /* overkill */
412 } else if (!promon) {
413 ether->promisc = 0;
414 wrindir(ctlr->regs, Afm, 0);
415 }
416 iunlock(ctlr);
417 }
418
419 /*
420 * start next dma into tx fifo, if there's a pkt in the output queue,
421 * room in the tx fifo, and the dma channel is idle.
422 *
423 * called for each new packet, but okay to send
424 * any and all packets in output queue.
425 */
426 void
temactransmit(Ether * ether)427 temactransmit(Ether *ether)
428 {
429 Temacctlr *ctlr;
430
431 ctlr = ether->ctlr;
432 ilock(ctlr);
433 dmatxstart(ether);
434 iunlock(ctlr);
435 }
436
437 /*
438 * allocate receive buffer space on cache-line boundaries
439 */
440 Block*
clallocb(void)441 clallocb(void)
442 {
443 Block *bp;
444
445 /* round up for sake of word-at-a-time dma */
446 bp = iallocb(ROUNDUP(ETHERMAXTU, BY2WD) + DCACHELINESZ-1);
447 if(bp == nil)
448 return bp;
449 dcflush(PTR2UINT(bp->base), BALLOC(bp));
450 bp->wp = bp->rp = (uchar*)
451 ((PTR2UINT(bp->base) + DCACHELINESZ - 1) & ~(DCACHELINESZ-1));
452 return bp;
453 }
454
455 static long
ifstat(Ether * ether,void * a,long n,ulong offset)456 ifstat(Ether* ether, void* a, long n, ulong offset)
457 {
458 char *p;
459 int len;
460
461 if(n == 0)
462 return 0;
463
464 p = malloc(READSTR);
465
466 len = snprint(p, READSTR, "interrupts: %lud\n", ether->interrupts);
467 len += snprint(p+len, READSTR-len, "dma rx intrs: %lud\n",
468 ether->dmarxintr);
469 len += snprint(p+len, READSTR-len, "dma tx intrs: %lud\n",
470 ether->dmatxintr);
471 len += snprint(p+len, READSTR-len, "broadcasts rcvd: %lud\n",
472 ether->bcasts);
473 len += snprint(p+len, READSTR-len, "multicasts rcvd: %lud\n",
474 ether->mcasts);
475 len += snprint(p+len, READSTR-len, "promiscuous: %lud\n",
476 ether->promisc);
477 len += snprint(p+len, READSTR-len, "dropped pkts: %lud\n",
478 ether->pktsdropped);
479 len += snprint(p+len, READSTR-len, "resets: %lud\n", ether->resets);
480 snprint(p+len, READSTR-len, "misaligned buffers: %lud\n",
481 ether->pktsmisaligned);
482
483 n = readstr(offset, a, n, p);
484 free(p);
485
486 return n;
487 }
488
489 static void
init(Ether * ether)490 init(Ether *ether)
491 {
492 int i;
493 ulong ealo, eahi;
494 uvlong ea;
495 Temacctlr *ctlr;
496 Temacregs *trp;
497 static uchar pausemac[Eaddrlen] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x01 };
498
499 trp = (Temacregs *)Temac + ether->ctlrno;
500 ctlr = ether->ctlr;
501
502 wrindir(trp, Mc, Mdioen | 29); /* 29 is divisor; see p.47 of ds537 */
503 delay(100); /* guess */
504
505 /*
506 * mac addr is stored little-endian in longs in Uaw[01].
507 * default address is rubbish.
508 */
509 memmove(ether->ea, mymac, Eaddrlen);
510 ea = 0;
511 for (i = 0; i < Eaddrlen; i++)
512 ea |= (uvlong)mymac[i] << (i * 8);
513 wrindir(trp, Uaw0, (ulong)ea);
514 wrindir(trp, Uaw1, (ulong)(ea >> 32));
515 ealo = rdindir(trp, Uaw0);
516 eahi = rdindir(trp, Uaw1) & 0xffff;
517 if (ealo != (ulong)ea || eahi != (ulong)(ea >> 32))
518 panic("temac mac address wouldn't set, got %lux %lux",
519 eahi, ealo);
520
521 /*
522 * admit broadcast packets too
523 */
524 wrindir(trp, Maw0, ~0ul);
525 wrindir(trp, Maw1, 0xffff); /* write to mat reg 0 */
526
527 wrindir(trp, Afm, 0); /* not promiscuous */
528 wrindir(trp, Tc, Tx);
529 ether->promisc = 0;
530
531 if (0) {
532 ea = 0;
533 for (i = 0; i < Eaddrlen; i++)
534 ea |= (uvlong)pausemac[i] << (i * 8);
535 wrindir(trp, Rcw0, (ulong)ea);
536 wrindir(trp, Rcw1, (ulong)(ea >> 32) | Rx);
537 wrindir(trp, Fcc, Fcrx); /* honour pause frames sent to us */
538 } else
539 wrindir(trp, Fcc, 0); /* no flow control */
540
541 wrindir(trp, Emmc, Defls);
542
543 ctlr->active = 1;
544 barriers();
545
546 intrenable(Inttemac, temacintr, "lltemac");
547 trp->ie = Autoneg | Rxfifoovr;
548 barriers();
549
550 fifoinit(ether);
551 }
552
553 int
temacreset(Ether * ether)554 temacreset(Ether* ether)
555 {
556 Temacctlr *ctlr;
557 Temacregs *trp;
558
559 if ((unsigned)ether->ctlrno >= nelem(ethers) || ethers[ether->ctlrno])
560 return -1; /* already probed & found */
561 trp = (Temacregs *)Temac + ether->ctlrno;
562
563 /* too early to probe on virtex 4 at least; up must be set first */
564 // if (probeaddr((uintptr)trp) < 0)
565 // return -1;
566
567 ethers[ether->ctlrno] = ether;
568 ether->ctlr = ctlr = malloc(sizeof *ctlr);
569 ctlr->regs = trp;
570 ether->port = (uintptr)trp;
571 trp->ie = 0;
572 barriers();
573 ether->interrupts = 0; /* should be redundant */
574
575 /* we can't tell, so assert what we hope for */
576 ether->mbps = Defmbps;
577 ether->fullduplex = ether->link = 1;
578
579 /*
580 * whatever loaded this kernel (9load or another kernel)
581 * must have configured the ethernet in order to use it to load
582 * this kernel. so try not to reset the hardware, which could
583 * force a seconds-long link negotiation.
584 */
585 reset(ether);
586 // resetsw(ether);
587 init(ether);
588 /*
589 * Linkage to the generic ethernet driver.
590 */
591 ether->attach = attach;
592 ether->closed = closed;
593 ether->shutdown = temacshutdown;
594 ether->transmit = temactransmit;
595 ether->interrupt = temacintr;
596 ether->ifstat = ifstat;
597
598 ether->arg = ether;
599 ether->promiscuous = promiscuous;
600 ether->multicast = multicast;
601 return 0;
602 }
603
604 void
etherlltemaclink(void)605 etherlltemaclink(void)
606 {
607 addethercard("lltemac", temacreset);
608 }
609
610 /*
611 * Xilinx Local Link FIFOs for Temac, in pairs (rx and tx).
612 */
613
614 /*
615 * as of dma controller v2, keyhole operations are on ulongs,
616 * but otherwise it's as if memmove were used.
617 * addresses need not be word-aligned, though registers are.
618 */
619 static void
fifocpy(void * vdest,void * vsrc,uint bytes,ulong flags)620 fifocpy(void *vdest, void *vsrc, uint bytes, ulong flags)
621 {
622 int words;
623 ulong *dest, *src;
624 uchar buf[ETHERMAXTU + 2*BY2WD];
625
626 dest = vdest;
627 src = vsrc;
628 words = bytes / BY2WD;
629 if (bytes % BY2WD != 0)
630 words++;
631
632 switch (flags & (Sinc | Dinc)) {
633 case Sinc | Dinc:
634 memmove(vdest, vsrc, bytes);
635 break;
636 case Sinc: /* mem to register */
637 memmove(buf, vsrc, bytes); /* ensure src alignment */
638 src = (ulong *)buf;
639 while (words-- > 0)
640 *dest = *src++;
641 break;
642 case Dinc: /* register to mem */
643 dest = (ulong *)buf;
644 while (words-- > 0)
645 *dest++ = *src;
646 memmove(vdest, buf, bytes); /* ensure dest alignment */
647 break;
648 case 0: /* register-to-null or vice versa */
649 while (words-- > 0)
650 *dest = *src;
651 break;
652 }
653 }
654
655 /* returns true iff we whacked the ether */
656 static int
whackiferr(Ether * ether,int whack,int sts)657 whackiferr(Ether *ether, int whack, int sts)
658 {
659 Error *ep;
660
661 /*
662 * these require a reset of the receive logic: Rpure, Rpore, Rpue.
663 * same for transmit logic: Tpoe, Tse.
664 */
665 if (whack || sts & Errors) {
666 iprint("fifo: errors:");
667 for (ep = errs; ep < errs + nelem(errs); ep++)
668 if (sts & ep->bit)
669 iprint(" %s;", ep->msg);
670 iprint("\n");
671 whackether(ether);
672 return 1;
673 }
674 return 0;
675 }
676
677 static int dmarecv(Ether *);
678
679 static void
fifointrset(Temacctlr * ctlr)680 fifointrset(Temacctlr *ctlr)
681 {
682 frp->ier = ctlr->fifoier;
683 barriers();
684 }
685
686 static void
enafifointr(Temacctlr * ctlr,int bits)687 enafifointr(Temacctlr *ctlr, int bits)
688 {
689 ctlr->fifoier |= bits;
690 fifointrset(ctlr);
691 }
692
693 static void
disfifointr(Temacctlr * ctlr,int bits)694 disfifointr(Temacctlr *ctlr, int bits)
695 {
696 ctlr->fifoier &= ~bits;
697 fifointrset(ctlr);
698 }
699
700 static long
getrdfo(void)701 getrdfo(void)
702 {
703 ulong rdfo;
704
705 rdfo = frp->rdfo;
706 if (rdfo & ~Wordcnt) {
707 iprint("fifo: impossible rdfo value\n");
708 return -1;
709 }
710 return rdfo;
711 }
712
713 static void
dmarxdone(int)714 dmarxdone(int)
715 {
716 int whack, multi;
717 long rdfo;
718 Block *bp;
719 Ether *ether;
720 Etherpkt *pkt;
721 Temacctlr *ctlr;
722
723 ether = ethers[0];
724 ctlr = ether->ctlr;
725
726 ilock(ctlr);
727 ether->dmarxintr++;
728 bp = ctlr->rbp;
729 ctlr->rbp = nil; /* prevent accidents */
730 if (ctlr->rxdma == 0 || bp == nil) {
731 if (bp != nil)
732 freeb(bp);
733 if (ctlr->rxdma == 0)
734 iprint("dmarxdone: no rx dma in progress\n");
735 else
736 iprint("dmarxdone: no block for rx dma just finished!\n");
737 lightbitoff(Ledethinwait);
738 enafifointr(ctlr, Rc);
739 iunlock(ctlr);
740 return;
741 }
742 ctlr->rxdma = 0;
743 barriers();
744
745 /*
746 * rx Step 2: packet is in Block, pass it upstream.
747 */
748 /* could check for dma errors */
749 pkt = (Etherpkt*)bp->rp;
750 assert(pkt != nil);
751 multi = pkt->d[0] & 1;
752 if (multi)
753 if(memcmp(pkt->d, ether->bcast, sizeof pkt->d) == 0)
754 ether->bcasts++;
755 else
756 ether->mcasts++;
757
758 etheriq(ether, bp, 1);
759 lightbitoff(Ledethinwait);
760
761 /*
762 * rx Step 3/0: if there's another packet in the rx fifo,
763 * start dma into a new Block, else reenable recv intrs.
764 */
765 whack = 0;
766 rdfo = getrdfo();
767 if (rdfo < 0)
768 whack = 1; /* ether is buggered */
769 else if (rdfo > 0) /* more packets in rx fifo? */
770 whack = dmarecv(ether); /* if dma starts, disables Rc */
771 else {
772 if (frp->isr & Rc)
773 wave('|'); /* isr Rc was set when fifo was empty */
774 enafifointr(ctlr, Rc);
775 }
776 /* if this whacks the ctlr, all the intr enable bits will be set */
777 whackiferr(ether, whack, frp->isr);
778 iunlock(ctlr);
779 }
780
781 static void
discard(Ether * ether,unsigned ruplen)782 discard(Ether *ether, unsigned ruplen)
783 {
784 ulong null;
785
786 /* discard the rx fifo's packet */
787 fifocpy(&null, &frp->rdfd, ruplen, 0);
788 ether->pktsdropped++;
789 }
790
791 /*
792 * called when interrupt cause Rc is set (the rx fifo has at least one packet)
793 * to begin dma to memory of the next packet in the input fifo.
794 *
795 * returns true iff the ether ctlr needs to be whacked.
796 * may be called from interrupt routine; must be called with
797 * interrupts masked.
798 */
799 static int
dmarecv(Ether * ether)800 dmarecv(Ether *ether)
801 {
802 long rdfo;
803 ulong len, ruplen;
804 Block *bp;
805 Temacctlr *ctlr;
806
807 ctlr = ether->ctlr;
808 if (ctlr->rxdma)
809 return 0; /* next rx dma interrupt should process this packet*/
810
811 /* ignore frp->isr & Rc; just look at rx fifo occupancy */
812 rdfo = getrdfo();
813 if (rdfo < 0) {
814 iprint("dmarecv: negative rdfo\n");
815 return 1; /* ether is buggered */
816 }
817 if (rdfo == 0)
818 return 0; /* no packets in the rx fifo */
819
820 if (!(frp->isr & Rc))
821 wave('@'); /* isr Rc wasn't set when fifo had stuff in it */
822
823 /*
824 * We have at least one packet in the rx fifo. Read the length
825 * of the first one, if not already known.
826 */
827 if (ctlr->rlf >= 0)
828 len = ctlr->rlf; /* from a previous call */
829 else {
830 assert(frp != nil);
831 /* read length word from rx fifo */
832 len = frp->rlf;
833 if (len & ~Bytecnt) {
834 iprint("fifo: impossible rlf value\n");
835 return 1;
836 }
837 if (len == 0) {
838 iprint("fifo: rdfo %lud > 0 but rlf == 0\n", rdfo);
839 return 1;
840 }
841 ctlr->rlf = len; /* save in case dma is busy below */
842 }
843
844 ruplen = ROUNDUP(len, BY2WD);
845 if (len > ETHERMAXTU) {
846 iprint("fifo: jumbo pkt tossed\n");
847 discard(ether, ruplen);
848 return 0;
849 }
850
851 if (!dmaready) /* too early, dma not really set up */
852 return 0;
853 bp = clallocb();
854 if(bp == nil){
855 iprint("fifo: no buffer for input pkt\n");
856 discard(ether, ruplen);
857 ether->soverflows++;
858 return 0;
859 }
860
861 /*
862 * rx Step 1: dma from rx fifo into Block, turn off recv interrupts.
863 * wait for dmarxdone (interrupt) to pass the Block upstream.
864 */
865 if (!dmastart(Chan0, bp->rp, &frp->rdfd, ruplen, Dinc, dmarxdone)) {
866 /* should never get here */
867 iprint("dmarecv: dmastart failed for Chan0\n");
868 freeb(bp);
869 enafifointr(ctlr, Rc);
870 /* we'll try again next time we're called */
871 return 0;
872 }
873 ctlr->rlf = -1; /* we're committed now */
874 lightbiton(Ledethinwait);
875 bp->wp = bp->rp + len;
876 assert(ctlr->rbp == nil);
877 ctlr->rbp = bp;
878 ctlr->rxdma = 1;
879 barriers();
880 /*
881 * we're waiting for dma and can't start dma of another
882 * incoming packet until the current dma is finished.
883 */
884 disfifointr(ctlr, Rc);
885 return 0;
886 }
887
888 void
whackether(Ether * ether)889 whackether(Ether *ether)
890 {
891 int s = splhi();
892
893 iprint("resetting fifo+temac...");
894 reset(ether);
895 init(ether);
896 iprint("\n");
897 ether->resets++;
898 splx(s);
899 }
900
901 /*
902 * we've had trouble transmitting 60-byte packets and
903 * 77-byte packets, so round up the length to make it even
904 * and enforce a minimum of 64 bytes (ETHERMINTU+4).
905 * rounding to a multiple of 4 (rather than 2) will make 1514
906 * into 1516, which is a jumbo packet, so take care.
907 * it's a bit sleazy, but this will just pick up a few junk
908 * bytes beyond the packet for padding.
909 */
910 static uint
padpktlen(uint len)911 padpktlen(uint len)
912 {
913 len = ROUNDUP(len, BY2WD);
914 if (len > ethermedium.maxtu)
915 len = ethermedium.maxtu;
916 return len;
917 }
918
919 int
fifointr(ulong bit)920 fifointr(ulong bit)
921 {
922 int r, whack, ic;
923 ulong sts;
924 Ether *ether;
925
926 ether = ethers[0];
927 if (ether == nil)
928 return 0; /* not for me */
929 ether->interrupts++;
930 r = 0;
931 while ((sts = frp->isr) != 0) {
932 ic = sts & (Rc | FifoTc); /* interrupt causes */
933 r |= ic;
934 whack = 0;
935 if (sts & Rc)
936 whack = dmarecv(ether);
937 else
938 if (getrdfo() != 0)
939 wave('~'); /* isr Rc off, yet fifo !empty */
940 if (sts & FifoTc) {
941 /*
942 * not much to do, really. turn out the light and
943 * attempt another dma transfer anyway.
944 */
945 lightbitoff(Ledethoutwait);
946 temactransmit(ether);
947 }
948 frp->isr = ic; /* extinguish intr sources */
949 barriers();
950 sts &= ~ic;
951 if (sts)
952 iprint("fifointr: sts %#lux\n", sts);
953 r |= whackiferr(ether, whack, sts);
954 }
955 if (r) {
956 intrack(bit);
957 return 1;
958 }
959 return 0;
960 }
961
962 static void
fiforeset(Ether * ether)963 fiforeset(Ether *ether)
964 {
965 Temacctlr *ctlr;
966
967 barriers();
968 dma0init(); /* could be dma in progress, so shut that down */
969
970 ctlr = ether->ctlr;
971 ctlr->fifoier = 0;
972 fifointrset(ctlr);
973
974 /* should put a timeout on this and do a hard reset if it fails */
975 frp->tdfr = Reset; /* try it the graceful way first */
976 frp->rdfr = Reset;
977 barriers();
978 while ((frp->isr & (Trc | Rrc)) != (Trc | Rrc))
979 ;
980 frp->isr = Trc | Rrc; /* reset the `reset done' bits */
981 barriers();
982
983 if (0) {
984 frp->llr = Reset;
985 barriers();
986 while ((frp->isr & (Trc | Rrc)) != (Trc | Rrc))
987 ;
988 }
989 }
990
991 void
fifoinit(Ether * ether)992 fifoinit(Ether *ether)
993 {
994 if (ethers[0] != nil)
995 assert(ethers[0] == ether);
996 // fiforeset(ether);
997 frp->isr = frp->isr; /* extinguish intr source */
998 barriers();
999
1000 intrenable(Intllfifo, fifointr, "fifo");
1001 barriers();
1002 enafifointr(ether->ctlr, Rc | FifoTc | Rpure | Rpore | Rpue | Tpoe | Tse);
1003 }
1004
1005 static void
tmoutreset(ulong bit)1006 tmoutreset(ulong bit)
1007 {
1008 USED(bit);
1009 whackether(ethers[0]);
1010 }
1011
1012 /*
1013 * tx Step 2: write frp->tlr, thus initiating ethernet transmission of
1014 * the Block just copied into the tx fifo, and free that Block.
1015 */
1016 static void
dmatxdone(int)1017 dmatxdone(int)
1018 {
1019 Block *bp;
1020 Ether *ether;
1021 Temacctlr *ctlr;
1022
1023 ether = ethers[0];
1024 ctlr = ether->ctlr;
1025
1026 ilock(ctlr);
1027 ether->dmatxintr++;
1028 ctlr->txdma = 0;
1029
1030 /*
1031 * start transmitting this packet from the output fifo.
1032 * contrary to DS568 Table 5's description of TSE, it seems
1033 * to be legal to write an odd value into tlf (unless the word
1034 * `match' implies ±1), but it may be necessary to provide a
1035 * padding byte in the fifo if you do.
1036 */
1037 bp = ctlr->tbp;
1038 if (bp != nil) {
1039 ctlr->tbp = nil;
1040 frp->tlf = padpktlen(BLEN(bp));
1041 barriers();
1042 freeb(bp);
1043 ether->tbusy = 0;
1044 }
1045
1046 dmatxstart(ether); /* attempt another dma to tx fifo */
1047 iunlock(ctlr);
1048 }
1049
1050 /*
1051 * if possible, start dma of the first packet of the output queue into
1052 * the tx fifo.
1053 *
1054 * must be called with ether->ctlr ilocked,
1055 * thus we cannot sleep nor qlock.
1056 *
1057 * output buffers are always misaligned, but that doesn't matter
1058 * as of v2 of the dma controller.
1059 */
1060 static int
dmatxstart(Ether * ether)1061 dmatxstart(Ether *ether)
1062 {
1063 unsigned len, ruplen;
1064 Block *bp;
1065 Temacctlr *ctlr;
1066
1067 if (ether == nil || ether->oq == nil || ether->tbusy)
1068 return 0;
1069 ctlr = ether->ctlr;
1070 if (ctlr->txdma)
1071 return 0;
1072 SET(len);
1073 while ((bp = qget(ether->oq)) != nil) {
1074 len = padpktlen(BLEN(bp));
1075 if (len > ETHERMAXTU) {
1076 iprint("fifo: dropping outgoing jumbo (%ud) pkt\n",
1077 len);
1078 freeb(bp);
1079 } else
1080 break;
1081 }
1082 if (bp == nil)
1083 return 0;
1084 if (!dmaready) { /* too early? */
1085 iprint("dmatxstart: dma not ready\n");
1086 freeb(bp);
1087 disfifointr(ctlr, FifoTc);
1088 return 0;
1089 }
1090
1091 if (len == 0)
1092 print("idiot sending zero-byte packet\n");
1093 ruplen = ROUNDUP(len, BY2WD); /* must be multiple of 4 for dma */
1094
1095 /*
1096 * if there isn't enough room in the fifo for this
1097 * packet, return and assume that the next transmit
1098 * interrupt will resume transmission of it.
1099 */
1100 if ((frp->tdfv & Wordcnt) < ruplen / BY2WD) {
1101 iprint("dmatxstart: no room in tx fifo\n");
1102 return 0;
1103 }
1104
1105 /* tx Step 1: dma to tx fifo, wait for dma tx interrupt */
1106 lightbiton(Ledethoutwait);
1107 if (dmastart(Chan1, &frp->tdfd, bp->rp, ruplen, Sinc, dmatxdone)) {
1108 ether->tbusy = 1;
1109 ctlr->txdma = 1;
1110 barriers();
1111 /* Rc may be off if we got Rc intrs too early */
1112 // enafifointr(ctlr, FifoTc | Rc);
1113 ctlr->tbp = bp; /* remember this block */
1114 } else
1115 iprint("dmatxstart: dmastart failed for Chan1\n");
1116 return 1;
1117 }
1118