1 /* $NetBSD: iommu.c,v 1.99 2010/06/17 06:48:46 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 2001, 2002 Eduardo Horvath 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. The name of the author may not be used to endorse or promote products 42 * derived from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 49 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 50 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 51 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 52 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57 /* 58 * UltraSPARC IOMMU support; used by both the sbus and pci code. 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: iommu.c,v 1.99 2010/06/17 06:48:46 mrg Exp $"); 63 64 #include "opt_ddb.h" 65 66 #include <sys/param.h> 67 #include <sys/extent.h> 68 #include <sys/malloc.h> 69 #include <sys/systm.h> 70 #include <sys/device.h> 71 #include <sys/proc.h> 72 73 #include <uvm/uvm_extern.h> 74 75 #include <machine/bus.h> 76 #include <sparc64/dev/iommureg.h> 77 #include <sparc64/dev/iommuvar.h> 78 79 #include <machine/autoconf.h> 80 #include <machine/cpu.h> 81 82 #ifdef DEBUG 83 #define IDB_BUSDMA 0x1 84 #define IDB_IOMMU 0x2 85 #define IDB_INFO 0x4 86 #define IDB_SYNC 0x8 87 int iommudebug = 0x0; 88 #define DPRINTF(l, s) do { if (iommudebug & l) printf s; } while (0) 89 #define IOTTE_DEBUG(n) (n) 90 #else 91 #define DPRINTF(l, s) 92 #define IOTTE_DEBUG(n) 0 93 #endif 94 95 #define iommu_strbuf_flush(i, v) do { \ 96 if ((i)->sb_flush) \ 97 bus_space_write_8((i)->sb_is->is_bustag, (i)->sb_sb, \ 98 STRBUFREG(strbuf_pgflush), (v)); \ 99 } while (0) 100 101 static int iommu_strbuf_flush_done(struct strbuf_ctl *); 102 static void _iommu_dvmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 103 bus_size_t, int); 104 105 /* 106 * initialise the UltraSPARC IOMMU (SBUS or PCI): 107 * - allocate and setup the iotsb. 108 * - enable the IOMMU 109 * - initialise the streaming buffers (if they exist) 110 * - create a private DVMA map. 111 */ 112 void 113 iommu_init(char *name, struct iommu_state *is, int tsbsize, uint32_t iovabase) 114 { 115 psize_t size; 116 vaddr_t va; 117 paddr_t pa; 118 struct vm_page *pg; 119 struct pglist pglist; 120 121 /* 122 * Setup the iommu. 123 * 124 * The sun4u iommu is part of the SBUS or PCI controller so we will 125 * deal with it here.. 126 * 127 * For sysio and psycho/psycho+ the IOMMU address space always ends at 128 * 0xffffe000, but the starting address depends on the size of the 129 * map. The map size is 1024 * 2 ^ is->is_tsbsize entries, where each 130 * entry is 8 bytes. The start of the map can be calculated by 131 * (0xffffe000 << (8 + is->is_tsbsize)). 132 * 133 * But sabre and hummingbird use a different scheme that seems to 134 * be hard-wired, so we read the start and size from the PROM and 135 * just use those values. 136 */ 137 is->is_cr = (tsbsize << 16) | IOMMUCR_EN; 138 is->is_tsbsize = tsbsize; 139 if (iovabase == -1) { 140 is->is_dvmabase = IOTSB_VSTART(is->is_tsbsize); 141 is->is_dvmaend = IOTSB_VEND - 1; 142 } else { 143 is->is_dvmabase = iovabase; 144 is->is_dvmaend = iovabase + IOTSB_VSIZE(tsbsize) - 1; 145 } 146 147 /* 148 * Allocate memory for I/O pagetables. They need to be physically 149 * contiguous. 150 */ 151 152 size = PAGE_SIZE << is->is_tsbsize; 153 if (uvm_pglistalloc((psize_t)size, (paddr_t)0, (paddr_t)-1, 154 (paddr_t)PAGE_SIZE, (paddr_t)0, &pglist, 1, 0) != 0) 155 panic("iommu_init: no memory"); 156 157 va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY); 158 if (va == 0) 159 panic("iommu_init: no memory"); 160 is->is_tsb = (int64_t *)va; 161 162 is->is_ptsb = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist)); 163 164 /* Map the pages */ 165 TAILQ_FOREACH(pg, &pglist, pageq.queue) { 166 pa = VM_PAGE_TO_PHYS(pg); 167 pmap_kenter_pa(va, pa | PMAP_NVC, 168 VM_PROT_READ | VM_PROT_WRITE, 0); 169 va += PAGE_SIZE; 170 } 171 pmap_update(pmap_kernel()); 172 memset(is->is_tsb, 0, size); 173 174 #ifdef DEBUG 175 if (iommudebug & IDB_INFO) 176 { 177 /* Probe the iommu */ 178 179 printf("iommu regs at: cr=%lx tsb=%lx flush=%lx\n", 180 (u_long)bus_space_read_8(is->is_bustag, is->is_iommu, 181 offsetof (struct iommureg, iommu_cr)), 182 (u_long)bus_space_read_8(is->is_bustag, is->is_iommu, 183 offsetof (struct iommureg, iommu_tsb)), 184 (u_long)bus_space_read_8(is->is_bustag, is->is_iommu, 185 offsetof (struct iommureg, iommu_flush))); 186 printf("iommu cr=%llx tsb=%llx\n", 187 (unsigned long long)bus_space_read_8(is->is_bustag, 188 is->is_iommu, 189 offsetof (struct iommureg, iommu_cr)), 190 (unsigned long long)bus_space_read_8(is->is_bustag, 191 is->is_iommu, 192 offsetof (struct iommureg, iommu_tsb))); 193 printf("TSB base %p phys %llx\n", (void *)is->is_tsb, 194 (unsigned long long)is->is_ptsb); 195 delay(1000000); /* 1 s */ 196 } 197 #endif 198 199 /* 200 * now actually start up the IOMMU 201 */ 202 iommu_reset(is); 203 204 /* 205 * Now all the hardware's working we need to allocate a dvma map. 206 */ 207 aprint_debug("DVMA map: %x to %x\n", 208 (unsigned int)is->is_dvmabase, 209 (unsigned int)is->is_dvmaend); 210 aprint_debug("IOTSB: %llx to %llx\n", 211 (unsigned long long)is->is_ptsb, 212 (unsigned long long)(is->is_ptsb + size - 1)); 213 is->is_dvmamap = extent_create(name, 214 is->is_dvmabase, is->is_dvmaend, 215 M_DEVBUF, 0, 0, EX_NOWAIT); 216 /* XXXMRG Check is_dvmamap is valid. */ 217 } 218 219 /* 220 * Streaming buffers don't exist on the UltraSPARC IIi; we should have 221 * detected that already and disabled them. If not, we will notice that 222 * they aren't there when the STRBUF_EN bit does not remain. 223 */ 224 void 225 iommu_reset(struct iommu_state *is) 226 { 227 int i; 228 struct strbuf_ctl *sb; 229 230 /* Need to do 64-bit stores */ 231 bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_tsb), 232 is->is_ptsb); 233 234 /* Enable IOMMU in diagnostic mode */ 235 bus_space_write_8(is->is_bustag, is->is_iommu, IOMMUREG(iommu_cr), 236 is->is_cr|IOMMUCR_DE); 237 238 for (i = 0; i < 2; i++) { 239 if ((sb = is->is_sb[i])) { 240 241 /* Enable diagnostics mode? */ 242 bus_space_write_8(is->is_bustag, is->is_sb[i]->sb_sb, 243 STRBUFREG(strbuf_ctl), STRBUF_EN); 244 245 /* No streaming buffers? Disable them */ 246 if (bus_space_read_8(is->is_bustag, 247 is->is_sb[i]->sb_sb, 248 STRBUFREG(strbuf_ctl)) == 0) { 249 is->is_sb[i]->sb_flush = NULL; 250 } else { 251 252 /* 253 * locate the pa of the flush buffer. 254 */ 255 (void)pmap_extract(pmap_kernel(), 256 (vaddr_t)is->is_sb[i]->sb_flush, 257 &is->is_sb[i]->sb_flushpa); 258 } 259 } 260 } 261 } 262 263 /* 264 * Here are the iommu control routines. 265 */ 266 void 267 iommu_enter(struct strbuf_ctl *sb, vaddr_t va, int64_t pa, int flags) 268 { 269 struct iommu_state *is = sb->sb_is; 270 int strbuf = (flags & BUS_DMA_STREAMING); 271 int64_t tte; 272 273 #ifdef DIAGNOSTIC 274 if (va < is->is_dvmabase || va > is->is_dvmaend) 275 panic("iommu_enter: va %#lx not in DVMA space", va); 276 #endif 277 278 /* Is the streamcache flush really needed? */ 279 if (sb->sb_flush) 280 iommu_strbuf_flush(sb, va); 281 else 282 /* If we can't flush the strbuf don't enable it. */ 283 strbuf = 0; 284 285 tte = MAKEIOTTE(pa, !(flags & BUS_DMA_NOWRITE), 286 !(flags & BUS_DMA_NOCACHE), (strbuf)); 287 #ifdef DEBUG 288 tte |= (flags & 0xff000LL)<<(4*8); 289 #endif 290 291 DPRINTF(IDB_IOMMU, ("Clearing TSB slot %d for va %p\n", 292 (int)IOTSBSLOT(va,is->is_tsbsize), (void *)(u_long)va)); 293 is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] = tte; 294 bus_space_write_8(is->is_bustag, is->is_iommu, 295 IOMMUREG(iommu_flush), va); 296 DPRINTF(IDB_IOMMU, ("iommu_enter: va %lx pa %lx TSB[%lx]@%p=%lx\n", 297 va, (long)pa, (u_long)IOTSBSLOT(va,is->is_tsbsize), 298 (void *)(u_long)&is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)], 299 (u_long)tte)); 300 } 301 302 /* 303 * Find the value of a DVMA address (debug routine). 304 */ 305 paddr_t 306 iommu_extract(struct iommu_state *is, vaddr_t dva) 307 { 308 int64_t tte = 0; 309 310 if (dva >= is->is_dvmabase && dva <= is->is_dvmaend) 311 tte = is->is_tsb[IOTSBSLOT(dva, is->is_tsbsize)]; 312 313 if ((tte & IOTTE_V) == 0) 314 return ((paddr_t)-1L); 315 return (tte & IOTTE_PAMASK); 316 } 317 318 /* 319 * iommu_remove: removes mappings created by iommu_enter 320 * 321 * Only demap from IOMMU if flag is set. 322 * 323 * XXX: this function needs better internal error checking. 324 */ 325 void 326 iommu_remove(struct iommu_state *is, vaddr_t va, size_t len) 327 { 328 329 #ifdef DIAGNOSTIC 330 if (va < is->is_dvmabase || va > is->is_dvmaend) 331 panic("iommu_remove: va 0x%lx not in DVMA space", (u_long)va); 332 if ((long)(va + len) < (long)va) 333 panic("iommu_remove: va 0x%lx + len 0x%lx wraps", 334 (long) va, (long) len); 335 if (len & ~0xfffffff) 336 panic("iommu_remove: ridiculous len 0x%lx", (u_long)len); 337 #endif 338 339 va = trunc_page(va); 340 DPRINTF(IDB_IOMMU, ("iommu_remove: va %lx TSB[%lx]@%p\n", 341 va, (u_long)IOTSBSLOT(va, is->is_tsbsize), 342 &is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)])); 343 while (len > 0) { 344 DPRINTF(IDB_IOMMU, ("iommu_remove: clearing TSB slot %d " 345 "for va %p size %lx\n", 346 (int)IOTSBSLOT(va,is->is_tsbsize), (void *)(u_long)va, 347 (u_long)len)); 348 if (len <= PAGE_SIZE) 349 len = 0; 350 else 351 len -= PAGE_SIZE; 352 353 #if 0 354 /* 355 * XXX Zero-ing the entry would not require RMW 356 * 357 * Disabling valid bit while a page is used by a device 358 * causes an uncorrectable DMA error. 359 * Workaround to avoid an uncorrectable DMA error is 360 * eliminating the next line, but the page is mapped 361 * until the next iommu_enter call. 362 */ 363 is->is_tsb[IOTSBSLOT(va,is->is_tsbsize)] &= ~IOTTE_V; 364 membar_storestore(); 365 #endif 366 bus_space_write_8(is->is_bustag, is->is_iommu, 367 IOMMUREG(iommu_flush), va); 368 va += PAGE_SIZE; 369 } 370 } 371 372 static int 373 iommu_strbuf_flush_done(struct strbuf_ctl *sb) 374 { 375 struct iommu_state *is = sb->sb_is; 376 struct timeval cur, flushtimeout; 377 378 #define BUMPTIME(t, usec) { \ 379 register volatile struct timeval *tp = (t); \ 380 register long us; \ 381 \ 382 tp->tv_usec = us = tp->tv_usec + (usec); \ 383 if (us >= 1000000) { \ 384 tp->tv_usec = us - 1000000; \ 385 tp->tv_sec++; \ 386 } \ 387 } 388 389 if (!sb->sb_flush) 390 return (0); 391 392 /* 393 * Streaming buffer flushes: 394 * 395 * 1 Tell strbuf to flush by storing va to strbuf_pgflush. If 396 * we're not on a cache line boundary (64-bits): 397 * 2 Store 0 in flag 398 * 3 Store pointer to flag in flushsync 399 * 4 wait till flushsync becomes 0x1 400 * 401 * If it takes more than .5 sec, something 402 * went wrong. 403 */ 404 405 *sb->sb_flush = 0; 406 bus_space_write_8(is->is_bustag, sb->sb_sb, 407 STRBUFREG(strbuf_flushsync), sb->sb_flushpa); 408 409 microtime(&flushtimeout); 410 cur = flushtimeout; 411 BUMPTIME(&flushtimeout, 500000); /* 1/2 sec */ 412 413 DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flush = %lx " 414 "at va = %lx pa = %lx now=%"PRIx64":%"PRIx32" until = %"PRIx64":%"PRIx32"\n", 415 (long)*sb->sb_flush, (long)sb->sb_flush, (long)sb->sb_flushpa, 416 cur.tv_sec, cur.tv_usec, 417 flushtimeout.tv_sec, flushtimeout.tv_usec)); 418 419 /* Bypass non-coherent D$ */ 420 while ((!ldxa(sb->sb_flushpa, ASI_PHYS_CACHED)) && 421 timercmp(&cur, &flushtimeout, <=)) 422 microtime(&cur); 423 424 #ifdef DIAGNOSTIC 425 if (!ldxa(sb->sb_flushpa, ASI_PHYS_CACHED)) { 426 printf("iommu_strbuf_flush_done: flush timeout %p, at %p\n", 427 (void *)(u_long)*sb->sb_flush, 428 (void *)(u_long)sb->sb_flushpa); /* panic? */ 429 #ifdef DDB 430 Debugger(); 431 #endif 432 } 433 #endif 434 DPRINTF(IDB_IOMMU, ("iommu_strbuf_flush_done: flushed\n")); 435 return (*sb->sb_flush); 436 } 437 438 /* 439 * IOMMU DVMA operations, common to SBUS and PCI. 440 */ 441 int 442 iommu_dvmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 443 bus_size_t buflen, struct proc *p, int flags) 444 { 445 struct strbuf_ctl *sb = (struct strbuf_ctl *)map->_dm_cookie; 446 struct iommu_state *is = sb->sb_is; 447 int s; 448 int err, needsflush; 449 bus_size_t sgsize; 450 paddr_t curaddr; 451 u_long dvmaddr, sgstart, sgend, bmask; 452 bus_size_t align, boundary, len; 453 vaddr_t vaddr = (vaddr_t)buf; 454 int seg; 455 struct pmap *pmap; 456 457 if (map->dm_nsegs) { 458 /* Already in use?? */ 459 #ifdef DIAGNOSTIC 460 printf("iommu_dvmamap_load: map still in use\n"); 461 #endif 462 bus_dmamap_unload(t, map); 463 } 464 465 /* 466 * Make sure that on error condition we return "no valid mappings". 467 */ 468 map->dm_nsegs = 0; 469 KASSERT(map->dm_maxsegsz <= map->_dm_maxmaxsegsz); 470 471 if (buflen > map->_dm_size) { 472 DPRINTF(IDB_BUSDMA, 473 ("iommu_dvmamap_load(): error %d > %d -- " 474 "map size exceeded!\n", (int)buflen, (int)map->_dm_size)); 475 return (EINVAL); 476 } 477 478 sgsize = round_page(buflen + ((int)vaddr & PGOFSET)); 479 480 /* 481 * A boundary presented to bus_dmamem_alloc() takes precedence 482 * over boundary in the map. 483 */ 484 if ((boundary = (map->dm_segs[0]._ds_boundary)) == 0) 485 boundary = map->_dm_boundary; 486 align = max(map->dm_segs[0]._ds_align, PAGE_SIZE); 487 488 /* 489 * If our segment size is larger than the boundary we need to 490 * split the transfer up int little pieces ourselves. 491 */ 492 s = splhigh(); 493 err = extent_alloc(is->is_dvmamap, sgsize, align, 494 (sgsize > boundary) ? 0 : boundary, 495 EX_NOWAIT|EX_BOUNDZERO, &dvmaddr); 496 splx(s); 497 498 #ifdef DEBUG 499 if (err || (dvmaddr == (u_long)-1)) { 500 printf("iommu_dvmamap_load(): extent_alloc(%d, %x) failed!\n", 501 (int)sgsize, flags); 502 #ifdef DDB 503 Debugger(); 504 #endif 505 } 506 #endif 507 if (err != 0) 508 return (err); 509 510 if (dvmaddr == (u_long)-1) 511 return (ENOMEM); 512 513 /* Set the active DVMA map */ 514 map->_dm_dvmastart = dvmaddr; 515 map->_dm_dvmasize = sgsize; 516 517 /* 518 * Now split the DVMA range into segments, not crossing 519 * the boundary. 520 */ 521 seg = 0; 522 sgstart = dvmaddr + (vaddr & PGOFSET); 523 sgend = sgstart + buflen - 1; 524 map->dm_segs[seg].ds_addr = sgstart; 525 DPRINTF(IDB_INFO, ("iommu_dvmamap_load: boundary %lx boundary - 1 %lx " 526 "~(boundary - 1) %lx\n", (long)boundary, (long)(boundary - 1), 527 (long)~(boundary - 1))); 528 bmask = ~(boundary - 1); 529 while ((sgstart & bmask) != (sgend & bmask) || 530 sgend - sgstart + 1 > map->dm_maxsegsz) { 531 /* Oops. We crossed a boundary or large seg. Split the xfer. */ 532 len = map->dm_maxsegsz; 533 if ((sgstart & bmask) != (sgend & bmask)) 534 len = min(len, boundary - (sgstart & (boundary - 1))); 535 map->dm_segs[seg].ds_len = len; 536 DPRINTF(IDB_INFO, ("iommu_dvmamap_load: " 537 "seg %d start %lx size %lx\n", seg, 538 (long)map->dm_segs[seg].ds_addr, 539 (long)map->dm_segs[seg].ds_len)); 540 if (++seg >= map->_dm_segcnt) { 541 /* Too many segments. Fail the operation. */ 542 DPRINTF(IDB_INFO, ("iommu_dvmamap_load: " 543 "too many segments %d\n", seg)); 544 s = splhigh(); 545 err = extent_free(is->is_dvmamap, 546 dvmaddr, sgsize, EX_NOWAIT); 547 map->_dm_dvmastart = 0; 548 map->_dm_dvmasize = 0; 549 splx(s); 550 if (err != 0) 551 printf("warning: %s: %" PRId64 552 " of DVMA space lost\n", __func__, sgsize); 553 return (EFBIG); 554 } 555 sgstart += len; 556 map->dm_segs[seg].ds_addr = sgstart; 557 } 558 map->dm_segs[seg].ds_len = sgend - sgstart + 1; 559 DPRINTF(IDB_INFO, ("iommu_dvmamap_load: " 560 "seg %d start %lx size %lx\n", seg, 561 (long)map->dm_segs[seg].ds_addr, (long)map->dm_segs[seg].ds_len)); 562 map->dm_nsegs = seg + 1; 563 map->dm_mapsize = buflen; 564 565 if (p != NULL) 566 pmap = p->p_vmspace->vm_map.pmap; 567 else 568 pmap = pmap_kernel(); 569 570 needsflush = 0; 571 for (; buflen > 0; ) { 572 573 /* 574 * Get the physical address for this page. 575 */ 576 if (pmap_extract(pmap, (vaddr_t)vaddr, &curaddr) == FALSE) { 577 #ifdef DIAGNOSTIC 578 printf("iommu_dvmamap_load: pmap_extract failed %lx\n", vaddr); 579 #endif 580 bus_dmamap_unload(t, map); 581 return (-1); 582 } 583 584 /* 585 * Compute the segment size, and adjust counts. 586 */ 587 sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET); 588 if (buflen < sgsize) 589 sgsize = buflen; 590 591 DPRINTF(IDB_BUSDMA, 592 ("iommu_dvmamap_load: map %p loading va %p " 593 "dva %lx at pa %lx\n", 594 map, (void *)vaddr, (long)dvmaddr, 595 (long)trunc_page(curaddr))); 596 iommu_enter(sb, trunc_page(dvmaddr), trunc_page(curaddr), 597 flags | IOTTE_DEBUG(0x4000)); 598 needsflush = 1; 599 600 dvmaddr += PAGE_SIZE; 601 vaddr += sgsize; 602 buflen -= sgsize; 603 } 604 if (needsflush) 605 iommu_strbuf_flush_done(sb); 606 #ifdef DIAGNOSTIC 607 for (seg = 0; seg < map->dm_nsegs; seg++) { 608 if (map->dm_segs[seg].ds_addr < is->is_dvmabase || 609 map->dm_segs[seg].ds_addr > is->is_dvmaend) { 610 printf("seg %d dvmaddr %lx out of range %x - %x\n", 611 seg, (long)map->dm_segs[seg].ds_addr, 612 is->is_dvmabase, is->is_dvmaend); 613 #ifdef DDB 614 Debugger(); 615 #endif 616 } 617 } 618 #endif 619 return (0); 620 } 621 622 623 void 624 iommu_dvmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 625 { 626 struct strbuf_ctl *sb = (struct strbuf_ctl *)map->_dm_cookie; 627 struct iommu_state *is = sb->sb_is; 628 int error, s; 629 bus_size_t sgsize = map->_dm_dvmasize; 630 631 /* Flush the iommu */ 632 #ifdef DEBUG 633 if (!map->_dm_dvmastart) { 634 printf("iommu_dvmamap_unload: No dvmastart is zero\n"); 635 #ifdef DDB 636 Debugger(); 637 #endif 638 } 639 #endif 640 iommu_remove(is, map->_dm_dvmastart, map->_dm_dvmasize); 641 642 /* Flush the caches */ 643 bus_dmamap_unload(t->_parent, map); 644 645 s = splhigh(); 646 error = extent_free(is->is_dvmamap, map->_dm_dvmastart, 647 map->_dm_dvmasize, EX_NOWAIT); 648 map->_dm_dvmastart = 0; 649 map->_dm_dvmasize = 0; 650 splx(s); 651 if (error != 0) 652 printf("warning: %s: %" PRId64 " of DVMA space lost\n", 653 __func__, sgsize); 654 655 /* Clear the map */ 656 } 657 658 659 int 660 iommu_dvmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 661 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 662 { 663 struct strbuf_ctl *sb = (struct strbuf_ctl *)map->_dm_cookie; 664 struct iommu_state *is = sb->sb_is; 665 struct vm_page *pg; 666 int i, j, s; 667 int left; 668 int err, needsflush; 669 bus_size_t sgsize; 670 paddr_t pa; 671 bus_size_t boundary, align; 672 u_long dvmaddr, sgstart, sgend, bmask; 673 struct pglist *pglist; 674 const int pagesz = PAGE_SIZE; 675 #ifdef DEBUG 676 int npg = 0; 677 #endif 678 679 if (map->dm_nsegs) { 680 /* Already in use?? */ 681 #ifdef DIAGNOSTIC 682 printf("iommu_dvmamap_load_raw: map still in use\n"); 683 #endif 684 bus_dmamap_unload(t, map); 685 } 686 687 /* 688 * A boundary presented to bus_dmamem_alloc() takes precedence 689 * over boundary in the map. 690 */ 691 if ((boundary = segs[0]._ds_boundary) == 0) 692 boundary = map->_dm_boundary; 693 694 align = max(segs[0]._ds_align, pagesz); 695 696 /* 697 * Make sure that on error condition we return "no valid mappings". 698 */ 699 map->dm_nsegs = 0; 700 /* Count up the total number of pages we need */ 701 pa = trunc_page(segs[0].ds_addr); 702 sgsize = 0; 703 left = size; 704 for (i = 0; left > 0 && i < nsegs; i++) { 705 if (round_page(pa) != round_page(segs[i].ds_addr)) 706 sgsize = round_page(sgsize) + 707 (segs[i].ds_addr & PGOFSET); 708 sgsize += min(left, segs[i].ds_len); 709 left -= segs[i].ds_len; 710 pa = segs[i].ds_addr + segs[i].ds_len; 711 } 712 sgsize = round_page(sgsize); 713 714 s = splhigh(); 715 /* 716 * If our segment size is larger than the boundary we need to 717 * split the transfer up into little pieces ourselves. 718 */ 719 err = extent_alloc(is->is_dvmamap, sgsize, align, 720 (sgsize > boundary) ? 0 : boundary, 721 ((flags & BUS_DMA_NOWAIT) == 0 ? EX_WAITOK : EX_NOWAIT) | 722 EX_BOUNDZERO, &dvmaddr); 723 splx(s); 724 725 if (err != 0) 726 return (err); 727 728 #ifdef DEBUG 729 if (dvmaddr == (u_long)-1) 730 { 731 printf("iommu_dvmamap_load_raw(): extent_alloc(%d, %x) failed!\n", 732 (int)sgsize, flags); 733 #ifdef DDB 734 Debugger(); 735 #endif 736 } 737 #endif 738 if (dvmaddr == (u_long)-1) 739 return (ENOMEM); 740 741 /* Set the active DVMA map */ 742 map->_dm_dvmastart = dvmaddr; 743 map->_dm_dvmasize = sgsize; 744 745 bmask = ~(boundary - 1); 746 if ((pglist = segs[0]._ds_mlist) == NULL) { 747 u_long prev_va = 0UL, last_va = dvmaddr; 748 paddr_t prev_pa = 0; 749 int end = 0, offset; 750 bus_size_t len = size; 751 752 /* 753 * This segs is made up of individual physical 754 * segments, probably by _bus_dmamap_load_uio() or 755 * _bus_dmamap_load_mbuf(). Ignore the mlist and 756 * load each one individually. 757 */ 758 j = 0; 759 needsflush = 0; 760 for (i = 0; i < nsegs ; i++) { 761 762 pa = segs[i].ds_addr; 763 offset = (pa & PGOFSET); 764 pa = trunc_page(pa); 765 dvmaddr = trunc_page(dvmaddr); 766 left = min(len, segs[i].ds_len); 767 768 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: converting " 769 "physseg %d start %lx size %lx\n", i, 770 (long)segs[i].ds_addr, (long)segs[i].ds_len)); 771 772 if ((pa == prev_pa) && 773 ((offset != 0) || (end != offset))) { 774 /* We can re-use this mapping */ 775 dvmaddr = prev_va; 776 } 777 778 sgstart = dvmaddr + offset; 779 sgend = sgstart + left - 1; 780 781 /* Are the segments virtually adjacent? */ 782 if ((j > 0) && (end == offset) && 783 ((offset == 0) || (pa == prev_pa)) && 784 (map->dm_segs[j-1].ds_len + left <= 785 map->dm_maxsegsz)) { 786 /* Just append to the previous segment. */ 787 map->dm_segs[--j].ds_len += left; 788 /* Restore sgstart for boundary check */ 789 sgstart = map->dm_segs[j].ds_addr; 790 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: " 791 "appending seg %d start %lx size %lx\n", j, 792 (long)map->dm_segs[j].ds_addr, 793 (long)map->dm_segs[j].ds_len)); 794 } else { 795 if (j >= map->_dm_segcnt) { 796 iommu_remove(is, map->_dm_dvmastart, 797 last_va - map->_dm_dvmastart); 798 goto fail; 799 } 800 map->dm_segs[j].ds_addr = sgstart; 801 map->dm_segs[j].ds_len = left; 802 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: " 803 "seg %d start %lx size %lx\n", j, 804 (long)map->dm_segs[j].ds_addr, 805 (long)map->dm_segs[j].ds_len)); 806 } 807 end = (offset + left) & PGOFSET; 808 809 /* Check for boundary issues */ 810 while ((sgstart & bmask) != (sgend & bmask)) { 811 /* Need a new segment. */ 812 map->dm_segs[j].ds_len = 813 boundary - (sgstart & (boundary - 1)); 814 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: " 815 "seg %d start %lx size %lx\n", j, 816 (long)map->dm_segs[j].ds_addr, 817 (long)map->dm_segs[j].ds_len)); 818 if (++j >= map->_dm_segcnt) { 819 iommu_remove(is, map->_dm_dvmastart, 820 last_va - map->_dm_dvmastart); 821 goto fail; 822 } 823 sgstart += map->dm_segs[j-1].ds_len; 824 map->dm_segs[j].ds_addr = sgstart; 825 map->dm_segs[j].ds_len = sgend - sgstart + 1; 826 } 827 828 if (sgsize == 0) 829 panic("iommu_dmamap_load_raw: size botch"); 830 831 /* Now map a series of pages. */ 832 while (dvmaddr <= sgend) { 833 DPRINTF(IDB_BUSDMA, 834 ("iommu_dvmamap_load_raw: map %p " 835 "loading va %lx at pa %lx\n", 836 map, (long)dvmaddr, 837 (long)(pa))); 838 /* Enter it if we haven't before. */ 839 if (prev_va != dvmaddr) { 840 iommu_enter(sb, prev_va = dvmaddr, 841 prev_pa = pa, 842 flags | IOTTE_DEBUG(++npg << 12)); 843 needsflush = 1; 844 } 845 dvmaddr += pagesz; 846 pa += pagesz; 847 last_va = dvmaddr; 848 } 849 850 len -= left; 851 ++j; 852 } 853 if (needsflush) 854 iommu_strbuf_flush_done(sb); 855 856 map->dm_mapsize = size; 857 map->dm_nsegs = j; 858 #ifdef DIAGNOSTIC 859 { int seg; 860 for (seg = 0; seg < map->dm_nsegs; seg++) { 861 if (map->dm_segs[seg].ds_addr < is->is_dvmabase || 862 map->dm_segs[seg].ds_addr > is->is_dvmaend) { 863 printf("seg %d dvmaddr %lx out of range %x - %x\n", 864 seg, (long)map->dm_segs[seg].ds_addr, 865 is->is_dvmabase, is->is_dvmaend); 866 #ifdef DDB 867 Debugger(); 868 #endif 869 } 870 } 871 } 872 #endif 873 return (0); 874 } 875 876 /* 877 * This was allocated with bus_dmamem_alloc. 878 * The pages are on a `pglist'. 879 */ 880 i = 0; 881 sgstart = dvmaddr; 882 sgend = sgstart + size - 1; 883 map->dm_segs[i].ds_addr = sgstart; 884 while ((sgstart & bmask) != (sgend & bmask)) { 885 /* Oops. We crossed a boundary. Split the xfer. */ 886 map->dm_segs[i].ds_len = boundary - (sgstart & (boundary - 1)); 887 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: " 888 "seg %d start %lx size %lx\n", i, 889 (long)map->dm_segs[i].ds_addr, 890 (long)map->dm_segs[i].ds_len)); 891 if (++i >= map->_dm_segcnt) { 892 /* Too many segments. Fail the operation. */ 893 goto fail; 894 } 895 sgstart += map->dm_segs[i-1].ds_len; 896 map->dm_segs[i].ds_addr = sgstart; 897 } 898 DPRINTF(IDB_INFO, ("iommu_dvmamap_load_raw: " 899 "seg %d start %lx size %lx\n", i, 900 (long)map->dm_segs[i].ds_addr, (long)map->dm_segs[i].ds_len)); 901 map->dm_segs[i].ds_len = sgend - sgstart + 1; 902 903 needsflush = 0; 904 TAILQ_FOREACH(pg, pglist, pageq.queue) { 905 if (sgsize == 0) 906 panic("iommu_dmamap_load_raw: size botch"); 907 pa = VM_PAGE_TO_PHYS(pg); 908 909 DPRINTF(IDB_BUSDMA, 910 ("iommu_dvmamap_load_raw: map %p loading va %lx at pa %lx\n", 911 map, (long)dvmaddr, (long)(pa))); 912 iommu_enter(sb, dvmaddr, pa, flags | IOTTE_DEBUG(0x8000)); 913 needsflush = 1; 914 915 dvmaddr += pagesz; 916 sgsize -= pagesz; 917 } 918 if (needsflush) 919 iommu_strbuf_flush_done(sb); 920 map->dm_mapsize = size; 921 map->dm_nsegs = i+1; 922 #ifdef DIAGNOSTIC 923 { int seg; 924 for (seg = 0; seg < map->dm_nsegs; seg++) { 925 if (map->dm_segs[seg].ds_addr < is->is_dvmabase || 926 map->dm_segs[seg].ds_addr > is->is_dvmaend) { 927 printf("seg %d dvmaddr %lx out of range %x - %x\n", 928 seg, (long)map->dm_segs[seg].ds_addr, 929 is->is_dvmabase, is->is_dvmaend); 930 #ifdef DDB 931 Debugger(); 932 #endif 933 } 934 } 935 } 936 #endif 937 return (0); 938 939 fail: 940 s = splhigh(); 941 err = extent_free(is->is_dvmamap, map->_dm_dvmastart, sgsize, 942 EX_NOWAIT); 943 map->_dm_dvmastart = 0; 944 map->_dm_dvmasize = 0; 945 splx(s); 946 if (err != 0) 947 printf("warning: %s: %" PRId64 " of DVMA space lost\n", 948 __func__, sgsize); 949 return (EFBIG); 950 } 951 952 953 /* 954 * Flush an individual dma segment, returns non-zero if the streaming buffers 955 * need flushing afterwards. 956 */ 957 static int 958 iommu_dvmamap_sync_range(struct strbuf_ctl *sb, vaddr_t va, bus_size_t len) 959 { 960 vaddr_t vaend; 961 struct iommu_state *is = sb->sb_is; 962 963 #ifdef DIAGNOSTIC 964 if (va < is->is_dvmabase || va > is->is_dvmaend) 965 panic("invalid va: %llx", (long long)va); 966 #endif 967 968 if ((is->is_tsb[IOTSBSLOT(va, is->is_tsbsize)] & IOTTE_STREAM) == 0) { 969 DPRINTF(IDB_BUSDMA, 970 ("iommu_dvmamap_sync_range: attempting to flush " 971 "non-streaming entry\n")); 972 return (0); 973 } 974 975 vaend = round_page(va + len) - 1; 976 va = trunc_page(va); 977 978 #ifdef DIAGNOSTIC 979 if (va < is->is_dvmabase || vaend > is->is_dvmaend) 980 panic("invalid va range: %llx to %llx (%x to %x)", 981 (long long)va, (long long)vaend, 982 is->is_dvmabase, 983 is->is_dvmaend); 984 #endif 985 986 for ( ; va <= vaend; va += PAGE_SIZE) { 987 DPRINTF(IDB_BUSDMA, 988 ("iommu_dvmamap_sync_range: flushing va %p\n", 989 (void *)(u_long)va)); 990 iommu_strbuf_flush(sb, va); 991 } 992 993 return (1); 994 } 995 996 static void 997 _iommu_dvmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 998 bus_size_t len, int ops) 999 { 1000 struct strbuf_ctl *sb = (struct strbuf_ctl *)map->_dm_cookie; 1001 bus_size_t count; 1002 int i, needsflush = 0; 1003 1004 if (!sb->sb_flush) 1005 return; 1006 1007 for (i = 0; i < map->dm_nsegs; i++) { 1008 if (offset < map->dm_segs[i].ds_len) 1009 break; 1010 offset -= map->dm_segs[i].ds_len; 1011 } 1012 1013 if (i == map->dm_nsegs) 1014 panic("iommu_dvmamap_sync: segment too short %llu", 1015 (unsigned long long)offset); 1016 1017 if (ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_POSTWRITE)) { 1018 /* Nothing to do */; 1019 } 1020 1021 if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_PREWRITE)) { 1022 1023 for (; len > 0 && i < map->dm_nsegs; i++) { 1024 count = MIN(map->dm_segs[i].ds_len - offset, len); 1025 if (count > 0 && 1026 iommu_dvmamap_sync_range(sb, 1027 map->dm_segs[i].ds_addr + offset, count)) 1028 needsflush = 1; 1029 offset = 0; 1030 len -= count; 1031 } 1032 #ifdef DIAGNOSTIC 1033 if (i == map->dm_nsegs && len > 0) 1034 panic("iommu_dvmamap_sync: leftover %llu", 1035 (unsigned long long)len); 1036 #endif 1037 1038 if (needsflush) 1039 iommu_strbuf_flush_done(sb); 1040 } 1041 } 1042 1043 void 1044 iommu_dvmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 1045 bus_size_t len, int ops) 1046 { 1047 1048 /* If len is 0, then there is nothing to do */ 1049 if (len == 0) 1050 return; 1051 1052 if (ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) { 1053 /* Flush the CPU then the IOMMU */ 1054 bus_dmamap_sync(t->_parent, map, offset, len, ops); 1055 _iommu_dvmamap_sync(t, map, offset, len, ops); 1056 } 1057 if (ops & (BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE)) { 1058 /* Flush the IOMMU then the CPU */ 1059 _iommu_dvmamap_sync(t, map, offset, len, ops); 1060 bus_dmamap_sync(t->_parent, map, offset, len, ops); 1061 } 1062 } 1063 1064 int 1065 iommu_dvmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, 1066 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, 1067 int flags) 1068 { 1069 1070 DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_alloc: sz %llx align %llx bound %llx " 1071 "segp %p flags %d\n", (unsigned long long)size, 1072 (unsigned long long)alignment, (unsigned long long)boundary, 1073 segs, flags)); 1074 return (bus_dmamem_alloc(t->_parent, size, alignment, boundary, 1075 segs, nsegs, rsegs, flags|BUS_DMA_DVMA)); 1076 } 1077 1078 void 1079 iommu_dvmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) 1080 { 1081 1082 DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_free: segp %p nsegs %d\n", 1083 segs, nsegs)); 1084 bus_dmamem_free(t->_parent, segs, nsegs); 1085 } 1086 1087 /* 1088 * Map the DVMA mappings into the kernel pmap. 1089 * Check the flags to see whether we're streaming or coherent. 1090 */ 1091 int 1092 iommu_dvmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 1093 size_t size, void **kvap, int flags) 1094 { 1095 struct vm_page *pg; 1096 vaddr_t va; 1097 bus_addr_t addr; 1098 struct pglist *pglist; 1099 int cbit; 1100 const uvm_flag_t kmflags = 1101 (flags & BUS_DMA_NOWAIT) != 0 ? UVM_KMF_NOWAIT : 0; 1102 1103 DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: segp %p nsegs %d size %lx\n", 1104 segs, nsegs, size)); 1105 1106 /* 1107 * Allocate some space in the kernel map, and then map these pages 1108 * into this space. 1109 */ 1110 size = round_page(size); 1111 va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags); 1112 if (va == 0) 1113 return (ENOMEM); 1114 1115 *kvap = (void *)va; 1116 1117 /* 1118 * digest flags: 1119 */ 1120 cbit = 0; 1121 if (flags & BUS_DMA_COHERENT) /* Disable vcache */ 1122 cbit |= PMAP_NVC; 1123 if (flags & BUS_DMA_NOCACHE) /* side effects */ 1124 cbit |= PMAP_NC; 1125 1126 /* 1127 * Now take this and map it into the CPU. 1128 */ 1129 pglist = segs[0]._ds_mlist; 1130 TAILQ_FOREACH(pg, pglist, pageq.queue) { 1131 #ifdef DIAGNOSTIC 1132 if (size == 0) 1133 panic("iommu_dvmamem_map: size botch"); 1134 #endif 1135 addr = VM_PAGE_TO_PHYS(pg); 1136 DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_map: " 1137 "mapping va %lx at %llx\n", va, (unsigned long long)addr | cbit)); 1138 pmap_kenter_pa(va, addr | cbit, 1139 VM_PROT_READ | VM_PROT_WRITE, 0); 1140 va += PAGE_SIZE; 1141 size -= PAGE_SIZE; 1142 } 1143 pmap_update(pmap_kernel()); 1144 return (0); 1145 } 1146 1147 /* 1148 * Unmap DVMA mappings from kernel 1149 */ 1150 void 1151 iommu_dvmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) 1152 { 1153 1154 DPRINTF(IDB_BUSDMA, ("iommu_dvmamem_unmap: kvm %p size %lx\n", 1155 kva, size)); 1156 1157 #ifdef DIAGNOSTIC 1158 if ((u_long)kva & PGOFSET) 1159 panic("iommu_dvmamem_unmap"); 1160 #endif 1161 1162 size = round_page(size); 1163 pmap_kremove((vaddr_t)kva, size); 1164 pmap_update(pmap_kernel()); 1165 uvm_km_free(kernel_map, (vaddr_t)kva, size, UVM_KMF_VAONLY); 1166 } 1167