xref: /plan9-contrib/sys/src/9k/386/etherdummy.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
1*9ef1f84bSDavid du Colombier /*
2*9ef1f84bSDavid du Colombier   *	Dummy ethernet
3*9ef1f84bSDavid du Colombier   */
4*9ef1f84bSDavid du Colombier #include "u.h"
5*9ef1f84bSDavid du Colombier #include "../port/lib.h"
6*9ef1f84bSDavid du Colombier #include "mem.h"
7*9ef1f84bSDavid du Colombier #include "dat.h"
8*9ef1f84bSDavid du Colombier #include "fns.h"
9*9ef1f84bSDavid du Colombier #include "io.h"
10*9ef1f84bSDavid du Colombier #include "../port/error.h"
11*9ef1f84bSDavid du Colombier #include "../port/netif.h"
12*9ef1f84bSDavid du Colombier #include "etherif.h"
13*9ef1f84bSDavid du Colombier 
14*9ef1f84bSDavid du Colombier enum {
15*9ef1f84bSDavid du Colombier 	Rbsz	= ETHERMAXTU+32, /* +slop is for vlan headers, crcs, etc. */
16*9ef1f84bSDavid du Colombier 	Descalign= 128,		/* 599 manual needs 128-byte alignment */
17*9ef1f84bSDavid du Colombier 
18*9ef1f84bSDavid du Colombier 	/* tunable parameters */
19*9ef1f84bSDavid du Colombier 	Nrd	= 4,
20*9ef1f84bSDavid du Colombier 	Nrb	= 8,
21*9ef1f84bSDavid du Colombier 	Ntd	= 4,
22*9ef1f84bSDavid du Colombier };
23*9ef1f84bSDavid du Colombier 
24*9ef1f84bSDavid du Colombier enum {
25*9ef1f84bSDavid du Colombier 	Factive		= 1<<0,
26*9ef1f84bSDavid du Colombier };
27*9ef1f84bSDavid du Colombier 
28*9ef1f84bSDavid du Colombier typedef struct {
29*9ef1f84bSDavid du Colombier 	Pcidev	*p;
30*9ef1f84bSDavid du Colombier 	Ether	*edev;
31*9ef1f84bSDavid du Colombier 	int	type;
32*9ef1f84bSDavid du Colombier 
33*9ef1f84bSDavid du Colombier 	/* virtual */
34*9ef1f84bSDavid du Colombier 	uintptr	*reg;
35*9ef1f84bSDavid du Colombier 
36*9ef1f84bSDavid du Colombier 	uchar	flag;
37*9ef1f84bSDavid du Colombier 	int	nrd;
38*9ef1f84bSDavid du Colombier 	int	ntd;
39*9ef1f84bSDavid du Colombier 	int	nrb;
40*9ef1f84bSDavid du Colombier 	uint	rbsz;
41*9ef1f84bSDavid du Colombier 	int	procsrunning;
42*9ef1f84bSDavid du Colombier 	int	attached;
43*9ef1f84bSDavid du Colombier 
44*9ef1f84bSDavid du Colombier 	Lock	slock;
45*9ef1f84bSDavid du Colombier 	Lock	alock;			/* attach lock */
46*9ef1f84bSDavid du Colombier 	QLock	tlock;
47*9ef1f84bSDavid du Colombier 
48*9ef1f84bSDavid du Colombier 	uint	im;
49*9ef1f84bSDavid du Colombier 	Lock	imlock;
50*9ef1f84bSDavid du Colombier 
51*9ef1f84bSDavid du Colombier 	Block	**rb;
52*9ef1f84bSDavid du Colombier 	uint	rdt;
53*9ef1f84bSDavid du Colombier 	uint	rdfree;
54*9ef1f84bSDavid du Colombier 
55*9ef1f84bSDavid du Colombier 	uint	tdh;
56*9ef1f84bSDavid du Colombier 	uint	tdt;
57*9ef1f84bSDavid du Colombier 	Block	**tb;
58*9ef1f84bSDavid du Colombier 
59*9ef1f84bSDavid du Colombier 	uchar	ra[Eaddrlen];
60*9ef1f84bSDavid du Colombier } Ctlr;
61*9ef1f84bSDavid du Colombier 
62*9ef1f84bSDavid du Colombier static	Ctlr	*ctlrtab[4];
63*9ef1f84bSDavid du Colombier static	int	nctlr;
64*9ef1f84bSDavid du Colombier static	Lock	rblock;
65*9ef1f84bSDavid du Colombier static	Block	*rbpool;
66*9ef1f84bSDavid du Colombier 
67*9ef1f84bSDavid du Colombier static long
ifstat(Ether * e,void * a,long n,ulong offset)68*9ef1f84bSDavid du Colombier ifstat(Ether *e, void *a, long n, ulong offset)
69*9ef1f84bSDavid du Colombier {
70*9ef1f84bSDavid du Colombier 	char *s, *p, *q;
71*9ef1f84bSDavid du Colombier 	Ctlr *c;
72*9ef1f84bSDavid du Colombier 
73*9ef1f84bSDavid du Colombier 	c = e->ctlr;
74*9ef1f84bSDavid du Colombier 	p = s = malloc(READSTR);
75*9ef1f84bSDavid du Colombier 	if(p == nil)
76*9ef1f84bSDavid du Colombier 		error(Enomem);
77*9ef1f84bSDavid du Colombier 	q = p + READSTR;
78*9ef1f84bSDavid du Colombier 
79*9ef1f84bSDavid du Colombier 	p = seprint(p, q, "mtu: min:%d max:%d\n", e->minmtu, e->maxmtu);
80*9ef1f84bSDavid du Colombier 	seprint(p, q, "rdfree %d\n", c->rdfree);
81*9ef1f84bSDavid du Colombier 	n = readstr(offset, a, n, s);
82*9ef1f84bSDavid du Colombier 	free(s);
83*9ef1f84bSDavid du Colombier 
84*9ef1f84bSDavid du Colombier 	return n;
85*9ef1f84bSDavid du Colombier }
86*9ef1f84bSDavid du Colombier 
87*9ef1f84bSDavid du Colombier static long
ctl(Ether *,void *,long)88*9ef1f84bSDavid du Colombier ctl(Ether *, void *, long)
89*9ef1f84bSDavid du Colombier {
90*9ef1f84bSDavid du Colombier 	error(Ebadarg);
91*9ef1f84bSDavid du Colombier 	return -1;
92*9ef1f84bSDavid du Colombier }
93*9ef1f84bSDavid du Colombier 
94*9ef1f84bSDavid du Colombier static Block*
rballoc(void)95*9ef1f84bSDavid du Colombier rballoc(void)
96*9ef1f84bSDavid du Colombier {
97*9ef1f84bSDavid du Colombier 	Block *bp;
98*9ef1f84bSDavid du Colombier 
99*9ef1f84bSDavid du Colombier 	ilock(&rblock);
100*9ef1f84bSDavid du Colombier 	if((bp = rbpool) != nil){
101*9ef1f84bSDavid du Colombier 		rbpool = bp->next;
102*9ef1f84bSDavid du Colombier 		bp->next = 0;
103*9ef1f84bSDavid du Colombier //		ainc(&bp->ref);		/* prevent bp from being freed */
104*9ef1f84bSDavid du Colombier 	}
105*9ef1f84bSDavid du Colombier 	iunlock(&rblock);
106*9ef1f84bSDavid du Colombier 	return bp;
107*9ef1f84bSDavid du Colombier }
108*9ef1f84bSDavid du Colombier 
109*9ef1f84bSDavid du Colombier void
drbfree(Block * b)110*9ef1f84bSDavid du Colombier drbfree(Block *b)
111*9ef1f84bSDavid du Colombier {
112*9ef1f84bSDavid du Colombier 	b->rp = b->wp = (uchar*)ROUNDUP((uintptr)b->base, 2*KiB);
113*9ef1f84bSDavid du Colombier 	b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
114*9ef1f84bSDavid du Colombier 	ilock(&rblock);
115*9ef1f84bSDavid du Colombier 	b->next = rbpool;
116*9ef1f84bSDavid du Colombier 	rbpool = b;
117*9ef1f84bSDavid du Colombier 	iunlock(&rblock);
118*9ef1f84bSDavid du Colombier }
119*9ef1f84bSDavid du Colombier 
120*9ef1f84bSDavid du Colombier void
dtransmit(Ether * e)121*9ef1f84bSDavid du Colombier dtransmit(Ether *e)
122*9ef1f84bSDavid du Colombier {
123*9ef1f84bSDavid du Colombier 	Block *b;
124*9ef1f84bSDavid du Colombier 
125*9ef1f84bSDavid du Colombier 	while((b = qget(e->oq)) != nil)
126*9ef1f84bSDavid du Colombier 		freeb(b);
127*9ef1f84bSDavid du Colombier }
128*9ef1f84bSDavid du Colombier 
129*9ef1f84bSDavid du Colombier static void
rxinit(Ctlr * c)130*9ef1f84bSDavid du Colombier rxinit(Ctlr *c)
131*9ef1f84bSDavid du Colombier {
132*9ef1f84bSDavid du Colombier 	int i;
133*9ef1f84bSDavid du Colombier 	Block *b;
134*9ef1f84bSDavid du Colombier 
135*9ef1f84bSDavid du Colombier 	for(i = 0; i < c->nrd; i++){
136*9ef1f84bSDavid du Colombier 		b = c->rb[i];
137*9ef1f84bSDavid du Colombier 		c->rb[i] = 0;
138*9ef1f84bSDavid du Colombier 		if(b)
139*9ef1f84bSDavid du Colombier 			freeb(b);
140*9ef1f84bSDavid du Colombier 	}
141*9ef1f84bSDavid du Colombier 	c->rdfree = 0;
142*9ef1f84bSDavid du Colombier }
143*9ef1f84bSDavid du Colombier 
144*9ef1f84bSDavid du Colombier static void
promiscuous(void *,int)145*9ef1f84bSDavid du Colombier promiscuous(void*, int)
146*9ef1f84bSDavid du Colombier {
147*9ef1f84bSDavid du Colombier }
148*9ef1f84bSDavid du Colombier 
149*9ef1f84bSDavid du Colombier static void
multicast(void *,uchar *,int)150*9ef1f84bSDavid du Colombier multicast(void *, uchar *, int)
151*9ef1f84bSDavid du Colombier {
152*9ef1f84bSDavid du Colombier }
153*9ef1f84bSDavid du Colombier 
154*9ef1f84bSDavid du Colombier static void
freemem(Ctlr * c)155*9ef1f84bSDavid du Colombier freemem(Ctlr *c)
156*9ef1f84bSDavid du Colombier {
157*9ef1f84bSDavid du Colombier 	Block *b;
158*9ef1f84bSDavid du Colombier 
159*9ef1f84bSDavid du Colombier 	while(b = rballoc()){
160*9ef1f84bSDavid du Colombier 		b->free = 0;
161*9ef1f84bSDavid du Colombier 		freeb(b);
162*9ef1f84bSDavid du Colombier 	}
163*9ef1f84bSDavid du Colombier 	free(c->rb);
164*9ef1f84bSDavid du Colombier 	c->rb = nil;
165*9ef1f84bSDavid du Colombier 	free(c->tb);
166*9ef1f84bSDavid du Colombier 	c->tb = nil;
167*9ef1f84bSDavid du Colombier }
168*9ef1f84bSDavid du Colombier 
169*9ef1f84bSDavid du Colombier static int
detach(Ctlr * c)170*9ef1f84bSDavid du Colombier detach(Ctlr *c)
171*9ef1f84bSDavid du Colombier {
172*9ef1f84bSDavid du Colombier 	c->attached = 0;
173*9ef1f84bSDavid du Colombier 	return 0;
174*9ef1f84bSDavid du Colombier }
175*9ef1f84bSDavid du Colombier 
176*9ef1f84bSDavid du Colombier static void
shutdown(Ether * e)177*9ef1f84bSDavid du Colombier shutdown(Ether *e)
178*9ef1f84bSDavid du Colombier {
179*9ef1f84bSDavid du Colombier 	detach(e->ctlr);
180*9ef1f84bSDavid du Colombier //	freemem(e->ctlr);
181*9ef1f84bSDavid du Colombier }
182*9ef1f84bSDavid du Colombier 
183*9ef1f84bSDavid du Colombier 
184*9ef1f84bSDavid du Colombier static int
reset(Ctlr * c)185*9ef1f84bSDavid du Colombier reset(Ctlr *c)
186*9ef1f84bSDavid du Colombier {
187*9ef1f84bSDavid du Colombier 	if(detach(c)){
188*9ef1f84bSDavid du Colombier 		print("dummy: reset timeout\n");
189*9ef1f84bSDavid du Colombier 		return -1;
190*9ef1f84bSDavid du Colombier 	}
191*9ef1f84bSDavid du Colombier 	return 0;
192*9ef1f84bSDavid du Colombier }
193*9ef1f84bSDavid du Colombier 
194*9ef1f84bSDavid du Colombier static void
txinit(Ctlr * c)195*9ef1f84bSDavid du Colombier txinit(Ctlr *c)
196*9ef1f84bSDavid du Colombier {
197*9ef1f84bSDavid du Colombier 	Block *b;
198*9ef1f84bSDavid du Colombier 	int i;
199*9ef1f84bSDavid du Colombier 
200*9ef1f84bSDavid du Colombier 	for(i = 0; i < c->ntd; i++){
201*9ef1f84bSDavid du Colombier 		b = c->tb[i];
202*9ef1f84bSDavid du Colombier 		c->tb[i] = 0;
203*9ef1f84bSDavid du Colombier 		if(b)
204*9ef1f84bSDavid du Colombier 			freeb(b);
205*9ef1f84bSDavid du Colombier 	}
206*9ef1f84bSDavid du Colombier }
207*9ef1f84bSDavid du Colombier 
208*9ef1f84bSDavid du Colombier static void
attach(Ether * e)209*9ef1f84bSDavid du Colombier attach(Ether *e)
210*9ef1f84bSDavid du Colombier {
211*9ef1f84bSDavid du Colombier 	Block *b;
212*9ef1f84bSDavid du Colombier 	Ctlr *c;
213*9ef1f84bSDavid du Colombier 
214*9ef1f84bSDavid du Colombier 	c = e->ctlr;
215*9ef1f84bSDavid du Colombier 	c->edev = e;			/* point back to Ether* */
216*9ef1f84bSDavid du Colombier 	lock(&c->alock);
217*9ef1f84bSDavid du Colombier 	if(waserror()){
218*9ef1f84bSDavid du Colombier 		unlock(&c->alock);
219*9ef1f84bSDavid du Colombier 		freemem(c);
220*9ef1f84bSDavid du Colombier 		nexterror();
221*9ef1f84bSDavid du Colombier 	}
222*9ef1f84bSDavid du Colombier 	if(c->rb == nil) {
223*9ef1f84bSDavid du Colombier 		c->nrd = Nrd;
224*9ef1f84bSDavid du Colombier 		c->ntd = Ntd;
225*9ef1f84bSDavid du Colombier 		c->rb = malloc(c->nrd * sizeof(Block *));
226*9ef1f84bSDavid du Colombier 		c->tb = malloc(c->ntd * sizeof(Block *));
227*9ef1f84bSDavid du Colombier 		if (c->rb == nil || c->tb == nil)
228*9ef1f84bSDavid du Colombier 			error(Enomem);
229*9ef1f84bSDavid du Colombier 
230*9ef1f84bSDavid du Colombier 		for(c->nrb = 0; c->nrb < 2*Nrb; c->nrb++){
231*9ef1f84bSDavid du Colombier 			b = allocb(c->rbsz + 2*KiB);	/* see rbfree() */
232*9ef1f84bSDavid du Colombier 			if(b == nil)
233*9ef1f84bSDavid du Colombier 				error(Enomem);
234*9ef1f84bSDavid du Colombier 			b->free = drbfree;
235*9ef1f84bSDavid du Colombier 			freeb(b);
236*9ef1f84bSDavid du Colombier 		}
237*9ef1f84bSDavid du Colombier 	}
238*9ef1f84bSDavid du Colombier 	if (!c->attached) {
239*9ef1f84bSDavid du Colombier 		rxinit(c);
240*9ef1f84bSDavid du Colombier 		txinit(c);
241*9ef1f84bSDavid du Colombier 		c->attached = 1;
242*9ef1f84bSDavid du Colombier 	}
243*9ef1f84bSDavid du Colombier 	unlock(&c->alock);
244*9ef1f84bSDavid du Colombier 	poperror();
245*9ef1f84bSDavid du Colombier }
246*9ef1f84bSDavid du Colombier 
247*9ef1f84bSDavid du Colombier static void
interrupt(Ureg *,void *)248*9ef1f84bSDavid du Colombier interrupt(Ureg*, void *)
249*9ef1f84bSDavid du Colombier {
250*9ef1f84bSDavid du Colombier }
251*9ef1f84bSDavid du Colombier 
252*9ef1f84bSDavid du Colombier static void
scan(void)253*9ef1f84bSDavid du Colombier scan(void)
254*9ef1f84bSDavid du Colombier {
255*9ef1f84bSDavid du Colombier 	Ctlr *c;
256*9ef1f84bSDavid du Colombier 	int i;
257*9ef1f84bSDavid du Colombier 
258*9ef1f84bSDavid du Colombier 	for(i = 0; i < 2; i++){
259*9ef1f84bSDavid du Colombier 		if(nctlr == nelem(ctlrtab)){
260*9ef1f84bSDavid du Colombier 			print("dummy: too many controllers\n");
261*9ef1f84bSDavid du Colombier 			return;
262*9ef1f84bSDavid du Colombier 		}
263*9ef1f84bSDavid du Colombier 
264*9ef1f84bSDavid du Colombier 		c = malloc(sizeof *c);
265*9ef1f84bSDavid du Colombier 		c->rbsz = Rbsz;
266*9ef1f84bSDavid du Colombier 		if(reset(c)){
267*9ef1f84bSDavid du Colombier 			print("dummy: can't reset\n");
268*9ef1f84bSDavid du Colombier 			free(c);
269*9ef1f84bSDavid du Colombier 			continue;
270*9ef1f84bSDavid du Colombier 		}
271*9ef1f84bSDavid du Colombier 		ctlrtab[nctlr++] = c;
272*9ef1f84bSDavid du Colombier 	}
273*9ef1f84bSDavid du Colombier }
274*9ef1f84bSDavid du Colombier 
275*9ef1f84bSDavid du Colombier static int
pnp(Ether * e)276*9ef1f84bSDavid du Colombier pnp(Ether *e)
277*9ef1f84bSDavid du Colombier {
278*9ef1f84bSDavid du Colombier 	int i;
279*9ef1f84bSDavid du Colombier 	Ctlr *c = nil;
280*9ef1f84bSDavid du Colombier 
281*9ef1f84bSDavid du Colombier 	if(nctlr == 0)
282*9ef1f84bSDavid du Colombier 		scan();
283*9ef1f84bSDavid du Colombier 	for(i = 0; i < nctlr; i++){
284*9ef1f84bSDavid du Colombier 		c = ctlrtab[i];
285*9ef1f84bSDavid du Colombier 		if(c == nil || c->flag & Factive)
286*9ef1f84bSDavid du Colombier 			continue;
287*9ef1f84bSDavid du Colombier 		if(e->port == 0 || e->port == PTR2UINT(c->reg))
288*9ef1f84bSDavid du Colombier 			break;
289*9ef1f84bSDavid du Colombier 	}
290*9ef1f84bSDavid du Colombier 	if (i >= nctlr)
291*9ef1f84bSDavid du Colombier 		return -1;
292*9ef1f84bSDavid du Colombier 
293*9ef1f84bSDavid du Colombier 	c->flag |= Factive;
294*9ef1f84bSDavid du Colombier 	e->ctlr = c;
295*9ef1f84bSDavid du Colombier 	e->irq = -1;
296*9ef1f84bSDavid du Colombier 	e->mbps = 10000;
297*9ef1f84bSDavid du Colombier 	e->maxmtu = ETHERMAXTU;
298*9ef1f84bSDavid du Colombier 	memmove(e->ea, c->ra, Eaddrlen);
299*9ef1f84bSDavid du Colombier 
300*9ef1f84bSDavid du Colombier 	e->arg = e;
301*9ef1f84bSDavid du Colombier 	e->attach = attach;
302*9ef1f84bSDavid du Colombier 	e->ctl = ctl;
303*9ef1f84bSDavid du Colombier 	e->ifstat = ifstat;
304*9ef1f84bSDavid du Colombier 	e->interrupt = interrupt;
305*9ef1f84bSDavid du Colombier 	e->multicast = multicast;
306*9ef1f84bSDavid du Colombier 	e->promiscuous = promiscuous;
307*9ef1f84bSDavid du Colombier 	e->shutdown = shutdown;
308*9ef1f84bSDavid du Colombier 	e->transmit = dtransmit;
309*9ef1f84bSDavid du Colombier 
310*9ef1f84bSDavid du Colombier 	return 0;
311*9ef1f84bSDavid du Colombier }
312*9ef1f84bSDavid du Colombier 
313*9ef1f84bSDavid du Colombier void
etherdummylink(void)314*9ef1f84bSDavid du Colombier etherdummylink(void)
315*9ef1f84bSDavid du Colombier {
316*9ef1f84bSDavid du Colombier 	addethercard("dummy", pnp);
317*9ef1f84bSDavid du Colombier }
318