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