Merge illumos-gate
[unleashed/lotheac.git] / usr / src / uts / i86pc / io / immu.c
blob5c9f723e653b7b531875435239dade1fe1f50f47
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Portions Copyright (c) 2010, Oracle and/or its affiliates.
23 * All rights reserved.
26 * Copyright (c) 2009, Intel Corporation.
27 * All rights reserved.
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.
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/avl.h>
57 #include <sys/bootconf.h>
58 #include <sys/bootinfo.h>
59 #include <sys/atomic.h>
60 #include <sys/immu.h>
61 /* ########################### Globals and tunables ######################## */
63 * Global switches (boolean) that can be toggled either via boot options
64 * or via /etc/system or kmdb
67 /* Various features */
68 boolean_t immu_enable = B_TRUE;
69 boolean_t immu_dvma_enable = B_TRUE;
71 /* accessed in other files so not static */
72 boolean_t immu_gfxdvma_enable = B_TRUE;
73 boolean_t immu_intrmap_enable = B_FALSE;
74 boolean_t immu_qinv_enable = B_TRUE;
76 /* various quirks that need working around */
78 /* XXX We always map page 0 read/write for now */
79 boolean_t immu_quirk_usbpage0 = B_TRUE;
80 boolean_t immu_quirk_usbrmrr = B_TRUE;
81 boolean_t immu_quirk_usbfullpa;
82 boolean_t immu_quirk_mobile4;
84 /* debug messages */
85 boolean_t immu_dmar_print;
87 /* Tunables */
88 int64_t immu_flush_gran = 5;
90 immu_flags_t immu_global_dvma_flags;
92 /* ############ END OPTIONS section ################ */
95 * Global used internally by Intel IOMMU code
97 dev_info_t *root_devinfo;
98 kmutex_t immu_lock;
99 list_t immu_list;
100 boolean_t immu_setup;
101 boolean_t immu_running;
102 boolean_t immu_quiesced;
104 /* ######################## END Globals and tunables ###################### */
105 /* Globals used only in this file */
106 static char **black_array;
107 static uint_t nblacks;
109 static char **unity_driver_array;
110 static uint_t nunity;
111 static char **xlate_driver_array;
112 static uint_t nxlate;
114 static char **premap_driver_array;
115 static uint_t npremap;
116 static char **nopremap_driver_array;
117 static uint_t nnopremap;
118 /* ###################### Utility routines ############################# */
121 * Check if the device has mobile 4 chipset
123 static int
124 check_mobile4(dev_info_t *dip, void *arg)
126 _NOTE(ARGUNUSED(arg));
127 int vendor, device;
128 int *ip = (int *)arg;
130 vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
131 "vendor-id", -1);
132 device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
133 "device-id", -1);
135 if (vendor == 0x8086 && device == 0x2a40) {
136 *ip = B_TRUE;
137 ddi_err(DER_NOTE, dip, "iommu: Mobile 4 chipset detected. "
138 "Force setting IOMMU write buffer");
139 return (DDI_WALK_TERMINATE);
140 } else {
141 return (DDI_WALK_CONTINUE);
145 static void
146 map_bios_rsvd_mem(dev_info_t *dip)
148 struct memlist *mp;
151 * Make sure the domain for the device is set up before
152 * mapping anything.
154 (void) immu_dvma_device_setup(dip, 0);
156 memlist_read_lock();
158 mp = bios_rsvd;
159 while (mp != NULL) {
160 memrng_t mrng = {0};
162 ddi_err(DER_LOG, dip, "iommu: Mapping BIOS rsvd range "
163 "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address,
164 mp->ml_address + mp->ml_size);
166 mrng.mrng_start = IMMU_ROUNDOWN(mp->ml_address);
167 mrng.mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE;
169 (void) immu_map_memrange(dip, &mrng);
171 mp = mp->ml_next;
174 memlist_read_unlock();
179 * Check if the driver requests a specific type of mapping.
181 /*ARGSUSED*/
182 static void
183 check_conf(dev_info_t *dip, void *arg)
185 immu_devi_t *immu_devi;
186 const char *dname;
187 uint_t i;
188 int hasmapprop = 0, haspreprop = 0;
189 boolean_t old_premap;
192 * Only PCI devices can use an IOMMU. Legacy ISA devices
193 * are handled in check_lpc.
195 if (!DEVI_IS_PCI(dip))
196 return;
198 dname = ddi_driver_name(dip);
199 if (dname == NULL)
200 return;
201 immu_devi = immu_devi_get(dip);
203 for (i = 0; i < nunity; i++) {
204 if (strcmp(unity_driver_array[i], dname) == 0) {
205 hasmapprop = 1;
206 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
210 for (i = 0; i < nxlate; i++) {
211 if (strcmp(xlate_driver_array[i], dname) == 0) {
212 hasmapprop = 1;
213 immu_devi->imd_dvma_flags &= ~IMMU_FLAGS_UNITY;
217 old_premap = immu_devi->imd_use_premap;
219 for (i = 0; i < nnopremap; i++) {
220 if (strcmp(nopremap_driver_array[i], dname) == 0) {
221 haspreprop = 1;
222 immu_devi->imd_use_premap = B_FALSE;
226 for (i = 0; i < npremap; i++) {
227 if (strcmp(premap_driver_array[i], dname) == 0) {
228 haspreprop = 1;
229 immu_devi->imd_use_premap = B_TRUE;
234 * Report if we changed the value from the default.
236 if (hasmapprop && (immu_devi->imd_dvma_flags ^ immu_global_dvma_flags))
237 ddi_err(DER_LOG, dip, "using %s DVMA mapping",
238 immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY ?
239 DDI_DVMA_MAPTYPE_UNITY : DDI_DVMA_MAPTYPE_XLATE);
241 if (haspreprop && (immu_devi->imd_use_premap != old_premap))
242 ddi_err(DER_LOG, dip, "%susing premapped DVMA space",
243 immu_devi->imd_use_premap ? "" : "not ");
247 * Check if the device is USB controller
249 /*ARGSUSED*/
250 static void
251 check_usb(dev_info_t *dip, void *arg)
253 const char *drv = ddi_driver_name(dip);
254 immu_devi_t *immu_devi;
258 * It's not clear if xHCI really needs these quirks; however, to be on
259 * the safe side until we know for certain we add it to the list below.
261 if (drv == NULL ||
262 (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 &&
263 strcmp(drv, "ehci") != 0 && strcmp(drv, "xhci") != 0)) {
264 return;
267 immu_devi = immu_devi_get(dip);
270 * If unit mappings are already specified, globally or
271 * locally, we're done here, since that covers both
272 * quirks below.
274 if (immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY)
275 return;
277 /* This must come first since it does unity mapping */
278 if (immu_quirk_usbfullpa == B_TRUE) {
279 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
280 } else if (immu_quirk_usbrmrr == B_TRUE) {
281 ddi_err(DER_LOG, dip, "Applying USB RMRR quirk");
282 map_bios_rsvd_mem(dip);
287 * Check if the device is a LPC device
289 /*ARGSUSED*/
290 static void
291 check_lpc(dev_info_t *dip, void *arg)
293 immu_devi_t *immu_devi;
295 immu_devi = immu_devi_get(dip);
296 if (immu_devi->imd_lpc == B_TRUE) {
297 ddi_err(DER_LOG, dip, "iommu: Found LPC device");
298 /* This will put the immu_devi on the LPC "specials" list */
299 (void) immu_dvma_device_setup(dip, IMMU_FLAGS_SLEEP);
304 * Check if the device is a GFX device
306 /*ARGSUSED*/
307 static void
308 check_gfx(dev_info_t *dip, void *arg)
310 immu_devi_t *immu_devi;
312 immu_devi = immu_devi_get(dip);
313 if (immu_devi->imd_display == B_TRUE) {
314 immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
315 ddi_err(DER_LOG, dip, "iommu: Found GFX device");
316 /* This will put the immu_devi on the GFX "specials" list */
317 (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP);
321 static void
322 walk_tree(int (*f)(dev_info_t *, void *), void *arg)
324 int count;
326 ndi_devi_enter(root_devinfo, &count);
327 ddi_walk_devs(ddi_get_child(root_devinfo), f, arg);
328 ndi_devi_exit(root_devinfo, count);
331 static int
332 check_pre_setup_quirks(dev_info_t *dip, void *arg)
334 /* just 1 check right now */
335 return (check_mobile4(dip, arg));
338 static int
339 check_pre_startup_quirks(dev_info_t *dip, void *arg)
341 if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) {
342 ddi_err(DER_PANIC, dip, "Failed to get immu_devi");
345 check_gfx(dip, arg);
347 check_lpc(dip, arg);
349 check_conf(dip, arg);
351 check_usb(dip, arg);
353 return (DDI_WALK_CONTINUE);
356 static void
357 pre_setup_quirks(void)
359 walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4);
362 static void
363 pre_startup_quirks(void)
365 walk_tree(check_pre_startup_quirks, NULL);
367 immu_dmar_rmrr_map();
370 static int
371 get_conf_str(char *bopt, char **val)
373 int ret;
376 * Check the rootnex.conf property
377 * Fake up a dev_t since searching the global
378 * property list needs it
380 ret = ddi_prop_lookup_string(
381 makedevice(ddi_name_to_major("rootnex"), 0),
382 root_devinfo, DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
383 bopt, val);
385 return (ret);
389 * get_conf_opt()
390 * get a rootnex.conf setting (always a boolean)
392 static void
393 get_conf_opt(char *bopt, boolean_t *kvar)
395 char *val = NULL;
398 * Check the rootnex.conf property
399 * Fake up a dev_t since searching the global
400 * property list needs it
403 if (get_conf_str(bopt, &val) != DDI_PROP_SUCCESS)
404 return;
406 if (strcmp(val, "true") == 0) {
407 *kvar = B_TRUE;
408 } else if (strcmp(val, "false") == 0) {
409 *kvar = B_FALSE;
410 } else {
411 ddi_err(DER_WARN, NULL, "rootnex.conf switch %s=\"%s\" ",
412 "is not set to true or false. Ignoring option.",
413 bopt, val);
415 ddi_prop_free(val);
419 * get_bootopt()
420 * check a boot option (always a boolean)
422 static int
423 get_boot_str(char *bopt, char **val)
425 int ret;
427 ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo,
428 DDI_PROP_DONTPASS, bopt, val);
430 return (ret);
433 static void
434 get_bootopt(char *bopt, boolean_t *kvar)
436 char *val = NULL;
439 * All boot options set at the GRUB menu become
440 * properties on the rootnex.
442 if (get_boot_str(bopt, &val) != DDI_PROP_SUCCESS)
443 return;
445 if (strcmp(val, "true") == 0) {
446 *kvar = B_TRUE;
447 } else if (strcmp(val, "false") == 0) {
448 *kvar = B_FALSE;
449 } else {
450 ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ",
451 "is not set to true or false. Ignoring option.",
452 bopt, val);
454 ddi_prop_free(val);
457 static void
458 get_boot_dvma_mode(void)
460 char *val = NULL;
462 if (get_boot_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
463 != DDI_PROP_SUCCESS)
464 return;
466 if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
467 immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
468 } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
469 immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
470 } else {
471 ddi_err(DER_WARN, NULL, "bad value \"%s\" for boot option %s",
472 val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
474 ddi_prop_free(val);
477 static void
478 get_conf_dvma_mode(void)
480 char *val = NULL;
482 if (get_conf_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
483 != DDI_PROP_SUCCESS)
484 return;
486 if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
487 immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
488 } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
489 immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
490 } else {
491 ddi_err(DER_WARN, NULL, "bad value \"%s\" for rootnex "
492 "option %s", val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
494 ddi_prop_free(val);
498 static void
499 get_conf_tunables(char *bopt, int64_t *ivar)
501 int64_t *iarray;
502 uint_t n;
505 * Check the rootnex.conf property
506 * Fake up a dev_t since searching the global
507 * property list needs it
509 if (ddi_prop_lookup_int64_array(
510 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
511 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, bopt,
512 &iarray, &n) != DDI_PROP_SUCCESS) {
513 return;
516 if (n != 1) {
517 ddi_err(DER_WARN, NULL, "More than one value specified for "
518 "%s property. Ignoring and using default",
519 "immu-flush-gran");
520 ddi_prop_free(iarray);
521 return;
524 if (iarray[0] < 0) {
525 ddi_err(DER_WARN, NULL, "Negative value specified for "
526 "%s property. Inoring and Using default value",
527 "immu-flush-gran");
528 ddi_prop_free(iarray);
529 return;
532 *ivar = iarray[0];
534 ddi_prop_free(iarray);
537 static void
538 read_conf_options(void)
540 /* enable/disable options */
541 get_conf_opt("immu-enable", &immu_enable);
542 get_conf_opt("immu-dvma-enable", &immu_dvma_enable);
543 get_conf_opt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
544 get_conf_opt("immu-intrmap-enable", &immu_intrmap_enable);
545 get_conf_opt("immu-qinv-enable", &immu_qinv_enable);
547 /* workaround switches */
548 get_conf_opt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
549 get_conf_opt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
550 get_conf_opt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
552 /* debug printing */
553 get_conf_opt("immu-dmar-print", &immu_dmar_print);
555 /* get tunables */
556 get_conf_tunables("immu-flush-gran", &immu_flush_gran);
558 get_conf_dvma_mode();
561 static void
562 read_boot_options(void)
564 /* enable/disable options */
565 get_bootopt("immu-enable", &immu_enable);
566 get_bootopt("immu-dvma-enable", &immu_dvma_enable);
567 get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
568 get_bootopt("immu-intrmap-enable", &immu_intrmap_enable);
569 get_bootopt("immu-qinv-enable", &immu_qinv_enable);
571 /* workaround switches */
572 get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
573 get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
574 get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
576 /* debug printing */
577 get_bootopt("immu-dmar-print", &immu_dmar_print);
579 get_boot_dvma_mode();
582 static void
583 mapping_list_setup(void)
585 char **string_array;
586 uint_t nstrings;
588 if (ddi_prop_lookup_string_array(
589 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
590 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
591 "immu-dvma-unity-drivers",
592 &string_array, &nstrings) == DDI_PROP_SUCCESS) {
593 unity_driver_array = string_array;
594 nunity = nstrings;
597 if (ddi_prop_lookup_string_array(
598 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
599 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
600 "immu-dvma-xlate-drivers",
601 &string_array, &nstrings) == DDI_PROP_SUCCESS) {
602 xlate_driver_array = string_array;
603 nxlate = nstrings;
606 if (ddi_prop_lookup_string_array(
607 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
608 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
609 "immu-dvma-premap-drivers",
610 &string_array, &nstrings) == DDI_PROP_SUCCESS) {
611 premap_driver_array = string_array;
612 npremap = nstrings;
615 if (ddi_prop_lookup_string_array(
616 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
617 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
618 "immu-dvma-nopremap-drivers",
619 &string_array, &nstrings) == DDI_PROP_SUCCESS) {
620 nopremap_driver_array = string_array;
621 nnopremap = nstrings;
626 * Note, this will not catch hardware not enumerated
627 * in early boot
629 static boolean_t
630 blacklisted_driver(void)
632 char **strptr;
633 int i;
634 major_t maj;
636 /* need at least 2 strings */
637 if (nblacks < 2) {
638 return (B_FALSE);
641 for (i = 0; nblacks - i > 1; i++) {
642 strptr = &black_array[i];
643 if (strcmp(*strptr++, "DRIVER") == 0) {
644 if ((maj = ddi_name_to_major(*strptr++))
645 != DDI_MAJOR_T_NONE) {
646 /* is there hardware bound to this drvr */
647 if (devnamesp[maj].dn_head != NULL) {
648 return (B_TRUE);
651 i += 1; /* for loop adds 1, so add only 1 here */
655 return (B_FALSE);
658 static boolean_t
659 blacklisted_smbios(void)
661 id_t smid;
662 smbios_hdl_t *smhdl;
663 smbios_info_t sminf;
664 smbios_system_t smsys;
665 char *mfg, *product, *version;
666 char **strptr;
667 int i;
669 /* need at least 4 strings for this setting */
670 if (nblacks < 4) {
671 return (B_FALSE);
674 smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL);
675 if (smhdl == NULL ||
676 (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR ||
677 smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) {
678 return (B_FALSE);
681 mfg = (char *)sminf.smbi_manufacturer;
682 product = (char *)sminf.smbi_product;
683 version = (char *)sminf.smbi_version;
685 ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n");
686 ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg);
687 ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product);
688 ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version);
690 for (i = 0; nblacks - i > 3; i++) {
691 strptr = &black_array[i];
692 if (strcmp(*strptr++, "SMBIOS") == 0) {
693 if (strcmp(*strptr++, mfg) == 0 &&
694 (*strptr[0] == '\0' ||
695 strcmp(*strptr++, product) == 0) &&
696 (*strptr[0] == '\0' ||
697 strcmp(*strptr++, version) == 0)) {
698 return (B_TRUE);
700 i += 3;
704 return (B_FALSE);
707 static boolean_t
708 blacklisted_acpi(void)
710 if (nblacks == 0) {
711 return (B_FALSE);
714 return (immu_dmar_blacklisted(black_array, nblacks));
718 * Check if system is blacklisted by Intel IOMMU driver
719 * i.e. should Intel IOMMU be disabled on this system
720 * Currently a system can be blacklistd based on the
721 * following bases:
723 * 1. DMAR ACPI table information.
724 * This information includes things like
725 * manufacturer and revision number. If rootnex.conf
726 * has matching info set in its blacklist property
727 * then Intel IOMMu will be disabled
729 * 2. SMBIOS information
731 * 3. Driver installed - useful if a particular
732 * driver or hardware is toxic if Intel IOMMU
733 * is turned on.
736 static void
737 blacklist_setup(void)
739 char **string_array;
740 uint_t nstrings;
743 * Check the rootnex.conf blacklist property.
744 * Fake up a dev_t since searching the global
745 * property list needs it
747 if (ddi_prop_lookup_string_array(
748 makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
749 DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist",
750 &string_array, &nstrings) != DDI_PROP_SUCCESS) {
751 return;
754 /* smallest blacklist criteria works with multiples of 2 */
755 if (nstrings % 2 != 0) {
756 ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist "
757 "rootnex.conf: number of strings must be a "
758 "multiple of 2");
759 ddi_prop_free(string_array);
760 return;
763 black_array = string_array;
764 nblacks = nstrings;
767 static void
768 blacklist_destroy(void)
770 if (black_array) {
771 ddi_prop_free(black_array);
772 black_array = NULL;
773 nblacks = 0;
777 static char *
778 immu_alloc_name(const char *str, int instance)
780 size_t slen;
781 char *s;
783 slen = strlen(str) + IMMU_ISTRLEN + 1;
784 s = kmem_zalloc(slen, VM_SLEEP);
785 if (s != NULL)
786 (void) snprintf(s, slen, "%s%d", str, instance);
788 return (s);
793 * Now set all the fields in the order they are defined
794 * We do this only as a defensive-coding practice, it is
795 * not a correctness issue.
797 static void *
798 immu_state_alloc(int seg, void *dmar_unit)
800 immu_t *immu;
801 char *nodename, *hcachename, *pcachename;
802 int instance;
804 dmar_unit = immu_dmar_walk_units(seg, dmar_unit);
805 if (dmar_unit == NULL) {
806 /* No more IOMMUs in this segment */
807 return (NULL);
810 immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP);
812 mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL);
814 mutex_enter(&(immu->immu_lock));
816 immu->immu_dmar_unit = dmar_unit;
817 immu->immu_dip = immu_dmar_unit_dip(dmar_unit);
819 nodename = ddi_node_name(immu->immu_dip);
820 instance = ddi_get_instance(immu->immu_dip);
822 immu->immu_name = immu_alloc_name(nodename, instance);
823 if (immu->immu_name == NULL)
824 return (NULL);
827 * the immu_intr_lock mutex is grabbed by the IOMMU
828 * unit's interrupt handler so we need to use an
829 * interrupt cookie for the mutex
831 mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER,
832 (void *)ipltospl(IMMU_INTR_IPL));
834 /* IOMMU regs related */
835 mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL);
836 cv_init(&(immu->immu_regs_cv), NULL, CV_DEFAULT, NULL);
837 immu->immu_regs_busy = B_FALSE;
839 /* DVMA related */
840 immu->immu_dvma_coherent = B_FALSE;
842 /* DVMA context related */
843 rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL);
845 /* DVMA domain related */
846 list_create(&(immu->immu_domain_list), sizeof (domain_t),
847 offsetof(domain_t, dom_immu_node));
849 /* DVMA special device lists */
850 immu->immu_dvma_gfx_only = B_FALSE;
851 list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t),
852 offsetof(immu_devi_t, imd_spc_node));
853 list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t),
854 offsetof(immu_devi_t, imd_spc_node));
856 /* interrupt remapping related */
857 mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL);
859 /* qinv related */
860 mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL);
863 * insert this immu unit into the system-wide list
865 list_insert_tail(&immu_list, immu);
867 pcachename = immu_alloc_name("immu_pgtable_cache", instance);
868 if (pcachename == NULL)
869 return (NULL);
871 hcachename = immu_alloc_name("immu_hdl_cache", instance);
872 if (hcachename == NULL)
873 return (NULL);
875 immu->immu_pgtable_cache = kmem_cache_create(pcachename,
876 sizeof (pgtable_t), 0, pgtable_ctor, pgtable_dtor, NULL, immu,
877 NULL, 0);
878 immu->immu_hdl_cache = kmem_cache_create(hcachename,
879 sizeof (immu_hdl_priv_t), 64, immu_hdl_priv_ctor,
880 NULL, NULL, immu, NULL, 0);
882 mutex_exit(&(immu->immu_lock));
884 ddi_err(DER_LOG, immu->immu_dip, "unit setup");
886 immu_dmar_set_immu(dmar_unit, immu);
888 return (dmar_unit);
891 static void
892 immu_subsystems_setup(void)
894 int seg;
895 void *unit_hdl;
897 ddi_err(DER_VERB, NULL,
898 "Creating state structures for Intel IOMMU units");
900 mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL);
901 list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node));
903 mutex_enter(&immu_lock);
905 unit_hdl = NULL;
906 for (seg = 0; seg < IMMU_MAXSEG; seg++) {
907 while (unit_hdl = immu_state_alloc(seg, unit_hdl)) {
912 immu_regs_setup(&immu_list); /* subsequent code needs this first */
913 immu_dvma_setup(&immu_list);
914 if (immu_qinv_setup(&immu_list) == DDI_SUCCESS)
915 immu_intrmap_setup(&immu_list);
916 else
917 immu_intrmap_enable = B_FALSE;
919 mutex_exit(&immu_lock);
923 * immu_subsystems_startup()
924 * startup all units that were setup
926 static void
927 immu_subsystems_startup(void)
929 immu_t *immu;
930 iommulib_ops_t *iommulib_ops;
932 mutex_enter(&immu_lock);
934 immu_dmar_startup();
936 immu = list_head(&immu_list);
937 for (; immu; immu = list_next(&immu_list, immu)) {
939 mutex_enter(&(immu->immu_lock));
941 immu_intr_register(immu);
942 immu_dvma_startup(immu);
943 immu_intrmap_startup(immu);
944 immu_qinv_startup(immu);
947 * Set IOMMU unit's regs to do
948 * the actual startup. This will
949 * set immu->immu_running field
950 * if the unit is successfully
951 * started
953 immu_regs_startup(immu);
955 mutex_exit(&(immu->immu_lock));
957 iommulib_ops = kmem_alloc(sizeof (iommulib_ops_t), KM_SLEEP);
958 *iommulib_ops = immulib_ops;
959 iommulib_ops->ilops_data = (void *)immu;
960 (void) iommulib_iommu_register(immu->immu_dip, iommulib_ops,
961 &immu->immu_iommulib_handle);
964 mutex_exit(&immu_lock);
967 /* ################## Intel IOMMU internal interfaces ###################### */
970 * Internal interfaces for IOMMU code (i.e. not exported to rootnex
971 * or rest of system)
975 * ddip can be NULL, in which case we walk up until we find the root dip
976 * NOTE: We never visit the root dip since its not a hardware node
979 immu_walk_ancestor(
980 dev_info_t *rdip,
981 dev_info_t *ddip,
982 int (*func)(dev_info_t *, void *arg),
983 void *arg,
984 int *lvlp,
985 immu_flags_t immu_flags)
987 dev_info_t *pdip;
988 int level;
989 int error = DDI_SUCCESS;
991 /* ddip and immu can be NULL */
993 /* Hold rdip so that branch is not detached */
994 ndi_hold_devi(rdip);
995 for (pdip = rdip, level = 1; pdip && pdip != root_devinfo;
996 pdip = ddi_get_parent(pdip), level++) {
998 if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) {
999 error = DDI_FAILURE;
1000 break;
1002 if (func(pdip, arg) == DDI_WALK_TERMINATE) {
1003 break;
1005 if (immu_flags & IMMU_FLAGS_DONTPASS) {
1006 break;
1008 if (pdip == ddip) {
1009 break;
1013 ndi_rele_devi(rdip);
1015 if (lvlp)
1016 *lvlp = level;
1018 return (error);
1021 /* ######################## Intel IOMMU entry points ####################### */
1023 * immu_init()
1024 * called from rootnex_attach(). setup but don't startup the Intel IOMMU
1025 * This is the first function called in Intel IOMMU code
1027 void
1028 immu_init(void)
1030 char *phony_reg = "A thing of beauty is a joy forever";
1032 /* Set some global shorthands that are needed by all of IOMMU code */
1033 root_devinfo = ddi_root_node();
1036 * Intel IOMMU only supported only if MMU(CPU) page size is ==
1037 * IOMMU pages size.
1039 /*LINTED*/
1040 if (MMU_PAGESIZE != IMMU_PAGESIZE) {
1041 ddi_err(DER_WARN, NULL,
1042 "MMU page size (%d) is not equal to\n"
1043 "IOMMU page size (%d). "
1044 "Disabling Intel IOMMU. ",
1045 MMU_PAGESIZE, IMMU_PAGESIZE);
1046 immu_enable = B_FALSE;
1047 return;
1051 * Read rootnex.conf options. Do this before
1052 * boot options so boot options can override .conf options.
1054 read_conf_options();
1057 * retrieve the Intel IOMMU boot options.
1058 * Do this before parsing immu ACPI table
1059 * as a boot option could potentially affect
1060 * ACPI parsing.
1062 ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n");
1063 read_boot_options();
1066 * Check the IOMMU enable boot-option first.
1067 * This is so that we can skip parsing the ACPI table
1068 * if necessary because that may cause problems in
1069 * systems with buggy BIOS or ACPI tables
1071 if (immu_enable == B_FALSE) {
1072 return;
1075 if (immu_intrmap_enable == B_TRUE)
1076 immu_qinv_enable = B_TRUE;
1079 * Next, check if the system even has an Intel IOMMU
1080 * We use the presence or absence of the IOMMU ACPI
1081 * table to detect Intel IOMMU.
1083 if (immu_dmar_setup() != DDI_SUCCESS) {
1084 immu_enable = B_FALSE;
1085 return;
1088 mapping_list_setup();
1091 * Check blacklists
1093 blacklist_setup();
1095 if (blacklisted_smbios() == B_TRUE) {
1096 blacklist_destroy();
1097 immu_enable = B_FALSE;
1098 return;
1101 if (blacklisted_driver() == B_TRUE) {
1102 blacklist_destroy();
1103 immu_enable = B_FALSE;
1104 return;
1108 * Read the "raw" DMAR ACPI table to get information
1109 * and convert into a form we can use.
1111 if (immu_dmar_parse() != DDI_SUCCESS) {
1112 blacklist_destroy();
1113 immu_enable = B_FALSE;
1114 return;
1118 * now that we have processed the ACPI table
1119 * check if we need to blacklist this system
1120 * based on ACPI info
1122 if (blacklisted_acpi() == B_TRUE) {
1123 immu_dmar_destroy();
1124 blacklist_destroy();
1125 immu_enable = B_FALSE;
1126 return;
1129 blacklist_destroy();
1132 * Check if system has HW quirks.
1134 pre_setup_quirks();
1136 /* Now do the rest of the setup */
1137 immu_subsystems_setup();
1140 * Now that the IMMU is setup, create a phony
1141 * reg prop so that suspend/resume works
1143 if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg",
1144 (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) {
1145 ddi_err(DER_PANIC, NULL, "Failed to create reg prop for "
1146 "rootnex node");
1147 /*NOTREACHED*/
1150 immu_setup = B_TRUE;
1154 * immu_startup()
1155 * called directly by boot code to startup
1156 * all units of the IOMMU
1158 void
1159 immu_startup(void)
1162 * If IOMMU is disabled, do nothing
1164 if (immu_enable == B_FALSE) {
1165 return;
1168 if (immu_setup == B_FALSE) {
1169 ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, "
1170 "skipping IOMMU startup");
1171 return;
1174 pre_startup_quirks();
1176 ddi_err(DER_CONT, NULL,
1177 "?Starting Intel IOMMU (dmar) units...\n");
1179 immu_subsystems_startup();
1181 immu_running = B_TRUE;
1185 * Hook to notify IOMMU code of device tree changes
1187 void
1188 immu_device_tree_changed(void)
1190 if (immu_setup == B_FALSE) {
1191 return;
1194 ddi_err(DER_WARN, NULL, "Intel IOMMU currently "
1195 "does not use device tree updates");
1199 * Hook to notify IOMMU code of memory changes
1201 void
1202 immu_physmem_update(uint64_t addr, uint64_t size)
1204 if (immu_setup == B_FALSE) {
1205 return;
1207 immu_dvma_physmem_update(addr, size);
1211 * immu_quiesce()
1212 * quiesce all units that are running
1215 immu_quiesce(void)
1217 immu_t *immu;
1218 int ret = DDI_SUCCESS;
1220 mutex_enter(&immu_lock);
1222 if (immu_running == B_FALSE) {
1223 mutex_exit(&immu_lock);
1224 return (DDI_SUCCESS);
1227 immu = list_head(&immu_list);
1228 for (; immu; immu = list_next(&immu_list, immu)) {
1230 /* if immu is not running, we dont quiesce */
1231 if (immu->immu_regs_running == B_FALSE)
1232 continue;
1234 /* flush caches */
1235 rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
1236 immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
1237 immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
1238 rw_exit(&(immu->immu_ctx_rwlock));
1239 immu_regs_wbf_flush(immu);
1241 mutex_enter(&(immu->immu_lock));
1244 * Set IOMMU unit's regs to do
1245 * the actual shutdown.
1247 immu_regs_shutdown(immu);
1248 immu_regs_suspend(immu);
1250 /* if immu is still running, we failed */
1251 if (immu->immu_regs_running == B_TRUE)
1252 ret = DDI_FAILURE;
1253 else
1254 immu->immu_regs_quiesced = B_TRUE;
1256 mutex_exit(&(immu->immu_lock));
1259 if (ret == DDI_SUCCESS) {
1260 immu_running = B_FALSE;
1261 immu_quiesced = B_TRUE;
1263 mutex_exit(&immu_lock);
1265 return (ret);
1269 * immu_unquiesce()
1270 * unquiesce all units
1273 immu_unquiesce(void)
1275 immu_t *immu;
1276 int ret = DDI_SUCCESS;
1278 mutex_enter(&immu_lock);
1280 if (immu_quiesced == B_FALSE) {
1281 mutex_exit(&immu_lock);
1282 return (DDI_SUCCESS);
1285 immu = list_head(&immu_list);
1286 for (; immu; immu = list_next(&immu_list, immu)) {
1288 mutex_enter(&(immu->immu_lock));
1290 /* if immu was not quiesced, i.e was not running before */
1291 if (immu->immu_regs_quiesced == B_FALSE) {
1292 mutex_exit(&(immu->immu_lock));
1293 continue;
1296 if (immu_regs_resume(immu) != DDI_SUCCESS) {
1297 ret = DDI_FAILURE;
1298 mutex_exit(&(immu->immu_lock));
1299 continue;
1302 /* flush caches before unquiesce */
1303 rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
1304 immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
1305 immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
1306 rw_exit(&(immu->immu_ctx_rwlock));
1309 * Set IOMMU unit's regs to do
1310 * the actual startup. This will
1311 * set immu->immu_regs_running field
1312 * if the unit is successfully
1313 * started
1315 immu_regs_startup(immu);
1317 if (immu->immu_regs_running == B_FALSE) {
1318 ret = DDI_FAILURE;
1319 } else {
1320 immu_quiesced = B_TRUE;
1321 immu_running = B_TRUE;
1322 immu->immu_regs_quiesced = B_FALSE;
1325 mutex_exit(&(immu->immu_lock));
1328 mutex_exit(&immu_lock);
1330 return (ret);
1333 void
1334 immu_init_inv_wait(immu_inv_wait_t *iwp, const char *name, boolean_t sync)
1336 caddr_t vaddr;
1337 uint64_t paddr;
1339 iwp->iwp_sync = sync;
1341 vaddr = (caddr_t)&iwp->iwp_vstatus;
1342 paddr = pfn_to_pa(hat_getpfnum(kas.a_hat, vaddr));
1343 paddr += ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
1345 iwp->iwp_pstatus = paddr;
1346 iwp->iwp_name = name;
1349 /* ############## END Intel IOMMU entry points ################## */