xref: /original-bsd/sys/tahoe/if/if_ace.c (revision 226df7bf)
1 /*	if_ace.c	1.1	85/07/21	*/
2 
3 /*
4  * ACC VERSAbus Ethernet controller
5  */
6 #include "ace.h"
7 #if NACE > 0
8 
9 #include "../machine/pte.h"
10 
11 #include "../h/param.h"
12 #include "../h/systm.h"
13 #include "../h/mbuf.h"
14 #include "../h/buf.h"
15 #include "../h/protosw.h"
16 #include "../h/socket.h"
17 #include "../h/vmmac.h"
18 #include "../h/ioctl.h"
19 #include "../h/errno.h"
20 #include "../h/vmparam.h"
21 
22 #include "../net/if.h"
23 #include "../net/netisr.h"
24 #include "../net/route.h"
25 #include "../netinet/in.h"
26 #include "../netinet/in_systm.h"
27 #include "../netinet/ip.h"
28 #include "../netinet/ip_var.h"
29 #include "../netinet/if_ether.h"
30 #include "../netpup/pup.h"
31 
32 #include "../tahoe/mtpr.h"
33 #include "../tahoeif/if_acereg.h"
34 #include "../vba/vbavar.h"
35 
36 #define	LONET	124
37 
38 /*
39  * Configuration table, for 2 units (should be defined by config)
40  */
41 #define	ACEVECTOR	0x90
42 long	acestd[] = { 0x0ff0000, 0xff0100 };		/* controller */
43 
44 extern	char ace0utl[], ace1utl[];			/* dpm */
45 char	*acemap[]= { ace0utl, ace1utl };
46 extern	long ACE0map[], ACE1map[];
47 long	*ACEmap[] = { ACE0map, ACE1map };
48 long	ACEmapa[] = { 0xfff80000, 0xfff90000 };
49 
50 /* station address */
51 char	ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 };
52 /* multicast hash table initializer */
53 char	ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF };
54 /* backoff table masks */
55 short random_mask_tbl[16] = {
56 	0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
57 	0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
58 };
59 
60 int	aceprobe(), aceattach(), acerint(), acecint();
61 struct	vba_device *aceinfo[NACE];
62 struct	vba_driver acedriver =
63 	{ aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
64 
65 #define	ACEUNIT(x)	minor(x)
66 
67 int	aceinit(), aceoutput(), aceioctl(), acereset();
68 struct	mbuf *aceget();
69 
70 /*
71  * Ethernet software status per interface.
72  *
73  * Each interface is referenced by a network interface structure,
74  * is_if, which the routing code uses to locate the interface.
75  * This structure contains the output queue for the interface, its address, ...
76  */
77 struct	ace_softc {
78 	struct	arpcom is_ac;		/* Ethernet common part	*/
79 #define	is_if	is_ac.ac_if		/* network-visible interface */
80 #define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address */
81 	char	*is_dpm;
82 	short	is_flags;
83 #define	ACEF_OACTIVE	0x1		/* output is active */
84 #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
85 	short	is_promiscuous;		/* true is enabled */
86 	short	is_segboundry;		/* first TX Seg in dpm */
87 	short	is_eictr;		/* Rx segment tracking ctr */
88 	short	is_eoctr;		/* Tx segment tracking ctr */
89 	short	is_txnext;		/* Next available Tx segment */
90 	short	is_currnd;		/* current random backoff */
91 	struct	ace_stats is_stats;	/* holds board statistics */
92 	short	is_xcnt;		/* count xmitted segments to be acked
93 					   by the controller */
94 } ace_softc[NACE];
95 extern	struct ifnet loif;
96 
97 aceprobe(reg)
98 	caddr_t reg;
99 {
100 	register struct acedevice *addr = (struct acedevice *)reg;
101 
102 #ifdef lint
103 	acerint(0); acecint(0);
104 #endif
105 	if (badaddr(reg, 2))
106 		return(0);
107 	movew((short)CSR_RESET, &addr->csr);
108 	DELAY(10000);
109 	return (sizeof (struct acedevice));
110 }
111 
112 /*
113  * Interface exists: make available by filling in network interface
114  * record.  System will initialize the interface when it is ready
115  * to accept packets.
116  */
117 aceattach(ui)
118 	struct vba_device *ui;
119 {
120 	register short unit = ui->ui_unit;
121 	register struct ace_softc *is = &ace_softc[unit];
122 	register struct ifnet *ifp = &is->is_if;
123 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
124 	register short *wp, i;
125 	struct sockaddr_in *sin;
126 
127 	ifp->if_unit = unit;
128 	ifp->if_name = "ace";
129 	ifp->if_mtu = ETHERMTU;
130 	/*
131 	 * Set station's addresses, multicast
132 	 * hash table, and initialize dual ported memory.
133 	 */
134 	ace_station[5] = ~(unit + 1);
135 	acesetetaddr(unit, addr, ace_station);
136 	is->is_promiscuous = 0;
137 	wp = (short *)addr->hash;
138 	for (i =  0; i < 8; i++)
139 		movew((short)ace_hash[i], wp++);
140 	movew((short)~0xffff, &addr->bcastena[0]);
141 	movew((short)~0xffff, &addr->bcastena[1]);
142 	aceclean(unit);
143 	sin = (struct sockaddr_in *)&ifp->if_addr;
144 	sin->sin_family = AF_INET;
145 	ifp->if_init = aceinit;
146 	ifp->if_output = aceoutput;
147 	ifp->if_ioctl = aceioctl;
148 	ifp->if_reset = acereset;
149 	if_attach(ifp);
150 }
151 
152 acesetetaddr(unit, addr, station_addr)
153 	short unit;
154 	struct acedevice *addr;
155 	char *station_addr;
156 {
157 	register short *wp, i;
158 	register char *cp;
159 	struct ace_softc *is = &ace_softc[unit];
160 
161 	wp = (short *)addr->station;
162 	cp = station_addr;
163 	for (i = 0; i < 6; i++)
164 		movew((short)*cp++, wp++);
165 	wp = (short *)addr->station;
166 	cp = (char *)&is->is_addr;
167 	for (i = 0; i < 6; i++)
168 		*cp++ = ~(*wp++);
169 }
170 
171 /*
172  * Reset of interface after "system" reset.
173  */
174 acereset(unit, vban)
175 	int unit, vban;
176 {
177 	register struct vba_device *ui;
178 
179 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
180 	    ui->ui_vbanum != vban)
181 		return;
182 	printf(" ace%d", unit);
183 	aceinit(unit);
184 }
185 
186 /*
187  * Initialization of interface; clear recorded pending operations
188  */
189 aceinit(unit)
190 	int unit;
191 {
192 	register struct ace_softc *is = &ace_softc[unit];
193 	register struct vba_device *ui = aceinfo[unit];
194 	register struct acedevice *addr;
195 	register struct ifnet *ifp = &is->is_if;
196 	register struct sockaddr_in *sin;
197 	register short Csr;
198 	register int i, s;
199 
200 	sin = (struct sockaddr_in *)&ifp->if_addr;
201 	if (sin->sin_addr.s_addr == 0)		/* address still unknown */
202 		return;
203 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
204 		/*
205 		 * Reset the controller, initialize the recieve buffers,
206 		 * and turn the controller on again and set board online.
207 		 */
208 		addr = (struct acedevice *)ui->ui_addr;
209 		s = splimp();
210 		movew((short)CSR_RESET, &addr->csr);
211 		DELAY(10000);
212 
213 		/*
214 		 * clean up dpm since the controller might
215 		 * jumble dpm after reset
216 		 */
217 		aceclean(unit);
218 		movew((short)CSR_GO, &addr->csr);
219 		Csr = addr->csr;
220 		if (Csr & CSR_ACTIVE) {
221 			movew((short)(ACEVECTOR + unit*8), &addr->ivct);
222 			Csr |= CSR_IENA | is->is_promiscuous;
223 			if (ifp->if_net == LONET)
224 				Csr |= CSR_LOOP3;
225 			movew(Csr, &addr->csr);
226 			is->is_flags = 0;
227 			is->is_xcnt = 0;
228 			is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
229 		}
230 		splx(s);
231 	}
232 
233 	if (is->is_if.if_flags & IFF_UP) {
234 		if_rtinit(&is->is_if, RTF_UP);
235 		aceStart(unit);
236 	}
237 	arpwhohas(&is->is_ac, &sin->sin_addr);
238 }
239 
240 /*
241  * Start output on interface.
242  * Get another datagram to send off of the interface queue,
243  * and map it to the interface before starting the output.
244  *
245  */
246 acestart(dev)
247 	dev_t dev;
248 {
249 	register struct tx_segment *txs;
250 	register long len, x;
251 	int unit = ACEUNIT(dev);
252 	struct vba_device *ui = aceinfo[unit];
253 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
254 	register struct ace_softc *is = &ace_softc[unit];
255 	struct mbuf *m;
256 	short retries, idx;
257 
258 again:
259 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
260 	if (txs->tx_csr & TCS_TBFULL) {
261 		is->is_stats.tx_busy++;
262 		return;
263 	}
264 	x = splimp();
265 	IF_DEQUEUE(&is->is_if.if_snd, m);
266 	splx(x);
267 	if (m == 0)
268 		return;
269 	len = aceput(unit, txs->tx_data, m);
270 	retries = txs->tx_csr & TCS_RTC;
271 	if (retries > 0)
272 		acebakoff(is, txs, retries);
273 
274 	/*
275 	 * Ensure minimum packet length.
276 	 * This makes the safe assumtion that there are no virtual holes
277 	 * after the data.
278 	 * For security, it might be wise to zero out the added bytes,
279 	 * but we're mainly interested in speed at the moment.
280 	 */
281 #ifdef notdef
282 	if (len - sizeof (struct ether_header) < ETHERMIN)
283 		len = ETHERMIN + sizeof (struct ether_header);
284 #else
285 	if (len - 14 < ETHERMIN)
286 		len = ETHERMIN + 14;
287 #endif
288 	if (++is->is_txnext > SEG_MAX)
289 		is->is_txnext = is->is_segboundry;
290 	is->is_if.if_opackets++;
291 	is->is_xcnt++;
292 	len = (len & 0x7fff) | TCS_TBFULL;
293 	movew((short)len, txs);
294 	goto again;
295 }
296 
297 /*
298  * Transmit done interrupt.
299  */
300 acecint(unit)
301 	int unit;
302 {
303 	register struct ace_softc *is = &ace_softc[unit];
304 	struct vba_device *ui = aceinfo[unit];
305 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
306 	register struct tx_segment *txseg;
307 	short txidx, eostat;
308 
309 	if (is->is_xcnt <= 0)  {
310 		txidx = (addr->tseg >> 11) & 0xf;
311 		printf("ace%d: stray xmit interrupt, xcnt %d\n",
312 		    unit, is->is_xcnt);
313 		is->is_xcnt = 0;
314 		aceStart(unit);
315 		return;
316 	}
317 	is->is_xcnt--;
318 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
319 	eostat = txseg->tx_csr;
320 	if ((eostat & TCS_TBFULL) == 0) {
321 		is->is_stats.tx_retries += eostat & TCS_RTC;
322 		if (eostat & TCS_RTFAIL)  {
323 			is->is_stats.tx_discarded++;
324 			is->is_if.if_oerrors++;
325 		} else
326 			is->is_stats.tx_datagrams++;
327 		if (++is->is_eoctr >= 16)
328 			is->is_eoctr = is->is_segboundry;
329 	}
330 	aceStart(unit);
331 }
332 
333 /*
334  * Ethernet interface receiver interrupt.
335  * If input error just drop packet.
336  * Otherwise purge input buffered data path and examine
337  * packet to determine type.  If can't determine length
338  * from type, then have to drop packet.  Othewise decapsulate
339  * packet based on type and pass to type specific higher-level
340  * input routine.
341  */
342 acerint(unit)
343 	int unit;
344 {
345 	register struct ace_softc *is = &ace_softc[unit];
346 	register struct ifqueue *inq;
347 	register struct ether_header *ace;
348 	register struct rx_segment *rxseg;
349 	struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr;
350 	int len, s, off, resid;
351 	struct mbuf *m;
352 	short eistat;
353 
354 again:
355 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
356 	eistat = rxseg->rx_csr;
357 	if ((eistat & RCS_RBFULL) == 0)
358 		return;
359 	is->is_if.if_ipackets++;
360 	if (++is->is_eictr >= is->is_segboundry)
361 		is->is_eictr = 0;
362 	len = eistat & RCS_RBC;
363 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
364 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
365 		if (eistat & RCS_ROVRN)
366 			is->is_stats.rx_overruns++;
367 		if (eistat & RCS_RCRC)
368 			is->is_stats.rx_crc_errors++;
369 		if (eistat & RCS_RODD)
370 			is->is_stats.rx_align_errors++;
371 		if (len < ET_MINLEN)
372 			is->is_stats.rx_underruns++;
373 		if (len > ET_MAXLEN+CRC_SIZE)
374 			is->is_stats.rx_overruns++;
375 		is->is_if.if_ierrors++;
376 		rxseg->rx_csr = 0;
377 		return;
378 	} else
379 		is->is_stats.rx_datagrams++;
380 	ace = (struct ether_header *)rxseg->rx_data;
381 #ifdef notdef
382 	len -= sizeof (struct ether_header);
383 #else
384 	len -= 14;
385 #endif
386 	/*
387 	 * Deal with trailer protocol: if type is PUP trailer
388 	 * get true type from first 16-bit word past data.
389 	 * Remember that type was trailer by setting off.
390 	 */
391 	ace->ether_type = ntohs((u_short)ace->ether_type);
392 #ifdef notdef
393 #define	acedataaddr(ace, off, type) \
394     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
395 #else
396 #define	acedataaddr(ace, off, type) \
397     ((type)(((caddr_t)(((char *)ace)+14)+(off))))
398 #endif
399 	if (ace->ether_type >= ETHERPUP_TRAIL &&
400 	    ace->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
401 		off = (ace->ether_type - ETHERPUP_TRAIL) * 512;
402 		if (off >= ETHERMTU)
403 			goto setup;		/* sanity */
404 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
405 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
406 		if (off + resid > len)
407 			goto setup;		/* sanity */
408 		len = off + resid;
409 	} else
410 		off = 0;
411 	if (len == 0)
412 		goto setup;
413 
414 	/*
415 	 * Pull packet off interface.  Off is nonzero if packet
416 	 * has trailing header; aceget will then force this header
417 	 * information to be at the front, but we still have to drop
418 	 * the type and length which are at the front of any trailer data.
419 	 */
420 	m = aceget(unit, rxseg->rx_data, len, off);
421 	if (m == 0)
422 		goto setup;
423 	if (off) {
424 		m->m_off += 2 * sizeof (u_short);
425 		m->m_len -= 2 * sizeof (u_short);
426 	}
427 	switch (ace->ether_type) {
428 
429 #ifdef INET
430 	case ETHERPUP_IPTYPE:
431 		schednetisr(NETISR_IP);
432 		inq = &ipintrq;
433 		break;
434 
435 	case ETHERPUP_ARPTYPE:
436 		arpinput(&is->is_ac, m);
437 		goto setup;
438 #endif
439 	default:
440 		m_freem(m);
441 		goto setup;
442 	}
443 	if (IF_QFULL(inq)) {
444 		IF_DROP(inq);
445 		m_freem(m);
446 		goto setup;
447 	}
448 	s = splimp();
449 	IF_ENQUEUE(inq, m);
450 	splx(s);
451 setup:
452 	rxseg->rx_csr = 0;
453 	goto again;
454 }
455 
456 /*
457  * Ethernet output routine.
458  * Encapsulate a packet of type family for the local net.
459  * Use trailer local net encapsulation if enough data in first
460  * packet leaves a multiple of 512 bytes of data in remainder.
461  */
462 aceoutput(ifp, m0, dst)
463 	struct ifnet *ifp;
464 	struct mbuf *m0;
465 	struct sockaddr *dst;
466 {
467 	register struct ace_softc *is = &ace_softc[ifp->if_unit];
468 	register struct mbuf *m = m0;
469 	register struct ether_header *ace;
470 	register int off;
471 	struct mbuf *mcopy = (struct mbuf *)0;
472 	int type, s, error;
473 	struct ether_addr edst;
474 	struct in_addr idst;
475 
476 	switch (dst->sa_family) {
477 
478 #ifdef INET
479 	case AF_INET:
480 		idst = ((struct sockaddr_in *)dst)->sin_addr;
481 		if (!arpresolve(&is->is_ac, m, &idst, &edst))
482 			return (0);	/* if not yet resolved */
483 		if (in_lnaof(idst) == INADDR_ANY)
484 			mcopy = m_copy(m, 0, (int)M_COPYALL);
485 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
486 		/* need per host negotiation */
487 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 &&
488 		    (off & 0x1ff) == 0 &&
489 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
490 			type = ETHERPUP_TRAIL + (off>>9);
491 			m->m_off -= 2 * sizeof (u_short);
492 			m->m_len += 2 * sizeof (u_short);
493 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
494 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
495 			goto gottrailertype;
496 		}
497 		type = ETHERPUP_IPTYPE;
498 		off = 0;
499 		goto gottype;
500 #endif
501 
502 	case AF_UNSPEC:
503 		ace = (struct ether_header *)dst->sa_data;
504 #ifdef notdef
505 		edst = ace->ether_dhost;
506 #else
507 		bcopy((caddr_t)ace->ether_dhost, (caddr_t)&edst, 6);
508 #endif
509 		type = ace->ether_type;
510 		goto gottype;
511 
512 	default:
513 		printf("ace%d: can't handle af%d\n",
514 		    ifp->if_unit, dst->sa_family);
515 		error = EAFNOSUPPORT;
516 		goto bad;
517 	}
518 
519 gottrailertype:
520 	/*
521 	 * Packet to be sent as trailer: move first packet
522 	 * (control information) to end of chain.
523 	 */
524 	while (m->m_next)
525 		m = m->m_next;
526 	m->m_next = m0;
527 	m = m0->m_next;
528 	m0->m_next = 0;
529 	m0 = m;
530 
531 gottype:
532 	/*
533 	 * Add local net header.  If no space in first mbuf,
534 	 * allocate another.
535 	 */
536 	if (m->m_off > MMAXOFF ||
537 #ifdef notdef
538 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
539 #else
540 	    MMINOFF + 14 > m->m_off) {
541 #endif
542 		m = m_get(M_DONTWAIT, MT_HEADER);
543 		if (m == 0) {
544 			error = ENOBUFS;
545 			goto bad;
546 		}
547 		m->m_next = m0;
548 		m->m_off = MMINOFF;
549 #ifdef notdef
550 		m->m_len = sizeof (struct ether_header);
551 #else
552 		m->m_len = 14;
553 #endif
554 	} else {
555 #ifdef notdef
556 		m->m_off -= sizeof (struct ether_header);
557 		m->m_len += sizeof (struct ether_header);
558 #else
559 		m->m_off -= 14;
560 		m->m_len += 14;
561 #endif
562 	}
563 	ace = mtod(m, struct ether_header *);
564 #ifdef notdef
565 	ace->ether_dhost = edst;
566 	ace->ether_shost = is->is_addr;
567 #else
568 	bcopy((caddr_t)&edst, (caddr_t)ace->ether_dhost, 6);
569 	bcopy((caddr_t)&is->is_addr, (caddr_t)ace->ether_shost, 6);
570 #endif
571 	ace->ether_type = htons((u_short)type);
572 
573 	/*
574 	 * Queue message on interface, and start output if interface
575 	 * not yet active.
576 	 */
577 	s = splimp();
578 	if (IF_QFULL(&ifp->if_snd)) {
579 		IF_DROP(&ifp->if_snd);
580 		error = ENOBUFS;
581 		goto qfull;
582 	}
583 	IF_ENQUEUE(&ifp->if_snd, m);
584 	splx(s);
585 	aceStart(ifp->if_unit);
586 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
587 qfull:
588 	m0 = m;
589 	splx(s);
590 bad:
591 	m_freem(m0);
592 	if (mcopy)
593 		m_freem(mcopy);
594 	return (error);
595 }
596 
597 aceStart(unit)
598 	int unit;
599 {
600 	register struct ace_softc *is = &ace_softc[unit];
601 
602 	if (is->is_flags & ACEF_OACTIVE)
603 		return;
604 	is->is_flags |= ACEF_OACTIVE;
605 	acestart((dev_t)unit);
606 	is->is_flags &= ~ACEF_OACTIVE;
607 }
608 
609 /*
610  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
611  * If packet size is less than the minimum legal size,
612  * the buffer is expanded.  We probably should zero out the extra
613  * bytes for security, but that would slow things down.
614  */
615 aceput(unit, txbuf, m)
616 	int unit;			/* for statistics collection */
617 	u_char *txbuf;
618 	struct mbuf *m;
619 {
620 	register u_char *bp, *mcp;	/* known to be r12, r11 */
621 	register short *s1, *s2;	/* known to be r10, r9 */
622 	register unsigned len;
623 	register struct mbuf *mp;
624 	int total, idx;
625 
626 	total = 0;
627 	bp = txbuf;
628 	for (mp = m;(mp); mp = mp->m_next) {
629 		len = mp->m_len;
630 		if (len == 0)
631 			continue;
632 		total += len;
633 		mcp = mtod(mp, u_char *);
634 		if (((int)mcp & 01) && ((int)bp & 01)) {
635 			/* source & destination at odd addresses */
636 			/* *bp++ = *mcp++; */
637 			asm("movob (r11),(r12)");
638 			bp++, mcp++;
639 			--len;
640 		}
641 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
642 			register int l;
643 
644 			s1 = (short *)bp;
645 			s2 = (short *)mcp;
646 			l = len >> 1;		/* count # of shorts */
647 			while (l-- > 0) {
648 				/* *s1++ = *s2++; */
649 				asm("movow (r9),(r10)");
650 				s1++, s2++;
651 			}
652 			len &= 1;		/* # remaining bytes */
653 			bp = (u_char *)s1;
654 			mcp = (u_char *)s2;
655 		}
656 		while (len-- > 0) {
657 			/* *bp++ = *mcp++;  */
658 			asm("movob (r11),(r12)");
659 			bp++, mcp++;
660 		}
661 	}
662 	m_freem(m);
663 	return (total);
664 }
665 
666 movew(data, to)
667 	short data, *to;
668 {
669 
670 	asm("movow 6(fp),*8(fp)");
671 }
672 
673 /*
674  * Routine to copy from VERSAbus memory into mbufs.
675  *
676  * Warning: This makes the fairly safe assumption that
677  * mbufs have even lengths.
678  */
679 struct mbuf *
680 aceget(unit, rxbuf, totlen, off0)
681 	int unit;			/* for statistics collection */
682 	u_char *rxbuf;
683 	int totlen, off0;
684 {
685 	register u_char *cp, *mcp;	/* known to be r12, r11 */
686 	register int tlen;
687 	register struct mbuf *m;
688 	struct mbuf *top = 0, **mp = &top;
689 	int len, off = off0;
690 
691 #ifdef notdef
692 	cp = rxbuf + sizeof (struct ether_header);
693 #else
694 	cp = rxbuf + 14;
695 #endif
696 	while (totlen > 0) {
697 		register int words;
698 
699 		MGET(m, M_DONTWAIT, MT_DATA);
700 		if (m == 0)
701 			goto bad;
702 		if (off) {
703 			len = totlen - off;
704 #ifdef notdef
705 			cp = rxbuf + sizeof (struct ether_header) + off;
706 #else
707 			cp = rxbuf + 14 + off;
708 #endif
709 		} else
710 			len = totlen;
711 		if (len >= CLBYTES) {
712 			struct mbuf *p;
713 
714 			MCLGET(p, 1);
715 			if (p != 0) {
716 				m->m_len = len = CLBYTES;
717 				m->m_off = (int)p - (int)m;
718 			} else {
719 				m->m_len = len = MIN(MLEN, len);
720 				m->m_off = MMINOFF;
721 			}
722 		} else {
723 			m->m_len = len = MIN(MLEN, len);
724 			m->m_off = MMINOFF;
725 		}
726 		mcp = mtod(m, u_char *);
727 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
728 		/*cp += len; mcp += len;*/
729 		tlen = len;
730 		if (((int)mcp & 01) && ((int)cp & 01)) {
731 			/* source & destination at odd addresses */
732 			*mcp++ = *cp++;
733 			--tlen;
734 		}
735 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
736 			register short *s1, *s2;
737 			register int l;
738 
739 			s1 = (short *)mcp;
740 			s2 = (short *)cp;
741 			l = tlen >> 1;		/* count # of shorts */
742 			while (l-- > 0)		/* copy shorts */
743 				*s1++ = *s2++;
744 			tlen &= 1;		/* # remaining bytes */
745 			mcp = (u_char *)s1;
746 			cp = (u_char *)s2;
747 		}
748 		while (tlen-- > 0)
749 			*mcp++ = *cp++;
750 		*mp = m;
751 		mp = &m->m_next;
752 		if (off == 0) {
753 			totlen -= len;
754 			continue;
755 		}
756 		off += len;
757 		if (off == totlen) {
758 #ifdef notdef
759 			cp = rxbuf + sizeof (struct ether_header);
760 #else
761 			cp = rxbuf + 14;
762 #endif
763 			off = 0;
764 			totlen = off0;
765 		}
766 	}
767 	return (top);
768 bad:
769 	m_freem(top);
770 	return (0);
771 }
772 
773 acebakoff(is, txseg, retries)
774 	struct ace_softc *is;
775 	struct tx_segment *txseg;
776 	register int retries;
777 {
778 	register short *pBakNum, random_num;
779 	short *pMask;
780 
781 	pMask = &random_mask_tbl[0];
782 	pBakNum = &txseg->tx_backoff[0];
783 	while (--retries >= 0) {
784 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
785 		random_num &= *pMask++;
786 		*pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC);
787 	}
788 }
789 
790 /*
791  * Process an ioctl request.
792  */
793 aceioctl(ifp, cmd, data)
794 	register struct ifnet *ifp;
795 	int cmd;
796 	caddr_t data;
797 {
798 	register struct ifreq *ifr = (struct ifreq *)data;
799 	int s, error = 0;
800 
801 	s = splimp();
802 	switch (cmd) {
803 
804 	case SIOCSIFADDR:
805 		if (ifp->if_flags & IFF_RUNNING)
806 			if_rtinit(ifp, -1);	/* delete previous route */
807 		acesetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
808 		aceinit(ifp->if_unit);
809 		break;
810 
811 #ifdef notdef
812 	case SIOCSETETADDR: {		/* set Ethernet station address */
813 		struct vba_device *ui;
814 		struct acedevice *addr;
815 		struct sockaddr_in *sin;
816 
817 		ifp->if_flags &= ~IFF_RUNNING | IFF_UP;
818 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
819 		ui = aceinfo[ifp->if_unit];
820 		addr = (struct acedevice *)ui->ui_addr;
821 		movew((short)CSR_RESET, &addr->csr);
822 		DELAY(10000);
823 		/* set station address and copy addr to arp struct */
824 		acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]);
825 		aceinit(ifp->if_unit);		/* Re-initialize */
826 		break;
827 	}
828 #endif
829 
830 	default:
831 		error = EINVAL;
832 	}
833 	splx(s);
834 	return (error);
835 }
836 
837 acesetaddr(ifp, sin)
838 	register struct ifnet *ifp;
839 	register struct sockaddr_in *sin;
840 {
841 
842 	ifp->if_addr = *(struct sockaddr *)sin;
843 	ifp->if_net = in_netof(sin->sin_addr);
844 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
845 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
846 	sin->sin_family = AF_INET;
847 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
848 	ifp->if_flags |= IFF_BROADCAST;
849 }
850 
851 aceclean(unit)
852 	int unit;
853 {
854 	register struct ace_softc *is = &ace_softc[unit];
855 	register struct ifnet *ifp = &is->is_if;
856 	register struct vba_device *ui = aceinfo[unit];
857 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
858 	register short i, data;
859 	register char *pData1;
860 
861 	ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE);
862 	is->is_dpm = acemap[unit];		/* init dpm */
863 	bzero((char *)is->is_dpm, 16384*2);
864 
865 	is->is_currnd = 49123;
866 	is->is_segboundry = (addr->segb >> 11) & 0xf;
867 	pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11));
868 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
869 		acebakoff(is, (struct tx_segment *)pData1, 15);
870 		pData1 += sizeof (struct tx_segment);
871 	}
872 	is->is_eictr = 0;
873 	is->is_eoctr = is->is_txnext = is->is_segboundry;
874 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
875 }
876 #endif
877