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