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