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