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