|
|
1.1 root 1: #include "ec.h"
2: #if NEC > 0
3:
4:
5: #include "../h/param.h"
6: #include "../h/systm.h"
7: #include "../h/pte.h"
8: #include "../h/map.h"
9: #include "../h/buf.h"
10: #include "../h/ubareg.h"
11: #include "../h/ubavar.h"
12: #include "../h/conf.h"
13: #include "../h/ioctl.h"
14: #include "../h/ttyld.h"
15: #include "../h/stream.h"
16: #include "../h/ethernet.h"
17: #include "sparam.h"
18:
19: extern char ECmem[]; /* .set in locore.s */
20: #define ECADDR ((caddr_t)(ECmem)) /* Virt addr of EC buffer mem */
21:
22: /* NOTE: The ECRHBF/ECRLBF/ECTBF definitions must match the address
23: and size of EC memory as defined in locore.s in the kernel.
24: If locore maps in full 32K, then use all buffers, otherwise,
25: change accordingly.
26: */
27:
28: #define ENETDOWN ENODEV
29: #define ECRHBF 11
30: #define ECRLBF 1
31: #define ECTBF 0
32:
33: /* Following ethernet address only has meaning if UE prom is missing */
34:
35: #define ECPRI (PZERO+8)
36: #define ECBFSZ 2048 /* Size of each EC buffer */
37:
38: struct ecdevice {
39: short ecrcr; /* Transmit Control Register */
40: short ecxcr; /* Receive Control Register */
41: };
42:
43: /* Bits in ecxcr: */
44: #define EC_WBN 0x0010 /* Write Buffer Number */
45: #define EC_CLRDN 0x0020 /* Clear Done */
46: #define EC_IE 0x0040 /* Interrupt Enable */
47: #define EC_DONE 0x0080 /* Xmt/Rcv complete */
48: #define EC_CLR 0x0100 /* Clear EC */
49: #define EC_CLRJAM 0x2000 /* Clear Jam */
50: #define EC_JIE 0x4000 /* Jam Interrupt Enable */
51: #define EC_JAM 0x8000 /* Jam */
52:
53: /* Bits WBN, CLRDN, IE, and DONE are also used for ecrcr */
54: #define EC_BITS "\20\20JAM\17JIE\16CLRJAM\11CLR\10DONE\7IE\6CLRDN\5WBN"
55:
56: /* Bits in ecrcr: */
57: #define EC_RANDATA 0xA00 /* Alternating 1/0 in 4 data bits */
58: #define EC_ADATAMSK 0xF00 /* Mask for 4 data bits */
59: #define EC_OWN_BDCST 0x600 /* Recog addrs for me + broadcast*/
60: #define EC_ARALL 0 /* Pass all addresses */
61: #define EC_AWCLK 0x1000 /* Clock data into address recog ram */
62: #define EC_AROM 0x2000 /* Select rom vs default ram */
63: #define EC_ASTEP 0x4000 /* Step rom/ram address one bit */
64:
65:
66: /*
67: * Useful combinations
68: */
69: #define EC_READ (EC_OWN_BDCST|EC_IE|EC_WBN)
70: #define EC_WRITE (EC_JIE|EC_IE|EC_WBN)
71: #define EC_CLEAR (EC_JIE|EC_IE|EC_CLRJAM)
72:
73: #define ECXBUSY 010
74: #define ECDEBUG 0200
75:
76: /* corresponds to minor device numbers (# of servers) */
77: #define CHANS_PER_UNIT 8
78:
79: struct ec { /* per controller */
80: char myethadr[6]; /* My Ethernet address */
81: char attached; /* Non zero when ec has been attached */
82: char active;
83: short collisions; /* Jam counter */
84: int state; /* Device state */
85: int bits;
86: int ierrors, oerrors;
87: int ipackets, opackets;
88: } ec[NEC] = { {0x02, 0x60, 0x8c, 0x00, 0x4, 0x62}, };
89:
90: #define NECCHAN (CHANS_PER_UNIT * NEC)
91: struct ecchan {
92: int unit;
93: int packets;
94: struct queue *ecq;
95: int type;
96: } ecchan[NECCHAN];
97:
98: int nodev(), ecopen(), ecclose(), ecput(), ecsrv();
99: static struct qinit ecrinit = { nodev, NULL, ecopen, ecclose, 0, 0 };
100: static struct qinit ecwinit = { ecput, NULL, ecopen, ecclose, 1514, 0 };
101: /* 1514 bytes is minimum highwater mark to send 1514 byte packets */
102: struct streamtab ecsinfo = { &ecrinit, &ecwinit };
103:
104: /* JUNK FOR AUTOCONFIGURE */
105: struct uba_device *ecinfo[1];
106: int ecprobe(), ecattach();
107: u_short ecstd[] = { 0 };
108: struct uba_driver ecdriver =
109: { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo };
110: extern bsize[];
111:
112: ecprobe(reg)
113: caddr_t reg;
114: {
115: register int br, cvec; /* value-result */
116: br = 0x16; /* BR Level 16 = UNIBUS 6 */
117: cvec = 0440; /* Int vector */
118: return 1;
119: }
120:
121: /* ARGSUSED */
122: ecattach(ui)
123: struct uba_device *ui;
124: {
125: register struct ecdevice *ecaddr = (struct ecdevice *)ui->ui_addr;
126: register struct ec *ecu = &ec[ui->ui_unit];
127: unsigned short s0, s1;
128: register i, j;
129: register char *cp;
130: char bdethadr[6]; /* copy of bd rom; -1=>chip missing */
131:
132:
133: if(ecu->attached) /* Do this only once */
134: return;
135: ecaddr->ecxcr = EC_CLR; /* Reset the EC */
136:
137: /* Fetch out the ROM ethernet address into tmp ethadr */
138:
139: ecaddr->ecrcr = EC_AROM; /* Select the ROM */
140: cp = bdethadr;
141: for(i = 0; i < 6; i++) {
142: *cp = 0;
143: for(j = 0; j <= 4; j += 4) {
144: s1 = ecaddr->ecrcr;
145: *cp |= ((s1 >> 8) & 017) << j;
146: for(s1 = 0; s1 < 4; s1++) {
147: ecaddr->ecrcr = EC_ASTEP+EC_AROM;
148: ecaddr->ecrcr = EC_AROM;
149: }
150: }
151: cp++;
152: }
153: for(i = 0, cp = bdethadr; i < 6; i++)
154: if(*cp++ != -1) { /* Rom is good if not -1 */
155: for(i = 0; i < 6; i++)
156: ecu->myethadr[i] = bdethadr[i];
157: }
158: /* use the RAM for addr recog */
159: laddrec(ui);
160:
161: for(i = ECRHBF; i >= ECRLBF; i--)
162: ecaddr->ecrcr = EC_READ + i;
163: ecsrand((long)ecu->myethadr[5]);
164: ecu->attached = 1;
165: ecu->bits = EC_READ;
166: }
167:
168: laddrec(ui)
169: struct uba_device *ui;
170: {
171: register struct ecdevice *ecaddr = (struct ecdevice *)ui->ui_addr;
172: register struct ec *ecu = &ec[ui->ui_unit];
173: register i, j, s0, s1;
174: register char *cp;
175:
176: /* Have to load myethadr into hardware ram! */
177: ecaddr->ecxcr = EC_CLR; /* Reset bit ptr */
178: for(i = 0, cp = ecu->myethadr; i < 6; i++, cp++)
179: for(j = 0; j <= 4; j += 4) {
180: s1 = ((*cp >> j) & 017) << 8;
181: ecaddr->ecrcr = s1;
182: ecaddr->ecrcr = s1 | EC_AWCLK;
183: ecaddr->ecrcr = s1;
184: for(s0 = 0; s0 < 4; s0++) {
185: ecaddr->ecrcr = EC_ASTEP;
186: ecaddr->ecrcr = 0;
187: }
188: }
189: }
190:
191:
192: /* ARGSUSED */
193: ecopen(q, dev)
194: register struct queue *q;
195: register dev_t dev;
196: {
197: register struct ecchan *ecd;
198: register struct ec *ecu;
199: register unit;
200:
201: dev = minor(dev);
202: unit = dev / CHANS_PER_UNIT;
203:
204: if (dev >= NECCHAN)
205: return(0);
206: if (unit >= NEC)
207: return(0);
208:
209: ecu = &ec[unit];
210: if(!ecu->attached)
211: return(0);
212: ecd = &ecchan[dev];
213: if (ecd->ecq)
214: return(0);
215:
216: ecd->unit = unit;
217: ecd->ecq = q;
218: q->ptr = (caddr_t)ecd;
219: q->flag |= QBIGB | QDELIM;
220: WR(q)->ptr = (caddr_t)ecd;
221: WR(q)->flag |= QBIGB|QDELIM;
222:
223: if (ecu->state & ECDEBUG)
224: printf("ECo%d, ", minor(dev));
225: return(1);
226: }
227: ecclose(q)
228: register struct queue *q;
229: {
230: register struct ecchan *ecd;
231: register struct ec *ecu;
232: register unit;
233:
234: ecd = (struct ecchan *)q->ptr;
235: ecu = &ec[ecd->unit];
236: if (ecu->state & ECDEBUG)
237: printf("ECc\n");
238: flushq(WR(q), 1);
239: ecd->ecq = NULL;
240: }
241:
242: ecput(q, bp)
243: register struct queue *q;
244: register struct block *bp;
245: {
246: register struct ecchan *ecd;
247: register struct ec *ecu;
248: register unit, type, count, ps;
249:
250: ecd = (struct ecchan *)q->ptr;
251: unit = ecd->unit;
252: ecu = &ec[unit];
253:
254: switch(bp->type) {
255:
256: case M_IOCTL:
257: ecioctl(q, bp);
258: return;
259:
260: case M_DATA:
261: putq(q, bp);
262: return;
263:
264: case M_DELIM:
265: break;
266:
267: default:
268: freeb(bp);
269: return;
270: }
271:
272: putq(q, bp);
273: ps = spl6();
274: ecd->packets++;
275: if (ecu->active == 0)
276: ecstart(unit);
277: splx(ps);
278: }
279: ecstart(unit)
280: {
281: register u_char *tsp, *fsp;
282: register struct ec *ecu;
283: register struct ecchan *ecd;
284: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr;
285: register struct queue *q, *bq;
286: register struct block *bp, *head, *nbp, **bnext;
287: register len, count = 0, i;
288:
289: ecu = &ec[unit];
290: if (ecu->active) {
291: printf(" start but active %d\n", unit);
292: ecu->active = 0;
293: }
294: ecd = &ecchan[unit * CHANS_PER_UNIT];
295: for(i = 0; i < CHANS_PER_UNIT; i++, ecd++)
296: if (ecd->ecq && ecd->packets > 0)
297: break;
298: if (i >= CHANS_PER_UNIT)
299: return;
300:
301: ecd->packets--;
302: q = WR(ecd->ecq);
303:
304: /* The packet must be justified to the end of the buffer.
305: * Therefore, we have to count the bytes before copying.
306: */
307: bnext = &head;
308: while (*bnext = bp = getq(q)) {
309: if (bp->type == M_DELIM) {
310: bp->next = 0;
311: break;
312: }
313: count += bp->wptr - bp->rptr;
314: bnext = &bp->next;
315: }
316: bp = head;
317:
318: /* if there is no ethernet header in packet, throw it out */
319: if (count < sizeof(struct ether_out)) {
320: while(bp) {
321: nbp = bp->next;
322: freeb(bp);
323: bp = nbp;
324: }
325: return;
326: }
327: ecu->active = 1;
328:
329: /* test for small packets */
330: if (count < 46 + sizeof(struct ether_out))
331: count = 46 + sizeof(struct ether_out);
332:
333: /* test for too large packets */
334: else if (count > 1500 + sizeof(struct ether_out))
335: count = 1500 + sizeof(struct ether_out);
336:
337: /* Fill buffer - packet is justified to end of buffer. */
338: tsp = (u_char *)(ECmem+(ECBFSZ*ECTBF));
339: *(short *)tsp = (ECBFSZ) - count; /* Stuff offset into buffer */
340: tsp += ((ECBFSZ) - count); /* Adjust ptr into buffer */
341:
342: while (count > 0 && bp != 0) {
343: len = bp->wptr - bp->rptr;
344: fsp = bp->rptr;
345: count -= len;
346: while (len-- > 0) /* Could this use scopy()? */
347: *tsp++ = *fsp++;
348: nbp = bp->next;
349: freeb(bp);
350: bp = nbp;
351: }
352:
353: /* if no buffers left but count > 0, (i.e. padded packet), zero fill */
354: while (count-- > 0)
355: *tsp++ = 0;
356:
357: /* flush remaining buffers, if any (too large packet: count > 1500) */
358: while (bp) {
359: nbp = bp->next;
360: freeb(bp);
361: bp = nbp;
362: }
363:
364: if (ecu->state & ECDEBUG) {
365: register i;
366: printf("\ncount=%d, packet = ", count);
367: tsp = (u_char *)(ECmem+(ECBFSZ*ECTBF)) + (ECBFSZ - count);
368: for(i = 0; i < count; i++)
369: printf("%02x ", (unsigned int)*tsp++);
370: printf("\n");
371: }
372: ecu->state |= ECXBUSY;
373: ecu->collisions = 0;
374: ecaddr->ecxcr = EC_WRITE + ECTBF;
375: }
376:
377: ecioctl(q, bp)
378: register struct queue *q;
379: register struct block *bp;
380: {
381: #ifndef EIOCSETP
382: #define EIOCSETP (('e'<<8)|3) /* set ec_state (state of driver) */
383: #define EIOCGETP (('e'<<8)|4) /* get ec_state (driver state) */
384: #define EIOCAREC (('e'<<8)|5) /* set address recognition */
385: #endif
386: register struct ecdevice *ecaddr;
387: register struct ecchan *ecd;
388: register struct ec *ecu;
389: register u_char *msg;
390: register unit, i, ps, cmd;
391:
392: ecd = (struct ecchan *)q->ptr;
393: unit = ecd->unit;
394: ecu = &ec[unit];
395: ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr;
396: cmd = ((union stmsg *)(bp->rptr))->ioc1.com;
397: msg = (u_char *)&((union stmsg *)(bp->rptr))->ioc1.sb;
398:
399: bp->type = M_IOCACK;
400: if (ecu->state & ECDEBUG)
401: printf("ecioctl: cmd = %x\n");
402: switch(cmd) {
403: case ENIOADDR: /* get my Ethernet address */
404: bcopy(ecu->myethadr, (int *)msg, 6);
405: break;
406:
407: /*
408: * SETP, SETD, SSIG, AREC should be super user ioctl calls.
409: * Since it is impossible to know who the initiator of an ioctl call is,
410: * it would be desirable to have a special minor device number for super user
411: * privileges
412: */
413: case EIOCSETP:
414: case EIOCGETP:
415: if (cmd == EIOCGETP) {
416: *(int *)msg = ecu->state;
417: } else {
418: ecu->state = *(int *)msg;
419: }
420: if (ecu->state & ECDEBUG)
421: printf("state = %o\n", ecu->state);
422: break;
423:
424: case ENIOTYPE:
425: ecd->type = *(int *)msg;
426: break;
427:
428: case EIOCAREC:
429: ecu->bits = *(int *)msg;
430: ecu->bits |= EC_IE|EC_WBN;
431: if (ecu->state & ECDEBUG)
432: printf("set addr rec, bits = %b\n", ecu->bits, EC_BITS);
433: ps = spl6();
434: ecaddr->ecxcr = EC_CLR; /* Reset the UE */
435: for(i = ECRHBF; i >= ECRLBF; i--)
436: ecaddr->ecrcr = ecu->bits + i;
437: splx(ps);
438: break;
439:
440: default:
441: bp->type = M_IOCNAK;
442: break;
443: }
444: qreply(q, bp);
445: }
446:
447:
448: /* Come here only after hardware has decided packet is for us--
449: either exactly, or multi-cast */
450: ecrint(unit)
451: {
452: register struct ecchan *ecd;
453: register struct ec *ecu = &ec[unit];
454: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr;
455: register struct queue *q;
456: register struct block *bp;
457: register short buf; /* Extract done rcv buffer */
458: register short type;
459: register short *fsp;
460: register len, min, i;
461: register u_char *p;
462:
463: while (ecaddr->ecrcr & EC_DONE) {
464: buf = ecaddr->ecrcr & 0xF; /* Extract buffer # */
465: if (buf < ECRLBF || buf > ECRHBF)
466: panic("ec%d: rcvr interrupt (bad buf=%d)\n", unit, buf);
467:
468: /* fsp points to the buffer in VAX virt memory */
469:
470: fsp = (short *)(ECmem+(ECBFSZ*buf));
471: if (*fsp < 0) { /* negative offset => FCS err */
472: ecu->ierrors++;
473: goto out;
474: }
475: if (((*fsp) & 0x3fff) == 0) { /* 0 offset => TOO LONG pkt */
476: ecu->ierrors++;
477: goto out;
478: }
479: /* *fsp contains offset to end of packet - ie (length + beginning offset);
480: packet starts at offset 528 into the buffer */
481:
482: if (*fsp < 592 || *fsp > 2046) { /* illegal count */
483: ecu->ierrors++;
484: goto out;
485: }
486: len = *fsp - (528+4); /* +4 is the FCS */
487: fsp = fsp + (528/2); /* Offset of beg of packet */
488: type = *(fsp + 6);
489: p = (u_char *)fsp;
490:
491: ecd = &ecchan[unit * CHANS_PER_UNIT];
492: for (i = 0; i < CHANS_PER_UNIT; i++, ecd++)
493: if (ecd->ecq && ecd->type == type)
494: break;
495: if (i >= CHANS_PER_UNIT)
496: goto out;
497: q = ecd->ecq;
498: if (q->next->flag & QFULL) {
499: if(ecu->state & ECDEBUG)
500: printf(" q full\n");
501: ecu->ierrors++;
502: goto out;
503: }
504: while (len > 0) {
505: bp = allocb(len);
506: if (bp == 0) {
507: printf("ecrint no buffers\n");
508: goto out;
509: }
510: min = MIN((bp->lim - bp->base), len);
511: len -= min;
512: while (min-- > 0)
513: *bp->wptr++ = *p++;
514: (*q->next->qinfo->putp)(q->next, bp);
515: }
516: if (putctl(q->next, M_DELIM))
517: ecu->ipackets++;
518: else
519: printf("ecrint no DELIM bp\n");
520: out:
521: ecaddr->ecrcr = ecu->bits | EC_CLRDN | buf;
522: }
523: }
524:
525: ecjint(unit)
526: {
527: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr;
528: register struct ec *ecu = &ec[unit];
529: register i;
530:
531: if(++ecu->collisions > 8) {
532: printf("ec gak\n");
533: ecu->oerrors++;
534: /* Hmmm, can't xmit in 8 tries */
535: ecaddr->ecxcr = EC_CLR; /* Reset the UE */
536: /* And re-read all rcv buffers */
537: for(i = ECRHBF; i >= ECRLBF; i--)
538: ecaddr->ecrcr = ecu->bits + i;
539: ecu->state &= ~ECXBUSY;
540: } else {
541: ecu->collisions++;
542: backoff(ecu->collisions);
543: ecaddr->ecxcr = EC_CLEAR; /* RESET */
544: }
545: }
546:
547:
548: /* backoff: this routine implements an approximation of the binary
549: * exponential backoff algorithm. When called with an argument n,
550: * the retry number, this routine will delay (in a busy loop)
551: * a random amount of time between 0 and 2**n slot times. A slot
552: * time is defined as 51.2 microseconds. This routine assumes it
553: * takes about 300 microseconds to be called after the jam actually
554: * occurs, and that the random number generator takes about 50
555: * microseconds.
556: */
557: backoff(n)
558: register int n;
559: {
560: long ecrand();
561: register int time;
562:
563: if (n < 4)
564: return;
565: if (n > 10)
566: n = 10;
567:
568: /* compute number of slot times to delay */
569: time = ((int)ecrand() & ((1 << n) - 1)) - 7;
570: if (time <= 0)
571: return;
572:
573: while(time--)
574: ecidle();
575: }
576:
577: static long randx = 1;
578:
579: ecsrand(x)
580: unsigned x;
581: {
582: randx = x;
583: }
584:
585: ecrand()
586: {
587: return(((randx = randx*1103515245 + 12345)>>16) & 077777);
588: }
589:
590:
591: ecidle()
592: {
593: register i = 40;
594:
595: while(--i) ;
596: }
597:
598: /*
599: * ecxint gets called when a transmit completes normally.
600: */
601: ecxint(unit)
602: {
603: register struct ecdevice *ecaddr = (struct ecdevice *)ecinfo[unit]->ui_addr;
604: register struct ec *ecu;
605: register struct ecchan *ecd;
606: register struct block *bp;
607: register buf = ecaddr->ecxcr & 0xF;
608:
609: if((ecaddr->ecxcr & EC_DONE) == 0 || buf != ECTBF)
610: printf("ec%d: xmit interrupt-bad bufno, xcsr=%b\n", unit, ecaddr->ecxcr, EC_BITS);
611:
612: ecu = &ec[unit];
613: if(ecu->active == 0) {
614: printf("ec%d: stray xmit interrupt, xcsr=%b\n", unit, ecaddr->ecxcr, EC_BITS);
615: return;
616: }
617:
618: ecaddr->ecxcr = EC_CLRDN;
619: ecu->state &= ~ECXBUSY;
620: ecu->active = 0;
621: ecu->opackets++;
622: ecstart(unit);
623: }
624: scopy(f, t, c)
625: register u_char *f, *t;
626: register c;
627: {
628: while(c-- > 0)
629: *t++ = *f++;
630: }
631: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.