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