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