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