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