|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)if_ie.c 1.1 86/02/03 Copyr 1985 Sun Micro";
3: #endif
4:
5: /*
6: * Copyright (c) 1985 by Sun Microsystems, Inc.
7: */
8:
9: /*
10: * Parameters controlling TIMEBOMB action: times out if chip hangs.
11: *
12: */
13: #define TIMEBOMB 1000000 /* One million times around is all... */
14: #define TIMEOUT -1 /* if (function()) return (TIMEOUT); */
15: #define OK 0 /* Traditional OK value */
16:
17:
18: /*
19: * Sun Intel Ethernet Controller interface
20: */
21: #include "saio.h"
22: #include "param.h"
23: #include "../h/socket.h"
24: #include "../sunif/if_iereg.h"
25: #include "../sunif/if_mie.h"
26: #include "../sunif/if_obie.h"
27: #include "../mon/idprom.h"
28: #include "../mon/cpu.map.h"
29:
30: int iexmit(), iepoll(), iereset();
31:
32: unsigned long iestd[] = { 0x88000, 0x8C000 };
33: #define NSTD 2
34:
35: struct saif ieif = {
36: iexmit,
37: iepoll,
38: iereset,
39: };
40:
41: #define IEVVSIZ 1024 /* # of pages in page map */
42: #define IEPHYMEMSIZ (16*1024)
43: #define IEVIRMEMSIZ (16*1024)
44: #define IEPAGSIZ 1024
45: #define IERBUFSIZ 1600
46: #define IEXBUFSIZ 1600
47:
48: #ifdef SUN2
49: #define IEDMABASE 0x000000 /* Can access all of memory */
50: #endif SUN2
51: #ifdef SUN3
52: #define IEDMABASE 0x0F000000 /* Can access top 16MB of memory */
53: #endif SUN3
54:
55: /* Location in virtual memory of the SCP (System Configuration Pointer) */
56: #define SCP_LOC (char *)(IEDMABASE+IESCPADDR)
57:
58: /* controller types */
59: #define IE_MB 1 /* Multibus */
60: #define IE_OB 2 /* onboard */
61:
62: struct ie_softc {
63: /*
64: * This first item does two things. First, it reserves space for
65: * all the various protocols that need to put their locals somewhere
66: * (it was decided that HERE is convenient!). Second, it fills
67: * out the structure to align es_scp to the wierd-in address
68: * that Intel (thanks guys) fetches it from.
69: */
70: char es_fill[PROTOSCRATCH-sizeof(struct iescp)]; /* Align */
71: struct iescp es_scp; /* System config pointer (used once) */
72: struct ieiscp es_iscp; /* Intermediate sys config ptr (once) */
73: struct iescb es_scb; /* Sys Control Block, the real mama */
74: struct ierbd es_rbd;
75: struct ierbd es_rbd2; /* Hack for 82586 ucode bugs */
76: struct ierfd es_rfd;
77: struct ietfd es_tfd;
78: struct ietbd es_tbd;
79: struct mie_device *es_mie;
80: struct obie_device *es_obie;
81: short es_type;
82: struct ieiaddr es_iaddr; /* Cmd to set up our Ethernet addr */
83: struct ieconf es_ic; /* Cmd to configure the chip */
84: char es_rbuf[IERBUFSIZ];
85: char es_xbuf[IEXBUFSIZ]; /* buffer accessible by chip */
86: char es_rbuf2[10]; /* Hack for 82586 ucode bugs */
87: };
88:
89: /*
90: * This initializes the onboard Ethernet control reg to:
91: * Reset is active
92: * Loopback is NOT active
93: * Channel Attn is not active
94: * Interrupt enable is not active.
95: * Loopback is deactivated due to a bug in the Intel serial interface
96: * chip. This chip powers-up in a locked up state if Loopback is active.
97: * It "unlocks" itself if you release Loopback; then it's OK to reassert it.
98: */
99: struct obie_device obie_reset = {0, 1, 0, 0, 0, 0, 0};
100:
101: ieoff_t to_ieoff();
102: ieaddr_t to_ieaddr();
103:
104: #ifdef DEBUG
105: ieint_t from_ieint();
106: #endif DEBUG
107:
108: struct devinfo ieinfo = {
109: sizeof (struct mie_device),
110: sizeof(struct ie_softc),
111: 0,
112: NSTD,
113: iestd,
114: MAP_MBMEM,
115: 0, /* transfer size handled by ND */
116: };
117:
118: int xxprobe(), xxboot(), ieopen(), ieclose(), etherstrategy(), nullsys();
119:
120: struct boottab iedriver = {
121: "ie", xxprobe, xxboot, ieopen, ieclose,
122: etherstrategy, "ie: Sun/Intel Ethernet", &ieinfo,
123: };
124:
125: /*
126: * Open Intel Ethernet nd connection, return -1 for errors.
127: */
128: ieopen(sip)
129: struct saioreq *sip;
130: {
131: register int result;
132:
133: sip->si_sif = &ieif;
134: if ( ieinit(sip) || (result = etheropen(sip)) < 0 ) {
135: ieclose(sip); /* Make sure we kill chip */
136: return (-1);
137: }
138: return (result);
139: }
140:
141: /*
142: * Set up memory maps and Ethernet chip.
143: * Returns 1 for error, 0 for ok.
144: */
145: int
146: ieinit(sip)
147: struct saioreq *sip;
148: {
149: register struct ie_softc *es;
150: int paddr;
151: int i;
152: struct idprom id;
153:
154: if (idprom(IDFORM_1, &id) == IDFORM_1 &&
155: id.id_machine != IDM_SUN2_MULTI &&
156: (sip->si_ctlr == 0 || sip->si_ctlr == iestd[0])) {
157: /* onboard Ethernet */
158: register struct obie_device *obie;
159:
160: es = (struct ie_softc *)sip->si_dmaaddr;
161: bzero((char *)es, sizeof *es);
162: es->es_type = IE_OB;
163: es->es_obie = obie = (struct obie_device *)
164: devalloc(MAP_OBIO, VIOPG_ETHER << BYTES_PG_SHIFT,
165: sizeof(*obie));
166: } else {
167: register struct mie_device *mie;
168: struct miepg *pg;
169: short *ap;
170:
171: mie = (struct mie_device *) sip->si_devaddr;
172: mie->mie_peack = 1;
173: mie->mie_noloop = 0;
174: mie->mie_ie = 0;
175: mie->mie_pie = 0;
176: paddr = mie->mie_mbmhi << 16;
177: ap = (short *)mie->mie_pgmap;
178: for (i=0; i<IEVVSIZ; i++) /* note: sets p2mem -> 0 */
179: *ap++ = 0;
180: for (i=0; i<IEPHYMEMSIZ/IEPAGSIZ; i++) {
181: mie->mie_pgmap[0].mp_pfnum = i;
182: }
183: pg = &mie->mie_pgmap[0];
184: for (i=0; i<IEVIRMEMSIZ/IEPAGSIZ; i++) {
185: pg->mp_swab = 1;
186: pg->mp_pfnum = i;
187: pg++;
188: }
189: /* last page for chip init */
190: mie->mie_pgmap[IEVVSIZ-1].mp_pfnum = (PROTOSCRATCH/IEPAGSIZ)-1;
191: es = (struct ie_softc *)
192: devalloc(MAP_MBMEM, paddr, sizeof(struct ie_softc));
193: bzero((char *)es, sizeof *es);
194: es->es_type = IE_MB;
195: es->es_mie = mie;
196: }
197: /* FIXME, release multibus resources ifdef. */
198: sip->si_devdata = (caddr_t)es;
199: return iereset(es, sip);
200: }
201:
202: /*
203: * Basic 82586 initialization
204: * Returns 1 for error, 0 for ok.
205: */
206: int
207: iereset(es, sip)
208: register struct ie_softc *es;
209: struct saioreq *sip;
210: {
211: struct ieiscp *iscp = &es->es_iscp;
212: struct iescb *scb = &es->es_scb;
213: struct ieiaddr *iad = &es->es_iaddr;
214: struct ieconf *ic = &es->es_ic;
215: int j;
216: int savepmap;
217: register struct mie_device *mie = es->es_mie;
218: register struct obie_device *obie = es->es_obie;
219:
220: for (j = 0; j < 10; j++) {
221: /* Set up the control blocks for initializing the chip */
222: bzero((caddr_t)&es->es_scp, sizeof (struct iescp));
223: es->es_scp.ie_iscp = to_ieaddr(es, (caddr_t)iscp);
224: bzero((caddr_t)iscp, sizeof (struct ieiscp));
225: iscp->ie_busy = 1;
226: iscp->ie_scb = to_ieoff(es, (caddr_t)scb);
227: iscp->ie_cbbase = to_ieaddr(es, (caddr_t)es);
228: bzero((caddr_t)scb, sizeof (struct iescb));
229: if (es->es_type == IE_OB) {
230: /*
231: * The 82586 has bugs that require us to be in
232: * loopback mode while we initialize it, to avoid
233: * transitions on CRS (carrier sense).
234: *
235: * However, the Intel serial interface chip used
236: * on Carrera also has bugs: if it powers-up in
237: * loopback, you have to release loopback at least
238: * once to make it behave -- it powers up with
239: * CRS and CDT permanently active, which rapes the 586.
240: *
241: * How do you spell "broken"? I-N-T-E-L...
242: */
243: *obie = obie_reset; /* Reset chip & interface */
244: DELAY(20);
245: obie->obie_noloop = 0; /* Put it in loopback now */
246: DELAY(20);
247: obie->obie_noreset = 1; /* Release Reset on 82586 */
248: DELAY(200);
249: /*
250: * Now set up to let the Ethernet chip read the SCP.
251: * Intel wired in the address of the SCP. It happens
252: * to be 0xFFFFF6.
253: */
254: savepmap = getpgmap(SCP_LOC);
255: setpgmap(SCP_LOC, getpgmap((char *)&es->es_scp));
256: } else {
257: mie->mie_reset = 1;
258: DELAY(20);
259: mie->mie_reset = 0;
260: DELAY(200);
261: }
262:
263: /*
264: * We are set up. Give the chip a zap, then wait up to
265: * 1 sec, or until chip comes ready.
266: */
267: ieca(es);
268: CDELAY(iscp->ie_busy != 1, 1000);
269:
270: /* Whether or not it worked, we have to clean up. */
271: if (es->es_type == IE_OB) {
272: /* If it didn't init, reset chip again. */
273: if (iscp->ie_busy == 1)
274: obie->obie_noreset = 0;
275: setpgmap(SCP_LOC, savepmap);
276: }
277: if (iscp->ie_busy == 1)
278: continue; /* Continue loop until we get it */
279:
280: /*
281: * Now try to run a few simple commands before we say "OK".
282: */
283: bzero((caddr_t)iad, sizeof (struct ieiaddr));
284: iad->ieia_cb.ie_cmd = IE_IADDR;
285: myetheraddr((struct ether_addr *)iad->ieia_addr);
286: if (iesimple(es, &iad->ieia_cb)) {
287: printf("ie: hang while setting Ethernet address.\n");
288: continue;
289: }
290:
291: iedefaultconf(ic);
292: if (iesimple(es, &ic->ieconf_cb)) {
293: printf("ie: hang while setting chip config.\n");
294: continue;
295: }
296:
297: /*
298: * Take the Ethernet interface chip out of loopback mode, i.e.
299: * put us on the wire. We can't do this before having
300: * initialized the Ethernet chip because the chip does random
301: * things if its 'wire' is active between the time it's reset
302: * and the first CA. Also, the IA-setup and configure commands
303: * will hang under some conditions unless the interface is
304: * very quiet and still.
305: */
306: if (es->es_type == IE_OB)
307: obie->obie_noloop = 1;
308: if (es->es_type == IE_MB)
309: mie->mie_noloop = 1;
310: if (ierustart(es)) {
311: printf("ie: hang while starting receiver.\n");
312: continue;
313: }
314:
315: return 0; /* It all worked! */
316: }
317:
318: /* We tried a bunch of times, no luck. */
319: printf("ie: cannot initialize\n");
320: return 1;
321: }
322:
323: /*
324: * Initialize and start the Receive Unit
325: */
326: int
327: ierustart(es)
328: register struct ie_softc *es;
329: {
330: register struct ierbd *rbd = &es->es_rbd;
331: struct ierbd *rbd2 = &es->es_rbd2;
332: register struct ierfd *rfd = &es->es_rfd;
333: register struct iescb *scb = &es->es_scb;
334: int timebomb = TIMEBOMB;
335:
336: /*
337: * Stop the RU, since we're sharing buffers with it.
338: * Then wait until it has really stopped.
339: */
340: while (scb->ie_rus == IERUS_READY) {
341: while (scb->ie_cmd != 0) /* XXX */
342: if (timebomb-- <= 0) return TIMEOUT;
343: scb->ie_cmd = IECMD_RU_ABORT;
344: ieca(es);
345: }
346:
347: while (scb->ie_cmd != 0) /* XXX */
348: if (timebomb-- <= 0) return TIMEOUT;
349:
350: /* Real receive buffer descriptor */
351: *(short *)rbd = 0;
352: rbd->ierbd_next = to_ieoff(es, (caddr_t)rbd2); /* Fake */
353: rbd->ierbd_el = 0; /* Fake */
354: rbd->ierbd_buf = to_ieaddr(es, es->es_rbuf);
355: rbd->ierbd_sizehi = IERBUFSIZ >> 8;
356: rbd->ierbd_sizelo = IERBUFSIZ & 0xFF;
357:
358: /* Fake receive buffer to avoid chip lockups in B0 mask */
359: *(short *)rbd2 = 0;
360: rbd2->ierbd_next = -1; /* unnecessary since el = 1 */
361: rbd2->ierbd_el = 1;
362: rbd2->ierbd_buf = to_ieaddr(es, es->es_rbuf2);
363: rbd2->ierbd_sizehi = 0;
364: rbd2->ierbd_sizelo = sizeof(es->es_rbuf2) & 0xFF;
365:
366: /* Real receive frame descriptor */
367: *(short *)rfd = 0;
368: rfd->ierfd_next = -1; /* Unused since el = 1 */
369: rfd->ierfd_el = 1;
370: rfd->ierfd_susp = 1; /* Suspend after receiving one */
371: rfd->ierfd_rbd = to_ieoff(es, (caddr_t)rbd);
372:
373: /*
374: * Start the RU again.
375: */
376: scb->ie_rfa = to_ieoff(es, (caddr_t)rfd);
377: scb->ie_cmd = IECMD_RU_START;
378: ieca(es);
379: return OK;
380: }
381:
382: ieca(es)
383: register struct ie_softc *es;
384: {
385: if (es->es_type == IE_OB) {
386: es->es_obie->obie_ca = 1;
387: es->es_obie->obie_ca = 0;
388: } else {
389: es->es_mie->mie_ca = 1;
390: es->es_mie->mie_ca = 0;
391: }
392: }
393:
394: int
395: iesimple(es, cb)
396: register struct ie_softc *es;
397: register struct iecb *cb;
398: {
399: register struct iescb *scb = &es->es_scb;
400: register timebomb = TIMEBOMB;
401:
402: *(short *)cb = 0; /* clear status bits */
403: cb->ie_el = 1;
404: cb->ie_next = 0;
405:
406: /* start CU */
407: while (scb->ie_cmd != 0) /* XXX */
408: if (timebomb-- <= 0) return TIMEOUT;
409: scb->ie_cbl = to_ieoff(es, (caddr_t)cb);
410: scb->ie_cmd = IECMD_CU_START;
411: if (scb->ie_cx)
412: scb->ie_cmd |= IECMD_ACK_CX;
413: if (scb->ie_cnr)
414: scb->ie_cmd |= IECMD_ACK_CNR;
415: ieca(es);
416: while (!cb->ie_done) /* XXX */
417: if (timebomb-- <= 0) return TIMEOUT;
418: while (scb->ie_cmd != 0) /* XXX */
419: if (timebomb-- <= 0) return TIMEOUT;
420: if (scb->ie_cx)
421: scb->ie_cmd |= IECMD_ACK_CX;
422: if (scb->ie_cnr)
423: scb->ie_cmd |= IECMD_ACK_CNR;
424: ieca(es);
425: return OK;
426: }
427:
428: /*
429: * Transmit a packet.
430: * Always copy the packet for the sake of Multibus
431: * boards and Sun3's. This is not a performance critical situation
432: */
433: iexmit(es, buf, count)
434: register struct ie_softc *es;
435: char *buf;
436: int count;
437: {
438: register struct ietbd *tbd = &es->es_tbd;
439: register struct ietfd *td = &es->es_tfd;
440:
441: bzero((caddr_t)tbd, sizeof *tbd);
442: tbd->ietbd_eof = 1;
443: tbd->ietbd_cntlo = count & 0xFF;
444: tbd->ietbd_cnthi = count >> 8;
445: bcopy(buf, es->es_xbuf, count);
446: tbd->ietbd_buf = to_ieaddr(es, es->es_xbuf);
447: td->ietfd_tbd = to_ieoff(es, (caddr_t)tbd);
448: td->ietfd_cmd = IE_TRANSMIT;
449: if (iesimple(es, (struct iecb *)td)) {
450: printf("ie: xmit hang\n");
451: return -1;
452: }
453: #ifdef DEBUG
454: if (!td->ietfd_ok) {
455: /* Print status bits from transmit command */
456: printf("ie xmit failed: %x\n", *(unsigned short *)td);
457: }
458: #endif DEBUG
459: if (td->ietfd_ok)
460: return (0);
461: if (td->ietfd_xcoll)
462: printf("ie: Ethernet cable problem\n");
463: return (-1);
464: }
465:
466:
467:
468: int
469: iepoll(es, buf)
470: register struct ie_softc *es;
471: char *buf;
472: {
473: register struct ierbd *rbd = &es->es_rbd;
474: register struct ierfd *rfd = &es->es_rfd;
475: register struct iescb *scb = &es->es_scb;
476: int len;
477: int timebomb = TIMEBOMB;
478:
479: #ifdef DEBUG
480: /* Check for error status, and printf if so */
481: /*
482: * Resource errors should be ignored, they happen even when we
483: * are not interested in listening.
484: */
485: if (scb->ie_crcerrs || scb->ie_alnerrs || scb->ie_ovrnerrs) {
486: printf("ie recv %x CRC %d, ALN %d, OVRN %d\n",
487: scb->ie_rus,
488: from_ieint(scb->ie_crcerrs),
489: from_ieint(scb->ie_alnerrs),
490: from_ieint(scb->ie_ovrnerrs));
491: scb->ie_crcerrs = 0;
492: scb->ie_alnerrs = 0;
493: scb->ie_ovrnerrs = 0;
494: }
495: #endif DEBUG
496:
497: /*
498: * Note, this assumes that the RU is set up to get out of READY
499: * state after receiving one packet.
500: */
501: if (scb->ie_rus == IERUS_READY) {
502: return (0); /* No packet yet */
503: } else {
504: /* RU not ready, see if because we got a packet. */
505: if (!rfd->ierfd_done || !rbd->ierbd_eof) {
506: /* No, randomness zapped it. */
507: #ifdef DEBUG
508: printf("ie recv restart from %x: scb %x frm %x buf %x\n"
509: , scb->ie_rus,
510: *(unsigned short *)scb, *(unsigned short *)rfd,
511: *(unsigned short *)rbd);
512: #endif DEBUG
513: ierustart(es);
514: return (0);
515: }
516: }
517:
518: /*
519: * We got a packet.
520: */
521: len = (rbd->ierbd_cnthi << 8) + rbd->ierbd_cntlo;
522: bcopy(es->es_rbuf, buf, len);
523: while (scb->ie_cmd != 0) /* XXX */
524: if (timebomb-- <= 0) return TIMEOUT;
525: if (scb->ie_fr)
526: scb->ie_cmd |= IECMD_ACK_FR;
527: if (scb->ie_rnr)
528: scb->ie_cmd |= IECMD_ACK_RNR;
529: ieca(es);
530: ierustart(es);
531: return (len);
532: }
533:
534: /*
535: * Convert a CPU virtual address into an Ethernet virtual address.
536: *
537: * For Multibus, we assume it's in the Ethernet's memory space, and we
538: * just subtract off the start of the memory space (==es). For Model 50,
539: * the Ethernet chip has full access to supervisor virtual memory.
540: * For Carrera, the chip can access the top 16MB of virtual memory,
541: * but we never give it addresses outside that range, so the high
542: * order bits can be ignored.
543: */
544: ieaddr_t
545: to_ieaddr(es, cp)
546: struct ie_softc *es;
547: caddr_t cp;
548: {
549: union {
550: int n;
551: char c[4];
552: } a, b;
553:
554: #ifdef SUN3
555: #ifdef DEBUG
556: if (cp < (char *)0x0F000000 || cp >= (char *)0x10000000) {
557: /* printf("Bad ptr to_ieaddr(%x)\n", cp); */
558: ; asm(" .word 0xFFFF") ; ;
559: }
560: #endif DEBUG
561: #endif SUN3
562: if (es->es_type == IE_MB)
563: a.n = cp - (caddr_t)es;
564: else /* if (es->es_type == IE_OB) */
565: a.n = (int)cp;
566: b.c[0] = a.c[3];
567: b.c[1] = a.c[2];
568: b.c[2] = a.c[1];
569: b.c[3] = 0;
570: return (b.n);
571: }
572:
573: /*
574: * Convert a CPU virtual address into a 16-bit offset for the Ethernet
575: * chip.
576: *
577: * This is the same for Onboard and Multibus, since the offset is based
578: * on the absolute address supplied in the initial system configuration
579: * block -- which we customize for Multibus or Onboard.
580: */
581: ieoff_t
582: to_ieoff(es, addr)
583: register struct ie_softc *es;
584: caddr_t addr;
585: {
586: union {
587: short s;
588: char c[2];
589: } a, b;
590:
591: a.s = (short)(addr - (caddr_t)es);
592: b.c[0] = a.c[1];
593: b.c[1] = a.c[0];
594: return (b.s);
595: }
596:
597:
598: #ifdef DEBUG
599: ieint_t
600: from_ieint(n)
601: short n;
602: {
603: union {
604: short s;
605: char c[2];
606: } a, b;
607:
608: a.s = n;
609: b.c[0] = a.c[1];
610: b.c[1] = a.c[0];
611: return (b.s);
612: }
613: #endif DEBUG
614:
615: /*
616: * Set default configuration parameters
617: * As spec'd by Intel, except acloc == 1 for header in data
618: */
619: iedefaultconf(ic)
620: register struct ieconf *ic;
621: {
622: bzero((caddr_t)ic, sizeof (struct ieconf));
623: ic->ieconf_cb.ie_cmd = IE_CONFIG;
624: ic->ieconf_bytes = 12;
625: ic->ieconf_fifolim = 8;
626: ic->ieconf_pream = 2; /* 8 byte preamble */
627: ic->ieconf_alen = 6;
628: ic->ieconf_acloc = 1;
629: ic->ieconf_space = 96;
630: ic->ieconf_slttmh = 512 >> 8;
631: ic->ieconf_minfrm = 64;
632: ic->ieconf_retry = 15;
633: }
634:
635: /*
636: * Close down intel ethernet device.
637: * On the Model 50, we reset the chip and take it off the wire, since
638: * it is sharing main memory with us (occasionally reading and writing),
639: * and most programs don't know how to deal with that -- they just assume
640: * that main memory is theirs to play with.
641: */
642: ieclose(sip)
643: struct saioreq *sip;
644: {
645: register struct ie_softc *es = (struct ie_softc *) sip->si_devdata;
646:
647: if (es->es_type == IE_OB)
648: *es->es_obie = obie_reset;
649: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.