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