1 /* $NetBSD: if_le_vme.c,v 1.25 2009/03/18 17:06:43 cegger Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 maximum entropy. All rights reserved. 5 * Copyright (c) 1997 Leo Weppelman. All rights reserved. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Ralph Campbell and Rick Macklem. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 37 */ 38 39 /*- 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.25 2009/03/18 17:06:43 cegger 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 __arraycount(lestd) 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(struct le_softc *, int); 147 static void lepseudointr(struct le_softc *, void *); 148 static int le_vme_match(device_t, cfdata_t, void *); 149 static void le_vme_attach(device_t, device_t, void *); 150 static int probe_addresses(bus_space_tag_t *, bus_space_tag_t *, 151 bus_space_handle_t *, bus_space_handle_t *); 152 static void riebl_skip_reserved_area(struct lance_softc *); 153 static int nm93c06_read(bus_space_tag_t, bus_space_handle_t, int); 154 static int bvme410_probe(bus_space_tag_t, bus_space_handle_t); 155 static int bvme410_mem_size(bus_space_tag_t, u_long); 156 static void bvme410_copytobuf(struct lance_softc *, void *, int, int); 157 static void bvme410_zerobuf(struct lance_softc *, int, int); 158 159 CFATTACH_DECL_NEW(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(struct lance_softc *, uint16_t, uint16_t); 175 hide uint16_t lerdcsr(struct lance_softc *, uint16_t); 176 177 hide void 178 lewrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 179 { 180 struct le_softc *lesc = (struct le_softc *)sc; 181 int s; 182 183 s = splhigh(); 184 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 185 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val); 186 splx(s); 187 } 188 189 hide uint16_t 190 lerdcsr(struct lance_softc *sc, uint16_t port) 191 { 192 struct le_softc *lesc = (struct le_softc *)sc; 193 uint16_t val; 194 int s; 195 196 s = splhigh(); 197 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 198 val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP); 199 splx(s); 200 201 return (val); 202 } 203 204 static int 205 le_vme_match(device_t parent, cfdata_t cfp, void *aux) 206 { 207 struct vme_attach_args *va = aux; 208 int i; 209 bus_space_tag_t iot; 210 bus_space_tag_t memt; 211 bus_space_handle_t ioh; 212 bus_space_handle_t memh; 213 214 iot = va->va_iot; 215 memt = va->va_memt; 216 217 for (i = 0; i < NLESTD; i++) { 218 struct le_addresses *le_ap = &lestd[i]; 219 int found = 0; 220 221 if ((va->va_iobase != IOBASEUNK) 222 && (va->va_iobase != le_ap->reg_addr)) 223 continue; 224 225 if ((va->va_maddr != MADDRUNK) 226 && (va->va_maddr != le_ap->mem_addr)) 227 continue; 228 229 if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq)) 230 continue; 231 232 if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, &ioh)) { 233 aprint_error("leprobe: cannot map io-area\n"); 234 return (0); 235 } 236 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 237 if (bvme410_probe(iot, ioh)) { 238 bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */ 239 le_ap->mem_size = bvme410_mem_size(memt, le_ap->mem_addr); 240 } 241 } 242 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 243 bus_space_unmap(iot, ioh, le_ap->reg_size); 244 continue; 245 } 246 247 if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, &memh)) { 248 bus_space_unmap(iot, ioh, le_ap->reg_size); 249 aprint_error("leprobe: cannot map memory-area\n"); 250 return (0); 251 } 252 found = probe_addresses(&iot, &memt, &ioh, &memh); 253 bus_space_unmap(iot, ioh, le_ap->reg_size); 254 bus_space_unmap(memt, memh, le_ap->mem_size); 255 256 if (found) { 257 va->va_iobase = le_ap->reg_addr; 258 va->va_iosize = le_ap->reg_size; 259 va->va_maddr = le_ap->mem_addr; 260 va->va_msize = le_ap->mem_size; 261 va->va_aux = le_ap; 262 if (va->va_irq == IRQUNK) 263 va->va_irq = le_ap->irq; 264 return 1; 265 } 266 } 267 return (0); 268 } 269 270 static int 271 probe_addresses(bus_space_tag_t *iot, bus_space_tag_t *memt, 272 bus_space_handle_t *ioh, bus_space_handle_t *memh) 273 { 274 275 /* 276 * Test accesibility of register and memory area 277 */ 278 if (!bus_space_peek_2(*iot, *ioh, LER_RDP)) 279 return 0; 280 if (!bus_space_peek_1(*memt, *memh, 0)) 281 return 0; 282 283 /* 284 * Test for writable memory 285 */ 286 bus_space_write_2(*memt, *memh, 0, 0xa5a5); 287 if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5) 288 return 0; 289 290 /* 291 * Test writability of selector port. 292 */ 293 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1); 294 if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1) 295 return 0; 296 297 /* 298 * Do a small register test 299 */ 300 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0); 301 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP); 302 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 303 return 0; 304 305 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP); 306 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 307 return 0; 308 309 return 1; 310 } 311 312 /* 313 * Interrupt mess. Because the card's interrupt is hardwired to either 314 * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do 315 * (it kills the serial at the least), we use a 2-level interrupt scheme. The 316 * card interrupt is routed to 'le_intr'. If the previous ipl was below 317 * splnet, just call the mi-function. If not, save the interrupt status, 318 * turn off card interrupts (the card is *very* persistent) and arrange 319 * for a softint 'callback' through 'lepseudointr'. 320 */ 321 static int 322 le_intr(struct le_softc *lesc, int sr) 323 { 324 struct lance_softc *sc = &lesc->sc_am7990.lsc; 325 uint16_t csr0; 326 327 if ((sr & PSL_IPL) < (ipl2psl_table[IPL_NET] & PSL_IPL)) 328 am7990_intr(sc); 329 else { 330 sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0); 331 lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA); 332 add_sicallback((si_farg)lepseudointr, lesc, sc); 333 } 334 return 1; 335 } 336 337 338 static void 339 lepseudointr(struct le_softc *lesc, void *sc) 340 { 341 int s; 342 343 s = splx(lesc->sc_splval); 344 am7990_intr(sc); 345 splx(s); 346 } 347 348 static void 349 le_vme_attach(device_t parent, device_t self, void *aux) 350 { 351 struct le_softc *lesc = device_private(self); 352 struct lance_softc *sc = &lesc->sc_am7990.lsc; 353 struct vme_attach_args *va = aux; 354 bus_space_handle_t ioh; 355 bus_space_handle_t memh; 356 struct le_addresses *le_ap; 357 int i; 358 359 sc->sc_dev = self; 360 aprint_normal("\n%s: ", device_xname(self)); 361 362 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 363 panic("leattach: cannot map io-area"); 364 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 365 panic("leattach: cannot map mem-area"); 366 367 lesc->sc_iot = va->va_iot; 368 lesc->sc_ioh = ioh; 369 lesc->sc_memt = va->va_memt; 370 lesc->sc_memh = memh; 371 lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */ 372 le_ap = (struct le_addresses *)va->va_aux; 373 374 /* 375 * Go on to find board type 376 */ 377 if ((le_ap->type_hint & LE_PAM) 378 && bus_space_peek_1(va->va_iot, ioh, LER_EEPROM)) { 379 aprint_normal("PAM card"); 380 lesc->sc_type = LE_PAM; 381 bus_space_read_1(va->va_iot, ioh, LER_MEME); 382 } 383 else if((le_ap->type_hint & LE_BVME410) 384 && bvme410_probe(va->va_iot, ioh)) { 385 aprint_normal("BVME410"); 386 lesc->sc_type = LE_BVME410; 387 } 388 else if (le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) { 389 aprint_normal("Riebl card"); 390 if(bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR) 391 == RIEBL_MAGIC) 392 lesc->sc_type = LE_NEW_RIEBL; 393 else { 394 aprint_normal("(without battery) "); 395 lesc->sc_type = LE_OLD_RIEBL; 396 } 397 } 398 else 399 aprint_error("le_vme_attach: Unsupported card!"); 400 401 switch (lesc->sc_type) { 402 case LE_BVME410: 403 sc->sc_copytodesc = bvme410_copytobuf; 404 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 405 sc->sc_copytobuf = bvme410_copytobuf; 406 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 407 sc->sc_zerobuf = bvme410_zerobuf; 408 break; 409 default: 410 sc->sc_copytodesc = lance_copytobuf_contig; 411 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 412 sc->sc_copytobuf = lance_copytobuf_contig; 413 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 414 sc->sc_zerobuf = lance_zerobuf_contig; 415 break; 416 } 417 418 sc->sc_rdcsr = lerdcsr; 419 sc->sc_wrcsr = lewrcsr; 420 sc->sc_hwinit = NULL; 421 sc->sc_conf3 = LE_C3_BSWP; 422 sc->sc_addr = 0; 423 sc->sc_memsize = va->va_msize; 424 sc->sc_mem = (void *)memh; /* XXX */ 425 426 /* 427 * Get MAC address 428 */ 429 switch (lesc->sc_type) { 430 case LE_OLD_RIEBL: 431 memcpy( sc->sc_enaddr, riebl_def_mac, 432 sizeof(sc->sc_enaddr)); 433 break; 434 case LE_NEW_RIEBL: 435 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 436 sc->sc_enaddr[i] = 437 bus_space_read_1(va->va_memt, memh, i + RIEBL_MAC_ADDR); 438 break; 439 case LE_PAM: 440 i = bus_space_read_1(va->va_iot, ioh, LER_EEPROM); 441 for (i = 0; i < sizeof(sc->sc_enaddr); i++) { 442 sc->sc_enaddr[i] = 443 (bus_space_read_2(va->va_memt, memh, 2 * i) << 4) | 444 (bus_space_read_2(va->va_memt, memh, 2 * i + 1) & 0xf); 445 } 446 i = bus_space_read_1(va->va_iot, ioh, LER_MEME); 447 break; 448 case LE_BVME410: 449 for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) { 450 uint16_t tmp; 451 452 tmp = nm93c06_read(va->va_iot, ioh, i); 453 sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff; 454 sc->sc_enaddr[2 * i + 1] = tmp & 0xff; 455 } 456 bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */ 457 } 458 459 am7990_config(&lesc->sc_am7990); 460 461 if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL)) 462 riebl_skip_reserved_area(sc); 463 464 /* 465 * XXX: We always use uservector 64.... 466 */ 467 if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0, 468 (hw_ifun_t)le_intr, lesc)) == NULL) { 469 aprint_error("le_vme_attach: Can't establish interrupt\n"); 470 return; 471 } 472 473 /* 474 * Notify the card of the vector 475 */ 476 switch (lesc->sc_type) { 477 case LE_OLD_RIEBL: 478 case LE_NEW_RIEBL: 479 bus_space_write_2(va->va_memt, memh, RIEBL_IVEC_ADDR, 480 64 + 64); 481 break; 482 case LE_PAM: 483 bus_space_write_1(va->va_iot, ioh, LER_IVEC, 64 + 64); 484 break; 485 case LE_BVME410: 486 bus_space_write_2(va->va_iot, ioh, BVME410_IVEC, 64 + 64); 487 break; 488 } 489 490 /* 491 * Unmask the VME-interrupt we're on 492 */ 493 if (machineid & ATARI_TT) 494 SCU->vme_mask |= 1 << va->va_irq; 495 } 496 497 /* 498 * True if 'addr' containe within [start,len] 499 */ 500 #define WITHIN(start, len, addr) \ 501 ((addr >= start) && ((addr) <= ((start) + (len)))) 502 static void 503 riebl_skip_reserved_area(struct lance_softc *sc) 504 { 505 int offset = 0; 506 int i; 507 508 for(i = 0; i < sc->sc_nrbuf; i++) { 509 if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START) 510 || WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) { 511 offset = RIEBL_RES_END - sc->sc_rbufaddr[i]; 512 } 513 sc->sc_rbufaddr[i] += offset; 514 } 515 516 for(i = 0; i < sc->sc_ntbuf; i++) { 517 if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START) 518 || WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) { 519 offset = RIEBL_RES_END - sc->sc_tbufaddr[i]; 520 } 521 sc->sc_tbufaddr[i] += offset; 522 } 523 } 524 525 static int 526 nm93c06_read(bus_space_tag_t iot, bus_space_handle_t ioh, int nm93c06reg) 527 { 528 int bar; 529 int shift; 530 int bits = 0x180 | (nm93c06reg & 0xf); 531 int data = 0; 532 533 bar = 1 << BVME410_CS_SHIFT; 534 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 535 delay(1); /* tCSS = 1 us */ 536 for (shift = 9; shift >= 0; shift--) { 537 if (((bits >> shift) & 1) == 1) 538 bar |= 1 << BVME410_DIN_SHIFT; 539 else 540 bar &= ~(1 << BVME410_DIN_SHIFT); 541 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 542 delay(1); /* tDIS = 0.4 us */ 543 bar |= 1 << BVME410_CLK_SHIFT; 544 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 545 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 546 bar &= ~(1 << BVME410_CLK_SHIFT); 547 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 548 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 549 } 550 bar &= ~(1 << BVME410_DIN_SHIFT); 551 for (shift = 15; shift >= 0; shift--) { 552 delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */ 553 bar |= 1 << BVME410_CLK_SHIFT; 554 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 555 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 556 data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift; 557 bar &= ~(1 << BVME410_CLK_SHIFT); 558 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 559 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 560 } 561 bar &= ~(1 << BVME410_CS_SHIFT); 562 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 563 delay(1); /* tCS = 1 us */ 564 return data; 565 } 566 567 static int 568 bvme410_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 569 { 570 571 if (!bus_space_peek_2(iot, ioh, BVME410_IVEC)) 572 return 0; 573 574 bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000); 575 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00) 576 return 0; 577 578 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff); 579 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff) 580 return 0; 581 582 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5); 583 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5) 584 return 0; 585 586 return 1; 587 } 588 589 static int 590 bvme410_mem_size(bus_space_tag_t memt, u_long mem_addr) 591 { 592 bus_space_handle_t memh; 593 int r; 594 595 if (bus_space_map(memt, mem_addr, 256 * 1024, 0, &memh)) 596 return VMECF_MEMSIZ_DEFAULT; 597 if (!bus_space_peek_1(memt, memh, 0)) { 598 bus_space_unmap(memt, memh, 256 * 1024); 599 return VMECF_MEMSIZ_DEFAULT; 600 } 601 bus_space_write_1(memt, memh, 0, 128); 602 bus_space_write_1(memt, memh, 64 * 1024, 32); 603 bus_space_write_1(memt, memh, 32 * 1024, 8); 604 r = (int)(bus_space_read_1(memt, memh, 0) * 2048); 605 bus_space_unmap(memt, memh, 256 * 1024); 606 return r; 607 } 608 609 /* 610 * Need to be careful when writing to the bvme410 dual port memory. 611 * Continue writing each byte until it reads back the same. 612 */ 613 614 static void 615 bvme410_copytobuf(struct lance_softc *sc, void *from, int boff, int len) 616 { 617 volatile char *buf = (volatile char *)sc->sc_mem; 618 char *f = (char *)from; 619 620 for (buf += boff; len; buf++,f++,len--) 621 do { 622 *buf = *f; 623 } while (*buf != *f); 624 } 625 626 static void 627 bvme410_zerobuf(struct lance_softc *sc, int boff, int len) 628 { 629 volatile char *buf = (volatile char *)sc->sc_mem; 630 631 for (buf += boff; len; buf++,len--) 632 do { 633 *buf = '\0'; 634 } while (*buf != '\0'); 635 } 636 637