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