1 /* $NetBSD: mvmebus.c,v 1.26 2026/04/04 16:48:21 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Steve C. Woodford. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: mvmebus.c,v 1.26 2026/04/04 16:48:21 thorpej Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/kernel.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/kcore.h> 41 42 #include <sys/cpu.h> 43 #include <sys/bus.h> 44 45 #include <dev/vme/vmereg.h> 46 #include <dev/vme/vmevar.h> 47 48 #include <dev/mvme/mvmebus.h> 49 50 #ifdef __m68k__ 51 #include <m68k/seglist.h> 52 #else 53 #error Need a solution for non-68k. 54 #endif 55 56 #ifdef DIAGNOSTIC 57 int mvmebus_dummy_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, 58 bus_size_t, int, bus_dmamap_t *); 59 void mvmebus_dummy_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 60 int mvmebus_dummy_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, 61 bus_size_t, bus_dma_segment_t *, int, int *, int); 62 void mvmebus_dummy_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int); 63 #endif 64 65 #ifdef DEBUG 66 static const char *mvmebus_mod_string(vme_addr_t, vme_size_t, 67 vme_am_t, vme_datasize_t); 68 #endif 69 70 static void mvmebus_offboard_ram(struct mvmebus_softc *); 71 static int mvmebus_dmamap_load_common(struct mvmebus_softc *, bus_dmamap_t); 72 73 vme_am_t _mvmebus_am_cap[] = { 74 MVMEBUS_AM_CAP_BLKD64 | MVMEBUS_AM_CAP_USER, 75 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_USER, 76 MVMEBUS_AM_CAP_PROG | MVMEBUS_AM_CAP_USER, 77 MVMEBUS_AM_CAP_BLK | MVMEBUS_AM_CAP_USER, 78 MVMEBUS_AM_CAP_BLKD64 | MVMEBUS_AM_CAP_SUPER, 79 MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_SUPER, 80 MVMEBUS_AM_CAP_PROG | MVMEBUS_AM_CAP_SUPER, 81 MVMEBUS_AM_CAP_BLK | MVMEBUS_AM_CAP_SUPER 82 }; 83 84 const char *mvmebus_irq_name[] = { 85 "vmeirq0", "vmeirq1", "vmeirq2", "vmeirq3", 86 "vmeirq4", "vmeirq5", "vmeirq6", "vmeirq7" 87 }; 88 89 static void 90 mvmebus_offboard_ram(struct mvmebus_softc *sc) 91 { 92 struct mvmebus_range *svr, *mvr; 93 vme_addr_t start, end, size; 94 int i; 95 96 /* 97 * If we have any offboard RAM (i.e. a VMEbus RAM board) then 98 * we need to record its details since it's effectively another 99 * VMEbus slave image as far as we're concerned. 100 * The chip-specific backend will have reserved sc->sc_slaves[0] 101 * for exactly this purpose. 102 */ 103 svr = sc->sc_slaves; 104 if (phys_seg_list[1].ps_start == phys_seg_list[1].ps_end) { 105 svr->vr_am = MVMEBUS_AM_DISABLED; 106 return; 107 } 108 109 start = phys_seg_list[1].ps_start; 110 size = (phys_seg_list[1].ps_end - phys_seg_list[1].ps_start) - 1; 111 end = start + size; 112 113 /* 114 * Figure out which VMEbus master image the RAM is 115 * visible through. This will tell us the address 116 * modifier and datasizes it uses, as well as allowing 117 * us to calculate its `real' VMEbus address. 118 * 119 * XXX FIXME: This is broken if the RAM is mapped through 120 * a translated address space. For example, on mvme167 it's 121 * perfectly legal to set up the following A32 mapping: 122 * 123 * vr_locaddr == 0x80000000 124 * vr_vmestart == 0x10000000 125 * vr_vmeend == 0x10ffffff 126 * 127 * In this case, RAM at VMEbus address 0x10800000 will appear at local 128 * address 0x80800000, but we need to set the slave vr_vmestart to 129 * 0x10800000. 130 */ 131 for (i = 0, mvr = sc->sc_masters; i < sc->sc_nmasters; i++, mvr++) { 132 vme_addr_t vstart = mvr->vr_locstart + mvr->vr_vmestart; 133 134 if (start >= vstart && 135 end <= vstart + (mvr->vr_vmeend - mvr->vr_vmestart)) 136 break; 137 } 138 if (i == sc->sc_nmasters) { 139 svr->vr_am = MVMEBUS_AM_DISABLED; 140 #ifdef DEBUG 141 printf("%s: No VMEbus master mapping for offboard RAM!\n", 142 device_xname(sc->sc_dev)); 143 #endif 144 return; 145 } 146 147 svr->vr_locstart = start; 148 svr->vr_vmestart = start & mvr->vr_mask; 149 svr->vr_vmeend = svr->vr_vmestart + size; 150 svr->vr_datasize = mvr->vr_datasize; 151 svr->vr_mask = mvr->vr_mask; 152 svr->vr_am = mvr->vr_am & VME_AM_ADRSIZEMASK; 153 svr->vr_am |= MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG | 154 MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER; 155 } 156 157 void 158 mvmebus_attach(struct mvmebus_softc *sc) 159 { 160 struct vmebus_attach_args vaa; 161 int i; 162 163 /* Zap the IRQ reference counts */ 164 for (i = 0; i < 8; i++) 165 sc->sc_irqref[i] = 0; 166 167 /* If there's offboard RAM, get its VMEbus slave attributes */ 168 mvmebus_offboard_ram(sc); 169 170 #ifdef DEBUG 171 for (i = 0; i < sc->sc_nmasters; i++) { 172 struct mvmebus_range *vr = &sc->sc_masters[i]; 173 if (vr->vr_am == MVMEBUS_AM_DISABLED) { 174 printf("%s: Master#%d: disabled\n", 175 device_xname(sc->sc_dev), i); 176 continue; 177 } 178 printf("%s: Master#%d: 0x%08lx -> %s\n", 179 device_xname(sc->sc_dev), i, 180 vr->vr_locstart + (vr->vr_vmestart & vr->vr_mask), 181 mvmebus_mod_string(vr->vr_vmestart, 182 (vr->vr_vmeend - vr->vr_vmestart) + 1, 183 vr->vr_am, vr->vr_datasize)); 184 } 185 186 for (i = 0; i < sc->sc_nslaves; i++) { 187 struct mvmebus_range *vr = &sc->sc_slaves[i]; 188 if (vr->vr_am == MVMEBUS_AM_DISABLED) { 189 printf("%s: Slave#%d: disabled\n", 190 device_xname(sc->sc_dev), i); 191 continue; 192 } 193 printf("%s: Slave#%d: 0x%08lx -> %s\n", 194 device_xname(sc->sc_dev), i, vr->vr_locstart, 195 mvmebus_mod_string(vr->vr_vmestart, 196 (vr->vr_vmeend - vr->vr_vmestart) + 1, 197 vr->vr_am, vr->vr_datasize)); 198 } 199 #endif 200 201 sc->sc_vct.cookie = sc; 202 sc->sc_vct.vct_probe = mvmebus_probe; 203 sc->sc_vct.vct_map = mvmebus_map; 204 sc->sc_vct.vct_unmap = mvmebus_unmap; 205 sc->sc_vct.vct_int_map = mvmebus_intmap; 206 sc->sc_vct.vct_int_evcnt = mvmebus_intr_evcnt; 207 sc->sc_vct.vct_int_establish = mvmebus_intr_establish; 208 sc->sc_vct.vct_int_disestablish = mvmebus_intr_disestablish; 209 sc->sc_vct.vct_dmamap_create = mvmebus_dmamap_create; 210 sc->sc_vct.vct_dmamap_destroy = mvmebus_dmamap_destroy; 211 sc->sc_vct.vct_dmamem_alloc = mvmebus_dmamem_alloc; 212 sc->sc_vct.vct_dmamem_free = mvmebus_dmamem_free; 213 214 sc->sc_mvmedmat._cookie = sc; 215 sc->sc_mvmedmat._dmamap_load = mvmebus_dmamap_load; 216 sc->sc_mvmedmat._dmamap_load_mbuf = mvmebus_dmamap_load_mbuf; 217 sc->sc_mvmedmat._dmamap_load_uio = mvmebus_dmamap_load_uio; 218 sc->sc_mvmedmat._dmamap_load_raw = mvmebus_dmamap_load_raw; 219 sc->sc_mvmedmat._dmamap_unload = mvmebus_dmamap_unload; 220 sc->sc_mvmedmat._dmamap_sync = mvmebus_dmamap_sync; 221 sc->sc_mvmedmat._dmamem_map = mvmebus_dmamem_map; 222 sc->sc_mvmedmat._dmamem_unmap = mvmebus_dmamem_unmap; 223 sc->sc_mvmedmat._dmamem_mmap = mvmebus_dmamem_mmap; 224 225 #ifdef DIAGNOSTIC 226 sc->sc_mvmedmat._dmamap_create = mvmebus_dummy_dmamap_create; 227 sc->sc_mvmedmat._dmamap_destroy = mvmebus_dummy_dmamap_destroy; 228 sc->sc_mvmedmat._dmamem_alloc = mvmebus_dummy_dmamem_alloc; 229 sc->sc_mvmedmat._dmamem_free = mvmebus_dummy_dmamem_free; 230 #else 231 sc->sc_mvmedmat._dmamap_create = NULL; 232 sc->sc_mvmedmat._dmamap_destroy = NULL; 233 sc->sc_mvmedmat._dmamem_alloc = NULL; 234 sc->sc_mvmedmat._dmamem_free = NULL; 235 #endif 236 237 vaa.va_vct = &sc->sc_vct; 238 vaa.va_bdt = &sc->sc_mvmedmat; 239 vaa.va_slaveconfig = NULL; 240 241 config_found(sc->sc_dev, &vaa, 0, CFARGS_NONE); 242 } 243 244 int 245 mvmebus_map(void *vsc, vme_addr_t vmeaddr, vme_size_t len, vme_am_t am, vme_datasize_t datasize, vme_swap_t swap, bus_space_tag_t *tag, bus_space_handle_t *handle, vme_mapresc_t *resc) 246 { 247 struct mvmebus_softc *sc; 248 struct mvmebus_mapresc *mr; 249 struct mvmebus_range *vr; 250 vme_addr_t end; 251 vme_am_t cap, as; 252 paddr_t paddr; 253 int rv, i; 254 255 sc = vsc; 256 end = (vmeaddr + len) - 1; 257 paddr = 0; 258 vr = sc->sc_masters; 259 cap = MVMEBUS_AM2CAP(am); 260 as = am & VME_AM_ADRSIZEMASK; 261 262 for (i = 0; i < sc->sc_nmasters && paddr == 0; i++, vr++) { 263 if (vr->vr_am == MVMEBUS_AM_DISABLED) 264 continue; 265 266 if (cap == (vr->vr_am & cap) && 267 as == (vr->vr_am & VME_AM_ADRSIZEMASK) && 268 datasize <= vr->vr_datasize && 269 vmeaddr >= vr->vr_vmestart && end < vr->vr_vmeend) 270 paddr = vr->vr_locstart + (vmeaddr & vr->vr_mask); 271 } 272 if (paddr == 0) 273 return (ENOMEM); 274 275 rv = bus_space_map(sc->sc_bust, paddr, len, 0, handle); 276 if (rv != 0) 277 return (rv); 278 279 /* Allocate space for the resource tag */ 280 mr = malloc(sizeof(*mr), M_DEVBUF, M_WAITOK); 281 282 /* Record the range's details */ 283 mr->mr_am = am; 284 mr->mr_datasize = datasize; 285 mr->mr_addr = vmeaddr; 286 mr->mr_size = len; 287 mr->mr_handle = *handle; 288 mr->mr_range = i; 289 290 *tag = sc->sc_bust; 291 *resc = (vme_mapresc_t *) mr; 292 293 return (0); 294 } 295 296 /* ARGSUSED */ 297 void 298 mvmebus_unmap(void *vsc, vme_mapresc_t resc) 299 { 300 struct mvmebus_softc *sc = vsc; 301 struct mvmebus_mapresc *mr = (struct mvmebus_mapresc *) resc; 302 303 bus_space_unmap(sc->sc_bust, mr->mr_handle, mr->mr_size); 304 305 free(mr, M_DEVBUF); 306 } 307 308 int 309 mvmebus_probe(void *vsc, vme_addr_t vmeaddr, vme_size_t len, vme_am_t am, vme_datasize_t datasize, int (*callback)(void *, bus_space_tag_t, bus_space_handle_t), void *arg) 310 { 311 bus_space_tag_t tag; 312 bus_space_handle_t handle; 313 vme_mapresc_t resc; 314 vme_size_t offs; 315 int rv; 316 317 /* Get a temporary mapping to the VMEbus range */ 318 rv = mvmebus_map(vsc, vmeaddr, len, am, datasize, 0, 319 &tag, &handle, &resc); 320 if (rv) 321 return (rv); 322 323 if (callback) 324 rv = (*callback) (arg, tag, handle); 325 else 326 for (offs = 0; offs < len && rv == 0;) { 327 switch (datasize) { 328 case VME_D8: 329 rv = bus_space_peek_1(tag, handle, offs, NULL); 330 offs += 1; 331 break; 332 333 case VME_D16: 334 rv = bus_space_peek_2(tag, handle, offs, NULL); 335 offs += 2; 336 break; 337 338 case VME_D32: 339 rv = bus_space_peek_4(tag, handle, offs, NULL); 340 offs += 4; 341 break; 342 } 343 } 344 345 mvmebus_unmap(vsc, resc); 346 347 return (rv); 348 } 349 350 /* ARGSUSED */ 351 int 352 mvmebus_intmap(void *vsc, int level, int vector, vme_intr_handle_t *handlep) 353 { 354 355 if (level < 1 || level > 7 || vector < 0x80 || vector > 0xff) 356 return (EINVAL); 357 358 /* This is rather gross */ 359 *handlep = (void *) (int) ((level << 8) | vector); 360 return (0); 361 } 362 363 /* ARGSUSED */ 364 const struct evcnt * 365 mvmebus_intr_evcnt(void *vsc, vme_intr_handle_t handle) 366 { 367 struct mvmebus_softc *sc = vsc; 368 369 return (&sc->sc_evcnt[(((int) handle) >> 8) - 1]); 370 } 371 372 void * 373 mvmebus_intr_establish(void *vsc, vme_intr_handle_t handle, int prior, int (*func)(void *), void *arg) 374 { 375 struct mvmebus_softc *sc; 376 int level, vector, first; 377 378 sc = vsc; 379 380 /* Extract the interrupt's level and vector */ 381 level = ((int) handle) >> 8; 382 vector = ((int) handle) & 0xff; 383 384 #ifdef DIAGNOSTIC 385 if (vector < 0 || vector > 0xff) { 386 printf("%s: Illegal vector offset: 0x%x\n", 387 device_xname(sc->sc_dev), vector); 388 panic("mvmebus_intr_establish"); 389 } 390 if (level < 1 || level > 7) { 391 printf("%s: Illegal interrupt level: %d\n", 392 device_xname(sc->sc_dev), level); 393 panic("mvmebus_intr_establish"); 394 } 395 #endif 396 397 first = (sc->sc_irqref[level]++ == 0); 398 399 (*sc->sc_intr_establish)(sc->sc_chip, prior, level, vector, first, 400 func, arg, &sc->sc_evcnt[level - 1]); 401 402 return ((void *) handle); 403 } 404 405 void 406 mvmebus_intr_disestablish(void *vsc, vme_intr_handle_t handle) 407 { 408 struct mvmebus_softc *sc; 409 int level, vector, last; 410 411 sc = vsc; 412 413 /* Extract the interrupt's level and vector */ 414 level = ((int) handle) >> 8; 415 vector = ((int) handle) & 0xff; 416 417 #ifdef DIAGNOSTIC 418 if (vector < 0 || vector > 0xff) { 419 printf("%s: Illegal vector offset: 0x%x\n", 420 device_xname(sc->sc_dev), vector); 421 panic("mvmebus_intr_disestablish"); 422 } 423 if (level < 1 || level > 7) { 424 printf("%s: Illegal interrupt level: %d\n", 425 device_xname(sc->sc_dev), level); 426 panic("mvmebus_intr_disestablish"); 427 } 428 if (sc->sc_irqref[level] == 0) { 429 printf("%s: VMEirq#%d: Reference count already zero!\n", 430 device_xname(sc->sc_dev), level); 431 panic("mvmebus_intr_disestablish"); 432 } 433 #endif 434 435 last = (--(sc->sc_irqref[level]) == 0); 436 437 (*sc->sc_intr_disestablish)(sc->sc_chip, level, vector, last, 438 &sc->sc_evcnt[level - 1]); 439 } 440 441 #ifdef DIAGNOSTIC 442 /* ARGSUSED */ 443 int 444 mvmebus_dummy_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegs, bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) 445 { 446 447 panic("Must use vme_dmamap_create() in place of bus_dmamap_create()"); 448 return (0); /* Shutup the compiler */ 449 } 450 451 /* ARGSUSED */ 452 void 453 mvmebus_dummy_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 454 { 455 456 panic("Must use vme_dmamap_destroy() in place of bus_dmamap_destroy()"); 457 } 458 #endif 459 460 /* ARGSUSED */ 461 int 462 mvmebus_dmamap_create( 463 void *vsc, 464 vme_size_t len, 465 vme_am_t am, 466 vme_datasize_t datasize, 467 vme_swap_t swap, 468 int nsegs, 469 vme_size_t segsz, 470 vme_addr_t bound, 471 int flags, 472 bus_dmamap_t *mapp) 473 { 474 struct mvmebus_softc *sc = vsc; 475 struct mvmebus_dmamap *vmap; 476 struct mvmebus_range *vr; 477 vme_am_t cap, as; 478 int i, rv; 479 480 cap = MVMEBUS_AM2CAP(am); 481 as = am & VME_AM_ADRSIZEMASK; 482 483 /* 484 * Verify that we even stand a chance of satisfying 485 * the VMEbus address space and datasize requested. 486 */ 487 for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) { 488 if (vr->vr_am == MVMEBUS_AM_DISABLED) 489 continue; 490 491 if (as == (vr->vr_am & VME_AM_ADRSIZEMASK) && 492 cap == (vr->vr_am & cap) && datasize <= vr->vr_datasize && 493 len <= (vr->vr_vmeend - vr->vr_vmestart)) 494 break; 495 } 496 497 if (i == sc->sc_nslaves) 498 return (EINVAL); 499 500 if ((vmap = malloc(sizeof(*vmap), M_DMAMAP, 501 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) 502 return (ENOMEM); 503 504 505 rv = bus_dmamap_create(sc->sc_dmat, len, nsegs, segsz, 506 bound, flags, mapp); 507 if (rv != 0) { 508 free(vmap, M_DMAMAP); 509 return (rv); 510 } 511 512 vmap->vm_am = am; 513 vmap->vm_datasize = datasize; 514 vmap->vm_swap = swap; 515 vmap->vm_slave = vr; 516 517 (*mapp)->_dm_cookie = vmap; 518 519 return (0); 520 } 521 522 void 523 mvmebus_dmamap_destroy(void *vsc, bus_dmamap_t map) 524 { 525 struct mvmebus_softc *sc = vsc; 526 527 free(map->_dm_cookie, M_DMAMAP); 528 bus_dmamap_destroy(sc->sc_dmat, map); 529 } 530 531 static int 532 mvmebus_dmamap_load_common(struct mvmebus_softc *sc, bus_dmamap_t map) 533 { 534 struct mvmebus_dmamap *vmap = map->_dm_cookie; 535 struct mvmebus_range *vr = vmap->vm_slave; 536 bus_dma_segment_t *ds; 537 vme_am_t cap, am; 538 int i; 539 540 cap = MVMEBUS_AM2CAP(vmap->vm_am); 541 am = vmap->vm_am & VME_AM_ADRSIZEMASK; 542 543 /* 544 * Traverse the list of segments which make up this map, and 545 * convert the CPU-relative addresses therein to VMEbus addresses. 546 */ 547 for (ds = &map->dm_segs[0]; ds < &map->dm_segs[map->dm_nsegs]; ds++) { 548 /* 549 * First, see if this map's slave image can access the 550 * segment, otherwise we have to waste time scanning all 551 * the slave images. 552 */ 553 vr = vmap->vm_slave; 554 if (am == (vr->vr_am & VME_AM_ADRSIZEMASK) && 555 cap == (vr->vr_am & cap) && 556 vmap->vm_datasize <= vr->vr_datasize && 557 ds->_ds_cpuaddr >= vr->vr_locstart && 558 ds->ds_len <= (vr->vr_vmeend - vr->vr_vmestart)) 559 goto found; 560 561 for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) { 562 if (vr->vr_am == MVMEBUS_AM_DISABLED) 563 continue; 564 565 /* 566 * Filter out any slave images which don't have the 567 * same VMEbus address modifier and datasize as 568 * this DMA map, and those which don't cover the 569 * physical address region containing the segment. 570 */ 571 if (vr != vmap->vm_slave && 572 am == (vr->vr_am & VME_AM_ADRSIZEMASK) && 573 cap == (vr->vr_am & cap) && 574 vmap->vm_datasize <= vr->vr_datasize && 575 ds->_ds_cpuaddr >= vr->vr_locstart && 576 ds->ds_len <= (vr->vr_vmeend - vr->vr_vmestart)) 577 break; 578 } 579 580 /* 581 * Did we find an applicable slave image which covers this 582 * segment? 583 */ 584 if (i == sc->sc_nslaves) { 585 /* 586 * XXX TODO: 587 * 588 * Bounce this segment via a bounce buffer allocated 589 * from this DMA map. 590 */ 591 printf("mvmebus_dmamap_load_common: bounce needed!\n"); 592 return (EINVAL); 593 } 594 595 found: 596 /* 597 * Generate the VMEbus address of this segment 598 */ 599 ds->ds_addr = (ds->_ds_cpuaddr - vr->vr_locstart) + 600 vr->vr_vmestart; 601 } 602 603 return (0); 604 } 605 606 int 607 mvmebus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, struct proc *p, int flags) 608 { 609 struct mvmebus_softc *sc = t->_cookie; 610 int rv; 611 612 rv = bus_dmamap_load(sc->sc_dmat, map, buf, buflen, p, flags); 613 if (rv != 0) 614 return rv; 615 616 return mvmebus_dmamap_load_common(sc, map); 617 } 618 619 int 620 mvmebus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *chain, int flags) 621 { 622 struct mvmebus_softc *sc = t->_cookie; 623 int rv; 624 625 rv = bus_dmamap_load_mbuf(sc->sc_dmat, map, chain, flags); 626 if (rv != 0) 627 return rv; 628 629 return mvmebus_dmamap_load_common(sc, map); 630 } 631 632 int 633 mvmebus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags) 634 { 635 struct mvmebus_softc *sc = t->_cookie; 636 int rv; 637 638 rv = bus_dmamap_load_uio(sc->sc_dmat, map, uio, flags); 639 if (rv != 0) 640 return rv; 641 642 return mvmebus_dmamap_load_common(sc, map); 643 } 644 645 int 646 mvmebus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 647 { 648 struct mvmebus_softc *sc = t->_cookie; 649 int rv; 650 651 /* 652 * mvmebus_dmamem_alloc() will ensure that the physical memory 653 * backing these segments is 100% accessible in at least one 654 * of the board's VMEbus slave images. 655 */ 656 rv = bus_dmamap_load_raw(sc->sc_dmat, map, segs, nsegs, size, flags); 657 if (rv != 0) 658 return rv; 659 660 return mvmebus_dmamap_load_common(sc, map); 661 } 662 663 void 664 mvmebus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 665 { 666 struct mvmebus_softc *sc = t->_cookie; 667 668 /* XXX Deal with bounce buffers */ 669 670 bus_dmamap_unload(sc->sc_dmat, map); 671 } 672 673 void 674 mvmebus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, bus_size_t len, int ops) 675 { 676 struct mvmebus_softc *sc = t->_cookie; 677 678 /* XXX Bounce buffers */ 679 680 bus_dmamap_sync(sc->sc_dmat, map, offset, len, ops); 681 } 682 683 #ifdef DIAGNOSTIC 684 /* ARGSUSED */ 685 int 686 mvmebus_dummy_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t align, bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) 687 { 688 689 panic("Must use vme_dmamem_alloc() in place of bus_dmamem_alloc()"); 690 } 691 692 /* ARGSUSED */ 693 void 694 mvmebus_dummy_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) 695 { 696 697 panic("Must use vme_dmamem_free() in place of bus_dmamem_free()"); 698 } 699 #endif 700 701 /* ARGSUSED */ 702 int 703 mvmebus_dmamem_alloc(void *vsc, vme_size_t len, vme_am_t am, vme_datasize_t datasize, vme_swap_t swap, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) 704 { 705 extern paddr_t avail_start; 706 struct mvmebus_softc *sc = vsc; 707 struct mvmebus_range *vr; 708 bus_addr_t low, high; 709 bus_size_t bound; 710 vme_am_t cap; 711 int i; 712 713 cap = MVMEBUS_AM2CAP(am); 714 am &= VME_AM_ADRSIZEMASK; 715 716 /* 717 * Find a slave mapping in the requested VMEbus address space. 718 */ 719 for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) { 720 if (vr->vr_am == MVMEBUS_AM_DISABLED) 721 continue; 722 723 if (i == 0 && (flags & BUS_DMA_ONBOARD_RAM) != 0) 724 continue; 725 726 if (am == (vr->vr_am & VME_AM_ADRSIZEMASK) && 727 cap == (vr->vr_am & cap) && datasize <= vr->vr_datasize && 728 len <= (vr->vr_vmeend - vr->vr_vmestart)) 729 break; 730 } 731 if (i == sc->sc_nslaves) 732 return (EINVAL); 733 734 /* 735 * Set up the constraints so we can allocate physical memory which 736 * is visible in the requested address space 737 */ 738 low = uimax(vr->vr_locstart, avail_start); 739 high = vr->vr_locstart + (vr->vr_vmeend - vr->vr_vmestart) + 1; 740 bound = (bus_size_t) vr->vr_mask + 1; 741 742 /* 743 * Allocate physical memory. 744 * 745 * Note: This fills in the segments with CPU-relative physical 746 * addresses. A further call to bus_dmamap_load_raw() (with a 747 * DMA map which specifies the same VMEbus address space and 748 * constraints as the call to here) must be made. The segments 749 * of the DMA map will then contain VMEbus-relative physical 750 * addresses of the memory allocated here. 751 * 752 * N.B. since we are already constraining the allocation to match 753 * the requested VME address space, filter out any flags that might 754 * conflict. 755 */ 756 #ifdef BUS_DMA_24BIT 757 flags &= ~BUS_DMA_24BIT; 758 #endif 759 return _bus_dmamem_alloc_common(sc->sc_dmat, low, high, 760 len, 0, bound, segs, nsegs, rsegs, flags); 761 } 762 763 void 764 mvmebus_dmamem_free(void *vsc, bus_dma_segment_t *segs, int nsegs) 765 { 766 struct mvmebus_softc *sc = vsc; 767 768 bus_dmamem_free(sc->sc_dmat, segs, nsegs); 769 } 770 771 int 772 mvmebus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size, void **kvap, int flags) 773 { 774 struct mvmebus_softc *sc = t->_cookie; 775 776 return bus_dmamem_map(sc->sc_dmat, segs, nsegs, size, kvap, flags); 777 } 778 779 void 780 mvmebus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) 781 { 782 struct mvmebus_softc *sc = t->_cookie; 783 784 bus_dmamem_unmap(sc->sc_dmat, kva, size); 785 } 786 787 paddr_t 788 mvmebus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, off_t offset, int prot, int flags) 789 { 790 struct mvmebus_softc *sc = t->_cookie; 791 792 return bus_dmamem_mmap(sc->sc_dmat, segs, nsegs, offset, prot, flags); 793 } 794 795 #ifdef DEBUG 796 static const char * 797 mvmebus_mod_string(vme_addr_t addr, vme_size_t len, vme_am_t am, vme_datasize_t ds) 798 { 799 static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"}; 800 static const char *dsiz[] = {"(", "(D8,", "(D16,", "(D16-D8,", 801 "(D32,", "(D32,D8,", "(D32-D16,", "(D32-D8,"}; 802 static const char *adrfmt[] = { "A32:%08x-%08x ", "USR:%08x-%08x ", 803 "A16:%04x-%04x ", "A24:%06x-%06x " }; 804 static char mstring[40]; 805 806 snprintf(mstring, sizeof(mstring), 807 adrfmt[(am & VME_AM_ADRSIZEMASK) >> VME_AM_ADRSIZESHIFT], 808 addr, addr + len - 1); 809 strlcat(mstring, dsiz[ds & 0x7], sizeof(mstring)); 810 811 if (MVMEBUS_AM_HAS_CAP(am)) { 812 if (am & MVMEBUS_AM_CAP_DATA) 813 strlcat(mstring, "D", sizeof(mstring)); 814 if (am & MVMEBUS_AM_CAP_PROG) 815 strlcat(mstring, "P", sizeof(mstring)); 816 if (am & MVMEBUS_AM_CAP_USER) 817 strlcat(mstring, "U", sizeof(mstring)); 818 if (am & MVMEBUS_AM_CAP_SUPER) 819 strlcat(mstring, "S", sizeof(mstring)); 820 if (am & MVMEBUS_AM_CAP_BLK) 821 strlcat(mstring, "B", sizeof(mstring)); 822 if (am & MVMEBUS_AM_CAP_BLKD64) 823 strlcat(mstring, "6", sizeof(mstring)); 824 strlcat(mstring, ")", sizeof(mstring)); 825 } else { 826 strlcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ? 827 "USER," : "SUPER,", sizeof(mstring)); 828 strlcat(mstring, mode[am & VME_AM_MODEMASK], sizeof(mstring)); 829 } 830 831 return (mstring); 832 } 833 #endif 834