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