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