]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/etherseeq.c
merge
[plan9front.git] / sys / src / 9 / sgi / etherseeq.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/netif.h"
8 #include "etherif.h"
9
10 typedef struct Hio Hio;
11 typedef struct Desc Desc;
12 typedef struct Ring Ring;
13 typedef struct Ctlr Ctlr;
14
15 /*
16  * SEEQ 8003 interfaced to HPC3 (very different from IP20)
17  */
18 struct Hio
19 {
20         ulong   unused0[20480];
21         ulong   crbp;           /* current receive buf desc ptr */
22         ulong   nrbdp;          /* next receive buf desc ptr */
23         ulong   unused1[1022];
24         ulong   rbc;            /* receive byte count */
25         ulong   rstat;          /* receiver status */
26         ulong   rgio;           /* receive gio fifo ptr */
27         ulong   rdev;           /* receive device fifo ptr */
28         ulong   unused2;
29         ulong   ctl;            /* interrupt, channel reset, buf oflow */
30         ulong   dmacfg;         /* dma configuration */
31         ulong   piocfg;         /* pio configuration */
32         ulong   unused3[1016];
33         ulong   cxbdp;          /* current xmit buf desc ptr */
34         ulong   nxbdp;          /* next xmit buffer desc. pointer */
35         ulong   unused4[1022];
36         ulong   xbc;            /* xmit byte count */
37         ulong   xstat;
38         ulong   xgio;           /* xmit gio fifo ptr */
39         ulong   xdev;           /* xmit device fifo ptr */
40         ulong   unused5[1020];
41         ulong   crbdp;          /* current receive descriptor ptr */
42         ulong   unused6[2047];
43         ulong   cpfxbdp;        /* current/previous packet 1st xmit */
44         ulong   ppfxbdp;        /* desc ptr */
45         ulong   unused7[59390];
46         ulong   eaddr[6];       /* seeq station address wo */
47         ulong   csr;            /* seeq receiver cmd/status reg */
48         ulong   csx;            /* seeq transmitter cmd/status reg */
49 };
50
51 enum
52 {                       /* ctl */
53         Cover=  0x08,           /* receive buffer overflow */
54         Cnormal=0x00,           /* 1=normal, 0=loopback */
55         Cint=   0x02,           /* interrupt (write 1 to clear) */
56         Creset= 0x01,           /* ethernet channel reset */
57
58                         /* xstat */
59         Xdma=   0x200,          /* dma active */
60         Xold=   0x080,          /* register has been read */
61         Xok=    0x008,          /* transmission was successful */
62         Xmaxtry=0x004,          /* transmission failed after 16 attempts */
63         Xcoll=  0x002,          /* transmission collided */
64         Xunder= 0x001,          /* transmitter underflowed */
65
66                         /* csx */
67         Xreg0=  0x00,           /* access reg bank 0 incl station addr */
68         XIok=   0x08,
69         XImaxtry=0x04,
70         XIcoll= 0x02,
71         XIunder=0x01,
72
73                         /* rstat */
74         Rlshort=0x800,          /* [small len in received frame] */
75         Rdma=   0x200,          /* dma active */
76         Rold=   0x80,           /* register has been read */
77         Rok=    0x20,           /* received good frame */
78         Rend=   0x10,           /* received end of frame */
79         Rshort= 0x08,           /* received short frame */
80         Rdrbl=  0x04,           /* dribble error */
81         Rcrc=   0x02,           /* CRC error */
82         Rover=  0x01,           /* overflow error */
83
84                         /* csr */
85         Rsmb=   0xc0,           /* receive station/broadcast/multicast frames */
86         Rsb=    0x80,           /* receive station/broadcast frames */
87         Rprom=  0x40,           /* receive all frames */
88         RIok=   0x20,           /* interrupt on good frame */
89         RIend=  0x10,           /* interrupt on end of frame */
90         RIshort=0x08,           /* interrupt on short frame */
91         RIdrbl= 0x04,           /* interrupt on dribble error */
92         RIcrc=  0x02,           /* interrupt on CRC error */
93         RIover= 0x01,           /* interrupt on overflow error */
94
95         HPC_MODNORM=    0x0,    /* mode: 0=normal, 1=loopback */
96         HPC_FIX_INTR=   0x8000, /* start timeout counter after */
97         HPC_FIX_EOP=    0x4000, /* rcv_eop_intr/eop_in_chip is set */ 
98         HPC_FIX_RXDC=   0x2000, /* clear eop status upon rxdc */
99 };
100
101 struct Desc
102 {
103         ulong   addr;           /* addr */
104         ulong   count;          /* eox / eop / busy / xie / count:13 */
105         ulong   next;
106         uchar*  base;
107 };
108
109 struct Ring
110 {
111         Rendez;
112         int     size;
113         int     free;
114         uchar*  base;
115         Desc*   head;
116         Desc*   tail;
117 };
118
119 enum
120 {
121         Eor=    1<<31,          /* end of ring */
122         Eop=    1<<30,
123         Ioc=    1<<29,          /* interrupt on completion */
124         Busy=   1<<24,
125         Empty=  1<<14,          /* no data here */
126         Done=   1<<15,          /* transmit done */
127 };
128
129 enum {
130         Rbsize = ETHERMAXTU+3,
131 };
132
133 struct Ctlr
134 {
135         int     attach;
136         char*   txerr;
137         ulong   txwdog;
138
139         Hio*    io;
140
141         Ring    rx;
142         Ring    tx;
143 };
144
145 static int reset(Ether*);
146
147 static void
148 txintr(Ctlr *ctlr)
149 {
150         Hio *io;
151         ulong s;
152         Desc *p;
153
154         io = ctlr->io;
155         s = io->xstat;
156         if((s & Xdma) != 0)
157                 return;
158         if((s & Xmaxtry) != 0)
159                 ctlr->txerr = "transmission failed";
160         if((s & Xunder) != 0)
161                 ctlr->txerr = "transmitter underflowed";
162         for(p = IO(Desc, ctlr->tx.head->next); (p->count & Busy) != 0; p = IO(Desc, p->next)){
163                 if((p->count & Done) == 0){
164                         io->nxbdp = PADDR(p);
165                         io->xstat = Xdma;
166                         ctlr->txwdog = MACHP(0)->ticks;
167                         break;
168                 }
169                 p->count = Eor|Eop;
170                 ctlr->tx.head = p;
171                 ctlr->tx.free++;
172                 ctlr->txwdog = 0;
173         }
174         wakeup(&ctlr->tx);
175 }
176
177 static void
178 interrupt(Ureg *, void *arg)
179 {
180         Ether *edev;
181         Ctlr *ctlr;
182         Hio *io;
183         uint s;
184
185         edev = arg;
186         ctlr = edev->ctlr;
187         io = ctlr->io;
188         s = io->ctl;
189         if(s & Cover){
190                 io->ctl = Cnormal | Cover;
191                 edev->overflows++;
192         }
193         if(s & Cint) {
194                 io->ctl = Cnormal | Cint;
195                 txintr(ctlr);
196                 wakeup(&ctlr->rx);
197         }
198 }
199
200 static int
201 notempty(void *arg)
202 {
203         Ctlr *ctlr = arg;
204
205         return (IO(Desc, ctlr->rx.head->next)->count & Empty) == 0;
206 }
207
208 static char*
209 checkerr(Ctlr *ctlr)
210 {
211         ulong t;
212
213         if(ctlr->txerr != nil)
214                 return ctlr->txerr;
215         t = ctlr->txwdog;
216         if(t != 0 && TK2MS(MACHP(0)->ticks - t) > 1000)
217                 return "transmitter dma timeout";
218         if((ctlr->io->rstat & Rdma) == 0)
219                 return "recevier dma stopped";
220         return nil;
221 }
222
223 static void
224 rxproc(void *arg)
225 {
226         Ether *edev = arg;
227         Ctlr *ctlr;
228         char *err;
229         Block *b;
230         Desc *p;
231         int n;
232
233         while(waserror())
234                 ;
235
236         ctlr = edev->ctlr;
237         for(p = IO(Desc, ctlr->rx.head->next);; p = IO(Desc, p->next)){
238                 while((p->count & Empty) != 0){
239                         err = checkerr(ctlr);
240                         if(err != nil){
241                                 print("%s: %s; reseting\n", up->text, err);
242                                 splhi();
243                                 reset(edev);
244                                 spllo();
245                         }
246                         tsleep(&ctlr->rx, notempty, ctlr, 500);
247                 }
248                 n = Rbsize - (p->count & 0x3fff)-3;
249                 if(n >= ETHERMINTU && (p->base[n+2] & Rok) != 0){
250                         b = allocb(n);
251                         b->wp += n;
252                         memmove(b->rp, p->base+2, n);
253                         etheriq(edev, b, 1);
254                 }
255                 p->addr = PADDR(p->base);
256                 p->count = Ioc|Empty|Rbsize;
257                 ctlr->rx.head = p;
258         }
259 }
260
261 static int
262 notbusy(void *arg)
263 {
264         Ctlr *ctlr = arg;
265         return ctlr->tx.free > 0;
266 }
267
268 static void
269 txproc(void *arg)
270 {
271         Ether *edev = arg;
272         Ctlr *ctlr;
273         Block *b;
274         Desc *p;
275         int n;
276
277         while(waserror())
278                 ;
279
280         ctlr = edev->ctlr;
281         for(p = IO(Desc, ctlr->tx.tail->next); (b = qbread(edev->oq, 1000000)) != nil; p = IO(Desc, p->next)){
282                 while(ctlr->tx.free == 0)
283                         sleep(&ctlr->tx, notbusy, ctlr);
284
285                 n = BLEN(b);
286                 if(n > ETHERMAXTU)
287                         n = ETHERMAXTU;
288                 memmove(p->base, b->rp, n);
289
290                 p->addr = PADDR(p->base);
291                 p->count = Ioc|Eor|Eop|Busy|n;
292
293                 ctlr->tx.tail->count &= ~(Ioc|Eor);
294                 ctlr->tx.tail = p;
295
296                 splhi();
297                 ctlr->tx.free--;
298                 txintr(ctlr);
299                 spllo();
300
301                 freeb(b);
302         }
303 }
304
305 static void
306 allocring(Ring *r, int n)
307 {
308         uchar *b;
309         Desc *p;
310         int m;
311
312         r->size = n;
313         r->free = n;
314
315         m = n*BY2PG/2;
316         b = xspanalloc(m, BY2PG, 0);
317         dcflush(b, m);
318         b = IO(uchar, b);
319         memset(b, 0, m);
320         r->base = b;
321
322         m = n*sizeof(Desc);
323         p = xspanalloc(m, BY2PG, 0);
324         dcflush(p, m);
325         p = IO(Desc, p);
326         memset(p, 0, m);
327         r->head = r->tail = p;
328
329         for(m=0; m<n; m++, p++, b += (BY2PG/2)){
330                 p->base = b;
331                 p->next = PADDR(p+1);
332         }
333         p[-1].next = PADDR(r->head);
334 }
335
336 static int
337 reset(Ether *edev)
338 {
339         Ctlr *ctlr;
340         Desc *p;
341         Hio *io;
342         int i;
343
344         ctlr = edev->ctlr;
345         io = ctlr->io;
346
347         ctlr->txerr = nil;
348         ctlr->txwdog = 0;
349
350         io->csx = Xreg0;
351         io->rstat = 0;
352         io->xstat = 0;
353         io->ctl = Cnormal | Creset | Cint;
354         delay(10);
355         io->ctl = Cnormal;
356         io->csx = 0;
357         io->csr = 0;
358
359         io->dmacfg |= HPC_FIX_INTR | HPC_FIX_EOP | HPC_FIX_RXDC;
360
361         p = ctlr->rx.head;
362         do {
363                 p->addr = PADDR(p->base);
364                 p->count = Ioc|Empty|Rbsize;
365                 p = IO(Desc, p->next);
366         } while(p != ctlr->rx.head);
367         io->crbdp = PADDR(p);
368         io->nrbdp = p->next;
369         ctlr->rx.tail = p;
370         ctlr->rx.free = ctlr->rx.size;
371
372         p = ctlr->tx.tail;
373         do {
374                 p->addr = PADDR(p->base);
375                 p->count = Eor|Eop;
376                 p = IO(Desc, p->next);
377         } while(p != ctlr->tx.tail);
378         io->cxbdp = PADDR(p);
379         io->nxbdp = p->next;
380         ctlr->tx.head = p;
381         ctlr->tx.free = ctlr->tx.size;
382
383         for(i=0; i<6; i++)
384                 io->eaddr[i] = edev->ea[i];
385
386         io->csx = XIok | XImaxtry | XIcoll | XIunder;
387         io->csr = Rprom | RIok|RIend|RIshort|RIdrbl|RIcrc;
388
389         io->rstat = Rdma;
390
391         wakeup(&ctlr->rx);
392         wakeup(&ctlr->tx);
393
394         return 0;
395
396 }
397
398 static int
399 init(Ether *edev)
400 {
401         Ctlr *ctlr;
402
403         ctlr = edev->ctlr;
404         ctlr->io = IO(Hio, edev->port);
405         allocring(&ctlr->rx, 256);
406         allocring(&ctlr->tx, 64);
407
408         return reset(edev);
409 }
410
411 /*
412  * do nothing for promiscuous() and multicast() as we
413  * are always in promisc mode.
414  */
415 static void
416 promiscuous(void*, int)
417 {
418 }
419 static void
420 multicast(void*, uchar*, int)
421 {
422 }
423
424 static void
425 attach(Ether *edev)
426 {
427         Ctlr *ctlr;
428
429         ctlr = edev->ctlr;
430         if(ctlr->attach)
431                 return;
432         ctlr->attach = 1;
433         kproc("#l0rx", rxproc, edev);
434         kproc("#l0tx", txproc, edev);
435 }
436
437 static int
438 pnp(Ether *edev)
439 {
440         static Ctlr ct;
441         char *s;
442
443         /* only one controller */
444         if(edev->ctlrno != 0)
445                 return -1;
446
447         /* get mac address from nvram */
448         if((s = getconf("eaddr")) != nil)
449                 parseether(edev->ea, s);
450
451         edev->ctlr = &ct;
452         edev->port = HPC3_ETHER;
453         edev->irq = IRQENET;
454         edev->irqlevel = hpc3irqlevel(edev->irq);
455         edev->ctlr = &ct;
456         edev->promiscuous = promiscuous;
457         edev->multicast = multicast;
458         edev->interrupt = interrupt;
459         edev->attach = attach;
460         edev->arg = edev;
461         edev->mbps = 10;
462         edev->link = 1;
463         if(init(edev) < 0){
464                 edev->ctlr = nil;
465                 return -1;
466         }
467         return 0;
468 }
469
470 void
471 etherseeqlink(void)
472 {
473         addethercard("seeq", pnp);
474 }