xref: /plan9-contrib/sys/src/boot/vt4/llfifo.c (revision da917039c7f233c1a27d212bf012c6afa758af39)
1*da917039SDavid du Colombier /*
2*da917039SDavid du Colombier  * Xilinx Local Link FIFOs for Temac, in pairs (rx and tx).
3*da917039SDavid du Colombier  */
4*da917039SDavid du Colombier #include "include.h"
5*da917039SDavid du Colombier 
6*da917039SDavid du Colombier enum {
7*da917039SDavid du Colombier 	Reset	= 0xa5,		/* magic [tr]dfr & llr value */
8*da917039SDavid du Colombier 
9*da917039SDavid du Colombier 	/* dmacr; copied from dma.c */
10*da917039SDavid du Colombier 	Sinc	= 1<<31,	/* source increment */
11*da917039SDavid du Colombier 	Dinc	= 1<<30,	/* dest increment */
12*da917039SDavid du Colombier 
13*da917039SDavid du Colombier 	/* field masks */
14*da917039SDavid du Colombier 
15*da917039SDavid du Colombier 	Bytecnt	= (1<<11) - 1,
16*da917039SDavid du Colombier 	Wordcnt	= (1<<9) - 1,
17*da917039SDavid du Colombier };
18*da917039SDavid du Colombier 
19*da917039SDavid du Colombier enum {				/* register's bits */
20*da917039SDavid du Colombier 	/* isr, ier registers (*?e->*ee) */
21*da917039SDavid du Colombier 	Rpure	= 1<<31,	/* rx packet underrun read error */
22*da917039SDavid du Colombier 	Rpore	= 1<<30,	/* rx packet overrun read error */
23*da917039SDavid du Colombier 	Rpue	= 1<<29,	/* rx packet underrun error */
24*da917039SDavid du Colombier 	Tpoe	= 1<<28,	/* tx packet overrun error */
25*da917039SDavid du Colombier 	Tc	= 1<<27,	/* tx complete */
26*da917039SDavid du Colombier 	Rc	= 1<<26,	/* rx complete */
27*da917039SDavid du Colombier 	Tse	= 1<<25,	/* tx size error */
28*da917039SDavid du Colombier 	Trc	= 1<<24,	/* tx reset complete */
29*da917039SDavid du Colombier 	Rrc	= 1<<23,	/* rx reset complete */
30*da917039SDavid du Colombier };
31*da917039SDavid du Colombier 
32*da917039SDavid du Colombier typedef struct Llfiforegs Llfiforegs;
33*da917039SDavid du Colombier typedef struct Llfifosw Llfifosw;
34*da917039SDavid du Colombier 
35*da917039SDavid du Colombier struct Llfiforegs {
36*da917039SDavid du Colombier 	ulong	isr;		/* intr status */
37*da917039SDavid du Colombier 	ulong	ier;		/* intr enable */
38*da917039SDavid du Colombier 
39*da917039SDavid du Colombier 	ulong	tdfr;		/* tx data fifo reset */
40*da917039SDavid du Colombier 	ulong	tdfv;		/* tx data fifo vacancy (words free) */
41*da917039SDavid du Colombier 	ulong	tdfd;		/* tx data fifo write port */
42*da917039SDavid du Colombier 	ulong	tlf;		/* tx length fifo */
43*da917039SDavid du Colombier 
44*da917039SDavid du Colombier 	ulong	rdfr;		/* rx data fifo reset */
45*da917039SDavid du Colombier 	ulong	rdfo;		/* rx data fifo occupancy */
46*da917039SDavid du Colombier 	ulong	rdfd;		/* rx data fifo read port */
47*da917039SDavid du Colombier 	ulong	rlf;		/* tx length fifo */
48*da917039SDavid du Colombier 
49*da917039SDavid du Colombier 	ulong	llr;		/* locallink reset */
50*da917039SDavid du Colombier };
51*da917039SDavid du Colombier struct Llfifosw {
52*da917039SDavid du Colombier 	Llfiforegs *regs;
53*da917039SDavid du Colombier };
54*da917039SDavid du Colombier 
55*da917039SDavid du Colombier static Llfiforegs *frp = (Llfiforegs *)Llfifo;
56*da917039SDavid du Colombier static Ether *llether;
57*da917039SDavid du Colombier 
58*da917039SDavid du Colombier /*
59*da917039SDavid du Colombier  * as of dma controller v2, keyhole operations are on ulongs,
60*da917039SDavid du Colombier  * but otherwise it's as if memmove were used.
61*da917039SDavid du Colombier  * addresses need not be word-aligned, though registers are.
62*da917039SDavid du Colombier  */
63*da917039SDavid du Colombier static void
fifocpy(void * vdest,void * vsrc,uint bytes,ulong flags)64*da917039SDavid du Colombier fifocpy(void *vdest, void *vsrc, uint bytes, ulong flags)
65*da917039SDavid du Colombier {
66*da917039SDavid du Colombier 	int words;
67*da917039SDavid du Colombier 	ulong *dest, *dstbuf, *src;
68*da917039SDavid du Colombier 	/* +2*BY2WD is slop for alignment */
69*da917039SDavid du Colombier 	static uchar buf[ETHERMAXTU+8+2*BY2WD];
70*da917039SDavid du Colombier 
71*da917039SDavid du Colombier 	dest = vdest;
72*da917039SDavid du Colombier 	src = vsrc;
73*da917039SDavid du Colombier 	assert(bytes <= sizeof buf);
74*da917039SDavid du Colombier 	words = bytes / BY2WD;
75*da917039SDavid du Colombier 	if (bytes % BY2WD != 0)
76*da917039SDavid du Colombier 		words++;
77*da917039SDavid du Colombier 
78*da917039SDavid du Colombier 	switch (flags & (Sinc | Dinc)) {
79*da917039SDavid du Colombier 	case Sinc | Dinc:
80*da917039SDavid du Colombier 		memmove(vdest, vsrc, bytes);
81*da917039SDavid du Colombier 		break;
82*da917039SDavid du Colombier 	case Sinc:				/* mem to register */
83*da917039SDavid du Colombier 		src = (ulong *)ROUNDUP((uvlong)buf, BY2WD);
84*da917039SDavid du Colombier 		memmove(src, vsrc, bytes);	/* ensure src alignment */
85*da917039SDavid du Colombier 		assert((uintptr)src  % BY2WD == 0);
86*da917039SDavid du Colombier 		assert((uintptr)dest % BY2WD == 0);
87*da917039SDavid du Colombier 		while (words-- > 0)
88*da917039SDavid du Colombier 			*dest = *src++;
89*da917039SDavid du Colombier 		break;
90*da917039SDavid du Colombier 	case Dinc:				/* register to mem */
91*da917039SDavid du Colombier 		dest = dstbuf = (ulong *)ROUNDUP((uvlong)buf, BY2WD);
92*da917039SDavid du Colombier 		assert((uintptr)src  % BY2WD == 0);
93*da917039SDavid du Colombier 		assert((uintptr)dest % BY2WD == 0);
94*da917039SDavid du Colombier 		while (words-- > 0)
95*da917039SDavid du Colombier 			*dest++ = *src;
96*da917039SDavid du Colombier 		memmove(vdest, dstbuf, bytes);	/* ensure dest alignment */
97*da917039SDavid du Colombier 		break;
98*da917039SDavid du Colombier 	case 0:				/* register-to-null or vice versa */
99*da917039SDavid du Colombier 		while (words-- > 0)
100*da917039SDavid du Colombier 			*dest = *src;
101*da917039SDavid du Colombier 		break;
102*da917039SDavid du Colombier 	}
103*da917039SDavid du Colombier }
104*da917039SDavid du Colombier 
105*da917039SDavid du Colombier static void
discardinpkt(int len)106*da917039SDavid du Colombier discardinpkt(int len)		/* discard the rx fifo's packet */
107*da917039SDavid du Colombier {
108*da917039SDavid du Colombier 	ulong null;
109*da917039SDavid du Colombier 
110*da917039SDavid du Colombier 	fifocpy(&null, &frp->rdfd, len, 0);
111*da917039SDavid du Colombier 	coherence();
112*da917039SDavid du Colombier }
113*da917039SDavid du Colombier 
114*da917039SDavid du Colombier int
llfifointr(ulong bit)115*da917039SDavid du Colombier llfifointr(ulong bit)
116*da917039SDavid du Colombier {
117*da917039SDavid du Colombier 	ulong len, sts;
118*da917039SDavid du Colombier 	Ether *ether;
119*da917039SDavid du Colombier 	RingBuf *rb;
120*da917039SDavid du Colombier 	static uchar zaddrs[Eaddrlen * 2];
121*da917039SDavid du Colombier 
122*da917039SDavid du Colombier 	sts = frp->isr;
123*da917039SDavid du Colombier 	if (sts == 0)
124*da917039SDavid du Colombier 		return 0;			/* not for me */
125*da917039SDavid du Colombier 	ether = llether;
126*da917039SDavid du Colombier 	/* it's important to drain all packets in the rx fifo */
127*da917039SDavid du Colombier 	while ((frp->rdfo & Wordcnt) != 0) {
128*da917039SDavid du Colombier 		assert((frp->rdfo & ~Wordcnt) == 0);
129*da917039SDavid du Colombier 		len = frp->rlf & Bytecnt;	/* read rlf from fifo */
130*da917039SDavid du Colombier 		assert((len & ~Bytecnt) == 0);
131*da917039SDavid du Colombier 		assert(len > 0 && len <= ETHERMAXTU);
132*da917039SDavid du Colombier 		rb = &ether->rb[ether->ri];
133*da917039SDavid du Colombier 		if (rb->owner == Interface) {
134*da917039SDavid du Colombier 			/* from rx fifo into ring buffer */
135*da917039SDavid du Colombier 			fifocpy(rb->pkt, &frp->rdfd, len, Dinc);
136*da917039SDavid du Colombier 			if (memcmp(rb->pkt, zaddrs, sizeof zaddrs) == 0) {
137*da917039SDavid du Colombier 				iprint("ether header with all-zero mac "
138*da917039SDavid du Colombier 					"addresses\n");
139*da917039SDavid du Colombier 				continue;
140*da917039SDavid du Colombier 			}
141*da917039SDavid du Colombier 			rb->len = len;
142*da917039SDavid du Colombier 			rb->owner = Host;
143*da917039SDavid du Colombier 			coherence();
144*da917039SDavid du Colombier 			ether->ri = NEXT(ether->ri, ether->nrb);
145*da917039SDavid du Colombier 			coherence();
146*da917039SDavid du Colombier 		} else {
147*da917039SDavid du Colombier 			discardinpkt(len);
148*da917039SDavid du Colombier 			/* not too informative during booting */
149*da917039SDavid du Colombier 			iprint("llfifo: no buffer for input pkt\n");
150*da917039SDavid du Colombier 		}
151*da917039SDavid du Colombier 	}
152*da917039SDavid du Colombier 
153*da917039SDavid du Colombier 	if (sts & Tc)
154*da917039SDavid du Colombier 		ether->tbusy = 0;
155*da917039SDavid du Colombier 	ether->transmit(ether);
156*da917039SDavid du Colombier 
157*da917039SDavid du Colombier 	frp->isr = sts;			/* extinguish intr source */
158*da917039SDavid du Colombier 	coherence();
159*da917039SDavid du Colombier 
160*da917039SDavid du Colombier 	intrack(bit);
161*da917039SDavid du Colombier 	sts &= ~(Tc | Rc);
162*da917039SDavid du Colombier 	if (sts)
163*da917039SDavid du Colombier 		iprint("llfifo isr %#lux\n", sts);
164*da917039SDavid du Colombier 	return 1;
165*da917039SDavid du Colombier }
166*da917039SDavid du Colombier 
167*da917039SDavid du Colombier void
llfiforeset(void)168*da917039SDavid du Colombier llfiforeset(void)
169*da917039SDavid du Colombier {
170*da917039SDavid du Colombier 	frp->tdfr = Reset;
171*da917039SDavid du Colombier 	frp->rdfr = Reset;
172*da917039SDavid du Colombier 	coherence();
173*da917039SDavid du Colombier 	while ((frp->isr & (Trc | Rrc)) != (Trc | Rrc))
174*da917039SDavid du Colombier 		;
175*da917039SDavid du Colombier }
176*da917039SDavid du Colombier 
177*da917039SDavid du Colombier void
llfifoinit(Ether * ether)178*da917039SDavid du Colombier llfifoinit(Ether *ether)
179*da917039SDavid du Colombier {
180*da917039SDavid du Colombier 	llether = ether;
181*da917039SDavid du Colombier 	frp->ier = 0;
182*da917039SDavid du Colombier 	frp->isr = frp->isr;	/* extinguish intr source */
183*da917039SDavid du Colombier 	coherence();
184*da917039SDavid du Colombier 
185*da917039SDavid du Colombier 	intrenable(Intllfifo, llfifointr);
186*da917039SDavid du Colombier 	coherence();
187*da917039SDavid du Colombier 	frp->ier = Rc | Tc;
188*da917039SDavid du Colombier 	coherence();
189*da917039SDavid du Colombier }
190*da917039SDavid du Colombier 
191*da917039SDavid du Colombier void
llfifotransmit(uchar * ubuf,unsigned len)192*da917039SDavid du Colombier llfifotransmit(uchar *ubuf, unsigned len)
193*da917039SDavid du Colombier {
194*da917039SDavid du Colombier 	int wds;
195*da917039SDavid du Colombier 
196*da917039SDavid du Colombier 	llether->tbusy = 1;
197*da917039SDavid du Colombier 
198*da917039SDavid du Colombier 	assert(len <= ETHERMAXTU);
199*da917039SDavid du Colombier 	wds = ROUNDUP(len, BY2WD) / BY2WD;
200*da917039SDavid du Colombier 
201*da917039SDavid du Colombier 	/* wait for tx fifo to drain */
202*da917039SDavid du Colombier 	while ((frp->tdfv & Wordcnt) < wds)
203*da917039SDavid du Colombier 		;
204*da917039SDavid du Colombier 
205*da917039SDavid du Colombier 	/* to tx fifo */
206*da917039SDavid du Colombier 	assert((frp->tdfv & ~Wordcnt) == 0);
207*da917039SDavid du Colombier 	fifocpy(&frp->tdfd, ubuf, len, Sinc);
208*da917039SDavid du Colombier 	coherence();
209*da917039SDavid du Colombier 	frp->tlf = len;			/* send packet in tx fifo to ether */
210*da917039SDavid du Colombier 	coherence();
211*da917039SDavid du Colombier }
212