|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Computer Consoles Inc.
7: *
8: * Redistribution is only permitted until one year after the first shipment
9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
10: * binary forms are permitted provided that: (1) source distributions retain
11: * this entire copyright notice and comment, and (2) distributions including
12: * binaries display the following acknowledgement: This product includes
13: * software developed by the University of California, Berkeley and its
14: * contributors'' in the documentation or other materials provided with the
15: * distribution and in all advertising materials mentioning features or use
16: * of this software. Neither the name of the University nor the names of
17: * its contributors may be used to endorse or promote products derived from
18: * this software without specific prior written permission.
19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22: *
23: * @(#)if_enp.c 7.7 (Berkeley) 6/28/90
24: */
25:
26: #include "enp.h"
27: #if NENP > 0
28: /*
29: * CMC ENP-20 Ethernet Controller.
30: */
31: #include "param.h"
32: #include "systm.h"
33: #include "mbuf.h"
34: #include "buf.h"
35: #include "protosw.h"
36: #include "socket.h"
37: #include "vmmac.h"
38: #include "ioctl.h"
39: #include "errno.h"
40: #include "vmparam.h"
41: #include "syslog.h"
42: #include "uio.h"
43:
44: #include "../net/if.h"
45: #include "../net/netisr.h"
46: #include "../net/route.h"
47: #ifdef INET
48: #include "../netinet/in.h"
49: #include "../netinet/in_systm.h"
50: #include "../netinet/in_var.h"
51: #include "../netinet/ip.h"
52: #include "../netinet/ip_var.h"
53: #include "../netinet/if_ether.h"
54: #endif
55: #ifdef NS
56: #include "../netns/ns.h"
57: #include "../netns/ns_if.h"
58: #endif
59:
60: #include "../tahoe/cpu.h"
61: #include "../tahoe/pte.h"
62: #include "../tahoe/mtpr.h"
63:
64: #include "../tahoevba/vbavar.h"
65: #include "../tahoeif/if_enpreg.h"
66:
67: #define ENPSTART 0xf02000 /* standard enp start addr */
68: #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */
69: /* macros for dealing with longs in i/o space */
70: #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
71: #define ENPSETLONG(a,v) \
72: { register u_short *wp = (u_short *)(a); \
73: wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
74:
75: int enpprobe(), enpattach(), enpintr();
76: long enpstd[] = { 0xfff41000, 0xfff61000, 0 };
77: struct vba_device *enpinfo[NENP];
78: struct vba_driver enpdriver =
79: { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
80:
81: int enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart();
82: struct mbuf *enpget();
83:
84: /*
85: * Ethernet software status per interface.
86: *
87: * Each interface is referenced by a network interface structure,
88: * es_if, which the routing code uses to locate the interface.
89: * This structure contains the output queue for the interface, its address, ...
90: */
91: struct enp_softc {
92: struct arpcom es_ac; /* common ethernet structures */
93: #define es_if es_ac.ac_if
94: #define es_addr es_ac.ac_enaddr
95: short es_ivec; /* interrupt vector */
96: } enp_softc[NENP];
97: extern struct ifnet loif;
98:
99: enpprobe(reg, vi)
100: caddr_t reg;
101: struct vba_device *vi;
102: {
103: register br, cvec; /* must be r12, r11 */
104: register struct enpdevice *addr = (struct enpdevice *)reg;
105: struct enp_softc *es = &enp_softc[vi->ui_unit];
106:
107: #ifdef lint
108: br = 0; cvec = br; br = cvec;
109: enpintr(0);
110: #endif
111: if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
112: return (0);
113: es->es_ivec = --vi->ui_hd->vh_lastiv;
114: addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */
115: br = 0x14, cvec = es->es_ivec; /* XXX */
116: return (sizeof (struct enpdevice));
117: }
118:
119: /*
120: * Interface exists: make available by filling in network interface
121: * record. System will initialize the interface when it is ready
122: * to accept packets.
123: */
124: enpattach(ui)
125: register struct vba_device *ui;
126: {
127: struct enp_softc *es = &enp_softc[ui->ui_unit];
128: register struct ifnet *ifp = &es->es_if;
129:
130: ifp->if_unit = ui->ui_unit;
131: ifp->if_name = "enp";
132: ifp->if_mtu = ETHERMTU;
133: ifp->if_init = enpinit;
134: ifp->if_ioctl = enpioctl;
135: ifp->if_output = ether_output;
136: ifp->if_start = enpstart;
137: ifp->if_reset = enpreset;
138: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
139: if_attach(ifp);
140: }
141:
142: /*
143: * Reset of interface after "system" reset.
144: */
145: enpreset(unit, vban)
146: int unit, vban;
147: {
148: register struct vba_device *ui;
149:
150: if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
151: ui->ui_vbanum != vban)
152: return;
153: printf(" enp%d", unit);
154: enpinit(unit);
155: }
156:
157: /*
158: * Initialization of interface; clear recorded pending operations.
159: */
160: enpinit(unit)
161: int unit;
162: {
163: struct enp_softc *es = &enp_softc[unit];
164: register struct vba_device *ui = enpinfo[unit];
165: struct enpdevice *addr;
166: register struct ifnet *ifp = &es->es_if;
167: int s;
168:
169: if (ifp->if_addrlist == (struct ifaddr *)0)
170: return;
171: if ((ifp->if_flags & IFF_RUNNING) == 0) {
172: addr = (struct enpdevice *)ui->ui_addr;
173: s = splimp();
174: RESET_ENP(addr);
175: DELAY(200000);
176: es->es_if.if_flags |= IFF_RUNNING;
177: splx(s);
178: }
179: }
180:
181: /*
182: * Ethernet interface interrupt.
183: */
184: enpintr(unit)
185: int unit;
186: {
187: register struct enpdevice *addr;
188: register BCB *bcbp;
189:
190: addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
191: #if ENP == 30
192: if (!IS_ENP_INTR(addr))
193: return;
194: ACK_ENP_INTR(addr);
195: #endif
196: while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
197: enpread(&enp_softc[unit], bcbp);
198: (void) ringput((RING *)&addr->enp_enpfree, bcbp);
199: }
200: }
201:
202: /*
203: * Read input packet, examine its packet type, and enqueue it.
204: */
205: enpread(es, bcbp)
206: struct enp_softc *es;
207: register BCB *bcbp;
208: {
209: register struct ether_header *enp;
210: struct mbuf *m;
211: int s, len, off, resid;
212:
213: es->es_if.if_ipackets++;
214: /*
215: * Get input data length.
216: * Get pointer to ethernet header (in input buffer).
217: * Deal with trailer protocol: if type is PUP trailer
218: * get true type from first 16-bit word past data.
219: * Remember that type was trailer by setting off.
220: */
221: len = bcbp->b_msglen - sizeof (struct ether_header);
222: enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
223: #define enpdataaddr(enp, off, type) \
224: ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
225: enp->ether_type = ntohs((u_short)enp->ether_type);
226: if (enp->ether_type >= ETHERTYPE_TRAIL &&
227: enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
228: off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
229: if (off >= ETHERMTU)
230: return;
231: enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
232: resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
233: if (off + resid > len)
234: return;
235: len = off + resid;
236: } else
237: off = 0;
238: if (len == 0)
239: return;
240:
241: /*
242: * Pull packet off interface. Off is nonzero if packet
243: * has trailing header; enpget will then force this header
244: * information to be at the front.
245: */
246: m = enpget((u_char *)enp, len, off, &es->es_if);
247: if (m == 0)
248: return;
249: ether_input(&es->es_if, enp, m);
250: }
251:
252: enpstart(ifp)
253: struct ifnet *ifp;
254: {
255:
256: if (enpput(ifp))
257: return (ENOBUFS);
258: else
259: return (0);
260: }
261:
262: /*
263: * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
264: */
265: enpput(ifp)
266: struct ifnet *ifp;
267: {
268: register BCB *bcbp;
269: register struct enpdevice *addr;
270: register struct mbuf *mp;
271: register u_char *bp;
272: register u_int len;
273: int unit = ifp->if_unit, ret = 1;
274: struct mbuf *m;
275:
276: addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
277: again:
278: if (ringempty((RING *)&addr->enp_hostfree)) {
279: /* ifp->if_flags |= IFF_OACTIVE; */
280: return (ret);
281: }
282: IF_DEQUEUE(&ifp->if_snd, m);
283: if (m == 0) {
284: ifp->if_flags &= ~IFF_OACTIVE;
285: return (0);
286: }
287: bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
288: bcbp->b_len = 0;
289: bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
290: for (mp = m; mp; mp = mp->m_next) {
291: len = mp->m_len;
292: if (len == 0)
293: continue;
294: enpcopy(mtod(mp, u_char *), bp, len);
295: bp += len;
296: bcbp->b_len += len;
297: }
298: bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
299: bcbp->b_reserved = 0;
300: if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
301: INTR_ENP(addr);
302: m_freem(m);
303: ret = 0;
304: goto again;
305: }
306:
307: /*
308: * Routine to copy from VERSAbus memory into mbufs.
309: *
310: * Warning: This makes the fairly safe assumption that
311: * mbufs have even lengths.
312: */
313: struct mbuf *
314: enpget(rxbuf, totlen, off, ifp)
315: u_char *rxbuf;
316: int totlen, off;
317: struct ifnet *ifp;
318: {
319: register u_char *cp;
320: register struct mbuf *m;
321: struct mbuf *top = 0, **mp = ⊤
322: int len;
323: u_char *packet_end;
324:
325: rxbuf += sizeof (struct ether_header);
326: cp = rxbuf;
327: packet_end = cp + totlen;
328: if (off) {
329: off += 2 * sizeof(u_short);
330: totlen -= 2 *sizeof(u_short);
331: cp = rxbuf + off;
332: }
333:
334: MGETHDR(m, M_DONTWAIT, MT_DATA);
335: if (m == 0)
336: return (0);
337: m->m_pkthdr.rcvif = ifp;
338: m->m_pkthdr.len = totlen;
339: m->m_len = MHLEN;
340:
341: while (totlen > 0) {
342: if (top) {
343: MGET(m, M_DONTWAIT, MT_DATA);
344: if (m == 0) {
345: m_freem(top);
346: return (0);
347: }
348: m->m_len = MLEN;
349: }
350: len = min(totlen, (packet_end - cp));
351: if (len >= MINCLSIZE) {
352: MCLGET(m, M_DONTWAIT);
353: if (m->m_flags & M_EXT)
354: m->m_len = len = min(len, MCLBYTES);
355: else
356: len = m->m_len;
357: } else {
358: /*
359: * Place initial small packet/header at end of mbuf.
360: */
361: if (len < m->m_len) {
362: if (top == 0 && len + max_linkhdr <= m->m_len)
363: m->m_data += max_linkhdr;
364: m->m_len = len;
365: } else
366: len = m->m_len;
367: }
368: enpcopy(cp, mtod(m, u_char *), (u_int)len);
369: *mp = m;
370: mp = &m->m_next;
371: totlen -= len;
372: cp += len;
373: if (cp == packet_end)
374: cp = rxbuf;
375: }
376: return (top);
377: }
378:
379: enpcopy(from, to, cnt)
380: register u_char *from, *to;
381: register u_int cnt;
382: {
383: register c;
384: register short *f, *t;
385:
386: if (((int)from&01) && ((int)to&01)) {
387: /* source & dest at odd addresses */
388: *to++ = *from++;
389: --cnt;
390: }
391: if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
392: t = (short *)to;
393: f = (short *)from;
394: for (c = cnt>>1; c; --c) /* even address copy */
395: *t++ = *f++;
396: cnt &= 1;
397: if (cnt) { /* odd len */
398: from = (u_char *)f;
399: to = (u_char *)t;
400: *to = *from;
401: }
402: }
403: while ((int)cnt-- > 0) /* one of the address(es) must be odd */
404: *to++ = *from++;
405: }
406:
407: /*
408: * Process an ioctl request.
409: */
410: enpioctl(ifp, cmd, data)
411: register struct ifnet *ifp;
412: int cmd;
413: caddr_t data;
414: {
415: register struct ifaddr *ifa = (struct ifaddr *)data;
416: struct enpdevice *addr;
417: int s = splimp(), error = 0;
418:
419: switch (cmd) {
420:
421: case SIOCSIFADDR:
422: ifp->if_flags |= IFF_UP;
423: switch (ifa->ifa_addr->sa_family) {
424: #ifdef INET
425: case AF_INET:
426: enpinit(ifp->if_unit);
427: ((struct arpcom *)ifp)->ac_ipaddr =
428: IA_SIN(ifa)->sin_addr;
429: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
430: break;
431: #endif
432: #ifdef NS
433: case AF_NS: {
434: struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
435: struct enp_softc *es = &enp_softc[ifp->if_unit];
436:
437: if (!ns_nullhost(*ina)) {
438: ifp->if_flags &= ~IFF_RUNNING;
439: addr = (struct enpdevice *)
440: enpinfo[ifp->if_unit]->ui_addr;
441: enpsetaddr(ifp->if_unit, addr,
442: ina->x_host.c_host);
443: } else
444: ina->x_host = *(union ns_host *)es->es_addr;
445: enpinit(ifp->if_unit);
446: break;
447: }
448: #endif
449: default:
450: enpinit(ifp->if_unit);
451: break;
452: }
453: break;
454:
455: case SIOCSIFFLAGS:
456: if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
457: enpinit(ifp->if_unit); /* reset board */
458: ifp->if_flags &= ~IFF_RUNNING;
459: } else if (ifp->if_flags&IFF_UP &&
460: (ifp->if_flags&IFF_RUNNING) == 0)
461: enpinit(ifp->if_unit);
462: break;
463:
464: default:
465: error = EINVAL;
466: }
467: splx(s);
468: return (error);
469: }
470:
471: enpsetaddr(unit, addr, enaddr)
472: int unit;
473: struct enpdevice *addr;
474: u_char *enaddr;
475: {
476:
477: enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
478: sizeof (struct ether_addr));
479: enpinit(unit);
480: enpgetaddr(unit, addr);
481: }
482:
483: enpgetaddr(unit, addr)
484: int unit;
485: struct enpdevice *addr;
486: {
487: struct enp_softc *es = &enp_softc[unit];
488:
489: enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
490: sizeof (struct ether_addr));
491: printf("enp%d: hardware address %s\n",
492: unit, ether_sprintf(es->es_addr));
493: }
494:
495: /*
496: * Routines to synchronize enp and host.
497: */
498: #ifdef notdef
499: static
500: ringinit(rp, size)
501: register RING *rp;
502: {
503:
504: rp->r_rdidx = rp->r_wrtidx = 0;
505: rp->r_size = size;
506: }
507:
508: static
509: ringfull(rp)
510: register RING *rp;
511: {
512: register short idx;
513:
514: idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
515: return (idx == rp->r_rdidx);
516: }
517:
518: static
519: fir(rp)
520: register RING *rp;
521: {
522:
523: return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
524: }
525: #endif
526:
527: static
528: ringempty(rp)
529: register RING *rp;
530: {
531:
532: return (rp->r_rdidx == rp->r_wrtidx);
533: }
534:
535: static
536: ringput(rp, v)
537: register RING *rp;
538: BCB *v;
539: {
540: register int idx;
541:
542: idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
543: if (idx != rp->r_rdidx) {
544: ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
545: rp->r_wrtidx = idx;
546: if ((idx -= rp->r_rdidx) < 0)
547: idx += rp->r_size;
548: return (idx); /* num ring entries */
549: }
550: return (0);
551: }
552:
553: static
554: ringget(rp)
555: register RING *rp;
556: {
557: register int i = 0;
558:
559: if (rp->r_rdidx != rp->r_wrtidx) {
560: i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
561: rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
562: }
563: return (i);
564: }
565:
566: /*
567: * ENP Ram device.
568: */
569: enpr_open(dev)
570: dev_t dev;
571: {
572: register int unit = ENPUNIT(dev);
573: struct vba_device *ui;
574: struct enpdevice *addr;
575:
576: if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
577: (addr = (struct enpdevice *)ui->ui_addr) == 0)
578: return (ENODEV);
579: if (addr->enp_state != S_ENPRESET)
580: return (EACCES); /* enp is not in reset state, don't open */
581: return (0);
582: }
583:
584: /*ARGSUSED*/
585: enpr_close(dev)
586: dev_t dev;
587: {
588:
589: return (0);
590: }
591:
592: enpr_read(dev, uio)
593: dev_t dev;
594: register struct uio *uio;
595: {
596: register struct iovec *iov;
597: struct enpdevice *addr;
598:
599: if (uio->uio_offset > RAM_SIZE)
600: return (ENODEV);
601: iov = uio->uio_iov;
602: if (uio->uio_offset + iov->iov_len > RAM_SIZE)
603: iov->iov_len = RAM_SIZE - uio->uio_offset;
604: addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
605: if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
606: return (EFAULT);
607: enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
608: (u_char *)iov->iov_base, (u_int)iov->iov_len);
609: uio->uio_resid -= iov->iov_len;
610: iov->iov_len = 0;
611: return (0);
612: }
613:
614: enpr_write(dev, uio)
615: dev_t dev;
616: register struct uio *uio;
617: {
618: register struct enpdevice *addr;
619: register struct iovec *iov;
620:
621: addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
622: iov = uio->uio_iov;
623: if (uio->uio_offset > RAM_SIZE)
624: return (ENODEV);
625: if (uio->uio_offset + iov->iov_len > RAM_SIZE)
626: iov->iov_len = RAM_SIZE - uio->uio_offset;
627: if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
628: return (EFAULT);
629: enpcopy((u_char *)iov->iov_base,
630: (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
631: uio->uio_resid -= iov->iov_len;
632: uio->uio_offset += iov->iov_len;
633: iov->iov_len = 0;
634: return (0);
635: }
636:
637: /*ARGSUSED*/
638: enpr_ioctl(dev, cmd, data)
639: dev_t dev;
640: caddr_t data;
641: {
642: register unit = ENPUNIT(dev);
643: struct enpdevice *addr;
644:
645: addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
646: switch(cmd) {
647:
648: case ENPIOGO:
649: ENPSETLONG(&addr->enp_base, addr);
650: addr->enp_intrvec = enp_softc[unit].es_ivec;
651: ENP_GO(addr, ENPSTART);
652: DELAY(200000);
653: enpinit(unit);
654: /*
655: * Fetch Ethernet address after link level
656: * is booted (firmware copies manufacturer's
657: * address from on-board ROM).
658: */
659: enpgetaddr(unit, addr);
660: addr->enp_state = S_ENPRUN;
661: break;
662:
663: case ENPIORESET:
664: RESET_ENP(addr);
665: addr->enp_state = S_ENPRESET;
666: DELAY(100000);
667: break;
668: default:
669: return (EINVAL);
670: }
671: return (0);
672: }
673: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.