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 * Portions Copyright (c) 2010, Oracle and/or its affiliates. 23 * All rights reserved. 24 */ 25 /* 26 * Copyright (c) 2009, Intel Corporation. 27 * All rights reserved. 28 */ 29 30 /* 31 * Intel IOMMU implementation 32 * This file contains Intel IOMMU code exported 33 * to the rest of the system and code that deals 34 * with the Intel IOMMU as a whole. 35 */ 36 37 #include <sys/conf.h> 38 #include <sys/modctl.h> 39 #include <sys/pci.h> 40 #include <sys/pci_impl.h> 41 #include <sys/sysmacros.h> 42 #include <sys/ddi.h> 43 #include <sys/ddidmareq.h> 44 #include <sys/ddi_impldefs.h> 45 #include <sys/ddifm.h> 46 #include <sys/sunndi.h> 47 #include <sys/debug.h> 48 #include <sys/fm/protocol.h> 49 #include <sys/note.h> 50 #include <sys/apic.h> 51 #include <vm/hat_i86.h> 52 #include <sys/smp_impldefs.h> 53 #include <sys/spl.h> 54 #include <sys/archsystm.h> 55 #include <sys/x86_archext.h> 56 #include <sys/rootnex.h> 57 #include <sys/avl.h> 58 #include <sys/bootconf.h> 59 #include <sys/bootinfo.h> 60 #include <sys/atomic.h> 61 #include <sys/immu.h> 62 /* ########################### Globals and tunables ######################## */ 63 /* 64 * Global switches (boolean) that can be toggled either via boot options 65 * or via /etc/system or kmdb 66 */ 67 68 /* Various features */ 69 boolean_t immu_enable = B_TRUE; 70 boolean_t immu_dvma_enable = B_TRUE; 71 72 /* accessed in other files so not static */ 73 boolean_t immu_gfxdvma_enable = B_TRUE; 74 boolean_t immu_intrmap_enable = B_FALSE; 75 boolean_t immu_qinv_enable = B_FALSE; 76 77 /* various quirks that need working around */ 78 79 /* XXX We always map page 0 read/write for now */ 80 boolean_t immu_quirk_usbpage0 = B_TRUE; 81 boolean_t immu_quirk_usbrmrr = B_TRUE; 82 boolean_t immu_quirk_usbfullpa; 83 boolean_t immu_quirk_mobile4; 84 85 /* debug messages */ 86 boolean_t immu_dmar_print; 87 88 /* Tunables */ 89 int64_t immu_flush_gran = 5; 90 91 immu_flags_t immu_global_dvma_flags; 92 93 /* ############ END OPTIONS section ################ */ 94 95 /* 96 * Global used internally by Intel IOMMU code 97 */ 98 dev_info_t *root_devinfo; 99 kmutex_t immu_lock; 100 list_t immu_list; 101 void *immu_pgtable_cache; 102 boolean_t immu_setup; 103 boolean_t immu_running; 104 boolean_t immu_quiesced; 105 106 /* ######################## END Globals and tunables ###################### */ 107 /* Globals used only in this file */ 108 static char **black_array; 109 static uint_t nblacks; 110 111 static char **unity_driver_array; 112 static uint_t nunity; 113 static char **xlate_driver_array; 114 static uint_t nxlate; 115 /* ###################### Utility routines ############################# */ 116 117 /* 118 * Check if the device has mobile 4 chipset 119 */ 120 static int 121 check_mobile4(dev_info_t *dip, void *arg) 122 { 123 _NOTE(ARGUNUSED(arg)); 124 int vendor, device; 125 int *ip = (int *)arg; 126 127 ASSERT(arg); 128 129 vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 130 "vendor-id", -1); 131 device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 132 "device-id", -1); 133 134 if (vendor == 0x8086 && device == 0x2a40) { 135 *ip = B_TRUE; 136 ddi_err(DER_NOTE, dip, "IMMU: Mobile 4 chipset detected. " 137 "Force setting IOMMU write buffer"); 138 return (DDI_WALK_TERMINATE); 139 } else { 140 return (DDI_WALK_CONTINUE); 141 } 142 } 143 144 static void 145 map_bios_rsvd_mem(dev_info_t *dip) 146 { 147 struct memlist *mp; 148 int e; 149 150 memlist_read_lock(); 151 152 mp = bios_rsvd; 153 while (mp != NULL) { 154 memrng_t mrng = {0}; 155 156 ddi_err(DER_LOG, dip, "IMMU: Mapping BIOS rsvd range " 157 "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address, 158 mp->ml_address + mp->ml_size); 159 160 mrng.mrng_start = IMMU_ROUNDOWN(mp->ml_address); 161 mrng.mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE; 162 163 e = immu_dvma_map(NULL, NULL, &mrng, 0, dip, IMMU_FLAGS_MEMRNG); 164 ASSERT(e == DDI_DMA_MAPPED || e == DDI_DMA_USE_PHYSICAL); 165 166 mp = mp->ml_next; 167 } 168 169 memlist_read_unlock(); 170 } 171 172 173 /* 174 * Check if the driver requests a specific type of mapping. 175 */ 176 /*ARGSUSED*/ 177 static void 178 check_conf(dev_info_t *dip, void *arg) 179 { 180 immu_devi_t *immu_devi; 181 const char *dname; 182 uint_t i; 183 int hasprop = 0; 184 185 /* 186 * Only PCI devices can use an IOMMU. Legacy ISA devices 187 * are handled in check_lpc. 188 */ 189 if (!DEVI_IS_PCI(dip)) 190 return; 191 192 dname = ddi_driver_name(dip); 193 if (dname == NULL) 194 return; 195 immu_devi = immu_devi_get(dip); 196 197 for (i = 0; i < nunity; i++) { 198 if (strcmp(unity_driver_array[i], dname) == 0) { 199 hasprop = 1; 200 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY; 201 } 202 } 203 204 for (i = 0; i < nxlate; i++) { 205 if (strcmp(xlate_driver_array[i], dname) == 0) { 206 hasprop = 1; 207 immu_devi->imd_dvma_flags &= ~IMMU_FLAGS_UNITY; 208 } 209 } 210 211 /* 212 * Report if we changed the value from the default. 213 */ 214 if (hasprop && (immu_devi->imd_dvma_flags ^ immu_global_dvma_flags)) 215 ddi_err(DER_LOG, dip, "using %s DVMA mapping", 216 immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY ? 217 DDI_DVMA_MAPTYPE_UNITY : DDI_DVMA_MAPTYPE_XLATE); 218 } 219 220 /* 221 * Check if the device is USB controller 222 */ 223 /*ARGSUSED*/ 224 static void 225 check_usb(dev_info_t *dip, void *arg) 226 { 227 const char *drv = ddi_driver_name(dip); 228 immu_devi_t *immu_devi; 229 230 231 if (drv == NULL || 232 (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 && 233 strcmp(drv, "ehci") != 0)) { 234 return; 235 } 236 237 immu_devi = immu_devi_get(dip); 238 239 /* 240 * If unit mappings are already specified, globally or 241 * locally, we're done here, since that covers both 242 * quirks below. 243 */ 244 if (immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY) 245 return; 246 247 /* This must come first since it does unity mapping */ 248 if (immu_quirk_usbfullpa == B_TRUE) { 249 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY; 250 } else if (immu_quirk_usbrmrr == B_TRUE) { 251 ddi_err(DER_LOG, dip, "Applying USB RMRR quirk"); 252 map_bios_rsvd_mem(dip); 253 } 254 } 255 256 /* 257 * Check if the device is a LPC device 258 */ 259 /*ARGSUSED*/ 260 static void 261 check_lpc(dev_info_t *dip, void *arg) 262 { 263 immu_devi_t *immu_devi; 264 265 immu_devi = immu_devi_get(dip); 266 ASSERT(immu_devi); 267 if (immu_devi->imd_lpc == B_TRUE) { 268 ddi_err(DER_LOG, dip, "IMMU: Found LPC device"); 269 /* This will put the immu_devi on the LPC "specials" list */ 270 (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP); 271 } 272 } 273 274 /* 275 * Check if the device is a GFX device 276 */ 277 /*ARGSUSED*/ 278 static void 279 check_gfx(dev_info_t *dip, void *arg) 280 { 281 immu_devi_t *immu_devi; 282 283 immu_devi = immu_devi_get(dip); 284 ASSERT(immu_devi); 285 if (immu_devi->imd_display == B_TRUE) { 286 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY; 287 ddi_err(DER_LOG, dip, "IMMU: Found GFX device"); 288 /* This will put the immu_devi on the GFX "specials" list */ 289 (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP); 290 } 291 } 292 293 static void 294 walk_tree(int (*f)(dev_info_t *, void *), void *arg) 295 { 296 int count; 297 298 ndi_devi_enter(root_devinfo, &count); 299 ddi_walk_devs(ddi_get_child(root_devinfo), f, arg); 300 ndi_devi_exit(root_devinfo, count); 301 } 302 303 static int 304 check_pre_setup_quirks(dev_info_t *dip, void *arg) 305 { 306 /* just 1 check right now */ 307 return (check_mobile4(dip, arg)); 308 } 309 310 static int 311 check_pre_startup_quirks(dev_info_t *dip, void *arg) 312 { 313 if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) { 314 ddi_err(DER_PANIC, dip, "Failed to get immu_devi"); 315 } 316 317 check_gfx(dip, arg); 318 319 check_lpc(dip, arg); 320 321 check_conf(dip, arg); 322 323 check_usb(dip, arg); 324 325 return (DDI_WALK_CONTINUE); 326 } 327 328 static void 329 pre_setup_quirks(void) 330 { 331 walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4); 332 } 333 334 static void 335 pre_startup_quirks(void) 336 { 337 walk_tree(check_pre_startup_quirks, NULL); 338 339 immu_dmar_rmrr_map(); 340 } 341 342 static int 343 get_conf_str(char *bopt, char **val) 344 { 345 int ret; 346 347 /* 348 * Check the rootnex.conf property 349 * Fake up a dev_t since searching the global 350 * property list needs it 351 */ 352 ret = ddi_prop_lookup_string( 353 makedevice(ddi_name_to_major("rootnex"), 0), 354 root_devinfo, DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, 355 bopt, val); 356 357 return (ret); 358 } 359 360 /* 361 * get_conf_opt() 362 * get a rootnex.conf setting (always a boolean) 363 */ 364 static void 365 get_conf_opt(char *bopt, boolean_t *kvar) 366 { 367 char *val = NULL; 368 369 ASSERT(bopt); 370 ASSERT(kvar); 371 372 /* 373 * Check the rootnex.conf property 374 * Fake up a dev_t since searching the global 375 * property list needs it 376 */ 377 378 if (get_conf_str(bopt, &val) != DDI_PROP_SUCCESS) 379 return; 380 381 if (strcmp(val, "true") == 0) { 382 *kvar = B_TRUE; 383 } else if (strcmp(val, "false") == 0) { 384 *kvar = B_FALSE; 385 } else { 386 ddi_err(DER_WARN, NULL, "rootnex.conf switch %s=\"%s\" ", 387 "is not set to true or false. Ignoring option.", 388 bopt, val); 389 } 390 ddi_prop_free(val); 391 } 392 393 /* 394 * get_bootopt() 395 * check a boot option (always a boolean) 396 */ 397 static int 398 get_boot_str(char *bopt, char **val) 399 { 400 int ret; 401 402 ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo, 403 DDI_PROP_DONTPASS, bopt, val); 404 405 return (ret); 406 } 407 408 static void 409 get_bootopt(char *bopt, boolean_t *kvar) 410 { 411 char *val = NULL; 412 413 /* 414 * All boot options set at the GRUB menu become 415 * properties on the rootnex. 416 */ 417 if (get_boot_str(bopt, &val) != DDI_PROP_SUCCESS) 418 return; 419 420 if (strcmp(val, "true") == 0) { 421 *kvar = B_TRUE; 422 } else if (strcmp(val, "false") == 0) { 423 *kvar = B_FALSE; 424 } else { 425 ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ", 426 "is not set to true or false. Ignoring option.", 427 bopt, val); 428 } 429 ddi_prop_free(val); 430 } 431 432 static void 433 get_boot_dvma_mode(void) 434 { 435 char *val = NULL; 436 437 if (get_boot_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val) 438 != DDI_PROP_SUCCESS) 439 return; 440 441 if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) { 442 immu_global_dvma_flags |= IMMU_FLAGS_UNITY; 443 } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) { 444 immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY; 445 } else { 446 ddi_err(DER_WARN, NULL, "bad value \"%s\" for boot option %s", 447 val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP); 448 } 449 ddi_prop_free(val); 450 } 451 452 static void 453 get_conf_dvma_mode(void) 454 { 455 char *val = NULL; 456 457 if (get_conf_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val) 458 != DDI_PROP_SUCCESS) 459 return; 460 461 if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) { 462 immu_global_dvma_flags |= IMMU_FLAGS_UNITY; 463 } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) { 464 immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY; 465 } else { 466 ddi_err(DER_WARN, NULL, "bad value \"%s\" for rootnex " 467 "option %s", val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP); 468 } 469 ddi_prop_free(val); 470 } 471 472 473 static void 474 get_conf_tunables(char *bopt, int64_t *ivar) 475 { 476 int64_t *iarray; 477 uint_t n; 478 479 /* 480 * Check the rootnex.conf property 481 * Fake up a dev_t since searching the global 482 * property list needs it 483 */ 484 if (ddi_prop_lookup_int64_array( 485 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo, 486 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, bopt, 487 &iarray, &n) != DDI_PROP_SUCCESS) { 488 return; 489 } 490 491 if (n != 1) { 492 ddi_err(DER_WARN, NULL, "More than one value specified for " 493 "%s property. Ignoring and using default", 494 "immu-flush-gran"); 495 ddi_prop_free(iarray); 496 return; 497 } 498 499 if (iarray[0] < 0) { 500 ddi_err(DER_WARN, NULL, "Negative value specified for " 501 "%s property. Inoring and Using default value", 502 "immu-flush-gran"); 503 ddi_prop_free(iarray); 504 return; 505 } 506 507 *ivar = iarray[0]; 508 509 ddi_prop_free(iarray); 510 } 511 512 static void 513 read_conf_options(void) 514 { 515 /* enable/disable options */ 516 get_conf_opt("immu-enable", &immu_enable); 517 get_conf_opt("immu-dvma-enable", &immu_dvma_enable); 518 get_conf_opt("immu-gfxdvma-enable", &immu_gfxdvma_enable); 519 get_conf_opt("immu-intrmap-enable", &immu_intrmap_enable); 520 get_conf_opt("immu-qinv-enable", &immu_qinv_enable); 521 522 /* workaround switches */ 523 get_conf_opt("immu-quirk-usbpage0", &immu_quirk_usbpage0); 524 get_conf_opt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa); 525 get_conf_opt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr); 526 527 /* debug printing */ 528 get_conf_opt("immu-dmar-print", &immu_dmar_print); 529 530 /* get tunables */ 531 get_conf_tunables("immu-flush-gran", &immu_flush_gran); 532 533 get_conf_dvma_mode(); 534 } 535 536 static void 537 read_boot_options(void) 538 { 539 /* enable/disable options */ 540 get_bootopt("immu-enable", &immu_enable); 541 get_bootopt("immu-dvma-enable", &immu_dvma_enable); 542 get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable); 543 get_bootopt("immu-intrmap-enable", &immu_intrmap_enable); 544 get_bootopt("immu-qinv-enable", &immu_qinv_enable); 545 546 /* workaround switches */ 547 get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0); 548 get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa); 549 get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr); 550 551 /* debug printing */ 552 get_bootopt("immu-dmar-print", &immu_dmar_print); 553 554 get_boot_dvma_mode(); 555 } 556 557 static void 558 mapping_list_setup(void) 559 { 560 char **string_array; 561 uint_t nstrings; 562 563 if (ddi_prop_lookup_string_array( 564 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo, 565 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, 566 "immu-dvma-unity-drivers", 567 &string_array, &nstrings) == DDI_PROP_SUCCESS) { 568 unity_driver_array = string_array; 569 nunity = nstrings; 570 } 571 572 if (ddi_prop_lookup_string_array( 573 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo, 574 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, 575 "immu-dvma-xlate-drivers", 576 &string_array, &nstrings) == DDI_PROP_SUCCESS) { 577 xlate_driver_array = string_array; 578 nxlate = nstrings; 579 } 580 } 581 582 /* 583 * Note, this will not catch hardware not enumerated 584 * in early boot 585 */ 586 static boolean_t 587 blacklisted_driver(void) 588 { 589 char **strptr; 590 int i; 591 major_t maj; 592 593 ASSERT((black_array == NULL) ^ (nblacks != 0)); 594 595 /* need at least 2 strings */ 596 if (nblacks < 2) { 597 return (B_FALSE); 598 } 599 600 for (i = 0; nblacks - i > 1; i++) { 601 strptr = &black_array[i]; 602 if (strcmp(*strptr++, "DRIVER") == 0) { 603 if ((maj = ddi_name_to_major(*strptr++)) 604 != DDI_MAJOR_T_NONE) { 605 /* is there hardware bound to this drvr */ 606 if (devnamesp[maj].dn_head != NULL) { 607 return (B_TRUE); 608 } 609 } 610 i += 1; /* for loop adds 1, so add only 1 here */ 611 } 612 } 613 614 return (B_FALSE); 615 } 616 617 static boolean_t 618 blacklisted_smbios(void) 619 { 620 id_t smid; 621 smbios_hdl_t *smhdl; 622 smbios_info_t sminf; 623 smbios_system_t smsys; 624 char *mfg, *product, *version; 625 char **strptr; 626 int i; 627 628 ASSERT((black_array == NULL) ^ (nblacks != 0)); 629 630 /* need at least 4 strings for this setting */ 631 if (nblacks < 4) { 632 return (B_FALSE); 633 } 634 635 smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL); 636 if (smhdl == NULL || 637 (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR || 638 smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) { 639 return (B_FALSE); 640 } 641 642 mfg = (char *)sminf.smbi_manufacturer; 643 product = (char *)sminf.smbi_product; 644 version = (char *)sminf.smbi_version; 645 646 ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n"); 647 ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg); 648 ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product); 649 ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version); 650 651 for (i = 0; nblacks - i > 3; i++) { 652 strptr = &black_array[i]; 653 if (strcmp(*strptr++, "SMBIOS") == 0) { 654 if (strcmp(*strptr++, mfg) == 0 && 655 ((char *)strptr == '\0' || 656 strcmp(*strptr++, product) == 0) && 657 ((char *)strptr == '\0' || 658 strcmp(*strptr++, version) == 0)) { 659 return (B_TRUE); 660 } 661 i += 3; 662 } 663 } 664 665 return (B_FALSE); 666 } 667 668 static boolean_t 669 blacklisted_acpi(void) 670 { 671 ASSERT((black_array == NULL) ^ (nblacks != 0)); 672 if (nblacks == 0) { 673 return (B_FALSE); 674 } 675 676 return (immu_dmar_blacklisted(black_array, nblacks)); 677 } 678 679 /* 680 * Check if system is blacklisted by Intel IOMMU driver 681 * i.e. should Intel IOMMU be disabled on this system 682 * Currently a system can be blacklistd based on the 683 * following bases: 684 * 685 * 1. DMAR ACPI table information. 686 * This information includes things like 687 * manufacturer and revision number. If rootnex.conf 688 * has matching info set in its blacklist property 689 * then Intel IOMMu will be disabled 690 * 691 * 2. SMBIOS information 692 * 693 * 3. Driver installed - useful if a particular 694 * driver or hardware is toxic if Intel IOMMU 695 * is turned on. 696 */ 697 698 static void 699 blacklist_setup(void) 700 { 701 char **string_array; 702 uint_t nstrings; 703 704 /* 705 * Check the rootnex.conf blacklist property. 706 * Fake up a dev_t since searching the global 707 * property list needs it 708 */ 709 if (ddi_prop_lookup_string_array( 710 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo, 711 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist", 712 &string_array, &nstrings) != DDI_PROP_SUCCESS) { 713 return; 714 } 715 716 /* smallest blacklist criteria works with multiples of 2 */ 717 if (nstrings % 2 != 0) { 718 ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist " 719 "rootnex.conf: number of strings must be a " 720 "multiple of 2"); 721 ddi_prop_free(string_array); 722 return; 723 } 724 725 black_array = string_array; 726 nblacks = nstrings; 727 } 728 729 static void 730 blacklist_destroy(void) 731 { 732 if (black_array) { 733 ddi_prop_free(black_array); 734 black_array = NULL; 735 nblacks = 0; 736 } 737 738 ASSERT(black_array == NULL); 739 ASSERT(nblacks == 0); 740 } 741 742 743 /* 744 * Now set all the fields in the order they are defined 745 * We do this only as a defensive-coding practice, it is 746 * not a correctness issue. 747 */ 748 static void * 749 immu_state_alloc(int seg, void *dmar_unit) 750 { 751 immu_t *immu; 752 753 dmar_unit = immu_dmar_walk_units(seg, dmar_unit); 754 if (dmar_unit == NULL) { 755 /* No more IOMMUs in this segment */ 756 return (NULL); 757 } 758 759 immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP); 760 761 mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL); 762 763 mutex_enter(&(immu->immu_lock)); 764 765 immu->immu_dmar_unit = dmar_unit; 766 immu->immu_name = ddi_strdup(immu_dmar_unit_name(dmar_unit), 767 KM_SLEEP); 768 immu->immu_dip = immu_dmar_unit_dip(dmar_unit); 769 770 /* 771 * the immu_intr_lock mutex is grabbed by the IOMMU 772 * unit's interrupt handler so we need to use an 773 * interrupt cookie for the mutex 774 */ 775 mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER, 776 (void *)ipltospl(IMMU_INTR_IPL)); 777 778 /* IOMMU regs related */ 779 mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL); 780 cv_init(&(immu->immu_regs_cv), NULL, CV_DEFAULT, NULL); 781 immu->immu_regs_busy = B_FALSE; 782 783 /* DVMA related */ 784 immu->immu_dvma_coherent = B_FALSE; 785 786 /* DVMA context related */ 787 rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL); 788 789 /* DVMA domain related */ 790 list_create(&(immu->immu_domain_list), sizeof (domain_t), 791 offsetof(domain_t, dom_immu_node)); 792 793 /* DVMA special device lists */ 794 immu->immu_dvma_gfx_only = B_FALSE; 795 list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t), 796 offsetof(immu_devi_t, imd_spc_node)); 797 list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t), 798 offsetof(immu_devi_t, imd_spc_node)); 799 800 /* interrupt remapping related */ 801 mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL); 802 803 /* qinv related */ 804 mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL); 805 806 /* 807 * insert this immu unit into the system-wide list 808 */ 809 list_insert_tail(&immu_list, immu); 810 811 mutex_exit(&(immu->immu_lock)); 812 813 ddi_err(DER_LOG, immu->immu_dip, "IMMU: unit setup"); 814 815 immu_dmar_set_immu(dmar_unit, immu); 816 817 return (dmar_unit); 818 } 819 820 static void 821 immu_subsystems_setup(void) 822 { 823 int seg; 824 void *unit_hdl; 825 826 ddi_err(DER_VERB, NULL, 827 "Creating state structures for Intel IOMMU units\n"); 828 829 ASSERT(immu_setup == B_FALSE); 830 ASSERT(immu_running == B_FALSE); 831 832 mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL); 833 list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node)); 834 835 mutex_enter(&immu_lock); 836 837 ASSERT(immu_pgtable_cache == NULL); 838 839 immu_pgtable_cache = kmem_cache_create("immu_pgtable_cache", 840 sizeof (pgtable_t), 0, 841 pgtable_ctor, pgtable_dtor, NULL, NULL, NULL, 0); 842 843 unit_hdl = NULL; 844 for (seg = 0; seg < IMMU_MAXSEG; seg++) { 845 while (unit_hdl = immu_state_alloc(seg, unit_hdl)) { 846 ; 847 } 848 } 849 850 immu_regs_setup(&immu_list); /* subsequent code needs this first */ 851 immu_dvma_setup(&immu_list); 852 if (immu_qinv_setup(&immu_list) == DDI_SUCCESS) 853 immu_intrmap_setup(&immu_list); 854 else 855 immu_intrmap_enable = B_FALSE; 856 857 mutex_exit(&immu_lock); 858 } 859 860 /* 861 * immu_subsystems_startup() 862 * startup all units that were setup 863 */ 864 static void 865 immu_subsystems_startup(void) 866 { 867 immu_t *immu; 868 869 mutex_enter(&immu_lock); 870 871 ASSERT(immu_setup == B_TRUE); 872 ASSERT(immu_running == B_FALSE); 873 874 immu_dmar_startup(); 875 876 immu = list_head(&immu_list); 877 for (; immu; immu = list_next(&immu_list, immu)) { 878 879 mutex_enter(&(immu->immu_lock)); 880 881 immu_intr_register(immu); 882 immu_dvma_startup(immu); 883 immu_intrmap_startup(immu); 884 immu_qinv_startup(immu); 885 886 /* 887 * Set IOMMU unit's regs to do 888 * the actual startup. This will 889 * set immu->immu_running field 890 * if the unit is successfully 891 * started 892 */ 893 immu_regs_startup(immu); 894 895 mutex_exit(&(immu->immu_lock)); 896 } 897 898 mutex_exit(&immu_lock); 899 } 900 901 /* ################## Intel IOMMU internal interfaces ###################### */ 902 903 /* 904 * Internal interfaces for IOMMU code (i.e. not exported to rootnex 905 * or rest of system) 906 */ 907 908 /* 909 * ddip can be NULL, in which case we walk up until we find the root dip 910 * NOTE: We never visit the root dip since its not a hardware node 911 */ 912 int 913 immu_walk_ancestor( 914 dev_info_t *rdip, 915 dev_info_t *ddip, 916 int (*func)(dev_info_t *, void *arg), 917 void *arg, 918 int *lvlp, 919 immu_flags_t immu_flags) 920 { 921 dev_info_t *pdip; 922 int level; 923 int error = DDI_SUCCESS; 924 925 ASSERT(root_devinfo); 926 ASSERT(rdip); 927 ASSERT(rdip != root_devinfo); 928 ASSERT(func); 929 930 /* ddip and immu can be NULL */ 931 932 /* Hold rdip so that branch is not detached */ 933 ndi_hold_devi(rdip); 934 for (pdip = rdip, level = 1; pdip && pdip != root_devinfo; 935 pdip = ddi_get_parent(pdip), level++) { 936 937 if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) { 938 error = DDI_FAILURE; 939 break; 940 } 941 if (func(pdip, arg) == DDI_WALK_TERMINATE) { 942 break; 943 } 944 if (immu_flags & IMMU_FLAGS_DONTPASS) { 945 break; 946 } 947 if (pdip == ddip) { 948 break; 949 } 950 } 951 952 ndi_rele_devi(rdip); 953 954 if (lvlp) 955 *lvlp = level; 956 957 return (error); 958 } 959 960 /* ######################## Intel IOMMU entry points ####################### */ 961 /* 962 * immu_init() 963 * called from rootnex_attach(). setup but don't startup the Intel IOMMU 964 * This is the first function called in Intel IOMMU code 965 */ 966 void 967 immu_init(void) 968 { 969 char *phony_reg = "A thing of beauty is a joy forever"; 970 971 /* Set some global shorthands that are needed by all of IOMMU code */ 972 ASSERT(root_devinfo == NULL); 973 root_devinfo = ddi_root_node(); 974 975 /* 976 * Intel IOMMU only supported only if MMU(CPU) page size is == 977 * IOMMU pages size. 978 */ 979 /*LINTED*/ 980 if (MMU_PAGESIZE != IMMU_PAGESIZE) { 981 ddi_err(DER_WARN, NULL, 982 "MMU page size (%d) is not equal to\n" 983 "IOMMU page size (%d). " 984 "Disabling Intel IOMMU. ", 985 MMU_PAGESIZE, IMMU_PAGESIZE); 986 immu_enable = B_FALSE; 987 return; 988 } 989 990 /* 991 * Read rootnex.conf options. Do this before 992 * boot options so boot options can override .conf options. 993 */ 994 read_conf_options(); 995 996 /* 997 * retrieve the Intel IOMMU boot options. 998 * Do this before parsing immu ACPI table 999 * as a boot option could potentially affect 1000 * ACPI parsing. 1001 */ 1002 ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n"); 1003 read_boot_options(); 1004 1005 /* 1006 * Check the IOMMU enable boot-option first. 1007 * This is so that we can skip parsing the ACPI table 1008 * if necessary because that may cause problems in 1009 * systems with buggy BIOS or ACPI tables 1010 */ 1011 if (immu_enable == B_FALSE) { 1012 return; 1013 } 1014 1015 if (immu_intrmap_enable == B_TRUE) 1016 immu_qinv_enable = B_TRUE; 1017 1018 /* 1019 * Next, check if the system even has an Intel IOMMU 1020 * We use the presence or absence of the IOMMU ACPI 1021 * table to detect Intel IOMMU. 1022 */ 1023 if (immu_dmar_setup() != DDI_SUCCESS) { 1024 immu_enable = B_FALSE; 1025 return; 1026 } 1027 1028 mapping_list_setup(); 1029 1030 /* 1031 * Check blacklists 1032 */ 1033 blacklist_setup(); 1034 1035 if (blacklisted_smbios() == B_TRUE) { 1036 blacklist_destroy(); 1037 immu_enable = B_FALSE; 1038 return; 1039 } 1040 1041 if (blacklisted_driver() == B_TRUE) { 1042 blacklist_destroy(); 1043 immu_enable = B_FALSE; 1044 return; 1045 } 1046 1047 /* 1048 * Read the "raw" DMAR ACPI table to get information 1049 * and convert into a form we can use. 1050 */ 1051 if (immu_dmar_parse() != DDI_SUCCESS) { 1052 blacklist_destroy(); 1053 immu_enable = B_FALSE; 1054 return; 1055 } 1056 1057 /* 1058 * now that we have processed the ACPI table 1059 * check if we need to blacklist this system 1060 * based on ACPI info 1061 */ 1062 if (blacklisted_acpi() == B_TRUE) { 1063 immu_dmar_destroy(); 1064 blacklist_destroy(); 1065 immu_enable = B_FALSE; 1066 return; 1067 } 1068 1069 blacklist_destroy(); 1070 1071 /* 1072 * Check if system has HW quirks. 1073 */ 1074 pre_setup_quirks(); 1075 1076 /* Now do the rest of the setup */ 1077 immu_subsystems_setup(); 1078 1079 /* 1080 * Now that the IMMU is setup, create a phony 1081 * reg prop so that suspend/resume works 1082 */ 1083 if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg", 1084 (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) { 1085 ddi_err(DER_PANIC, NULL, "Failed to create reg prop for " 1086 "rootnex node"); 1087 /*NOTREACHED*/ 1088 } 1089 1090 immu_setup = B_TRUE; 1091 } 1092 1093 /* 1094 * immu_startup() 1095 * called directly by boot code to startup 1096 * all units of the IOMMU 1097 */ 1098 void 1099 immu_startup(void) 1100 { 1101 /* 1102 * If IOMMU is disabled, do nothing 1103 */ 1104 if (immu_enable == B_FALSE) { 1105 return; 1106 } 1107 1108 if (immu_setup == B_FALSE) { 1109 ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, " 1110 "skipping IOMU startup"); 1111 return; 1112 } 1113 1114 pre_startup_quirks(); 1115 1116 ddi_err(DER_CONT, NULL, 1117 "?Starting Intel IOMMU (dmar) units...\n"); 1118 1119 immu_subsystems_startup(); 1120 1121 immu_running = B_TRUE; 1122 } 1123 1124 /* 1125 * immu_map_sgl() 1126 * called from rootnex_coredma_bindhdl() when Intel 1127 * IOMMU is enabled to build DVMA cookies and map them. 1128 */ 1129 int 1130 immu_map_sgl(ddi_dma_impl_t *hp, struct ddi_dma_req *dmareq, 1131 int prealloc_count, dev_info_t *rdip) 1132 { 1133 if (immu_running == B_FALSE) { 1134 return (DDI_DMA_USE_PHYSICAL); 1135 } 1136 1137 return (immu_dvma_map(hp, dmareq, NULL, prealloc_count, rdip, 1138 IMMU_FLAGS_DMAHDL)); 1139 } 1140 1141 /* 1142 * immu_unmap_sgl() 1143 * called from rootnex_coredma_unbindhdl(), to unmap DVMA 1144 * cookies and free them 1145 */ 1146 int 1147 immu_unmap_sgl(ddi_dma_impl_t *hp, dev_info_t *rdip) 1148 { 1149 if (immu_running == B_FALSE) { 1150 return (DDI_DMA_USE_PHYSICAL); 1151 } 1152 1153 return (immu_dvma_unmap(hp, rdip)); 1154 } 1155 1156 /* 1157 * Hook to notify IOMMU code of device tree changes 1158 */ 1159 void 1160 immu_device_tree_changed(void) 1161 { 1162 if (immu_setup == B_FALSE) { 1163 return; 1164 } 1165 1166 ddi_err(DER_WARN, NULL, "Intel IOMMU currently " 1167 "does not use device tree updates"); 1168 } 1169 1170 /* 1171 * Hook to notify IOMMU code of memory changes 1172 */ 1173 void 1174 immu_physmem_update(uint64_t addr, uint64_t size) 1175 { 1176 if (immu_setup == B_FALSE) { 1177 return; 1178 } 1179 immu_dvma_physmem_update(addr, size); 1180 } 1181 1182 /* 1183 * immu_quiesce() 1184 * quiesce all units that are running 1185 */ 1186 int 1187 immu_quiesce(void) 1188 { 1189 immu_t *immu; 1190 int ret = DDI_SUCCESS; 1191 1192 mutex_enter(&immu_lock); 1193 1194 if (immu_running == B_FALSE) 1195 return (DDI_SUCCESS); 1196 1197 ASSERT(immu_setup == B_TRUE); 1198 1199 immu = list_head(&immu_list); 1200 for (; immu; immu = list_next(&immu_list, immu)) { 1201 1202 /* if immu is not running, we dont quiesce */ 1203 if (immu->immu_regs_running == B_FALSE) 1204 continue; 1205 1206 /* flush caches */ 1207 rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER); 1208 immu_flush_context_gbl(immu); 1209 rw_exit(&(immu->immu_ctx_rwlock)); 1210 immu_flush_iotlb_gbl(immu); 1211 immu_regs_wbf_flush(immu); 1212 1213 mutex_enter(&(immu->immu_lock)); 1214 1215 /* 1216 * Set IOMMU unit's regs to do 1217 * the actual shutdown. 1218 */ 1219 immu_regs_shutdown(immu); 1220 immu_regs_suspend(immu); 1221 1222 /* if immu is still running, we failed */ 1223 if (immu->immu_regs_running == B_TRUE) 1224 ret = DDI_FAILURE; 1225 else 1226 immu->immu_regs_quiesced = B_TRUE; 1227 1228 mutex_exit(&(immu->immu_lock)); 1229 } 1230 mutex_exit(&immu_lock); 1231 1232 if (ret == DDI_SUCCESS) { 1233 immu_running = B_FALSE; 1234 immu_quiesced = B_TRUE; 1235 } 1236 1237 return (ret); 1238 } 1239 1240 /* 1241 * immu_unquiesce() 1242 * unquiesce all units 1243 */ 1244 int 1245 immu_unquiesce(void) 1246 { 1247 immu_t *immu; 1248 int ret = DDI_SUCCESS; 1249 1250 mutex_enter(&immu_lock); 1251 1252 if (immu_quiesced == B_FALSE) 1253 return (DDI_SUCCESS); 1254 1255 ASSERT(immu_setup == B_TRUE); 1256 ASSERT(immu_running == B_FALSE); 1257 1258 immu = list_head(&immu_list); 1259 for (; immu; immu = list_next(&immu_list, immu)) { 1260 1261 mutex_enter(&(immu->immu_lock)); 1262 1263 /* if immu was not quiesced, i.e was not running before */ 1264 if (immu->immu_regs_quiesced == B_FALSE) { 1265 mutex_exit(&(immu->immu_lock)); 1266 continue; 1267 } 1268 1269 if (immu_regs_resume(immu) != DDI_SUCCESS) { 1270 ret = DDI_FAILURE; 1271 mutex_exit(&(immu->immu_lock)); 1272 continue; 1273 } 1274 1275 /* flush caches before unquiesce */ 1276 rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER); 1277 immu_flush_context_gbl(immu); 1278 rw_exit(&(immu->immu_ctx_rwlock)); 1279 immu_flush_iotlb_gbl(immu); 1280 1281 /* 1282 * Set IOMMU unit's regs to do 1283 * the actual startup. This will 1284 * set immu->immu_regs_running field 1285 * if the unit is successfully 1286 * started 1287 */ 1288 immu_regs_startup(immu); 1289 1290 if (immu->immu_regs_running == B_FALSE) { 1291 ret = DDI_FAILURE; 1292 } else { 1293 immu_quiesced = B_TRUE; 1294 immu_running = B_TRUE; 1295 immu->immu_regs_quiesced = B_FALSE; 1296 } 1297 1298 mutex_exit(&(immu->immu_lock)); 1299 } 1300 1301 mutex_exit(&immu_lock); 1302 1303 return (ret); 1304 } 1305 1306 /* ############## END Intel IOMMU entry points ################## */ 1307