Home | History | Annotate | Line # | Download | only in vme
if_le_vme.c revision 1.18
      1 /*	$NetBSD: if_le_vme.c,v 1.18 2003/08/07 16:27:08 agc Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Ralph Campbell and Rick Macklem.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
     35  */
     36 
     37 /*-
     38  * Copyright (c) 1998 maximum entropy.  All rights reserved.
     39  * Copyright (c) 1997 Leo Weppelman.  All rights reserved.
     40  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
     41  *
     42  * This code is derived from software contributed to Berkeley by
     43  * Ralph Campbell and Rick Macklem.
     44  *
     45  * Redistribution and use in source and binary forms, with or without
     46  * modification, are permitted provided that the following conditions
     47  * are met:
     48  * 1. Redistributions of source code must retain the above copyright
     49  *    notice, this list of conditions and the following disclaimer.
     50  * 2. Redistributions in binary form must reproduce the above copyright
     51  *    notice, this list of conditions and the following disclaimer in the
     52  *    documentation and/or other materials provided with the distribution.
     53  * 3. All advertising materials mentioning features or use of this software
     54  *    must display the following acknowledgement:
     55  *	This product includes software developed by the University of
     56  *	California, Berkeley and its contributors.
     57  * 4. Neither the name of the University nor the names of its contributors
     58  *    may be used to endorse or promote products derived from this software
     59  *    without specific prior written permission.
     60  *
     61  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     62  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     71  * SUCH DAMAGE.
     72  *
     73  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
     74  */
     75 
     76 #include <sys/cdefs.h>
     77 __KERNEL_RCSID(0, "$NetBSD: if_le_vme.c,v 1.18 2003/08/07 16:27:08 agc Exp $");
     78 
     79 #include "opt_inet.h"
     80 #include "bpfilter.h"
     81 
     82 #include <sys/param.h>
     83 #include <sys/systm.h>
     84 #include <sys/mbuf.h>
     85 #include <sys/syslog.h>
     86 #include <sys/socket.h>
     87 #include <sys/device.h>
     88 
     89 #include <net/if.h>
     90 #include <net/if_media.h>
     91 #include <net/if_ether.h>
     92 
     93 #ifdef INET
     94 #include <netinet/in.h>
     95 #include <netinet/if_inarp.h>
     96 #endif
     97 
     98 #include <machine/cpu.h>
     99 #include <machine/bus.h>
    100 #include <machine/iomap.h>
    101 #include <machine/scu.h>
    102 
    103 #include <atari/atari/device.h>
    104 #include <atari/atari/intr.h>
    105 
    106 #include <dev/ic/lancereg.h>
    107 #include <dev/ic/lancevar.h>
    108 #include <dev/ic/am7990reg.h>
    109 #include <dev/ic/am7990var.h>
    110 
    111 #include <atari/vme/vmevar.h>
    112 #include <atari/vme/if_levar.h>
    113 
    114 /*
    115  * All cards except BVME410 have 64KB RAM. However.... On the Riebl cards the
    116  * area between the offsets 0xee70-0xeec0 is used to store config data.
    117  */
    118 struct le_addresses {
    119 	u_long	reg_addr;
    120 	u_long	mem_addr;
    121 	int	irq;
    122 	int	reg_size;
    123 	int	mem_size;
    124 	int	type_hint;
    125 } lestd[] = {
    126 	{ 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024,
    127 				LE_OLD_RIEBL|LE_NEW_RIEBL }, /* Riebl	*/
    128 	{ 0xffcffff0, 0xffcf0000,      5, 16, 64*1024,
    129 				LE_PAM },		     /* PAM	*/
    130 	{ 0xfecffff0, 0xfecf0000,      5, 16, 64*1024,
    131 				LE_ROTHRON },		     /* Rhotron	*/
    132 	{ 0xfeff4100, 0xfe000000,      4,  8, VMECF_MEMSIZ_DEFAULT,
    133 				LE_BVME410 }		     /* BVME410 */
    134 };
    135 
    136 #define	NLESTD	(sizeof(lestd) / sizeof(lestd[0]))
    137 
    138 /*
    139  * Default mac for RIEBL cards without a (working) battery. The first 4 bytes
    140  * are the manufacturer id.
    141  */
    142 static u_char riebl_def_mac[] = {
    143 	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
    144 };
    145 
    146 static int le_intr __P((struct le_softc *, int));
    147 static void lepseudointr __P((struct le_softc *, void *));
    148 static int le_vme_match __P((struct device *, struct cfdata *, void *));
    149 static void le_vme_attach __P((struct device *, struct device *, void *));
    150 static int probe_addresses __P((bus_space_tag_t *, bus_space_tag_t *,
    151 				bus_space_handle_t *, bus_space_handle_t *));
    152 static void riebl_skip_reserved_area __P((struct lance_softc *));
    153 static int nm93c06_read __P((bus_space_tag_t, bus_space_handle_t, int));
    154 static int bvme410_probe __P((bus_space_tag_t, bus_space_handle_t));
    155 static int bvme410_mem_size __P((bus_space_tag_t, u_long));
    156 static void bvme410_copytobuf __P((struct lance_softc *, void *, int, int));
    157 static void bvme410_zerobuf __P((struct lance_softc *, int, int));
    158 
    159 CFATTACH_DECL(le_vme, sizeof(struct le_softc),
    160     le_vme_match, le_vme_attach, NULL, NULL);
    161 
    162 #if defined(_KERNEL_OPT)
    163 #include "opt_ddb.h"
    164 #endif
    165 
    166 #ifdef DDB
    167 #define	integrate
    168 #define hide
    169 #else
    170 #define	integrate	static __inline
    171 #define hide		static
    172 #endif
    173 
    174 hide void lewrcsr __P((struct lance_softc *, u_int16_t, u_int16_t));
    175 hide u_int16_t lerdcsr __P((struct lance_softc *, u_int16_t));
    176 
    177 hide void
    178 lewrcsr(sc, port, val)
    179 	struct lance_softc	*sc;
    180 	u_int16_t		port, val;
    181 {
    182 	struct le_softc		*lesc = (struct le_softc *)sc;
    183 	int			s;
    184 
    185 	s = splhigh();
    186 	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port);
    187 	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val);
    188 	splx(s);
    189 }
    190 
    191 hide u_int16_t
    192 lerdcsr(sc, port)
    193 	struct lance_softc	*sc;
    194 	u_int16_t		port;
    195 {
    196 	struct le_softc		*lesc = (struct le_softc *)sc;
    197 	u_int16_t		val;
    198 	int			s;
    199 
    200 	s = splhigh();
    201 	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port);
    202 	val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP);
    203 	splx(s);
    204 
    205 	return (val);
    206 }
    207 
    208 static int
    209 le_vme_match(parent, cfp, aux)
    210 	struct device	*parent;
    211 	struct cfdata	*cfp;
    212 	void		*aux;
    213 {
    214 	struct vme_attach_args	*va = aux;
    215 	int			i;
    216 	bus_space_tag_t		iot;
    217 	bus_space_tag_t		memt;
    218 	bus_space_handle_t	ioh;
    219 	bus_space_handle_t	memh;
    220 
    221 	iot  = va->va_iot;
    222 	memt = va->va_memt;
    223 
    224 	for (i = 0; i < NLESTD; i++) {
    225 		struct le_addresses	*le_ap = &lestd[i];
    226 		int			found  = 0;
    227 
    228 		if ((va->va_iobase != IOBASEUNK)
    229 		     && (va->va_iobase != le_ap->reg_addr))
    230 			continue;
    231 
    232 		if ((va->va_maddr != MADDRUNK)
    233 		     && (va->va_maddr != le_ap->mem_addr))
    234 			continue;
    235 
    236 		if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq))
    237 			continue;
    238 
    239 		if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, &ioh)) {
    240 			printf("leprobe: cannot map io-area\n");
    241 			return (0);
    242 		}
    243 		if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) {
    244 			if (bvme410_probe(iot, ioh)) {
    245 				bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */
    246 				le_ap->mem_size = bvme410_mem_size(memt, le_ap->mem_addr);
    247 			}
    248 		}
    249 		if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) {
    250 			bus_space_unmap(iot, ioh, le_ap->reg_size);
    251 			continue;
    252 		}
    253 
    254 		if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, &memh)) {
    255 			bus_space_unmap(iot, ioh, le_ap->reg_size);
    256 			printf("leprobe: cannot map memory-area\n");
    257 			return (0);
    258 		}
    259 		found = probe_addresses(&iot, &memt, &ioh, &memh);
    260 		bus_space_unmap(iot, ioh, le_ap->reg_size);
    261 		bus_space_unmap(memt, memh, le_ap->mem_size);
    262 
    263 		if (found) {
    264 			va->va_iobase = le_ap->reg_addr;
    265 			va->va_iosize = le_ap->reg_size;
    266 			va->va_maddr  = le_ap->mem_addr;
    267 			va->va_msize  = le_ap->mem_size;
    268 			va->va_aux    = le_ap;
    269 			if (va->va_irq == IRQUNK)
    270 				va->va_irq = le_ap->irq;
    271 			return 1;
    272 		}
    273     }
    274     return (0);
    275 }
    276 
    277 static int
    278 probe_addresses(iot, memt, ioh, memh)
    279 bus_space_tag_t		*iot;
    280 bus_space_tag_t		*memt;
    281 bus_space_handle_t	*ioh;
    282 bus_space_handle_t	*memh;
    283 {
    284 	/*
    285 	 * Test accesibility of register and memory area
    286 	 */
    287 	if(!bus_space_peek_2(*iot, *ioh, LER_RDP))
    288 		return 0;
    289 	if(!bus_space_peek_1(*memt, *memh, 0))
    290 		return 0;
    291 
    292 	/*
    293 	 * Test for writable memory
    294 	 */
    295 	bus_space_write_2(*memt, *memh, 0, 0xa5a5);
    296 	if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5)
    297 		return 0;
    298 
    299 	/*
    300 	 * Test writability of selector port.
    301 	 */
    302 	bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1);
    303 	if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1)
    304 		return 0;
    305 
    306 	/*
    307 	 * Do a small register test
    308 	 */
    309 	bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0);
    310 	bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP);
    311 	if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP)
    312 		return 0;
    313 
    314 	bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP);
    315 	if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP)
    316 		return 0;
    317 
    318 	return 1;
    319 }
    320 
    321 /*
    322  * Interrupt mess. Because the card's interrupt is hardwired to either
    323  * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do
    324  * (it kills the serial at the least), we use a 2-level interrupt scheme. The
    325  * card interrupt is routed to 'le_intr'. If the previous ipl was below
    326  * splnet, just call the mi-function. If not, save the interrupt status,
    327  * turn off card interrupts (the card is *very* persistent) and arrange
    328  * for a softint 'callback' through 'lepseudointr'.
    329  */
    330 static int
    331 le_intr(lesc, sr)
    332 	struct le_softc	*lesc;
    333 	int		 sr;
    334 {
    335 	struct lance_softc	*sc = &lesc->sc_am7990.lsc;
    336 	u_int16_t		csr0;
    337 
    338 	if ((sr & PSL_IPL) < (IPL_NET & PSL_IPL))
    339 		am7990_intr(sc);
    340 	else {
    341 		sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0);
    342 		lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA);
    343 		add_sicallback((si_farg)lepseudointr, lesc, sc);
    344 	}
    345 	return 1;
    346 }
    347 
    348 
    349 static void
    350 lepseudointr(lesc, sc)
    351 struct le_softc	*lesc;
    352 void		*sc;
    353 {
    354 	int	s;
    355 
    356 	s = splx(lesc->sc_splval);
    357 	am7990_intr(sc);
    358 	splx(s);
    359 }
    360 
    361 static void
    362 le_vme_attach(parent, self, aux)
    363 	struct device *parent, *self;
    364 	void *aux;
    365 {
    366 	struct le_softc		*lesc = (struct le_softc *)self;
    367 	struct lance_softc	*sc = &lesc->sc_am7990.lsc;
    368 	struct vme_attach_args	*va = aux;
    369 	bus_space_handle_t	ioh;
    370 	bus_space_handle_t	memh;
    371 	struct le_addresses	*le_ap;
    372 	int			i;
    373 
    374 	printf("\n%s: ", sc->sc_dev.dv_xname);
    375 
    376 	if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh))
    377 		panic("leattach: cannot map io-area");
    378 	if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh))
    379 		panic("leattach: cannot map mem-area");
    380 
    381 	lesc->sc_iot    = va->va_iot;
    382 	lesc->sc_ioh    = ioh;
    383 	lesc->sc_memt   = va->va_memt;
    384 	lesc->sc_memh   = memh;
    385 	lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */
    386 	le_ap           = (struct le_addresses *)va->va_aux;
    387 
    388 	/*
    389 	 * Go on to find board type
    390 	 */
    391 	if ((le_ap->type_hint & LE_PAM)
    392 		&& bus_space_peek_1(va->va_iot, ioh, LER_EEPROM)) {
    393 		printf("PAM card");
    394 		lesc->sc_type = LE_PAM;
    395 		bus_space_read_1(va->va_iot, ioh, LER_MEME);
    396 	}
    397 	else if((le_ap->type_hint & LE_BVME410)
    398 		&& bvme410_probe(va->va_iot, ioh)) {
    399 		printf("BVME410");
    400 		lesc->sc_type = LE_BVME410;
    401 	}
    402 	else if (le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) {
    403 		printf("Riebl card");
    404 		if(bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR)
    405 								== RIEBL_MAGIC)
    406 			lesc->sc_type = LE_NEW_RIEBL;
    407 		else {
    408 			printf("(without battery) ");
    409 			lesc->sc_type = LE_OLD_RIEBL;
    410 		}
    411 	}
    412 	else printf("le_vme_attach: Unsupported card!");
    413 
    414 	switch (lesc->sc_type) {
    415 	    case LE_BVME410:
    416 		sc->sc_copytodesc   = bvme410_copytobuf;
    417 		sc->sc_copyfromdesc = lance_copyfrombuf_contig;
    418 		sc->sc_copytobuf    = bvme410_copytobuf;
    419 		sc->sc_copyfrombuf  = lance_copyfrombuf_contig;
    420 		sc->sc_zerobuf      = bvme410_zerobuf;
    421 		break;
    422 	    default:
    423 		sc->sc_copytodesc   = lance_copytobuf_contig;
    424 		sc->sc_copyfromdesc = lance_copyfrombuf_contig;
    425 		sc->sc_copytobuf    = lance_copytobuf_contig;
    426 		sc->sc_copyfrombuf  = lance_copyfrombuf_contig;
    427 		sc->sc_zerobuf      = lance_zerobuf_contig;
    428 		break;
    429 	}
    430 
    431 	sc->sc_rdcsr   = lerdcsr;
    432 	sc->sc_wrcsr   = lewrcsr;
    433 	sc->sc_hwinit  = NULL;
    434 	sc->sc_conf3   = LE_C3_BSWP;
    435 	sc->sc_addr    = 0;
    436 	sc->sc_memsize = va->va_msize;
    437 	sc->sc_mem     = (void *)memh; /* XXX */
    438 
    439 	/*
    440 	 * Get MAC address
    441 	 */
    442 	switch (lesc->sc_type) {
    443 	    case LE_OLD_RIEBL:
    444 		bcopy(riebl_def_mac, sc->sc_enaddr,
    445 					sizeof(sc->sc_enaddr));
    446 		break;
    447 	    case LE_NEW_RIEBL:
    448 		for (i = 0; i < sizeof(sc->sc_enaddr); i++)
    449 		    sc->sc_enaddr[i] =
    450 			bus_space_read_1(va->va_memt, memh, i + RIEBL_MAC_ADDR);
    451 			break;
    452 	    case LE_PAM:
    453 		i = bus_space_read_1(va->va_iot, ioh, LER_EEPROM);
    454 		for (i = 0; i < sizeof(sc->sc_enaddr); i++) {
    455 		    sc->sc_enaddr[i] =
    456 			(bus_space_read_2(va->va_memt, memh, 2 * i) << 4) |
    457 			(bus_space_read_2(va->va_memt, memh, 2 * i + 1) & 0xf);
    458 		}
    459 		i = bus_space_read_1(va->va_iot, ioh, LER_MEME);
    460 		break;
    461 	    case LE_BVME410:
    462 		for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) {
    463 		    u_int16_t tmp;
    464 
    465 		    tmp = nm93c06_read(va->va_iot, ioh, i);
    466 		    sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff;
    467 		    sc->sc_enaddr[2 * i + 1] = tmp & 0xff;
    468 		}
    469 		bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */
    470 	}
    471 
    472 	am7990_config(&lesc->sc_am7990);
    473 
    474 	if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL))
    475 		riebl_skip_reserved_area(sc);
    476 
    477 	/*
    478 	 * XXX: We always use uservector 64....
    479 	 */
    480 	if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0,
    481 				(hw_ifun_t)le_intr, lesc)) == NULL) {
    482 		printf("le_vme_attach: Can't establish interrupt\n");
    483 		return;
    484 	}
    485 
    486 	/*
    487 	 * Notify the card of the vector
    488 	 */
    489 	switch (lesc->sc_type) {
    490 		case LE_OLD_RIEBL:
    491 		case LE_NEW_RIEBL:
    492 			bus_space_write_2(va->va_memt, memh, RIEBL_IVEC_ADDR,
    493 								64 + 64);
    494 			break;
    495 		case LE_PAM:
    496 			bus_space_write_1(va->va_iot, ioh, LER_IVEC, 64 + 64);
    497 			break;
    498 		case LE_BVME410:
    499 			bus_space_write_2(va->va_iot, ioh, BVME410_IVEC, 64 + 64);
    500 			break;
    501 	}
    502 
    503 	/*
    504 	 * Unmask the VME-interrupt we're on
    505 	 */
    506 	if (machineid & ATARI_TT)
    507 		SCU->vme_mask |= 1 << va->va_irq;
    508 }
    509 
    510 /*
    511  * True if 'addr' containe within [start,len]
    512  */
    513 #define WITHIN(start, len, addr)	\
    514 		((addr >= start) && ((addr) <= ((start) + (len))))
    515 static void
    516 riebl_skip_reserved_area(sc)
    517 	struct lance_softc	*sc;
    518 {
    519 	int	offset = 0;
    520 	int	i;
    521 
    522 	for(i = 0; i < sc->sc_nrbuf; i++) {
    523 		if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START)
    524 		    || WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) {
    525 			offset = RIEBL_RES_END - sc->sc_rbufaddr[i];
    526 		}
    527 		sc->sc_rbufaddr[i] += offset;
    528 	}
    529 
    530 	for(i = 0; i < sc->sc_ntbuf; i++) {
    531 		if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START)
    532 		    || WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) {
    533 			offset = RIEBL_RES_END - sc->sc_tbufaddr[i];
    534 		}
    535 		sc->sc_tbufaddr[i] += offset;
    536 	}
    537 }
    538 
    539 static int
    540 nm93c06_read(iot, ioh, nm93c06reg)
    541 	bus_space_tag_t iot;
    542 	bus_space_handle_t ioh;
    543 	int nm93c06reg;
    544 {
    545 	int bar;
    546 	int shift;
    547 	int bits = 0x180 | (nm93c06reg & 0xf);
    548 	int data = 0;
    549 
    550 	bar = 1<<BVME410_CS_SHIFT;
    551 	bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    552 	delay(1); /* tCSS = 1 us */
    553 	for (shift = 9; shift >= 0; shift--) {
    554 		if (((bits >> shift) & 1) == 1)
    555 			bar |= 1<<BVME410_DIN_SHIFT;
    556 		else
    557 			bar &= ~(1<<BVME410_DIN_SHIFT);
    558 		bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    559 		delay(1); /* tDIS = 0.4 us */
    560 		bar |= 1<<BVME410_CLK_SHIFT;
    561 		bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    562 		delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */
    563 		bar &= ~(1<<BVME410_CLK_SHIFT);
    564 		bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    565 		delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */
    566 	}
    567 	bar &= ~(1<<BVME410_DIN_SHIFT);
    568 	for (shift = 15; shift >= 0; shift--) {
    569 		delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */
    570 		bar |= 1<<BVME410_CLK_SHIFT;
    571 		bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    572 		delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */
    573 		data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift;
    574 		bar &= ~(1<<BVME410_CLK_SHIFT);
    575 		bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    576 		delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */
    577 	}
    578 	bar &= ~(1<<BVME410_CS_SHIFT);
    579 	bus_space_write_2(iot, ioh, BVME410_BAR, bar);
    580 	delay(1); /* tCS = 1 us */
    581 	return data;
    582 }
    583 
    584 static int
    585 bvme410_probe(iot, ioh)
    586 	bus_space_tag_t iot;
    587 	bus_space_handle_t ioh;
    588 {
    589 	if (!bus_space_peek_2(iot, ioh, BVME410_IVEC))
    590 		return 0;
    591 
    592 	bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000);
    593 	if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00)
    594 		return 0;
    595 
    596 	bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff);
    597 	if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff)
    598 		return 0;
    599 
    600 	bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5);
    601 	if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5)
    602 		return 0;
    603 
    604 	return 1;
    605 }
    606 
    607 static int
    608 bvme410_mem_size(memt, mem_addr)
    609 	bus_space_tag_t memt;
    610 	u_long mem_addr;
    611 {
    612 	bus_space_handle_t memh;
    613 	int r;
    614 
    615 	if (bus_space_map(memt, mem_addr, 256*1024, 0, &memh))
    616 		return VMECF_MEMSIZ_DEFAULT;
    617 	if (!bus_space_peek_1(memt, memh, 0)) {
    618 		bus_space_unmap(memt, memh, 256*1024);
    619 		return VMECF_MEMSIZ_DEFAULT;
    620 	}
    621 	bus_space_write_1(memt, memh, 0, 128);
    622 	bus_space_write_1(memt, memh, 64*1024, 32);
    623 	bus_space_write_1(memt, memh, 32*1024, 8);
    624 	r = (int)(bus_space_read_1(memt, memh, 0) * 2048);
    625 	bus_space_unmap(memt, memh, 256*1024);
    626 	return r;
    627 }
    628 
    629 /*
    630  * Need to be careful when writing to the bvme410 dual port memory.
    631  * Continue writing each byte until it reads back the same.
    632  */
    633 
    634 static void
    635 bvme410_copytobuf(sc, from, boff, len)
    636 	struct lance_softc *sc;
    637 	void *from;
    638 	int boff, len;
    639 {
    640 	volatile char *buf = (volatile char *) sc->sc_mem;
    641 	char *f = (char *) from;
    642 
    643 	for (buf += boff; len; buf++,f++,len--)
    644 		do {
    645  			*buf = *f;
    646 		} while (*buf != *f);
    647 }
    648 
    649 static void
    650 bvme410_zerobuf(sc, boff, len)
    651 	struct lance_softc *sc;
    652 	int boff, len;
    653 {
    654 	volatile char *buf = (volatile char *)sc->sc_mem;
    655 
    656 	for (buf += boff; len; buf++,len--)
    657 		do {
    658  			*buf = '\0';
    659 		} while (*buf != '\0');
    660 }
    661 
    662