1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 24 */ 25 26 #include <sys/sunddi.h> 27 #include <sys/sunndi.h> 28 #include <sys/errno.h> 29 #include <sys/modctl.h> 30 #include <sys/iommulib.h> 31 32 /* ******** Type definitions private to this file ********************** */ 33 34 /* 1 per IOMMU unit. There may be more than one per dip */ 35 typedef struct iommulib_unit { 36 kmutex_t ilu_lock; 37 uint64_t ilu_ref; 38 uint32_t ilu_unitid; 39 dev_info_t *ilu_dip; 40 iommulib_ops_t *ilu_ops; 41 void* ilu_data; 42 struct iommulib_unit *ilu_next; 43 struct iommulib_unit *ilu_prev; 44 iommulib_nexhandle_t ilu_nex; 45 } iommulib_unit_t; 46 47 typedef struct iommulib_nex { 48 dev_info_t *nex_dip; 49 iommulib_nexops_t nex_ops; 50 struct iommulib_nex *nex_next; 51 struct iommulib_nex *nex_prev; 52 uint_t nex_ref; 53 } iommulib_nex_t; 54 55 /* ********* Globals ************************ */ 56 57 /* For IOMMU drivers */ 58 smbios_hdl_t *iommulib_smbios; 59 60 /* IOMMU side: Following data protected by lock */ 61 static kmutex_t iommulib_lock; 62 static iommulib_unit_t *iommulib_list; 63 static uint64_t iommulib_unit_ids = 0; 64 static uint64_t iommulib_num_units = 0; 65 66 /* rootnex side data */ 67 68 static kmutex_t iommulib_nexus_lock; 69 static iommulib_nex_t *iommulib_nexus_list; 70 71 /* can be set atomically without lock */ 72 static volatile uint32_t iommulib_fini; 73 74 /* debug flag */ 75 static int iommulib_debug; 76 77 /* 78 * Module linkage information for the kernel. 79 */ 80 static struct modlmisc modlmisc = { 81 &mod_miscops, "IOMMU library module" 82 }; 83 84 static struct modlinkage modlinkage = { 85 MODREV_1, (void *)&modlmisc, NULL 86 }; 87 88 int 89 _init(void) 90 { 91 return (mod_install(&modlinkage)); 92 } 93 94 int 95 _fini(void) 96 { 97 mutex_enter(&iommulib_lock); 98 if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 99 mutex_exit(&iommulib_lock); 100 return (EBUSY); 101 } 102 iommulib_fini = 1; 103 104 mutex_exit(&iommulib_lock); 105 return (mod_remove(&modlinkage)); 106 } 107 108 int 109 _info(struct modinfo *modinfop) 110 { 111 return (mod_info(&modlinkage, modinfop)); 112 } 113 114 /* 115 * Routines with iommulib_iommu_* are invoked from the 116 * IOMMU driver. 117 * Routines with iommulib_nex* are invoked from the 118 * nexus driver (typically rootnex) 119 */ 120 121 int 122 iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 123 iommulib_nexhandle_t *handle) 124 { 125 iommulib_nex_t *nexp; 126 int instance = ddi_get_instance(dip); 127 const char *driver = ddi_driver_name(dip); 128 dev_info_t *pdip = ddi_get_parent(dip); 129 const char *f = "iommulib_nexus_register"; 130 131 ASSERT(nexops); 132 ASSERT(handle); 133 134 *handle = NULL; 135 136 /* 137 * Root node is never busy held 138 */ 139 if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 140 !DEVI_BUSY_OWNED(pdip))) { 141 cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 142 "or busy held for nexops vector (%p). Failing registration", 143 f, (void *)nexops); 144 return (DDI_FAILURE); 145 } 146 147 if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 148 cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 149 "in nexops vector (%p). Failing NEXUS registration", 150 f, driver, instance, (void *)nexops); 151 return (DDI_FAILURE); 152 } 153 154 ASSERT(nexops->nops_data == NULL); 155 156 if (nexops->nops_id == NULL) { 157 cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 158 "Failing registration for nexops vector: %p", 159 f, driver, instance, (void *)nexops); 160 return (DDI_FAILURE); 161 } 162 163 if (nexops->nops_dma_allochdl == NULL) { 164 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 165 "Failing registration for ops vector: %p", f, 166 driver, instance, (void *)nexops); 167 return (DDI_FAILURE); 168 } 169 170 if (nexops->nops_dma_freehdl == NULL) { 171 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 172 "Failing registration for ops vector: %p", f, 173 driver, instance, (void *)nexops); 174 return (DDI_FAILURE); 175 } 176 177 if (nexops->nops_dma_bindhdl == NULL) { 178 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 179 "Failing registration for ops vector: %p", f, 180 driver, instance, (void *)nexops); 181 return (DDI_FAILURE); 182 } 183 184 if (nexops->nops_dma_sync == NULL) { 185 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 186 "Failing registration for ops vector: %p", f, 187 driver, instance, (void *)nexops); 188 return (DDI_FAILURE); 189 } 190 191 if (nexops->nops_dma_reset_cookies == NULL) { 192 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. " 193 "Failing registration for ops vector: %p", f, 194 driver, instance, (void *)nexops); 195 return (DDI_FAILURE); 196 } 197 198 if (nexops->nops_dma_get_cookies == NULL) { 199 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 200 "Failing registration for ops vector: %p", f, 201 driver, instance, (void *)nexops); 202 return (DDI_FAILURE); 203 } 204 205 if (nexops->nops_dma_set_cookies == NULL) { 206 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_set_cookies op. " 207 "Failing registration for ops vector: %p", f, 208 driver, instance, (void *)nexops); 209 return (DDI_FAILURE); 210 } 211 212 if (nexops->nops_dma_clear_cookies == NULL) { 213 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_clear_cookies op. " 214 "Failing registration for ops vector: %p", f, 215 driver, instance, (void *)nexops); 216 return (DDI_FAILURE); 217 } 218 219 if (nexops->nops_dma_get_sleep_flags == NULL) { 220 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_sleep_flags op. " 221 "Failing registration for ops vector: %p", f, 222 driver, instance, (void *)nexops); 223 return (DDI_FAILURE); 224 } 225 226 if (nexops->nops_dma_win == NULL) { 227 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 228 "Failing registration for ops vector: %p", f, 229 driver, instance, (void *)nexops); 230 return (DDI_FAILURE); 231 } 232 233 if (nexops->nops_dmahdl_setprivate == NULL) { 234 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_setprivate op. " 235 "Failing registration for ops vector: %p", f, 236 driver, instance, (void *)nexops); 237 return (DDI_FAILURE); 238 } 239 240 if (nexops->nops_dmahdl_getprivate == NULL) { 241 cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_getprivate op. " 242 "Failing registration for ops vector: %p", f, 243 driver, instance, (void *)nexops); 244 return (DDI_FAILURE); 245 } 246 247 nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 248 249 mutex_enter(&iommulib_lock); 250 if (iommulib_fini == 1) { 251 mutex_exit(&iommulib_lock); 252 cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 253 "Failing NEXUS register.", f); 254 kmem_free(nexp, sizeof (iommulib_nex_t)); 255 return (DDI_FAILURE); 256 } 257 258 /* 259 * fini/register race conditions have been handled. Now create the 260 * nexus struct 261 */ 262 ndi_hold_devi(dip); 263 nexp->nex_dip = dip; 264 nexp->nex_ops = *nexops; 265 266 mutex_enter(&iommulib_nexus_lock); 267 nexp->nex_next = iommulib_nexus_list; 268 iommulib_nexus_list = nexp; 269 nexp->nex_prev = NULL; 270 271 if (nexp->nex_next != NULL) 272 nexp->nex_next->nex_prev = nexp; 273 274 nexp->nex_ref = 0; 275 276 /* 277 * The nexus device won't be controlled by an IOMMU. 278 */ 279 DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 280 281 DEVI(dip)->devi_iommulib_nex_handle = nexp; 282 283 mutex_exit(&iommulib_nexus_lock); 284 mutex_exit(&iommulib_lock); 285 286 cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 287 "nexops=%p", f, driver, instance, ddi_node_name(dip), 288 (void *)nexops); 289 290 *handle = nexp; 291 292 return (DDI_SUCCESS); 293 } 294 295 int 296 iommulib_nexus_unregister(iommulib_nexhandle_t handle) 297 { 298 dev_info_t *dip; 299 int instance; 300 const char *driver; 301 iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 302 const char *f = "iommulib_nexus_unregister"; 303 304 ASSERT(nexp); 305 306 if (nexp->nex_ref != 0) 307 return (DDI_FAILURE); 308 309 mutex_enter(&iommulib_nexus_lock); 310 311 dip = nexp->nex_dip; 312 driver = ddi_driver_name(dip); 313 instance = ddi_get_instance(dip); 314 315 /* A future enhancement would be to add ref-counts */ 316 317 if (nexp->nex_prev == NULL) { 318 iommulib_nexus_list = nexp->nex_next; 319 } else { 320 nexp->nex_prev->nex_next = nexp->nex_next; 321 } 322 323 if (nexp->nex_next != NULL) 324 nexp->nex_next->nex_prev = nexp->nex_prev; 325 326 mutex_exit(&iommulib_nexus_lock); 327 328 kmem_free(nexp, sizeof (iommulib_nex_t)); 329 330 cmn_err(CE_NOTE, "!%s: %s%d: NEXUS (%s) handle successfully " 331 "unregistered from IOMMULIB", f, driver, instance, 332 ddi_node_name(dip)); 333 334 ndi_rele_devi(dip); 335 336 return (DDI_SUCCESS); 337 } 338 339 int 340 iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 341 iommulib_handle_t *handle) 342 { 343 const char *vendor; 344 iommulib_unit_t *unitp; 345 int instance = ddi_get_instance(dip); 346 const char *driver = ddi_driver_name(dip); 347 const char *f = "iommulib_register"; 348 349 ASSERT(ops); 350 ASSERT(handle); 351 352 if (ops->ilops_vers != IOMMU_OPS_VERSION) { 353 cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 354 "in ops vector (%p). Failing registration", f, driver, 355 instance, (void *)ops); 356 return (DDI_FAILURE); 357 } 358 359 switch (ops->ilops_vendor) { 360 case AMD_IOMMU: 361 vendor = "AMD"; 362 break; 363 case INTEL_IOMMU: 364 vendor = "Intel"; 365 break; 366 case INVALID_VENDOR: 367 cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 368 "Failing registration for ops vector: %p", f, 369 driver, instance, ops->ilops_vendor, (void *)ops); 370 return (DDI_FAILURE); 371 default: 372 cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 373 "Failing registration for ops vector: %p", f, 374 driver, instance, ops->ilops_vendor, (void *)ops); 375 return (DDI_FAILURE); 376 } 377 378 cmn_err(CE_NOTE, "!%s: %s%d: Detected IOMMU registration from vendor" 379 " %s", f, driver, instance, vendor); 380 381 if (ops->ilops_data == NULL) { 382 cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 383 "Failing registration for ops vector: %p", f, 384 driver, instance, (void *)ops); 385 return (DDI_FAILURE); 386 } 387 388 if (ops->ilops_id == NULL) { 389 cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 390 "Failing registration for ops vector: %p", f, 391 driver, instance, (void *)ops); 392 return (DDI_FAILURE); 393 } 394 395 if (ops->ilops_probe == NULL) { 396 cmn_err(CE_WARN, "%s: %s%d: NULL probe op. " 397 "Failing registration for ops vector: %p", f, 398 driver, instance, (void *)ops); 399 return (DDI_FAILURE); 400 } 401 402 if (ops->ilops_dma_allochdl == NULL) { 403 cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. " 404 "Failing registration for ops vector: %p", f, 405 driver, instance, (void *)ops); 406 return (DDI_FAILURE); 407 } 408 409 if (ops->ilops_dma_freehdl == NULL) { 410 cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. " 411 "Failing registration for ops vector: %p", f, 412 driver, instance, (void *)ops); 413 return (DDI_FAILURE); 414 } 415 416 if (ops->ilops_dma_bindhdl == NULL) { 417 cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. " 418 "Failing registration for ops vector: %p", f, 419 driver, instance, (void *)ops); 420 return (DDI_FAILURE); 421 } 422 423 if (ops->ilops_dma_sync == NULL) { 424 cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 425 "Failing registration for ops vector: %p", f, 426 driver, instance, (void *)ops); 427 return (DDI_FAILURE); 428 } 429 430 if (ops->ilops_dma_win == NULL) { 431 cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 432 "Failing registration for ops vector: %p", f, 433 driver, instance, (void *)ops); 434 return (DDI_FAILURE); 435 } 436 437 unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 438 mutex_enter(&iommulib_lock); 439 if (iommulib_fini == 1) { 440 mutex_exit(&iommulib_lock); 441 cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 442 f); 443 kmem_free(unitp, sizeof (iommulib_unit_t)); 444 return (DDI_FAILURE); 445 } 446 447 /* 448 * fini/register race conditions have been handled. Now create the 449 * IOMMU unit 450 */ 451 mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 452 453 mutex_enter(&unitp->ilu_lock); 454 unitp->ilu_unitid = ++iommulib_unit_ids; 455 unitp->ilu_ref = 0; 456 ndi_hold_devi(dip); 457 unitp->ilu_dip = dip; 458 unitp->ilu_ops = ops; 459 unitp->ilu_data = ops->ilops_data; 460 461 unitp->ilu_next = iommulib_list; 462 iommulib_list = unitp; 463 unitp->ilu_prev = NULL; 464 if (unitp->ilu_next) 465 unitp->ilu_next->ilu_prev = unitp; 466 467 /* 468 * The IOMMU device itself is not controlled by an IOMMU. 469 */ 470 DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 471 472 mutex_exit(&unitp->ilu_lock); 473 474 iommulib_num_units++; 475 476 *handle = unitp; 477 478 mutex_exit(&iommulib_lock); 479 480 cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered IOMMU unit " 481 "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 482 f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 483 unitp->ilu_unitid); 484 485 return (DDI_SUCCESS); 486 } 487 488 int 489 iommulib_iommu_unregister(iommulib_handle_t handle) 490 { 491 uint32_t unitid; 492 dev_info_t *dip; 493 int instance; 494 const char *driver; 495 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 496 const char *f = "iommulib_unregister"; 497 498 ASSERT(unitp); 499 500 mutex_enter(&iommulib_lock); 501 mutex_enter(&unitp->ilu_lock); 502 503 unitid = unitp->ilu_unitid; 504 dip = unitp->ilu_dip; 505 driver = ddi_driver_name(dip); 506 instance = ddi_get_instance(dip); 507 508 if (unitp->ilu_ref != 0) { 509 mutex_exit(&unitp->ilu_lock); 510 mutex_exit(&iommulib_lock); 511 cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 512 "unregister IOMMULIB unitid %u", 513 f, driver, instance, unitid); 514 return (DDI_FAILURE); 515 } 516 unitp->ilu_unitid = 0; 517 ASSERT(unitp->ilu_ref == 0); 518 519 if (unitp->ilu_prev == NULL) { 520 iommulib_list = unitp->ilu_next; 521 unitp->ilu_next->ilu_prev = NULL; 522 } else { 523 unitp->ilu_prev->ilu_next = unitp->ilu_next; 524 unitp->ilu_next->ilu_prev = unitp->ilu_prev; 525 } 526 527 iommulib_num_units--; 528 529 mutex_exit(&unitp->ilu_lock); 530 531 mutex_destroy(&unitp->ilu_lock); 532 kmem_free(unitp, sizeof (iommulib_unit_t)); 533 534 mutex_exit(&iommulib_lock); 535 536 cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 537 "unregistered", f, driver, instance, unitid); 538 539 ndi_rele_devi(dip); 540 541 return (DDI_SUCCESS); 542 } 543 544 int 545 iommulib_nex_open(dev_info_t *dip, dev_info_t *rdip) 546 { 547 iommulib_unit_t *unitp; 548 int instance = ddi_get_instance(rdip); 549 const char *driver = ddi_driver_name(rdip); 550 const char *f = "iommulib_nex_open"; 551 552 ASSERT(DEVI(dip)->devi_iommulib_nex_handle != NULL); 553 ASSERT(DEVI(rdip)->devi_iommulib_handle == NULL); 554 555 /* prevent use of IOMMU for AMD IOMMU's DMA */ 556 if (strcmp(driver, "amd_iommu") == 0) { 557 DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 558 return (DDI_ENOTSUP); 559 } 560 561 /* 562 * Use the probe entry point to determine in a hardware specific 563 * manner whether this dip is controlled by an IOMMU. If yes, 564 * return the handle corresponding to the IOMMU unit. 565 */ 566 567 mutex_enter(&iommulib_lock); 568 for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 569 if (unitp->ilu_ops->ilops_probe(unitp, rdip) == DDI_SUCCESS) 570 break; 571 } 572 573 if (unitp == NULL) { 574 mutex_exit(&iommulib_lock); 575 if (iommulib_debug) { 576 char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 577 cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 578 "controlled by an IOMMU: path=%s", f, driver, 579 instance, (void *)rdip, ddi_pathname(rdip, buf)); 580 kmem_free(buf, MAXPATHLEN); 581 } 582 DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 583 return (DDI_ENOTSUP); 584 } 585 586 mutex_enter(&unitp->ilu_lock); 587 unitp->ilu_nex = DEVI(dip)->devi_iommulib_nex_handle; 588 unitp->ilu_ref++; 589 DEVI(rdip)->devi_iommulib_handle = unitp; 590 mutex_exit(&unitp->ilu_lock); 591 mutex_exit(&iommulib_lock); 592 593 atomic_inc_uint(&DEVI(dip)->devi_iommulib_nex_handle->nex_ref); 594 595 return (DDI_SUCCESS); 596 } 597 598 void 599 iommulib_nex_close(dev_info_t *rdip) 600 { 601 iommulib_unit_t *unitp; 602 const char *driver; 603 int instance; 604 uint32_t unitid; 605 iommulib_nex_t *nexp; 606 const char *f = "iommulib_nex_close"; 607 608 ASSERT(IOMMU_USED(rdip)); 609 610 unitp = DEVI(rdip)->devi_iommulib_handle; 611 612 mutex_enter(&iommulib_lock); 613 mutex_enter(&unitp->ilu_lock); 614 615 nexp = (iommulib_nex_t *)unitp->ilu_nex; 616 DEVI(rdip)->devi_iommulib_handle = NULL; 617 618 unitid = unitp->ilu_unitid; 619 driver = ddi_driver_name(unitp->ilu_dip); 620 instance = ddi_get_instance(unitp->ilu_dip); 621 622 unitp->ilu_ref--; 623 mutex_exit(&unitp->ilu_lock); 624 mutex_exit(&iommulib_lock); 625 626 atomic_dec_uint(&nexp->nex_ref); 627 628 if (iommulib_debug) { 629 char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 630 (void) ddi_pathname(rdip, buf); 631 cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 632 "unitid=%u rdip path = %s", f, driver, instance, 633 (void *)rdip, unitid, buf); 634 kmem_free(buf, MAXPATHLEN); 635 } 636 } 637 638 int 639 iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 640 ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 641 caddr_t arg, ddi_dma_handle_t *dma_handlep) 642 { 643 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 644 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 645 646 ASSERT(unitp); 647 648 /* No need to grab lock - the handle is reference counted */ 649 return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 650 attr, waitfp, arg, dma_handlep)); 651 } 652 653 int 654 iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 655 ddi_dma_handle_t dma_handle) 656 { 657 int error; 658 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 659 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 660 661 ASSERT(unitp); 662 663 /* No need to grab lock - the handle is reference counted */ 664 error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 665 rdip, dma_handle); 666 667 return (error); 668 } 669 670 int 671 iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 672 ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 673 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 674 { 675 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 676 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 677 678 ASSERT(unitp); 679 680 /* No need to grab lock - the handle is reference counted */ 681 return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 682 dmareq, cookiep, ccountp)); 683 } 684 685 int 686 iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 687 ddi_dma_handle_t dma_handle) 688 { 689 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 690 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 691 692 ASSERT(unitp); 693 694 /* No need to grab lock - the handle is reference counted */ 695 return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 696 dma_handle)); 697 } 698 699 int 700 iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 701 ddi_dma_handle_t dma_handle, off_t off, size_t len, 702 uint_t cache_flags) 703 { 704 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 705 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 706 707 ASSERT(unitp); 708 709 /* No need to grab lock - the handle is reference counted */ 710 return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 711 off, len, cache_flags)); 712 } 713 714 int 715 iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 716 ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 717 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 718 { 719 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 720 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 721 722 ASSERT(unitp); 723 724 /* No need to grab lock - the handle is reference counted */ 725 return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 726 win, offp, lenp, cookiep, ccountp)); 727 } 728 729 int 730 iommulib_nexdma_mapobject(dev_info_t *dip, dev_info_t *rdip, 731 ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 732 ddi_dma_obj_t *dmao) 733 { 734 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 735 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 736 737 return (unitp->ilu_ops->ilops_dma_mapobject(handle, dip, rdip, 738 dma_handle, dmareq, dmao)); 739 } 740 741 int 742 iommulib_nexdma_unmapobject(dev_info_t *dip, dev_info_t *rdip, 743 ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao) 744 { 745 iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 746 iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 747 748 return (unitp->ilu_ops->ilops_dma_unmapobject(handle, dip, rdip, 749 dma_handle, dmao)); 750 } 751 752 /* Utility routines invoked by IOMMU drivers */ 753 int 754 iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 755 ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 756 ddi_dma_handle_t *handlep) 757 { 758 iommulib_nexops_t *nexops; 759 760 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 761 return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 762 handlep)); 763 } 764 765 int 766 iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 767 ddi_dma_handle_t handle) 768 { 769 iommulib_nexops_t *nexops; 770 771 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 772 ASSERT(nexops); 773 return (nexops->nops_dma_freehdl(dip, rdip, handle)); 774 } 775 776 int 777 iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 778 ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 779 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 780 { 781 iommulib_nexops_t *nexops; 782 783 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 784 return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 785 cookiep, ccountp)); 786 } 787 788 int 789 iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 790 ddi_dma_handle_t handle) 791 { 792 iommulib_nexops_t *nexops; 793 794 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 795 return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 796 } 797 798 void 799 iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 800 { 801 iommulib_nexops_t *nexops; 802 803 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 804 nexops->nops_dma_reset_cookies(dip, handle); 805 } 806 807 int 808 iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 809 ddi_dma_cookie_t **cookiepp, uint_t *ccountp) 810 { 811 iommulib_nexops_t *nexops; 812 813 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 814 return (nexops->nops_dma_get_cookies(dip, handle, cookiepp, ccountp)); 815 } 816 817 int 818 iommulib_iommu_dma_set_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 819 ddi_dma_cookie_t *cookiep, uint_t ccount) 820 { 821 iommulib_nexops_t *nexops; 822 823 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 824 return (nexops->nops_dma_set_cookies(dip, handle, cookiep, ccount)); 825 } 826 827 int 828 iommulib_iommu_dma_clear_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 829 { 830 iommulib_nexops_t *nexops; 831 832 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 833 return (nexops->nops_dma_clear_cookies(dip, handle)); 834 } 835 836 int 837 iommulib_iommu_dma_get_sleep_flags(dev_info_t *dip, ddi_dma_handle_t handle) 838 { 839 iommulib_nexops_t *nexops; 840 841 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 842 return (nexops->nops_dma_get_sleep_flags(handle)); 843 } 844 845 int 846 iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 847 ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 848 { 849 iommulib_nexops_t *nexops; 850 851 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 852 return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 853 cache_flags)); 854 } 855 856 int 857 iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 858 ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 859 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 860 { 861 iommulib_nexops_t *nexops; 862 863 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 864 return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 865 cookiep, ccountp)); 866 } 867 868 int 869 iommulib_iommu_dmahdl_setprivate(dev_info_t *dip, dev_info_t *rdip, 870 ddi_dma_handle_t handle, void *priv) 871 { 872 iommulib_nexops_t *nexops; 873 874 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 875 return (nexops->nops_dmahdl_setprivate(dip, rdip, handle, priv)); 876 } 877 878 void * 879 iommulib_iommu_dmahdl_getprivate(dev_info_t *dip, dev_info_t *rdip, 880 ddi_dma_handle_t handle) 881 { 882 iommulib_nexops_t *nexops; 883 884 nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 885 return (nexops->nops_dmahdl_getprivate(dip, rdip, handle)); 886 } 887 888 int 889 iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 890 { 891 iommulib_unit_t *unitp; 892 uint64_t unitid; 893 894 unitp = (iommulib_unit_t *)handle; 895 896 ASSERT(unitp); 897 ASSERT(unitidp); 898 899 mutex_enter(&unitp->ilu_lock); 900 unitid = unitp->ilu_unitid; 901 mutex_exit(&unitp->ilu_lock); 902 903 ASSERT(unitid > 0); 904 *unitidp = (uint64_t)unitid; 905 906 return (DDI_SUCCESS); 907 } 908 909 dev_info_t * 910 iommulib_iommu_getdip(iommulib_handle_t handle) 911 { 912 iommulib_unit_t *unitp; 913 dev_info_t *dip; 914 915 unitp = (iommulib_unit_t *)handle; 916 917 ASSERT(unitp); 918 919 mutex_enter(&unitp->ilu_lock); 920 dip = unitp->ilu_dip; 921 ASSERT(dip); 922 ndi_hold_devi(dip); 923 mutex_exit(&unitp->ilu_lock); 924 925 return (dip); 926 } 927 928 iommulib_ops_t * 929 iommulib_iommu_getops(iommulib_handle_t handle) 930 { 931 iommulib_unit_t *unitp; 932 iommulib_ops_t *ops; 933 934 unitp = (iommulib_unit_t *)handle; 935 936 ASSERT(unitp); 937 938 mutex_enter(&unitp->ilu_lock); 939 ops = unitp->ilu_ops; 940 mutex_exit(&unitp->ilu_lock); 941 942 ASSERT(ops); 943 944 return (ops); 945 } 946 947 void * 948 iommulib_iommu_getdata(iommulib_handle_t handle) 949 { 950 iommulib_unit_t *unitp; 951 void *data; 952 953 unitp = (iommulib_unit_t *)handle; 954 955 ASSERT(unitp); 956 957 mutex_enter(&unitp->ilu_lock); 958 data = unitp->ilu_data; 959 mutex_exit(&unitp->ilu_lock); 960 961 ASSERT(data); 962 963 return (data); 964 } 965