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