xref: /original-bsd/sys/tahoe/if/if_ace.c (revision 8477994b)
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_ace.c	7.7 (Berkeley) 06/28/90
11  */
12 
13 /*
14  * ACC VERSAbus Ethernet controller
15  */
16 #include "ace.h"
17 #if NACE > 0
18 
19 #include "param.h"
20 #include "systm.h"
21 #include "malloc.h"
22 #include "mbuf.h"
23 #include "buf.h"
24 #include "protosw.h"
25 #include "socket.h"
26 #include "vmmac.h"
27 #include "ioctl.h"
28 #include "errno.h"
29 #include "vmparam.h"
30 #include "syslog.h"
31 
32 #include "../net/if.h"
33 #include "../net/netisr.h"
34 #include "../net/route.h"
35 #ifdef INET
36 #include "../netinet/in.h"
37 #include "../netinet/in_systm.h"
38 #include "../netinet/in_var.h"
39 #include "../netinet/ip.h"
40 #include "../netinet/ip_var.h"
41 #include "../netinet/if_ether.h"
42 #endif
43 #ifdef NS
44 #include "../netns/ns.h"
45 #include "../netns/ns_if.h"
46 #endif
47 
48 #include "machine/cpu.h"
49 #include "machine/pte.h"
50 
51 #include "../tahoe/mtpr.h"
52 #include "../tahoeif/if_acereg.h"
53 #include "../tahoevba/vbavar.h"
54 
55 int	aceprobe(), aceattach(), acerint(), acecint(), acestart();
56 struct	vba_device *aceinfo[NACE];
57 long	acestd[] = { 0 };
58 struct	vba_driver acedriver =
59     { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 };
60 
61 int	aceinit(), aceoutput(), aceioctl(), acereset();
62 struct	mbuf *aceget();
63 
64 /*
65  * Ethernet software status per interface.
66  *
67  * Each interface is referenced by a network interface structure,
68  * is_if, which the routing code uses to locate the interface.
69  * This structure contains the output queue for the interface, its address, ...
70  */
71 struct	ace_softc {
72 	struct	arpcom is_ac;		/* Ethernet common part	*/
73 #define	is_if	is_ac.ac_if		/* network-visible interface */
74 #define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address */
75 	short	is_flags;
76 #define	ACEF_OACTIVE	0x1		/* output is active */
77 #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
78 	short	is_promiscuous;		/* true is enabled */
79 	short	is_segboundry;		/* first TX Seg in dpm */
80 	short	is_eictr;		/* Rx segment tracking ctr */
81 	short	is_eoctr;		/* Tx segment tracking ctr */
82 	short	is_txnext;		/* Next available Tx segment */
83 	short	is_currnd;		/* current random backoff */
84 	struct	ace_stats is_stats;	/* holds board statistics */
85 	short	is_xcnt;		/* count xmitted segments to be acked
86 					   by the controller */
87 	long	is_ivec;		/* autoconfig interrupt vector base */
88 	struct	pte *is_map;		/* pte map for dual ported memory */
89 	caddr_t	is_dpm;			/* address of mapped memory */
90 } ace_softc[NACE];
91 extern	struct ifnet loif;
92 
93 aceprobe(reg, vi)
94 	caddr_t reg;
95 	struct vba_device *vi;
96 {
97 	register br, cvec;		/* must be r12, r11 */
98 	struct acedevice *ap = (struct acedevice *)reg;
99 	struct ace_softc *is = &ace_softc[vi->ui_unit];
100 
101 #ifdef lint
102 	br = 0; cvec = br; br = cvec;
103 	acerint(0); acecint(0);
104 #endif
105 	if (badaddr(reg, 2))
106 		return (0);
107 	movow(&ap->csr, CSR_RESET);
108 	DELAY(10000);
109 #ifdef notdef
110 	/*
111 	 * Select two spaces for the interrupts aligned to an
112 	 * eight vector boundary and fitting in 8 bits (as
113 	 * required by the controller) -- YECH.  The controller
114 	 * will be notified later at initialization time.
115 	 */
116 	if ((vi->ui_hd->vh_lastiv -= 2) > 0xff)
117 		vi->ui_hd->vh_lastiv  = 0x200;
118 	is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7;
119 #else
120 	is->is_ivec = 0x90+vi->ui_unit*8;
121 #endif
122 	br = 0x14, cvec = is->is_ivec;		/* XXX */
123 	return (sizeof (*ap));
124 }
125 
126 /*
127  * Interface exists: make available by filling in network interface
128  * record.  System will initialize the interface when it is ready
129  * to accept packets.
130  */
131 aceattach(ui)
132 	struct vba_device *ui;
133 {
134 	register short unit = ui->ui_unit;
135 	register struct ace_softc *is = &ace_softc[unit];
136 	register struct ifnet *ifp = &is->is_if;
137 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
138 	register short *wp, i;
139 
140 	ifp->if_unit = unit;
141 	ifp->if_name = "ace";
142 	ifp->if_mtu = ETHERMTU;
143 	/*
144 	 * Get station's addresses and set multicast hash table.
145 	 */
146 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
147 		is->is_addr[i] = ~*wp++;
148 	printf("ace%d: hardware address %s\n", unit,
149 	    ether_sprintf(is->is_addr));
150 	is->is_promiscuous = 0;
151 	for (wp = (short *)addr->hash, i =  0; i < 8; i++)
152 		movow(wp++, ~0xf);
153 	movow(&addr->bcastena[0], ~0xffff);
154 	movow(&addr->bcastena[1], ~0xffff);
155 	/*
156 	 * Allocate and map dual ported VERSAbus memory.
157 	 */
158 	if (vbmemalloc(32, (caddr_t)ui->ui_flags,
159 	    &is->is_map, &is->is_dpm) == 0) {
160 		printf("ace%d: can't allocate VERSAbus memory map\n", unit);
161 		return;
162 	}
163 
164 	ifp->if_init = aceinit;
165 	ifp->if_output = ether_output;
166 	ifp->if_start = acestart;
167 	ifp->if_ioctl = aceioctl;
168 	ifp->if_reset = acereset;
169 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
170 	if_attach(ifp);
171 }
172 
173 /*
174  * Reset of interface after "system" reset.
175  */
176 acereset(unit, vban)
177 	int unit, vban;
178 {
179 	register struct vba_device *ui;
180 
181 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
182 	    ui->ui_vbanum != vban)
183 		return;
184 	printf(" ace%d", unit);
185 	aceinit(unit);
186 }
187 
188 /*
189  * Initialization of interface; clear recorded pending operations
190  */
191 aceinit(unit)
192 	int unit;
193 {
194 	register struct ace_softc *is = &ace_softc[unit];
195 	register struct vba_device *ui = aceinfo[unit];
196 	register struct acedevice *addr;
197 	register short Csr;
198 	register int s;
199 
200 	if (is->is_if.if_addrlist == (struct ifaddr *)0)
201 		return;
202 	if ((is->is_if.if_flags & IFF_RUNNING) == 0) {
203 		/*
204 		 * Reset the controller, initialize the recieve buffers,
205 		 * and turn the controller on again and set board online.
206 		 */
207 		addr = (struct acedevice *)ui->ui_addr;
208 		s = splimp();
209 		movow(&addr->csr, CSR_RESET);
210 		DELAY(10000);
211 
212 		/*
213 		 * Clean up dpm since the controller might
214 		 * jumble dpm after reset.
215 		 */
216 		acesetup(unit);
217 		movow(&addr->csr, CSR_GO);
218 		Csr = addr->csr;
219 		if (Csr & CSR_ACTIVE) {
220 			movow(&addr->ivct, is->is_ivec);
221 			Csr |= CSR_IENA | is->is_promiscuous;
222 			movow(&addr->csr, Csr);
223 			is->is_flags = 0;
224 			is->is_xcnt = 0;
225 			is->is_if.if_flags |= IFF_RUNNING;
226 		}
227 		splx(s);
228 	}
229 	if (is->is_if.if_snd.ifq_head)
230 		acestart(&is->is_if);
231 }
232 
233 /*
234  * Start output on interface.
235  * Get another datagram to send off of the interface queue,
236  * and map it to the interface before starting the output.
237  */
238 acestart(ifp)
239 	register struct ifnet *ifp;
240 {
241 	register struct tx_segment *txs;
242 	register long len;
243 	register int s;
244 	struct mbuf *m;
245 	short retries;
246 #define	is ((struct ace_softc *)ifp)
247 
248 again:
249 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
250 	if (txs->tx_csr & TCS_TBFULL) {
251 		is->is_stats.tx_busy++;
252 		ifp->if_flags |= IFF_OACTIVE;
253 		return (0);
254 	}
255 	s = splimp();
256 	IF_DEQUEUE(&ifp->if_snd, m);
257 	splx(s);
258 	if (m == 0) {
259 		ifp->if_flags &= ~IFF_OACTIVE;
260 		return (0);
261 	}
262 	len = aceput(txs->tx_data, m);
263 	retries = txs->tx_csr & TCS_RTC;
264 	if (retries > 0)
265 		acebakoff(is, txs, retries);
266 
267 	/*
268 	 * Ensure minimum packet length.
269 	 * This makes the safe assumtion that there are no virtual holes
270 	 * after the data.
271 	 * For security, it might be wise to zero out the added bytes,
272 	 * but we're mainly interested in speed at the moment.
273 	 */
274 	if (len - sizeof (struct ether_header) < ETHERMIN)
275 		len = ETHERMIN + sizeof (struct ether_header);
276 	if (++is->is_txnext > SEG_MAX)
277 		is->is_txnext = is->is_segboundry;
278 	ifp->if_opackets++;
279 	is->is_xcnt++;
280 	len = (len & 0x7fff) | TCS_TBFULL;
281 	movow(txs, len);
282 	goto again;
283 #undef is
284 }
285 
286 /*
287  * Transmit done interrupt.
288  */
289 acecint(unit)
290 	int unit;
291 {
292 	register struct ace_softc *is = &ace_softc[unit];
293 	register struct tx_segment *txseg;
294 	short eostat;
295 
296 	if (is->is_xcnt <= 0)  {
297 		log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n",
298 		    unit, is->is_xcnt);
299 		is->is_xcnt = 0;
300 		if (is->is_if.if_snd.ifq_head)
301 			acestart(&is->is_if);
302 		return;
303 	}
304 	is->is_xcnt--;
305 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
306 	eostat = txseg->tx_csr;
307 	if ((eostat & TCS_TBFULL) == 0) {
308 		is->is_stats.tx_retries += eostat & TCS_RTC;
309 		if (eostat & TCS_RTFAIL)  {
310 			is->is_stats.tx_discarded++;
311 			is->is_if.if_oerrors++;
312 		} else
313 			is->is_stats.tx_datagrams++;
314 		if (++is->is_eoctr >= 16)
315 			is->is_eoctr = is->is_segboundry;
316 	}
317 	if (is->is_if.if_snd.ifq_head)
318 		acestart(&is->is_if);
319 }
320 
321 /*
322  * Ethernet interface receiver interrupt.
323  * If input error just drop packet.
324  * Otherwise purge input buffered data path and examine
325  * packet to determine type.  If can't determine length
326  * from type, then have to drop packet.  Othewise decapsulate
327  * packet based on type and pass to type specific higher-level
328  * input routine.
329  */
330 acerint(unit)
331 	int unit;
332 {
333 	register struct ace_softc *is = &ace_softc[unit];
334 	register struct ifqueue *inq;
335 	register struct ether_header *ace;
336 	register struct rx_segment *rxseg;
337 	int len, s, off, resid;
338 	struct mbuf *m;
339 	short eistat;
340 
341 	if ((is->is_if.if_flags&IFF_RUNNING) == 0)
342 		return;
343 again:
344 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
345 	eistat = rxseg->rx_csr;
346 	if ((eistat & RCS_RBFULL) == 0)
347 		return;
348 	is->is_if.if_ipackets++;
349 	if (++is->is_eictr >= is->is_segboundry)
350 		is->is_eictr = 0;
351 	len = eistat & RCS_RBC;
352 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
353 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
354 		if (eistat & RCS_ROVRN)
355 			is->is_stats.rx_overruns++;
356 		if (eistat & RCS_RCRC)
357 			is->is_stats.rx_crc_errors++;
358 		if (eistat & RCS_RODD)
359 			is->is_stats.rx_align_errors++;
360 		if (len < ET_MINLEN)
361 			is->is_stats.rx_underruns++;
362 		if (len > ET_MAXLEN+CRC_SIZE)
363 			is->is_stats.rx_overruns++;
364 		is->is_if.if_ierrors++;
365 		rxseg->rx_csr = 0;
366 		return;
367 	} else
368 		is->is_stats.rx_datagrams++;
369 	ace = (struct ether_header *)rxseg->rx_data;
370 	len -= sizeof (struct ether_header);
371 	/*
372 	 * Deal with trailer protocol: if type is trailer
373 	 * get true type from first 16-bit word past data.
374 	 * Remember that type was trailer by setting off.
375 	 */
376 	ace->ether_type = ntohs((u_short)ace->ether_type);
377 #define	acedataaddr(ace, off, type) \
378     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
379 	if (ace->ether_type >= ETHERTYPE_TRAIL &&
380 	    ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
381 		off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
382 		if (off >= ETHERMTU)
383 			goto setup;		/* sanity */
384 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
385 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
386 		if (off + resid > len)
387 			goto setup;		/* sanity */
388 		len = off + resid;
389 	} else
390 		off = 0;
391 	if (len == 0)
392 		goto setup;
393 
394 	/*
395 	 * Pull packet off interface.  Off is nonzero if packet
396 	 * has trailing header; aceget will then force this header
397 	 * information to be at the front.
398 	 */
399 	m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if);
400 	if (m)
401 		ether_input(&is->is_if, ace, m);
402 setup:
403 	rxseg->rx_csr = 0;
404 	goto again;
405 }
406 
407 /*
408  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
409  * If packet size is less than the minimum legal size,
410  * the buffer is expanded.  We probably should zero out the extra
411  * bytes for security, but that would slow things down.
412  */
413 aceput(txbuf, m)
414 	char *txbuf;
415 	struct mbuf *m;
416 #ifdef notdef
417 {
418 	register u_char *bp, *mcp;
419 	register short *s1, *s2;
420 	register u_int len;
421 	register struct mbuf *mp;
422 	int total;
423 
424 	total = mp->m_pkthdr.len;
425 	bp = (u_char *)txbuf;
426 	for (mp = m; mp; mp = mp->m_next) {
427 		len = mp->m_len;
428 		if (len == 0)
429 			continue;
430 		mcp = mtod(mp, u_char *);
431 		if (((int)mcp & 01) && ((int)bp & 01)) {
432 			/* source & destination at odd addresses */
433 			movob(bp++, *mcp++);
434 			--len;
435 		}
436 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
437 			int l = len & 1;
438 
439 			s1 = (short *)bp;
440 			s2 = (short *)mcp;
441 			len >>= 1;		/* count # of shorts */
442 			while (len-- != 0)
443 				movow(s1++, *s2++);
444 			len = l;		/* # remaining bytes */
445 			bp = (u_char *)s1;
446 			mcp = (u_char *)s2;
447 		}
448 		while (len-- != 0)
449 			movob(bp++, *mcp++);
450 	}
451 	m_freem(m);
452 	return (total);
453 }
454 #else
455 {
456 	register u_char *bp, *mcp;
457 	register short *s1, *s2;
458 	register u_int len;
459 	register struct mbuf *mp;
460 	int total;
461 
462 	total = 0;
463 	bp = (u_char *)txbuf;
464 	for (mp = m; (mp); mp = mp->m_next) {
465 		len = mp->m_len;
466 		if (len == 0)
467 			continue;
468 		total += len;
469 		mcp = mtod(mp, u_char *);
470 		if (((int)mcp & 01) && ((int)bp & 01)) {
471 			/* source & destination at odd addresses */
472 			movob(bp++, *mcp++);
473 			--len;
474 		}
475 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
476 			register u_int l;
477 
478 			s1 = (short *)bp;
479 			s2 = (short *)mcp;
480 			l = len >> 1;		/* count # of shorts */
481 			while (l-- != 0)
482 				movow(s1++, *s2++);
483 			len &= 1;		/* # remaining bytes */
484 			bp = (u_char *)s1;
485 			mcp = (u_char *)s2;
486 		}
487 		while (len-- != 0)
488 			movob(bp++, *mcp++);
489 	}
490 	m_freem(m);
491 	return (total);
492 }
493 #endif
494 
495 /*
496  * Routine to copy from VERSAbus memory into mbufs.
497  *
498  * Warning: This makes the fairly safe assumption that
499  * mbufs have even lengths.
500  */
501 struct mbuf *
502 aceget(rxbuf, totlen, off, ifp)
503 	u_char *rxbuf;
504 	int totlen, off;
505 	struct ifnet *ifp;
506 {
507 	register u_char *cp, *mcp;
508 	register struct mbuf *m;
509 	register int tlen;
510 	struct mbuf *top = 0, **mp = &top;
511 	int len;
512 	u_char *packet_end;
513 
514 	rxbuf += sizeof (struct ether_header);
515 	cp = rxbuf;
516 	packet_end = cp + totlen;
517 	if (off) {
518 		off += 2 * sizeof(u_short);
519 		totlen -= 2 * sizeof(u_short);
520 		cp = rxbuf + off;
521 	}
522 
523 	MGETHDR(m, M_DONTWAIT, MT_DATA);
524 	if (m == 0)
525 		return (0);
526 	m->m_pkthdr.rcvif = ifp;
527 	m->m_pkthdr.len = totlen;
528 	m->m_len = MHLEN;
529 
530 	while (totlen > 0) {
531 		if (top) {
532 			MGET(m, M_DONTWAIT, MT_DATA);
533 			if (m == 0) {
534 				m_freem(top);
535 				return (0);
536 			}
537 			m->m_len = MLEN;
538 		}
539 		len = min(totlen, (packet_end - cp));
540 		if (len >= MINCLSIZE) {
541 			MCLGET(m, M_DONTWAIT);
542 			if (m->m_flags & M_EXT)
543 				m->m_len = len = min(len, MCLBYTES);
544 			else
545 				len = m->m_len;
546 		} else {
547 			/*
548 			 * Place initial small packet/header at end of mbuf.
549 			 */
550 			if (len < m->m_len) {
551 				if (top == 0 && len + max_linkhdr <= m->m_len)
552 					m->m_data += max_linkhdr;
553 				m->m_len = len;
554 			} else
555 				len = m->m_len;
556 		}
557 		mcp = mtod(m, u_char *);
558 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
559 		/*cp += len; mcp += len;*/
560 		tlen = len;
561 		if (((int)mcp & 01) && ((int)cp & 01)) {
562 			/* source & destination at odd addresses */
563 			*mcp++ = *cp++;
564 			--tlen;
565 		}
566 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
567 			register short *s1, *s2;
568 			register int l;
569 
570 			s1 = (short *)mcp;
571 			s2 = (short *)cp;
572 			l = tlen >> 1;		/* count # of shorts */
573 			while (l-- > 0)		/* copy shorts */
574 				*s1++ = *s2++;
575 			tlen &= 1;		/* # remaining bytes */
576 			mcp = (u_char *)s1;
577 			cp = (u_char *)s2;
578 		}
579 		while (tlen-- > 0)
580 			*mcp++ = *cp++;
581 		*mp = m;
582 		mp = &m->m_next;
583 		totlen -= len;
584 		if (cp == packet_end)
585 			cp = rxbuf;
586 	}
587 	return (top);
588 }
589 
590 /* backoff table masks */
591 short	random_mask_tbl[16] = {
592 	0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0,
593 	0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0
594 };
595 
596 acebakoff(is, txseg, retries)
597 	struct ace_softc *is;
598 	struct tx_segment *txseg;
599 	register int retries;
600 {
601 	register short *pBakNum, random_num;
602 	short *pMask;
603 
604 	pMask = &random_mask_tbl[0];
605 	pBakNum = &txseg->tx_backoff[0];
606 	while (--retries >= 0) {
607 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
608 		random_num &= *pMask++;
609 		*pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc);
610 	}
611 }
612 
613 /*
614  * Process an ioctl request.
615  */
616 aceioctl(ifp, cmd, data)
617 	register struct ifnet *ifp;
618 	int cmd;
619 	caddr_t data;
620 {
621 	register struct ifaddr *ifa = (struct ifaddr *)data;
622 	struct acedevice *addr;
623 	int s = splimp(), error = 0;
624 
625 	switch (cmd) {
626 
627 	case SIOCSIFADDR:
628 		ifp->if_flags |= IFF_UP;
629 		switch (ifa->ifa_addr->sa_family) {
630 #ifdef INET
631 		case AF_INET:
632 			aceinit(ifp->if_unit);	/* before arpwhohas */
633 			((struct arpcom *)ifp)->ac_ipaddr =
634 				IA_SIN(ifa)->sin_addr;
635 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
636 			break;
637 #endif
638 #ifdef NS
639 		case AF_NS: {
640 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
641 			struct ace_softc *is = &ace_softc[ifp->if_unit];
642 
643 			if (!ns_nullhost(*ina)) {
644 				ifp->if_flags &= ~IFF_RUNNING;
645 				addr = (struct acedevice *)
646 				    aceinfo[ifp->if_unit]->ui_addr;
647 				movow(&addr->csr, CSR_RESET);
648 				DELAY(10000);
649 				/* set station address & copy addr to arp */
650 				acesetaddr(ifp->if_unit, addr,
651 				    ina->x_host.c_host);
652 			} else
653 				ina->x_host = *(union ns_host *)is->is_addr;
654 			aceinit(ifp->if_unit);
655 			break;
656 		}
657 #endif
658 		default:
659 			aceinit(ifp->if_unit);
660 			break;
661 		}
662 		break;
663 
664 	case SIOCSIFFLAGS:
665 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
666 			addr = (struct acedevice *)
667 			    (aceinfo[ifp->if_unit]->ui_addr);
668 			movow(&addr->csr, CSR_RESET);
669 			ifp->if_flags &= ~IFF_RUNNING;
670 		} else if (ifp->if_flags&IFF_UP &&
671 		    (ifp->if_flags&IFF_RUNNING) == 0)
672 			aceinit(ifp->if_unit);
673 		break;
674 
675 	default:
676 		error = EINVAL;
677 	}
678 	splx(s);
679 	return (error);
680 }
681 
682 /*
683  * Set the on-board station address, then read it back
684  * to initialize the address used by ARP (among others).
685  */
686 acesetaddr(unit, addr, station)
687 	short unit;
688 	struct acedevice *addr;
689 	u_char *station;
690 {
691 	struct ace_softc *is = &ace_softc[unit];
692 	register short *wp, i;
693 
694 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
695 		movow(wp++, ~*station++);
696 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
697 		is->is_addr[i] = ~*wp++;
698 	printf("ace%d: hardware address %s\n", unit,
699 	    ether_sprintf(is->is_addr));
700 }
701 
702 /*
703  * Setup the device for use.  Initialize dual-ported memory,
704  * backoff parameters, and various other software state.
705  */
706 acesetup(unit)
707 	int unit;
708 {
709 	register struct ace_softc *is = &ace_softc[unit];
710 	register char *pData1;
711 	register short i;
712 	struct acedevice *addr;
713 
714 	bzero(is->is_dpm, 16384*2);
715 	is->is_currnd = 49123;
716 	addr = (struct acedevice *)aceinfo[unit]->ui_addr;
717 	is->is_segboundry = (addr->segb >> 11) & 0xf;
718 	pData1 = is->is_dpm + (is->is_segboundry << 11);
719 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
720 		acebakoff(is, (struct tx_segment *)pData1, 15);
721 		pData1 += sizeof (struct tx_segment);
722 	}
723 	is->is_eictr = 0;
724 	is->is_eoctr = is->is_txnext = is->is_segboundry;
725 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
726 }
727 #endif
728