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