xref: /netbsd-src/sys/arch/acorn32/podulebus/if_ie.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /* $NetBSD: if_ie.c,v 1.25 2009/03/18 17:06:41 cegger Exp $ */
2 
3 /*
4  * Copyright (c) 1995 Melvin Tang-Richardson.
5  * All rights reserved.
6  *
7  * This driver is a major hash up of src/sys/dev/isa/if_ie.c and
8  * src/sys/arch/acorn32/podulebus/kgdb_ie.c  Please refer to copyright
9  * notices from them too.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by RiscBSD.
22  * 4. The name of the company nor the name of the author may be used to
23  *    endorse or promote products derived from this software without specific
24  *    prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
27  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * RiscBSD kernel project
39  *
40  * if_ie.c
41  *
42  * Ether 1 podule driver
43  *
44  * Created      : 26/06/95
45  */
46 
47 /*
48  *	This driver is at it's last beta release.  It should not cause
49  *	any problems (Touch wood)
50  *
51  * 	If it passes field tests again.  This will constitute the realse
52  *	version.
53  */
54 
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: if_ie.c,v 1.25 2009/03/18 17:06:41 cegger Exp $");
57 
58 #define IGNORE_ETHER1_IDROM_CHECKSUM
59 
60 /* Standard podule includes */
61 
62 #include "opt_inet.h"
63 #include "opt_ns.h"
64 
65 #include <sys/param.h>
66 
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/conf.h>
70 #include <sys/malloc.h>
71 #include <sys/device.h>
72 #include <machine/io.h>
73 #include <machine/intr.h>
74 #include <arm/arm32/katelib.h>
75 #include <acorn32/podulebus/podulebus.h>
76 #include <dev/podulebus/podules.h>
77 
78 /* Include for interface to the net and ethernet subsystems */
79 
80 #include <sys/socket.h>
81 #include <sys/syslog.h>
82 #include <sys/ioctl.h>
83 #include <sys/mbuf.h>
84 
85 #include <net/if.h>
86 #include <net/if_types.h>
87 #include <net/if_dl.h>
88 #include <net/if_ether.h>
89 
90 #ifdef INET
91 #include <netinet/in.h>
92 #include <netinet/in_systm.h>
93 #include <netinet/in_var.h>
94 #include <netinet/ip.h>
95 #include <netinet/if_inarp.h>
96 #endif
97 
98 #ifdef NS
99 #include <netns/ns.h>
100 #include <netns/ns_if.h>
101 #endif
102 
103 /* Import our data structres */
104 
105 #include "if_iereg.h"
106 
107 /* BPF support */
108 
109 #include "bpfilter.h"
110 #if NBPFILTER > 0
111 #include <net/bpf.h>
112 #include <net/bpfdesc.h>
113 #endif
114 
115 /* Some useful defines and macros */
116 
117 #define PODULE_IRQ_PENDING (1)
118 #define NFRAMES	(16)		/* number of frame to allow for receive */
119 #define NRXBUF	(48)		/* number of receive buffers to allocate */
120 #define IE_RXBUF_SIZE (256) 	/* receive buf size */
121 #define NTXBUF  (2)		/* number of transmit buffers to allocate */
122 #define IE_TXBUF_SIZE (1522) 	/* size of tx buffer */
123 
124 #define PWriteShort(a,b)	WriteWord(a,(b)<<16|(b))
125 
126 #define	xoffsetof(type, member)	(offsetof(type, member) << 1)
127 
128 /* Some data structres local to this file */
129 
130 struct ie_softc {
131 	struct device	sc_dev;
132 	int 		sc_podule_number;
133 	podule_t	*sc_podule;
134 	irqhandler_t 	sc_ih;
135 	int		sc_flags;
136 #define IE_BROKEN	1
137 	int		sc_iobase;
138 	int		sc_fastbase;
139 	int		sc_rom;
140 	int		sc_ram;
141 	int		sc_control;
142 	struct ethercom	sc_ethercom;
143 	int		promisc;
144 	int		sc_irqmode;
145 
146 	u_long	rframes[NFRAMES];
147 	u_long	rbuffs[NRXBUF];
148 	u_long	cbuffs[NRXBUF];
149 	int 	rfhead, rftail, rbhead, rbtail;
150 
151 	u_long 	xmit_cmds[NTXBUF];
152 	u_long 	xmit_buffs[NTXBUF];
153 	u_long 	xmit_cbuffs[NTXBUF];
154 	int	xmit_count;
155 	int	xmit_free;
156 	int	xchead;
157 	int 	xctail;
158 };
159 
160 /* Function and data prototypes */
161 
162 static void host2ie( struct ie_softc *sc, void *src, u_long dest, int size );
163 static void ie2host( struct ie_softc *sc, u_long src, void *dest, int size );
164 static void iezero( struct ie_softc *sc, u_long p, int size );
165 void        iereset( struct ie_softc *sc );
166 void        iewatchdog( struct ifnet *ifp );
167 int         ieioctl( struct ifnet *ifp, u_long cmd, void *data );
168 void        iestart( struct ifnet *ifp );
169 int 	    iestop( struct ie_softc *sc );
170 int         ieinit( struct ie_softc *sc );
171 int 	    ieintr( void *arg );
172 void 	    ietint( struct ie_softc *sc );
173 
174 /* A whopper of a function */
175 static int command_and_wait( struct ie_softc *sc, u_short cmd,
176 			      struct ie_sys_ctl_block *pscb,
177 			      void *pcmd, int ocmd, int scmd, int mask );
178 
179 int ieprobe(struct device *, struct cfdata *, void *);
180 void ieattach(struct device *, struct device *, void *);
181 
182 static inline void ie_cli(struct ie_softc *);
183 static inline void ieattn(struct ie_softc *);
184 static inline void setpage(struct ie_softc *, u_long);
185 static void ie_ack(struct ie_softc *, u_short);
186 void PWriteShorts(char *, char *, int);
187 void ReadShorts(char *, char *, int);
188 static void run_tdr(struct ie_softc *);
189 u_long setup_rfa(struct ie_softc *, u_long);
190 static inline int ie_buflen(struct ie_softc *, int);
191 static inline int ie_packet_len(struct ie_softc *);
192 struct mbuf *ieget(struct ie_softc *, int *);
193 void ie_drop_packet_buffer(struct ie_softc *);
194 void ie_read_frame(struct ie_softc *, int num);
195 void ierint(struct ie_softc *);
196 void iexmit(struct ie_softc *);
197 static void start_receiver(struct ie_softc *);
198 
199 
200 /*
201  * Our cfattach structure for the autoconfig system to chew on
202  */
203 
204 CFATTACH_DECL(ie, sizeof(struct ie_softc),
205     ieprobe, ieattach, NULL, NULL);
206 
207 /* Let's go! */
208 
209 /*
210  * Clear all pending interrupts from the i82586 chip
211  */
212 
213 static inline void
214 ie_cli(struct ie_softc *sc)
215 {
216 	WriteByte(sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_CLI);
217 }
218 
219 /*
220  * Wake the i82586 chip up and get it to do something
221  */
222 
223 static inline void
224 ieattn(struct ie_softc *sc)
225 {
226 	WriteByte ( sc->sc_control + (IE_CONTROL<<2), IE_CONT_ATTN );
227 }
228 
229 /*
230  * Set the podule page register to bring a given address into view
231  */
232 
233 static inline void
234 setpage(struct ie_softc *sc, u_long off)
235 {
236 	WriteByte ( sc->sc_control + (IE_PAGE<<2), IE_COFF2PAGE(off) );
237 }
238 
239 /*
240  * Ack the i82586
241  */
242 
243 static void
244 ie_ack(struct ie_softc *sc, u_short mask)
245 {
246 	u_short stat;
247 	int i;
248 	setpage(sc, IE_IBASE + IE_SCB_OFF );
249 
250 	stat = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
251 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
252 
253 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
254 		(xoffsetof(struct ie_sys_ctl_block, ie_command)),
255 		stat & mask );
256 
257 	ieattn(sc);
258 
259 	for ( i=4000; --i>=0; ) {
260 		if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
261 		    (xoffsetof(struct ie_sys_ctl_block, ie_command))) )
262 			break;
263 		delay(100);
264 	}
265 
266 	if ( i<=0 )
267 		printf ( "ie: command timed out\n" );
268 	ie_cli(sc);
269 }
270 
271 /*
272  * This routine does the checksumming for the idrom
273  */
274 
275 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
276 static u_long
277 crc32(u_char *p, int l)
278 {
279 	u_long crc=-1;
280 	int i, b;
281 	while ( --l >= 0 ) {
282 		b = *p++;
283 		for ( i=8; --i >= 0; b>>=1 )
284 			if ((b&1)^(crc>>31))
285 				crc=(crc<<1)^0x4c11db7;
286 			else
287 				crc<<=1;
288 	}
289 	return crc;
290 }
291 #endif
292 
293 /*
294  * Probe for the ether1 card.  return 1 on success 0 on failure
295  */
296 
297 int
298 ieprobe(struct device *parent, struct cfdata *cf, void *aux)
299 {
300 	struct podule_attach_args *pa = (void *)aux;
301 
302 /* Look for a network slot interface */
303 
304 	return (pa->pa_product == PODULE_ETHER1);
305 }
306 
307 /*
308  * Attach our driver to the interfaces it uses
309  */
310 
311 void ieattach ( struct device *parent, struct device *self, void *aux )
312 {
313 	struct ie_softc *sc = (void *)self;
314 	struct podule_attach_args *pa = (void *)aux;
315 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
316 	int i;
317 	char idrom[32];
318 	u_int8_t hwaddr[ETHER_ADDR_LEN];
319 
320 	/* Check a few things about the attach args */
321 
322 	if (pa->pa_podule_number == -1)
323 		panic("Podule has disappeared !");
324 
325 	sc->sc_podule_number = pa->pa_podule_number;
326 	sc->sc_podule = pa->pa_podule;
327 	podules[sc->sc_podule_number].attached = 1;
328 
329 	/*
330 	 * MESS MESS MESS
331 	 *
332 	 * This needs a serious clean up. Alot of this code was in the probe function
333 	 * but required the softc structure. As a temporary measure until I rewrite it
334 	 * I have just bolted in the probe code here.
335 	 */
336 
337 	/* Index some podule areas */
338 	sc->sc_iobase   = sc->sc_podule->sync_base;	/* OBSOLETE */
339 	sc->sc_fastbase = sc->sc_podule->fast_base;	/* OBSOLETE */
340 	sc->sc_rom      = sc->sc_podule->sync_base;
341 	sc->sc_control  = sc->sc_podule->fast_base;
342 	sc->sc_ram      = sc->sc_podule->fast_base + IE_MEMOFF;
343 
344 	/* Set the page mask to something know and neutral */
345 	setpage(sc, IE_SCB_OFF);
346 
347 	/* Fetch the first part of the idrom */
348 	for ( i=0; i<16; i++ )
349 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
350 
351 	/* Verify the podulebus probe incase RiscOS lied */
352         if ( ReadByte ( sc->sc_rom + (3<<2) ) != 0x03 ) {
353 		printf(": Ether1 ROM probablly broken.  ECID corrupt\n");
354 		sc->sc_flags |= IE_BROKEN;
355 		return;
356 	}
357 
358 	/* Reset the 82586 */
359 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_RESET );
360  	delay(1000);
361 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), 0 );
362 	delay(10000);
363 
364 	/* Clear pending interrupts */
365 	ie_cli (sc);
366 
367 	/* Setup SCP */
368 	{
369 		struct ie_sys_conf_ptr scp;
370 		bzero (&scp, sizeof(scp) );
371 		scp.ie_iscp_ptr = (void *)IE_ISCP_ADDR;
372 		host2ie(sc, &scp, IE_SCP_ADDR, sizeof (scp) );
373 	}
374 
375 	/* Setup ISCP */
376 	{
377 		struct ie_int_sys_conf_ptr iscp;
378 		bzero ( &iscp, sizeof(iscp) );
379 		iscp.ie_busy = 1;
380 		iscp.ie_base = (void *)IE_IBASE;
381 		iscp.ie_scb_offset = IE_SCB_OFF;
382 		host2ie(sc, &iscp, IE_ISCP_ADDR, sizeof(iscp) );
383 	}
384 
385 	/* Initialise the control block */
386 	iezero ( sc, IE_IBASE + IE_SCB_OFF, sizeof(struct ie_sys_ctl_block) );
387 	ieattn(sc);
388 
389 	/* Wait for not busy */
390 	setpage ( sc, IE_ISCP_ADDR );
391 	for ( i=10000; --i>=0; ) {
392 		if ( !ReadShort( sc->sc_ram + IE_COFF2POFF(IE_ISCP_ADDR) +
393 		    ( xoffsetof(struct ie_int_sys_conf_ptr, ie_busy)) ) )
394 			break;
395 		delay (10);
396 	}
397 
398 	/* If the busy didn't go low, the i82586 is broken or too slow */
399         if ( i<=0 ) {
400 		printf ( ": ether1 chipset didn't respond\n" );
401 		sc->sc_flags |= IE_BROKEN;
402 		return;
403 	}
404 
405 	/* Ensure that the podule sends interrupts */
406         for ( i=1000; --i>=0 ; ) {
407 		if ( ReadByte(sc->sc_rom + 0) & PODULE_IRQ_PENDING )
408 			break;
409 		delay (10);
410 	}
411 
412 	/* If we didn't see the interrupt then the IRQ line is broken */
413 	if ( i<=0 ) {
414 		printf ( ": interrupt from chipset didn't reach host\n" );
415 		sc->sc_flags |= IE_BROKEN;
416 		return;
417 	}
418 
419 	/* Ack our little test operation */
420 	ie_ack(sc,IE_ST_WHENCE);
421         ie_cli (sc);
422 
423 	/* Get second part of idrom */
424 	for ( i=16; i<32; i++ )
425 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
426 
427 	/* This checksum always fails.  For some reason the first 16 */
428 	/* bytes are duplicated in the second 16 bytes, the checksum */
429 	/* should be at location 28 it is clearly not		     */
430 
431 	/* It is possible that this ether1 card is buggered	     */
432 
433 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
434 	if ( crc32(idrom,28) != *(u_long *)(idrom+28) )
435 	{
436 	    printf ( "ie: ether1 idrom failed checksum %08x!=%08x\n",
437 					crc32(idrom,28), *(u_long *)(idrom+28));
438             for ( i=0; i<32; i+=8 ) {
439 	        printf ( "IDROM: %02x %02x %02x %02x %02x %02x %02x %02x\n",
440 		    idrom[0+i], idrom[1+i], idrom[2+i], idrom[3+i],
441 		    idrom[4+i], idrom[5+i], idrom[6+i], idrom[7+i] );
442 	    }
443 	    printf ( "ie: I'll ignore this fact for now!\n" );
444 	}
445 #endif
446 
447 	/* Get our ethernet address.  Do explicit copy */
448 	for ( i=0; i<ETHER_ADDR_LEN; i++ )
449 	    hwaddr[i] = idrom[9+i];
450 
451 	/* Fill in my application form to attach to the inet system */
452 
453 	memcpy( ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
454 	ifp->if_softc = sc;
455 	ifp->if_start = iestart;
456 	ifp->if_ioctl = ieioctl;
457 	ifp->if_watchdog = iewatchdog;
458 	ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
459 
460 	/* Signed, dated then sent */
461         if_attach (ifp);
462 	ether_ifattach(ifp, hwaddr);
463 
464 	/* "Hmm," said nuts, "what if the attach fails" */
465 
466 	/* Write some pretty things on the annoucement line */
467 	printf ( ": %s using %dk card ram",
468 	    ether_sprintf(hwaddr),
469 	    ((NRXBUF*IE_RXBUF_SIZE)+(NTXBUF*IE_TXBUF_SIZE))/1024 );
470 
471 	sc->sc_ih.ih_func = ieintr;
472 	sc->sc_ih.ih_arg = sc;
473 	sc->sc_ih.ih_level = IPL_NET;
474 	sc->sc_ih.ih_name = "net: ie";
475 	sc->sc_ih.ih_maskaddr = sc->sc_podule->irq_addr;
476 	sc->sc_ih.ih_maskbits = sc->sc_podule->irq_mask;
477 
478 	if (irq_claim(sc->sc_podule->interrupt, &sc->sc_ih)) {
479 		sc->sc_irqmode = 0;
480 		printf(" POLLED");
481 		panic("%s: Cannot install IRQ handler", sc->sc_dev.dv_xname);
482 	} else {
483 		sc->sc_irqmode = 1;
484 		printf(" IRQ");
485 	}
486 
487 	printf("\n");
488 }
489 
490 
491 /*
492  * Oh no!! Where's my shorts!!! I'm sure I put them on this morning
493  */
494 
495 void
496 PWriteShorts(char *src, char *dest, int cnt)
497 {
498 	for (cnt /= 2; --cnt >= 0; ) {
499 		PWriteShort(dest, *(u_short *)src);
500 		src+=2;
501 		dest+=4;
502 	}
503 }
504 
505 void
506 ReadShorts(char *src, char *dest, int cnt)
507 {
508 	for (cnt /= 2; --cnt >= 0; ) {
509 		*(u_short *)dest = ReadShort(src);
510 		src+=4;
511 		dest+=2;
512 	}
513 }
514 
515 /*
516  * A bcopy or memcpy to adapter ram.  It handles the page register for you
517  * so you dont have to worry about the ram windowing
518  */
519 
520 static void
521 host2ie(struct ie_softc *sc, void *src, u_long dest, int size)
522 {
523 	int cnt;
524 	char *sptr = src;
525 
526 #ifdef DIAGNOSTIC
527 	if (size & 1)
528 		panic("host2ie");
529 #endif
530 
531 	while (size > 0) {
532 		cnt = IE_PAGESIZE - dest % IE_PAGESIZE;
533 		if (cnt > size)
534 			cnt = size;
535 		setpage(sc, dest);
536 		PWriteShorts(sptr, (char *)sc->sc_ram + IE_COFF2POFF(dest), cnt);
537 		sptr+=cnt;
538 		dest+=cnt;
539 		size-=cnt;
540 	}
541 }
542 
543 static void
544 ie2host(struct ie_softc *sc, u_long src, void *dest, int size)
545 {
546 	int cnt;
547 	char *dptr = dest;
548 
549 #ifdef DIAGNOSTIC
550 	if (size & 1)
551 		panic ( "ie2host" );
552 #endif
553 
554 	while (size > 0) {
555 		cnt = IE_PAGESIZE - src % IE_PAGESIZE;
556 		if (cnt > size)
557 			cnt = size;
558 		setpage(sc, src);
559 		ReadShorts((char *)sc->sc_ram + IE_COFF2POFF(src), dptr, cnt);
560 		src+=cnt;
561 		dptr+=cnt;
562 		size-=cnt;
563 	}
564 }
565 
566 /*
567  * Like a bzero or memset 0 for adapter memory.  It handles the page
568  * register so you dont have to worry about it
569  */
570 
571 static void
572 iezero(struct ie_softc *sc, u_long p, int size)
573 {
574 	int cnt;
575 
576 	while (size > 0) {
577 		cnt = IE_PAGESIZE - p % IE_PAGESIZE;
578 		if (cnt > size)
579 			cnt=size;
580 		setpage(sc, p);
581 		memset((char *)sc->sc_ram + IE_COFF2POFF(p), 0, 2*cnt);
582 		p += cnt;
583 		size -= cnt;
584 	}
585 }
586 
587 /*
588  * I/O Control interface to the kernel, entry point here
589  */
590 
591 int
592 ieioctl(struct ifnet *ifp, unsigned long cmd, void *data)
593 {
594     struct ie_softc *sc = ifp->if_softc;
595     struct ifaddr *ifa = (struct ifaddr *)data;
596     int s;
597     int error=0;
598 
599     s=splnet();
600 
601     switch ( cmd )
602     {
603 	case SIOCINITIFADDR:
604 	    ifp->if_flags |= IFF_UP;
605 	    switch (ifa->ifa_addr->sa_family ) {
606 #ifdef INET
607 		case AF_INET:
608 		    ieinit(sc);
609 		    arp_ifinit(ifp, ifa );
610 		    break;
611 #endif
612 		default:
613 		    ieinit(sc);
614 		    break;
615 	    }
616 	    break;
617 
618 #define IZSET(a,b) ((a->if_flags&b)!=0)
619 #define IZCLR(a,b) ((a->if_flags&b)==0)
620 #define DOSET(a,b) (a->if_flags|=b)
621 #define DOCLR(a,b) (a->if_flags&=~b)
622 
623 	case SIOCSIFFLAGS:
624 	    if ((error = ifioctl_common(ifp, cmd, data)) != 0)
625 		return error;
626 	    sc->promisc = ifp->if_flags & ( IFF_PROMISC | IFF_ALLMULTI );
627 
628 	    if ( IZCLR(ifp,IFF_UP) && IZSET(ifp,IFF_RUNNING) )
629 	    {
630 		/* Interface was marked down and its running so stop it */
631 		iestop(sc);
632 		DOCLR(ifp,IFF_RUNNING);
633 	    }
634 	    else if ( IZSET(ifp,IFF_UP) && IZCLR(ifp,IFF_RUNNING) )
635 	    {
636 		/* Just marked up and we're not running so start it */
637 		ieinit(sc);
638 	    }
639 	    else
640 	    {
641 		/* else reset to invoke changes in other registers */
642 		iestop(sc);
643 		ieinit(sc);
644             }
645 
646 	default:
647 	    error = ether_ioctl(ifp, cmd, data);
648 	    break;
649     }
650     (void)splx(s);
651     return error;
652 }
653 
654 /*
655  * Reset the card.  Completely.
656  */
657 
658 void
659 iereset(struct ie_softc *sc)
660 {
661 	struct ie_sys_ctl_block scb;
662 	int s = splnet();
663 
664 	iestop(sc);
665 
666 	ie2host(sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb);
667 
668 	if (command_and_wait(sc, IE_RU_ABORT|IE_CU_ABORT, 0, 0, 0, 0, 0))
669 	        printf("ie0: abort commands timed out\n");
670 
671 	if (command_and_wait(sc, IE_RU_DISABLE|IE_CU_STOP, 0, 0, 0, 0, 0))
672 	        printf("ie0: abort commands timed out\n");
673 
674 	ieinit(sc);
675 
676 	(void)splx(s);
677 }
678 
679 /*
680  * Watchdog entry point.  This is the entry for the kernel to call us
681  */
682 
683 void
684 iewatchdog(struct ifnet *ifp)
685 {
686 	struct ie_softc *sc = ifp->if_softc;
687 
688 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
689 	++ifp->if_oerrors;
690 	iereset(sc);
691 }
692 
693 /*
694  * Start the time-domain-refloctometer running
695  */
696 
697 static void
698 run_tdr(struct ie_softc *sc)
699 {
700     struct ie_sys_ctl_block scb;
701     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
702     struct ie_tdr_cmd cmd;
703     int result;
704 
705     bzero ( &scb, sizeof(scb) );
706     bzero ( &cmd, sizeof(cmd) );
707 
708     cmd.com.ie_cmd_status = 0;
709     cmd.com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
710     cmd.com.ie_cmd_link = 0xffff;
711     cmd.ie_tdr_time = 0;
712 
713     scb.ie_command_list = (u_short)ptr;
714 
715     result=0;
716     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
717 	IE_STAT_COMPL) )
718     {
719 	    result = 0x10000;
720     }
721     else if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
722     {
723 	result = 0x10000;
724     }
725 
726     if ( result==0 )
727 	result = cmd.ie_tdr_time;
728 
729     ie_ack ( sc, IE_ST_WHENCE );
730 
731     if (result & IE_TDR_SUCCESS )
732 	return;
733 
734     /* Very messy.  I'll tidy it later */
735 
736     if ( result & 0x10000 )
737     {
738 	printf ( "ie: TDR command failed\n" );
739     }
740     else if ( result & IE_TDR_XCVR )
741     {
742 	printf ( "ie: tranceiver problem. Is it plugged in?\n" );
743     }
744     else if ( result & IE_TDR_OPEN )
745     {
746 	if ((result & IE_TDR_TIME)>0)
747 	    printf ( "ie: TDR detected an open %d clocks away.\n",
748 			result & IE_TDR_TIME );
749     }
750     else if ( result & IE_TDR_SHORT )
751     {
752 	if ((result & IE_TDR_TIME)>0)
753 	    printf ( "ie: TDR detected a short %d clock away.\n",
754 			result & IE_TDR_TIME );
755     }
756     else
757     {
758 	printf ( "ie: TDR returned unknown status %x\n", result );
759     }
760 }
761 
762 u_long
763 setup_rfa(struct ie_softc *sc, u_long ptr)
764 {
765     int i;
766     {
767 	/* Receive frame descriptors */
768         struct ie_recv_frame_desc rfd;
769 	memset( &rfd, 0, sizeof rfd );
770 	for ( i=0; i<NFRAMES; i++ )
771 	{
772 	    sc->rframes[i] = ptr;
773 	    rfd.ie_fd_next = ptr + sizeof rfd;
774 	    host2ie(sc, (char *)&rfd, ptr, sizeof rfd);
775 	    ptr += sizeof rfd;
776 	}
777 	rfd.ie_fd_next = sc->rframes[0];
778 	rfd.ie_fd_last |= IE_FD_LAST;
779 	host2ie(sc, (char *)&rfd, sc->rframes[NFRAMES-1], sizeof rfd );
780 
781 	ie2host(sc, sc->rframes[0], (char *)&rfd, sizeof rfd );
782 	rfd.ie_fd_buf_desc = (u_short) ptr;
783 	host2ie(sc, (char *)&rfd, sc->rframes[0], sizeof rfd );
784     }
785 
786     {
787 	/* Receive frame descriptors */
788 	struct ie_recv_buf_desc rbd;
789 	memset(&rbd, 0, sizeof rbd);
790 	for ( i=0; i<NRXBUF; i++ )
791 	{
792 	    sc->rbuffs[i] = ptr;
793 	    rbd.ie_rbd_length = IE_RXBUF_SIZE;
794 	    rbd.ie_rbd_buffer = (void *)(ptr + sizeof rbd);
795 	    rbd.ie_rbd_next = (u_short)(ptr + sizeof rbd + IE_RXBUF_SIZE);
796 	    host2ie(sc, &rbd, ptr, sizeof rbd);
797 	    ptr+=sizeof rbd;
798 
799 	    sc->cbuffs[i] = ptr;
800 	    ptr+=IE_RXBUF_SIZE;
801 	}
802 	rbd.ie_rbd_next = sc->rbuffs[0];
803 	rbd.ie_rbd_length |= IE_RBD_LAST;
804 	host2ie(sc, &rbd, sc->rbuffs[NRXBUF-1], sizeof rbd);
805     }
806 
807     sc->rfhead = 0;
808     sc->rftail = NFRAMES-1;
809     sc->rbhead = 0;
810     sc->rbtail = NRXBUF-1;
811 
812     {
813 	struct ie_sys_ctl_block scb;
814 	bzero ( &scb, sizeof scb );
815 	scb.ie_recv_list = (u_short)sc->rframes[0];
816 	host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
817     }
818     return ptr;
819 }
820 
821 static void
822 start_receiver(struct ie_softc *sc)
823 {
824     struct ie_sys_ctl_block scb;
825     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
826     scb.ie_recv_list = (u_short)sc->rframes[0];
827     command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
828     ie_ack(sc, IE_ST_WHENCE );
829 }
830 
831 /*
832  * Take our configuration and update all the other data structures that
833  * require information from the driver.
834  *
835  * CALL AT SPLIMP OR HIGHER
836  */
837 
838 int
839 ieinit(struct ie_softc *sc)
840 {
841     struct ifnet *ifp;
842     struct ie_sys_ctl_block scb;
843     struct ie_config_cmd cmd;
844     struct ie_iasetup_cmd iasetup_cmd;
845     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
846     int n;
847 
848     ifp = &sc->sc_ethercom.ec_if;
849 
850     bzero ( &scb, sizeof(scb) );
851 
852     /* Send the configure command */
853 
854     cmd.com.ie_cmd_status = 0;
855     cmd.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
856     cmd.com.ie_cmd_link = 0xffff;
857 
858     cmd.ie_config_count = 0x0c;
859     cmd.ie_fifo = 8;
860     cmd.ie_save_bad = 0x40;
861     cmd.ie_addr_len = 0x2e;
862     cmd.ie_priority = 0;
863     cmd.ie_ifs = 0x60;
864     cmd.ie_slot_low = 0;
865     cmd.ie_slot_high = 0xf2;
866     cmd.ie_promisc = 0;		/* Hey nuts, look at this! */
867     cmd.ie_crs_cdt = 0;
868     cmd.ie_min_len = 64;
869     cmd.ie_junk = 0xff;
870 
871     scb.ie_command_list = (u_short)ptr;
872 
873     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
874 	IE_STAT_COMPL) )
875     {
876 	printf ( "%s: command failed: timeout\n", sc->sc_dev.dv_xname );
877 	return 0;
878     }
879 
880     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
881     {
882 	printf ( "%s: command failed: !IE_STAT_OK\n", sc->sc_dev.dv_xname );
883 	return 0;
884     }
885 
886     /* Individual address setup command */
887 
888     iasetup_cmd.com.ie_cmd_status = 0;
889     iasetup_cmd.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
890     iasetup_cmd.com.ie_cmd_link = 0xffff;
891 
892     bcopy ( CLLADDR(ifp->if_sadl), (void *) &iasetup_cmd.ie_address,
893 	 	sizeof (iasetup_cmd.ie_address) );
894 
895     if ( command_and_wait(sc, IE_CU_START, &scb, &iasetup_cmd, ptr, sizeof cmd,
896 	IE_STAT_COMPL) )
897     {
898 	printf ( "%s: iasetup failed : timeout\n", sc->sc_dev.dv_xname );
899 	return 0;
900     }
901 
902     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
903     {
904 	printf ( "%s: iasetup failed : !IE_STAT_OK\n", sc->sc_dev.dv_xname );
905 	return 0;
906     }
907 
908     ie_ack ( sc, IE_ST_WHENCE );
909 
910     /* Run the time-domain refloctometer */
911     run_tdr ( sc );
912 
913     ie_ack ( sc, IE_ST_WHENCE );
914 
915     /* meminit */
916     ptr = setup_rfa(sc, ptr);
917 
918     ifp->if_flags |= IFF_RUNNING;
919     ifp->if_flags &= ~IFF_OACTIVE;
920 
921     /* Setup transmit buffers */
922 
923     for ( n=0; n<NTXBUF; n++ ) {
924 	sc->xmit_cmds[n] = ptr;
925 	iezero(sc, ptr, sizeof(struct ie_xmit_cmd) );
926 	ptr += sizeof(struct ie_xmit_cmd);
927 
928 	sc->xmit_buffs[n] = ptr;
929 	iezero(sc, ptr, sizeof(struct ie_xmit_buf));
930 	ptr += sizeof(struct ie_xmit_buf);
931     }
932 
933     for ( n=0; n<NTXBUF; n++ ) {
934 	sc->xmit_cbuffs[n] = ptr;
935 	ptr += IE_TXBUF_SIZE;
936     }
937 
938     sc->xmit_free = NTXBUF;
939     sc->xchead = sc->xctail = 0;
940 
941     {
942 	struct ie_xmit_cmd xmcmd;
943 	bzero ( &xmcmd, sizeof xmcmd );
944 	xmcmd.ie_xmit_status = IE_STAT_COMPL;
945 	host2ie(sc, &xmcmd, sc->xmit_cmds[0], sizeof xmcmd);
946     }
947 
948     start_receiver (sc);
949 
950     return 0;
951 }
952 
953 int
954 iestop(struct ie_softc *sc)
955 {
956     struct ie_sys_ctl_block scb;
957     int s = splnet();
958 
959     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
960 
961     if ( command_and_wait(sc, IE_RU_DISABLE, &scb, 0, 0, 0, 0) )
962         printf ( "ie0: abort commands timed out\n" );
963 
964     (void)splx(s);
965     return(0);
966 }
967 
968 /*
969  * Send a command to the card and awaits it's completion.
970  * Timeout if it's taking too long
971  */
972 
973 /*CAW*/
974 
975 static int
976 command_and_wait(struct ie_softc *sc, u_short cmd, struct ie_sys_ctl_block *pscb, void *pcmd, int ocmd, int scmd, int mask)
977 {
978     int i=0;
979 
980     /* Copy the command to the card */
981 
982     if ( pcmd )
983 	host2ie(sc, pcmd, ocmd, scmd); /* transfer the command to the card */
984 
985     /* Copy the scb to the card */
986 
987     if ( pscb ) {
988 	pscb->ie_command = cmd;
989 	host2ie(sc, pscb, IE_IBASE + IE_SCB_OFF, sizeof *pscb);
990     }
991     else
992     {
993 	setpage ( sc, IE_IBASE + IE_SCB_OFF );
994 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
995 		(xoffsetof(struct ie_sys_ctl_block, ie_command)), cmd );
996     }
997 
998     /* Prod the card to act on the newly loaded command */
999     ieattn(sc);
1000 
1001     /* Wait for the command to complete */
1002     if ( IE_ACTION_COMMAND(cmd) && pcmd )
1003     {
1004 	setpage(sc,ocmd);
1005 	for ( i=4000; --i>=0; ) {
1006 	    if ( ReadShort(sc->sc_ram + IE_COFF2POFF(ocmd) +
1007 		(xoffsetof(struct ie_config_cmd, ie_config_status))) & mask)
1008 		break;
1009 	    delay(100);
1010 	}
1011     }
1012     else
1013     {
1014 	for ( i=4000; --i>=0; ) {
1015 	    if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1016 		(xoffsetof(struct ie_sys_ctl_block, ie_command))) )
1017 		break;
1018 	    delay(100);
1019 	}
1020     }
1021 
1022     /* Update the host structures to reflect the state on the card */
1023     if ( pscb )
1024 	ie2host(sc, IE_IBASE + IE_SCB_OFF, pscb, sizeof *pscb );
1025     if ( pcmd )
1026 	ie2host(sc, ocmd, pcmd, scmd);
1027 
1028     return i < 0;
1029 }
1030 
1031 #define READ_MEMBER(sc,type,member,ptr,dest)			\
1032 	setpage(sc, ptr);					\
1033 	dest = ReadShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1034 	       (xoffsetof(type, member)) );
1035 
1036 #define WRITE_MEMBER(sc,type,member,ptr,dest)			\
1037 	setpage(sc, ptr);					\
1038 	PWriteShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1039 	       (xoffsetof(type, member)), dest );
1040 
1041 static inline int
1042 ie_buflen(struct ie_softc *sc, int head)
1043 {
1044 	int actual;
1045 
1046 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1047 	    sc->rbuffs[head], actual );
1048 
1049 	return(actual & (IE_RXBUF_SIZE | (IE_RXBUF_SIZE-1))) ;
1050 }
1051 
1052 static inline int
1053 ie_packet_len(struct ie_softc *sc)
1054 {
1055     int i;
1056     int actual;
1057     int head = sc->rbhead;
1058     int acc=0;
1059 
1060     do {
1061 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1062 			sc->rbuffs[sc->rbhead], actual );
1063 	if (!(actual&IE_RBD_USED))
1064 	{
1065 	    return (-1);
1066 	}
1067 
1068 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1069 			sc->rbuffs[head], i );
1070         i = i & IE_RBD_LAST;
1071 
1072 	acc += ie_buflen(sc, head);
1073 	head = (head+1) % NRXBUF;
1074     } while (!i);
1075 
1076     return acc;
1077 }
1078 
1079 struct mbuf *
1080 ieget(struct ie_softc *sc, int *to_bpf )
1081 {
1082     struct mbuf *top, **mp, *m;
1083     int head;
1084     int resid, totlen, thisrboff, thismboff;
1085     int len;
1086     struct ether_header eh;
1087 
1088     totlen = ie_packet_len(sc);
1089 
1090     if ( totlen > ETHER_MAX_LEN )
1091     {
1092 	printf ( "ie: Gosh that packet was s-o-o-o big.\n" );
1093 	return 0;
1094     }
1095 
1096     if ( totlen<=0 )
1097 	return 0;
1098 
1099     head = sc->rbhead;
1100 
1101     /* Read the ethernet header */
1102     ie2host ( sc, sc->cbuffs[head], (void *)&eh, sizeof eh );
1103 
1104     /* Check if the packet is for us */
1105 
1106     resid = totlen;
1107 
1108     MGETHDR ( m, M_DONTWAIT, MT_DATA );
1109     if ( m==0 )
1110 	return 0;
1111 
1112     m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
1113     m->m_pkthdr.len = totlen;
1114     len = MHLEN;
1115     top = 0;
1116     mp = &top;
1117 
1118     /*
1119      * This loop goes through and allocates mbufs for all the data we will
1120      * be copying in.  It does not actually do the copying yet.
1121      */
1122     while (totlen > 0) {
1123 	if (top) {
1124 	    MGET(m, M_DONTWAIT, MT_DATA);
1125 	    if (m == 0) {
1126 		m_freem(top);
1127 		return 0;
1128 	    }
1129 	    len = MLEN;
1130 	}
1131 	if (totlen >= MINCLSIZE) {
1132 	    MCLGET(m, M_DONTWAIT);
1133 	    if (m->m_flags & M_EXT)
1134 		len = MCLBYTES;
1135 	}
1136 
1137 	if (mp == &top) {
1138 		void *newdata = (void *)
1139 		    ALIGN(m->m_data + sizeof(struct ether_header)) -
1140 		    sizeof(struct ether_header);
1141 		len -= newdata - m->m_data;
1142 		m->m_data = newdata;
1143 	}
1144 
1145         m->m_len = len = min(totlen, len);
1146 
1147         totlen -= len;
1148         *mp = m;
1149         mp = &m->m_next;
1150     }
1151 
1152     m = top;
1153     thismboff = 0;
1154 
1155     /*
1156      * Copy the Ethernet header into the mbuf chain.
1157      */
1158     memcpy(mtod(m, void *), &eh, sizeof(struct ether_header));
1159     thismboff = sizeof(struct ether_header);
1160     thisrboff = sizeof(struct ether_header);
1161     resid -= sizeof(struct ether_header);
1162 
1163     /*
1164      * Now we take the mbuf chain (hopefully only one mbuf most of the
1165      * time) and stuff the data into it.  There are no possible failures at
1166      * or after this point.
1167      */
1168     while (resid > 0) {
1169 	int thisrblen = ie_buflen(sc, head) - thisrboff,
1170 	    thismblen = m->m_len - thismboff;
1171 	len = min(thisrblen, thismblen);
1172 
1173 /*      bcopy((void *)(sc->cbuffs[head] + thisrboff),
1174 	    mtod(m, void *) + thismboff, (u_int)len);	 */
1175 
1176 
1177 	if ( len&1 )
1178 	{
1179  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1180 		mtod(m, void *) + thismboff, (u_int)len+1);
1181   	}
1182 	else
1183 	{
1184  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1185 		mtod(m, void *) + thismboff, (u_int)len);
1186 	}
1187 
1188 	resid -= len;
1189 
1190 	if (len == thismblen) {
1191 		m = m->m_next;
1192 		thismboff = 0;
1193 	} else
1194 		thismboff += len;
1195 
1196 	if (len == thisrblen) {
1197 		head = (head + 1) % NRXBUF;
1198 		thisrboff = 0;
1199 	} else
1200 		thisrboff += len;
1201     }
1202 
1203 
1204     return top;
1205 }
1206 
1207 void
1208 ie_drop_packet_buffer(struct ie_softc *sc)
1209 {
1210     int i, actual, last;
1211 
1212     do {
1213 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1214 			sc->rbuffs[sc->rbhead], actual );
1215 	if (!(actual&IE_RBD_USED))
1216 	{
1217 	    iereset(sc);
1218 	    return;
1219 	}
1220 
1221 	i = actual & IE_RBD_LAST;
1222 
1223         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1224 			sc->rbuffs[sc->rbhead], last );
1225         last |= IE_RBD_LAST;
1226         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1227 			sc->rbuffs[sc->rbhead], last );
1228 
1229         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_actual,
1230 			sc->rbuffs[sc->rbhead], 0 );
1231 
1232 	sc->rbhead = ( sc->rbhead + 1 ) % NRXBUF;
1233 
1234         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1235 			sc->rbuffs[sc->rbtail], last );
1236         last &= ~IE_RBD_LAST;
1237         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1238 			sc->rbuffs[sc->rbtail], last );
1239 
1240 	sc->rbtail = ( sc->rbtail + 1 ) % NRXBUF;
1241     } while (!i);
1242 }
1243 
1244 void
1245 ie_read_frame(struct ie_softc *sc, int num)
1246 {
1247     int status;
1248     struct ie_recv_frame_desc rfd;
1249     struct mbuf *m=0;
1250     struct ifnet *ifp;
1251     int last;
1252 
1253     ifp = &sc->sc_ethercom.ec_if;
1254 
1255     ie2host(sc, sc->rframes[num], &rfd, sizeof rfd );
1256     status = rfd.ie_fd_status;
1257 
1258     /* Advance the RFD list, since we're done with this descriptor */
1259 
1260     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1261 			sc->rframes[num], 0 );
1262 
1263     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1264 			sc->rframes[num], last );
1265     last |= IE_FD_LAST;
1266     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1267 			sc->rframes[num], last );
1268 
1269     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1270 			sc->rframes[sc->rftail], last );
1271     last &= ~IE_FD_LAST;
1272     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1273 			sc->rframes[sc->rftail], last );
1274 
1275     sc->rftail = ( sc->rftail + 1 ) % NFRAMES;
1276     sc->rfhead = ( sc->rfhead + 1 ) % NFRAMES;
1277 
1278     if ( status & IE_FD_OK ) {
1279 	m = ieget(sc, 0);
1280 	ie_drop_packet_buffer(sc);
1281     }
1282 
1283     if ( m==0 ) {
1284 	ifp->if_ierrors++;
1285 	return;
1286     }
1287 
1288     ifp->if_ipackets++;
1289 
1290 #if NBPFILTER > 0
1291     if ( ifp->if_bpf ) {
1292 	bpf_mtap(ifp->if_bpf, m );
1293     };
1294 #endif
1295 
1296     (*ifp->if_input)(ifp, m);
1297 }
1298 
1299 void
1300 ierint(struct ie_softc *sc)
1301 {
1302     int i;
1303     int times_thru = 1024;
1304     struct ie_sys_ctl_block scb;
1305     int status;
1306     int safety_catch = 0;
1307 
1308     i = sc->rfhead;
1309     for (;;) {
1310 
1311 	if ( (safety_catch++)>100 )
1312 	{
1313 	    printf ( "ie: ierint safety catch tripped\n" );
1314 	    iereset(sc);
1315 	    return;
1316 	}
1317 
1318 	READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1319 				sc->rframes[i],status);
1320 
1321 	if ((status&IE_FD_COMPLETE)&&(status&IE_FD_OK)) {
1322 	    if ( !--times_thru ) {
1323 		printf ( "IERINT: Uh oh. Nuts, look at this bit!!!\n" );
1324     		ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1325 		sc->sc_ethercom.ec_if.if_ierrors += scb.ie_err_crc +
1326 						  scb.ie_err_align +
1327 						  scb.ie_err_resource +
1328 						  scb.ie_err_overrun;
1329 		scb.ie_err_crc      = scb.ie_err_align   = 0;
1330 		scb.ie_err_resource = scb.ie_err_overrun = 0;
1331 	        host2ie(sc, &scb, IE_SCP_ADDR, sizeof (scb) );
1332 	    }
1333 	    ie_read_frame(sc, i);
1334 	} else {
1335     	    ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1336 
1337 	    if ( ((status&IE_FD_RNR)!=0) && ((scb.ie_status&IE_RU_READY)==0) )
1338 	    {
1339 		WRITE_MEMBER(sc,struct ie_recv_frame_desc, ie_fd_buf_desc,
1340 				sc->rframes[0], sc->rbuffs[0] );
1341 
1342 		scb.ie_recv_list = sc->rframes[0];
1343 	        host2ie(sc, (char *)&scb, IE_IBASE + IE_SCB_OFF, sizeof (scb) );
1344     		command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
1345 	    }
1346 	    break;
1347 	}
1348 	i = (i + 1) % NFRAMES;
1349     }
1350 }
1351 
1352 static int in_intr = 0;
1353 
1354 int
1355 ieintr(void *arg)
1356 {
1357     struct ie_softc *sc = arg;
1358     u_short status;
1359     int safety_catch = 0;
1360     static int safety_net = 0;
1361 
1362     if (in_intr == 1)
1363 	panic ( "ie: INTERRUPT REENTERED\n" );
1364 
1365     /* Clear the interrrupt */
1366     ie_cli (sc);
1367 
1368     setpage(sc, IE_IBASE + IE_SCB_OFF );
1369     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1370 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1371 
1372     status = status & IE_ST_WHENCE;
1373 
1374     if (status == 0) {
1375 	in_intr = 0;
1376 	return(0);
1377     }
1378 
1379 loop:
1380 
1381     ie_ack(sc, status);
1382 
1383     if (status & (IE_ST_FR | IE_ST_RNR))
1384 	ierint(sc);
1385 
1386     if (status & IE_ST_CX)
1387 	ietint(sc);
1388 
1389     if (status & IE_ST_RNR) {
1390 	printf ( "ie: receiver not ready\n" );
1391 	sc->sc_ethercom.ec_if.if_ierrors++;
1392 	iereset(sc);
1393     }
1394 
1395     setpage(sc, IE_IBASE + IE_SCB_OFF );
1396     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1397 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1398     status = status & IE_ST_WHENCE;
1399 
1400     ie_cli(sc);
1401 
1402     if (status == 0) {
1403 	in_intr = 0;
1404 	return(0);
1405     }
1406 
1407     /* This is prehaps a little over cautious */
1408     if ( safety_catch++ > 10 )
1409     {
1410 	printf ( "ie: Interrupt couldn't be cleared\n" );
1411 	delay ( 1000 );
1412 	ie_cli(sc);
1413 	if ( safety_net++ > 50 )
1414 	{
1415 /*	    printf ( "ie: safety net catches driver, shutting down\n" );
1416 	    disable_irq ( IRQ_PODULE );*/
1417 	}
1418 	in_intr = 0;
1419 	return(0);
1420     }
1421 
1422     goto loop;
1423 }
1424 
1425 void
1426 iexmit(struct ie_softc *sc)
1427 {
1428 /*    int actual;*/
1429     struct ie_sys_ctl_block scb;
1430 
1431     struct ie_xmit_cmd xc;
1432     struct ie_xmit_buf xb;
1433 
1434     ie2host(sc, sc->xmit_buffs[sc->xctail], (char *)&xb, sizeof xb );
1435     xb.ie_xmit_flags |= IE_XMIT_LAST;
1436     xb.ie_xmit_next = 0xffff;
1437     xb.ie_xmit_buf = (void *)sc->xmit_cbuffs[sc->xctail];
1438     host2ie(sc, &xb, sc->xmit_buffs[sc->xctail], sizeof xb );
1439 
1440     bzero ( &xc, sizeof xc );
1441     xc.com.ie_cmd_link = 0xffff;
1442     xc.com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
1443     xc.ie_xmit_status = 0x0000;
1444     xc.ie_xmit_desc = sc->xmit_buffs[sc->xctail];
1445     host2ie(sc, (char *)&xc, sc->xmit_cmds[sc->xctail], sizeof xc );
1446 
1447     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1448     scb.ie_command_list = sc->xmit_cmds[sc->xctail];
1449     host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
1450 
1451     command_and_wait(sc, IE_CU_START, &scb, &xc, sc->xmit_cmds[sc->xctail]
1452 			, sizeof xc, IE_STAT_COMPL);
1453 
1454     sc->sc_ethercom.ec_if.if_timer = 5;
1455 }
1456 /*
1457  * Start sending all the queued buffers.
1458  */
1459 
1460 void
1461 iestart(struct ifnet *ifp)
1462 {
1463 	struct ie_softc *sc = ifp->if_softc;
1464 	struct mbuf *m0, *m;
1465 	u_char *buffer;
1466 	u_short len;
1467 	char txbuf[IE_TXBUF_SIZE];
1468 	int safety_catch = 0;
1469 
1470 	if ((ifp->if_flags & IFF_OACTIVE) != 0)
1471 		return;
1472 
1473 	for (;;) {
1474 		if ( (safety_catch++)>100 )
1475 		{
1476 		    printf ( "ie: iestart safety catch tripped\n" );
1477 		    iereset(sc);
1478 		    return;
1479 		}
1480 		if (sc->xmit_free == 0) {
1481 			ifp->if_flags |= IFF_OACTIVE;
1482 			break;
1483 		}
1484 
1485 		IF_DEQUEUE(&ifp->if_snd, m);
1486 		if (!m)
1487 			break;
1488 
1489 		/* TODO: Write directly to the card */
1490 		len = 0;
1491 		/* buffer = sc->xmit_cbuffs[sc->xchead]; */
1492 		buffer = txbuf;
1493 
1494 		for (m0 = m; m && (len + m->m_len) < IE_TXBUF_SIZE;
1495 		     m = m->m_next) {
1496 			memcpy( buffer, mtod(m, void *), m->m_len);
1497 			buffer += m->m_len;
1498 			len += m->m_len;
1499 		}
1500 
1501 #if NBPFILTER > 0
1502 		if ( ifp->if_bpf )
1503 		    bpf_mtap(ifp->if_bpf, m0);
1504 #endif
1505 
1506 		m_freem(m0);
1507 		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
1508 			memset(buffer, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - len);
1509 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
1510 			buffer += ETHER_MIN_LEN - ETHER_CRC_LEN;
1511 		}
1512 
1513 		/* When we write directly to the card we dont need this */
1514     		if (len&1)
1515    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len+1 );
1516 		else
1517    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len );
1518 
1519 		/* sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; */
1520 
1521 		WRITE_MEMBER(sc,struct ie_xmit_buf, ie_xmit_flags,
1522 				sc->xmit_buffs[sc->xchead], len)
1523 
1524 		/* Start the first packet transmitting. */
1525 		if (sc->xmit_free == NTXBUF)
1526 			iexmit(sc);
1527 
1528 		sc->xchead = (sc->xchead + 1) % NTXBUF;
1529 		sc->xmit_free--;
1530 	}
1531 }
1532 
1533 void
1534 ietint(struct ie_softc *sc)
1535 {
1536     struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1537 
1538     int status;
1539 
1540     ifp->if_timer=0;
1541     ifp->if_flags &= ~IFF_OACTIVE;
1542 
1543     READ_MEMBER(sc,struct ie_xmit_cmd, ie_xmit_status,
1544 	sc->xmit_cmds[sc->xctail], status );
1545 
1546     if (!(status&IE_STAT_COMPL) || (status & IE_STAT_BUSY) )
1547 	printf ( "ietint: command still busy!\n" );
1548 
1549     if ( status & IE_STAT_OK ) {
1550 	ifp->if_opackets++;
1551 	ifp->if_collisions += status & IE_XS_MAXCOLL;
1552     } else {
1553 	ifp->if_oerrors++;
1554 	if ( status & IE_STAT_ABORT )
1555 	    printf ( "ie: send aborted\n" );
1556 	if ( status & IE_XS_LATECOLL )
1557 	    printf ( "ie: late collision\n" );
1558 	if ( status & IE_XS_NOCARRIER )
1559 	    printf ( "ie: no carrier\n" );
1560 	if ( status & IE_XS_LOSTCTS )
1561 	    printf ( "ie: lost CTS\n" );
1562 	if ( status & IE_XS_UNDERRUN )
1563 	    printf ( "ie: DMA underrun\n" );
1564 	if ( status & IE_XS_EXCMAX )
1565 	    printf ( "ie: too many collisions\n" );
1566 	ifp->if_collisions+=16;
1567     }
1568     /* Done with the buffer */
1569     sc->xmit_free++;
1570     sc->xctail = (sc->xctail + 1 ) % NTXBUF;
1571 
1572     /* Start the next packet transmitting, if any */
1573     if ( sc->xmit_free<NTXBUF )
1574 	iexmit(sc);
1575 
1576     iestart(ifp);
1577 }
1578 
1579 /* End of if_ie.c */
1580