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