1 /* $NetBSD: if_le_vme.c,v 1.35 2023/01/06 10:28:28 tsutsui 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.35 2023/01/06 10:28:28 tsutsui Exp $"); 78 79 #include "opt_inet.h" 80 81 #include <sys/param.h> 82 #include <sys/systm.h> 83 #include <sys/mbuf.h> 84 #include <sys/syslog.h> 85 #include <sys/socket.h> 86 #include <sys/device.h> 87 88 #include <net/if.h> 89 #include <net/if_media.h> 90 #include <net/if_ether.h> 91 92 #ifdef INET 93 #include <netinet/in.h> 94 #include <netinet/if_inarp.h> 95 #endif 96 97 #include <machine/cpu.h> 98 #include <sys/bus.h> 99 #include <machine/iomap.h> 100 #include <machine/scu.h> 101 #include <machine/intr.h> 102 103 #include <atari/atari/device.h> 104 105 #include <dev/ic/lancereg.h> 106 #include <dev/ic/lancevar.h> 107 #include <dev/ic/am7990reg.h> 108 #include <dev/ic/am7990var.h> 109 110 #include <atari/vme/vmevar.h> 111 #include <atari/vme/if_levar.h> 112 113 /* 114 * All cards except BVME410 have 64KB RAM. However, 115 * - On the Riebl cards the area between the offsets 0xee70-0xeec0 is used 116 * to store config data. 117 * - On PAM and ROTHRON, mem_addr cannot be mapped if reg_addr is already 118 * mapped because they are overwrapped. Just use 32KB as Linux does. 119 */ 120 static struct le_addresses { 121 u_long reg_addr; 122 u_long mem_addr; 123 int irq; 124 int reg_size; 125 int mem_size; 126 int type_hint; 127 } lestd[] = { 128 { 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024, 129 LE_OLD_RIEBL|LE_NEW_RIEBL }, /* Riebl */ 130 { 0xfecffff0, 0xfecf0000, 5, 16, 32*1024, 131 LE_PAM }, /* PAM */ 132 { 0xfecffff0, 0xfecf0000, 5, 16, 32*1024, 133 LE_ROTHRON }, /* Rhotron */ 134 { 0xfeff4100, 0xfe000000, 4, 8, VMECF_MEMSIZ_DEFAULT, 135 LE_BVME410 } /* BVME410 */ 136 }; 137 138 #define NLESTD __arraycount(lestd) 139 140 /* 141 * Default mac for RIEBL cards without a (working) battery. The first 4 bytes 142 * are the manufacturer id. 143 */ 144 static const uint8_t riebl_def_mac[] = { 145 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 146 }; 147 148 static int le_intr(struct le_softc *, int); 149 static void lepseudointr(struct le_softc *, void *); 150 static int le_vme_match(device_t, cfdata_t, void *); 151 static void le_vme_attach(device_t, device_t, void *); 152 static int probe_addresses(bus_space_tag_t *, bus_space_tag_t *, 153 bus_space_handle_t *, bus_space_handle_t *); 154 static void riebl_skip_reserved_area(struct lance_softc *); 155 static int nm93c06_read(bus_space_tag_t, bus_space_handle_t, int); 156 static int bvme410_probe(bus_space_tag_t, bus_space_handle_t); 157 static int bvme410_mem_size(bus_space_tag_t, u_long); 158 static void bvme410_copytobuf(struct lance_softc *, void *, int, int); 159 static void bvme410_zerobuf(struct lance_softc *, int, int); 160 161 CFATTACH_DECL_NEW(le_vme, sizeof(struct le_softc), 162 le_vme_match, le_vme_attach, NULL, NULL); 163 164 #if defined(_KERNEL_OPT) 165 #include "opt_ddb.h" 166 #endif 167 168 static void lewrcsr(struct lance_softc *, uint16_t, uint16_t); 169 static uint16_t lerdcsr(struct lance_softc *, uint16_t); 170 171 static void 172 lewrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 173 { 174 struct le_softc *lesc = (struct le_softc *)sc; 175 int s; 176 177 s = splhigh(); 178 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 179 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val); 180 splx(s); 181 } 182 183 static uint16_t 184 lerdcsr(struct lance_softc *sc, uint16_t port) 185 { 186 struct le_softc *lesc = (struct le_softc *)sc; 187 uint16_t val; 188 int s; 189 190 s = splhigh(); 191 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 192 val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP); 193 splx(s); 194 195 return val; 196 } 197 198 static int 199 le_vme_match(device_t parent, cfdata_t cfp, void *aux) 200 { 201 struct vme_attach_args *va = aux; 202 int i; 203 bus_space_tag_t iot, memt; 204 bus_space_handle_t ioh, memh; 205 206 iot = va->va_iot; 207 memt = va->va_memt; 208 209 for (i = 0; i < NLESTD; i++) { 210 struct le_addresses *le_ap = &lestd[i]; 211 int found; 212 213 if ((va->va_iobase != IOBASEUNK) 214 && (va->va_iobase != le_ap->reg_addr)) 215 continue; 216 217 if ((va->va_maddr != MADDRUNK) 218 && (va->va_maddr != le_ap->mem_addr)) 219 continue; 220 221 if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq)) 222 continue; 223 224 if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, 225 &ioh)) { 226 continue; 227 } 228 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 229 if (bvme410_probe(iot, ioh)) { 230 bus_space_write_2(iot, ioh, 231 BVME410_BAR, 0x1); /* XXX */ 232 le_ap->mem_size = 233 bvme410_mem_size(memt, le_ap->mem_addr); 234 } 235 } 236 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 237 bus_space_unmap(iot, ioh, le_ap->reg_size); 238 continue; 239 } 240 241 if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, 242 &memh)) { 243 bus_space_unmap(iot, ioh, le_ap->reg_size); 244 continue; 245 } 246 found = probe_addresses(&iot, &memt, &ioh, &memh); 247 bus_space_unmap(iot, ioh, le_ap->reg_size); 248 bus_space_unmap(memt, memh, le_ap->mem_size); 249 250 if (found) { 251 va->va_iobase = le_ap->reg_addr; 252 va->va_iosize = le_ap->reg_size; 253 va->va_maddr = le_ap->mem_addr; 254 va->va_msize = le_ap->mem_size; 255 va->va_aux = le_ap; 256 if (va->va_irq == IRQUNK) 257 va->va_irq = le_ap->irq; 258 return 1; 259 } 260 } 261 return 0; 262 } 263 264 static int 265 probe_addresses(bus_space_tag_t *iot, bus_space_tag_t *memt, 266 bus_space_handle_t *ioh, bus_space_handle_t *memh) 267 { 268 269 /* 270 * Test accesibility of register and memory area 271 */ 272 if (!bus_space_peek_2(*iot, *ioh, LER_RDP)) 273 return 0; 274 if (!bus_space_peek_1(*memt, *memh, 0)) 275 return 0; 276 277 /* 278 * Test for writable memory 279 */ 280 bus_space_write_2(*memt, *memh, 0, 0xa5a5); 281 if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5) 282 return 0; 283 284 /* 285 * Test writability of selector port. 286 */ 287 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1); 288 if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1) 289 return 0; 290 291 /* 292 * Do a small register test 293 */ 294 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0); 295 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP); 296 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 297 return 0; 298 299 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP); 300 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 301 return 0; 302 303 return 1; 304 } 305 306 /* 307 * Interrupt mess. Because the card's interrupt is hardwired to either 308 * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do 309 * (it kills the serial at the least), we use a 2-level interrupt scheme. The 310 * card interrupt is routed to 'le_intr'. If the previous ipl was below 311 * splnet, just call the mi-function. If not, save the interrupt status, 312 * turn off card interrupts (the card is *very* persistent) and arrange 313 * for a softint 'callback' through 'lepseudointr'. 314 */ 315 static int 316 le_intr(struct le_softc *lesc, int sr) 317 { 318 struct lance_softc *sc = &lesc->sc_am7990.lsc; 319 uint16_t csr0; 320 321 if ((sr & PSL_IPL) < (ipl2psl_table[IPL_NET] & PSL_IPL)) 322 am7990_intr(sc); 323 else { 324 sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0); 325 lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA); 326 add_sicallback((si_farg)lepseudointr, lesc, sc); 327 } 328 return 1; 329 } 330 331 332 static void 333 lepseudointr(struct le_softc *lesc, void *sc) 334 { 335 int s; 336 337 s = splx(lesc->sc_splval); 338 am7990_intr(sc); 339 splx(s); 340 } 341 342 static void 343 le_vme_attach(device_t parent, device_t self, void *aux) 344 { 345 struct le_softc *lesc = device_private(self); 346 struct lance_softc *sc = &lesc->sc_am7990.lsc; 347 struct vme_attach_args *va = aux; 348 bus_space_tag_t iot, memt; 349 bus_space_handle_t ioh, memh; 350 struct le_addresses *le_ap; 351 int i; 352 353 sc->sc_dev = self; 354 aprint_normal("\n%s: ", device_xname(self)); 355 356 iot = va->va_iot; 357 memt = va->va_memt; 358 if (bus_space_map(iot, va->va_iobase, va->va_iosize, 0, &ioh)) 359 panic("%s: cannot map io-area", __func__); 360 if (bus_space_map(memt, va->va_maddr, va->va_msize, 0, &memh)) 361 panic("%s: cannot map mem-area", __func__); 362 363 lesc->sc_iot = iot; 364 lesc->sc_ioh = ioh; 365 lesc->sc_memt = memt; 366 lesc->sc_memh = memh; 367 lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */ 368 le_ap = (struct le_addresses *)va->va_aux; 369 370 /* 371 * Go on to find board type 372 */ 373 if ((le_ap->type_hint & LE_PAM) != 0 && 374 bus_space_peek_1(iot, ioh, LER_EEPROM)) { 375 aprint_normal("PAM card"); 376 lesc->sc_type = LE_PAM; 377 bus_space_read_1(iot, ioh, LER_MEME); 378 } else if ((le_ap->type_hint & LE_BVME410) != 0 && 379 bvme410_probe(iot, ioh)) { 380 aprint_normal("BVME410"); 381 lesc->sc_type = LE_BVME410; 382 } else if ((le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) != 0) { 383 aprint_normal("Riebl card"); 384 if (bus_space_read_4(memt, memh, RIEBL_MAGIC_ADDR) == 385 RIEBL_MAGIC) 386 lesc->sc_type = LE_NEW_RIEBL; 387 else { 388 aprint_normal("(without battery) "); 389 lesc->sc_type = LE_OLD_RIEBL; 390 } 391 } else { 392 aprint_error("Unsupported card!\n"); 393 return; 394 } 395 396 switch (lesc->sc_type) { 397 case LE_BVME410: 398 sc->sc_copytodesc = bvme410_copytobuf; 399 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 400 sc->sc_copytobuf = bvme410_copytobuf; 401 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 402 sc->sc_zerobuf = bvme410_zerobuf; 403 break; 404 default: 405 sc->sc_copytodesc = lance_copytobuf_contig; 406 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 407 sc->sc_copytobuf = lance_copytobuf_contig; 408 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 409 sc->sc_zerobuf = lance_zerobuf_contig; 410 break; 411 } 412 413 sc->sc_rdcsr = lerdcsr; 414 sc->sc_wrcsr = lewrcsr; 415 sc->sc_hwinit = NULL; 416 sc->sc_conf3 = LE_C3_BSWP; 417 sc->sc_addr = 0; 418 sc->sc_memsize = va->va_msize; 419 sc->sc_mem = (void *)memh; /* XXX */ 420 421 /* 422 * Get MAC address 423 */ 424 switch (lesc->sc_type) { 425 case LE_OLD_RIEBL: 426 memcpy(sc->sc_enaddr, riebl_def_mac, sizeof(sc->sc_enaddr)); 427 break; 428 case LE_NEW_RIEBL: 429 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 430 sc->sc_enaddr[i] = 431 bus_space_read_1(memt, memh, i + RIEBL_MAC_ADDR); 432 break; 433 case LE_PAM: 434 i = bus_space_read_1(iot, ioh, LER_EEPROM); 435 for (i = 0; i < sizeof(sc->sc_enaddr); i++) { 436 sc->sc_enaddr[i] = 437 (bus_space_read_2(memt, memh, 2 * i) << 4) | 438 (bus_space_read_2(memt, memh, 2 * i + 1) & 0xf); 439 } 440 i = bus_space_read_1(iot, ioh, LER_MEME); 441 break; 442 case LE_BVME410: 443 for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) { 444 uint16_t tmp; 445 446 tmp = nm93c06_read(iot, ioh, i); 447 sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff; 448 sc->sc_enaddr[2 * i + 1] = tmp & 0xff; 449 } 450 bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */ 451 } 452 453 am7990_config(&lesc->sc_am7990); 454 455 if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL)) 456 riebl_skip_reserved_area(sc); 457 458 /* 459 * XXX: We always use uservector 64.... 460 */ 461 if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0, 462 (hw_ifun_t)le_intr, lesc)) == NULL) { 463 aprint_error("le_vme_attach: Can't establish interrupt\n"); 464 return; 465 } 466 467 /* 468 * Notify the card of the vector 469 */ 470 switch (lesc->sc_type) { 471 case LE_OLD_RIEBL: 472 case LE_NEW_RIEBL: 473 bus_space_write_2(memt, memh, RIEBL_IVEC_ADDR, 64 + 64); 474 break; 475 case LE_PAM: 476 bus_space_write_1(iot, ioh, LER_IVEC, 64 + 64); 477 break; 478 case LE_BVME410: 479 bus_space_write_2(iot, ioh, BVME410_IVEC, 64 + 64); 480 break; 481 } 482 483 /* 484 * Unmask the VME-interrupt we're on 485 */ 486 if ((machineid & ATARI_TT) != 0) 487 SCU->vme_mask |= 1 << va->va_irq; 488 } 489 490 /* 491 * True if 'addr' containe within [start,len] 492 */ 493 #define WITHIN(start, len, addr) \ 494 ((addr >= start) && ((addr) <= ((start) + (len)))) 495 static void 496 riebl_skip_reserved_area(struct lance_softc *sc) 497 { 498 int offset = 0; 499 int i; 500 501 for (i = 0; i < sc->sc_nrbuf; i++) { 502 if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START) || 503 WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) { 504 offset = RIEBL_RES_END - sc->sc_rbufaddr[i]; 505 } 506 sc->sc_rbufaddr[i] += offset; 507 } 508 509 for (i = 0; i < sc->sc_ntbuf; i++) { 510 if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START) || 511 WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) { 512 offset = RIEBL_RES_END - sc->sc_tbufaddr[i]; 513 } 514 sc->sc_tbufaddr[i] += offset; 515 } 516 } 517 518 static int 519 nm93c06_read(bus_space_tag_t iot, bus_space_handle_t ioh, int nm93c06reg) 520 { 521 int bar; 522 int shift; 523 int bits = 0x180 | (nm93c06reg & 0xf); 524 int data = 0; 525 526 bar = 1 << BVME410_CS_SHIFT; 527 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 528 delay(1); /* tCSS = 1 us */ 529 for (shift = 9; shift >= 0; shift--) { 530 if (((bits >> shift) & 1) == 1) 531 bar |= 1 << BVME410_DIN_SHIFT; 532 else 533 bar &= ~(1 << BVME410_DIN_SHIFT); 534 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 535 delay(1); /* tDIS = 0.4 us */ 536 bar |= 1 << BVME410_CLK_SHIFT; 537 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 538 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 539 bar &= ~(1 << BVME410_CLK_SHIFT); 540 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 541 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 542 } 543 bar &= ~(1 << BVME410_DIN_SHIFT); 544 for (shift = 15; shift >= 0; shift--) { 545 delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */ 546 bar |= 1 << BVME410_CLK_SHIFT; 547 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 548 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 549 data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift; 550 bar &= ~(1 << BVME410_CLK_SHIFT); 551 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 552 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 553 } 554 bar &= ~(1 << BVME410_CS_SHIFT); 555 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 556 delay(1); /* tCS = 1 us */ 557 return data; 558 } 559 560 static int 561 bvme410_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 562 { 563 564 if (!bus_space_peek_2(iot, ioh, BVME410_IVEC)) 565 return 0; 566 567 bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000); 568 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00) 569 return 0; 570 571 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff); 572 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff) 573 return 0; 574 575 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5); 576 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5) 577 return 0; 578 579 return 1; 580 } 581 582 static int 583 bvme410_mem_size(bus_space_tag_t memt, u_long mem_addr) 584 { 585 bus_space_handle_t memh; 586 int r; 587 588 if (bus_space_map(memt, mem_addr, 256 * 1024, 0, &memh)) 589 return VMECF_MEMSIZ_DEFAULT; 590 if (!bus_space_peek_1(memt, memh, 0)) { 591 bus_space_unmap(memt, memh, 256 * 1024); 592 return VMECF_MEMSIZ_DEFAULT; 593 } 594 bus_space_write_1(memt, memh, 0, 128); 595 bus_space_write_1(memt, memh, 64 * 1024, 32); 596 bus_space_write_1(memt, memh, 32 * 1024, 8); 597 r = (int)(bus_space_read_1(memt, memh, 0) * 2048); 598 bus_space_unmap(memt, memh, 256 * 1024); 599 return r; 600 } 601 602 /* 603 * Need to be careful when writing to the bvme410 dual port memory. 604 * Continue writing each byte until it reads back the same. 605 */ 606 607 static void 608 bvme410_copytobuf(struct lance_softc *sc, void *from, int boff, int len) 609 { 610 volatile uint8_t *buf = (volatile uint8_t *)sc->sc_mem; 611 uint8_t *f = (uint8_t *)from; 612 613 for (buf += boff; len != 0; buf++, f++, len--) { 614 do { 615 *buf = *f; 616 } while (*buf != *f); 617 } 618 } 619 620 static void 621 bvme410_zerobuf(struct lance_softc *sc, int boff, int len) 622 { 623 volatile uint8_t *buf = (volatile uint8_t *)sc->sc_mem; 624 625 for (buf += boff; len != 0; buf++, len--) { 626 do { 627 *buf = '\0'; 628 } while (*buf != '\0'); 629 } 630 } 631