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