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