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