13a634bfcSVikram Hegde /*
23a634bfcSVikram Hegde * CDDL HEADER START
33a634bfcSVikram Hegde *
43a634bfcSVikram Hegde * The contents of this file are subject to the terms of the
53a634bfcSVikram Hegde * Common Development and Distribution License (the "License").
63a634bfcSVikram Hegde * You may not use this file except in compliance with the License.
73a634bfcSVikram Hegde *
83a634bfcSVikram Hegde * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93a634bfcSVikram Hegde * or http://www.opensolaris.org/os/licensing.
103a634bfcSVikram Hegde * See the License for the specific language governing permissions
113a634bfcSVikram Hegde * and limitations under the License.
123a634bfcSVikram Hegde *
133a634bfcSVikram Hegde * When distributing Covered Code, include this CDDL HEADER in each
143a634bfcSVikram Hegde * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153a634bfcSVikram Hegde * If applicable, add the following below this CDDL HEADER, with the
163a634bfcSVikram Hegde * fields enclosed by brackets "[]" replaced with your own identifying
173a634bfcSVikram Hegde * information: Portions Copyright [yyyy] [name of copyright owner]
183a634bfcSVikram Hegde *
193a634bfcSVikram Hegde * CDDL HEADER END
203a634bfcSVikram Hegde */
213a634bfcSVikram Hegde /*
229e986f0eSFrank Van Der Linden * Portions Copyright (c) 2010, Oracle and/or its affiliates.
239e986f0eSFrank Van Der Linden * All rights reserved.
243a634bfcSVikram Hegde */
253a634bfcSVikram Hegde /*
263a634bfcSVikram Hegde * Copyright (c) 2009, Intel Corporation.
273a634bfcSVikram Hegde * All rights reserved.
283a634bfcSVikram Hegde */
293a634bfcSVikram Hegde
303a634bfcSVikram Hegde /*
313a634bfcSVikram Hegde * Intel IOMMU implementation
323a634bfcSVikram Hegde * This file contains Intel IOMMU code exported
333a634bfcSVikram Hegde * to the rest of the system and code that deals
343a634bfcSVikram Hegde * with the Intel IOMMU as a whole.
353a634bfcSVikram Hegde */
363a634bfcSVikram Hegde
373a634bfcSVikram Hegde #include <sys/conf.h>
383a634bfcSVikram Hegde #include <sys/modctl.h>
393a634bfcSVikram Hegde #include <sys/pci.h>
403a634bfcSVikram Hegde #include <sys/pci_impl.h>
413a634bfcSVikram Hegde #include <sys/sysmacros.h>
423a634bfcSVikram Hegde #include <sys/ddi.h>
433a634bfcSVikram Hegde #include <sys/ddidmareq.h>
443a634bfcSVikram Hegde #include <sys/ddi_impldefs.h>
453a634bfcSVikram Hegde #include <sys/ddifm.h>
463a634bfcSVikram Hegde #include <sys/sunndi.h>
473a634bfcSVikram Hegde #include <sys/debug.h>
483a634bfcSVikram Hegde #include <sys/fm/protocol.h>
493a634bfcSVikram Hegde #include <sys/note.h>
503a634bfcSVikram Hegde #include <sys/apic.h>
513a634bfcSVikram Hegde #include <vm/hat_i86.h>
523a634bfcSVikram Hegde #include <sys/smp_impldefs.h>
533a634bfcSVikram Hegde #include <sys/spl.h>
543a634bfcSVikram Hegde #include <sys/archsystm.h>
553a634bfcSVikram Hegde #include <sys/x86_archext.h>
563a634bfcSVikram Hegde #include <sys/avl.h>
573a634bfcSVikram Hegde #include <sys/bootconf.h>
583a634bfcSVikram Hegde #include <sys/bootinfo.h>
593a634bfcSVikram Hegde #include <sys/atomic.h>
603a634bfcSVikram Hegde #include <sys/immu.h>
613a634bfcSVikram Hegde /* ########################### Globals and tunables ######################## */
623a634bfcSVikram Hegde /*
633a634bfcSVikram Hegde * Global switches (boolean) that can be toggled either via boot options
643a634bfcSVikram Hegde * or via /etc/system or kmdb
653a634bfcSVikram Hegde */
663a634bfcSVikram Hegde
673a634bfcSVikram Hegde /* Various features */
683adb2334SVikram Hegde boolean_t immu_enable = B_TRUE;
693a634bfcSVikram Hegde boolean_t immu_dvma_enable = B_TRUE;
703a634bfcSVikram Hegde
713a634bfcSVikram Hegde /* accessed in other files so not static */
723a634bfcSVikram Hegde boolean_t immu_gfxdvma_enable = B_TRUE;
733a634bfcSVikram Hegde boolean_t immu_intrmap_enable = B_FALSE;
7450200e77SFrank Van Der Linden boolean_t immu_qinv_enable = B_TRUE;
753a634bfcSVikram Hegde
763a634bfcSVikram Hegde /* various quirks that need working around */
773a634bfcSVikram Hegde
783a634bfcSVikram Hegde /* XXX We always map page 0 read/write for now */
793a634bfcSVikram Hegde boolean_t immu_quirk_usbpage0 = B_TRUE;
803a634bfcSVikram Hegde boolean_t immu_quirk_usbrmrr = B_TRUE;
813a634bfcSVikram Hegde boolean_t immu_quirk_usbfullpa;
823a634bfcSVikram Hegde boolean_t immu_quirk_mobile4;
833a634bfcSVikram Hegde
843a634bfcSVikram Hegde /* debug messages */
853a634bfcSVikram Hegde boolean_t immu_dmar_print;
863a634bfcSVikram Hegde
87e03dceedSVikram Hegde /* Tunables */
88e03dceedSVikram Hegde int64_t immu_flush_gran = 5;
89e03dceedSVikram Hegde
909e986f0eSFrank Van Der Linden immu_flags_t immu_global_dvma_flags;
919e986f0eSFrank Van Der Linden
923a634bfcSVikram Hegde /* ############ END OPTIONS section ################ */
933a634bfcSVikram Hegde
943a634bfcSVikram Hegde /*
953a634bfcSVikram Hegde * Global used internally by Intel IOMMU code
963a634bfcSVikram Hegde */
973a634bfcSVikram Hegde dev_info_t *root_devinfo;
983a634bfcSVikram Hegde kmutex_t immu_lock;
993a634bfcSVikram Hegde list_t immu_list;
1003a634bfcSVikram Hegde boolean_t immu_setup;
1013a634bfcSVikram Hegde boolean_t immu_running;
1023a634bfcSVikram Hegde boolean_t immu_quiesced;
1033a634bfcSVikram Hegde
1043a634bfcSVikram Hegde /* ######################## END Globals and tunables ###################### */
1053a634bfcSVikram Hegde /* Globals used only in this file */
1063a634bfcSVikram Hegde static char **black_array;
1073a634bfcSVikram Hegde static uint_t nblacks;
1089e986f0eSFrank Van Der Linden
1099e986f0eSFrank Van Der Linden static char **unity_driver_array;
1109e986f0eSFrank Van Der Linden static uint_t nunity;
1119e986f0eSFrank Van Der Linden static char **xlate_driver_array;
1129e986f0eSFrank Van Der Linden static uint_t nxlate;
11350200e77SFrank Van Der Linden
11450200e77SFrank Van Der Linden static char **premap_driver_array;
11550200e77SFrank Van Der Linden static uint_t npremap;
11650200e77SFrank Van Der Linden static char **nopremap_driver_array;
11750200e77SFrank Van Der Linden static uint_t nnopremap;
1183a634bfcSVikram Hegde /* ###################### Utility routines ############################# */
1193a634bfcSVikram Hegde
1203a634bfcSVikram Hegde /*
1213a634bfcSVikram Hegde * Check if the device has mobile 4 chipset
1223a634bfcSVikram Hegde */
1233a634bfcSVikram Hegde static int
check_mobile4(dev_info_t * dip,void * arg)1243a634bfcSVikram Hegde check_mobile4(dev_info_t *dip, void *arg)
1253a634bfcSVikram Hegde {
1263a634bfcSVikram Hegde _NOTE(ARGUNUSED(arg));
1273a634bfcSVikram Hegde int vendor, device;
1283a634bfcSVikram Hegde int *ip = (int *)arg;
1293a634bfcSVikram Hegde
1303a634bfcSVikram Hegde vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1313a634bfcSVikram Hegde "vendor-id", -1);
1323a634bfcSVikram Hegde device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1333a634bfcSVikram Hegde "device-id", -1);
1343a634bfcSVikram Hegde
1353a634bfcSVikram Hegde if (vendor == 0x8086 && device == 0x2a40) {
1363a634bfcSVikram Hegde *ip = B_TRUE;
13750200e77SFrank Van Der Linden ddi_err(DER_NOTE, dip, "iommu: Mobile 4 chipset detected. "
1383a634bfcSVikram Hegde "Force setting IOMMU write buffer");
1393a634bfcSVikram Hegde return (DDI_WALK_TERMINATE);
1403a634bfcSVikram Hegde } else {
1413a634bfcSVikram Hegde return (DDI_WALK_CONTINUE);
1423a634bfcSVikram Hegde }
1433a634bfcSVikram Hegde }
1443a634bfcSVikram Hegde
1453a634bfcSVikram Hegde static void
map_bios_rsvd_mem(dev_info_t * dip)1463a634bfcSVikram Hegde map_bios_rsvd_mem(dev_info_t *dip)
1473a634bfcSVikram Hegde {
1483a634bfcSVikram Hegde struct memlist *mp;
14950200e77SFrank Van Der Linden
15050200e77SFrank Van Der Linden /*
15150200e77SFrank Van Der Linden * Make sure the domain for the device is set up before
15250200e77SFrank Van Der Linden * mapping anything.
15350200e77SFrank Van Der Linden */
15450200e77SFrank Van Der Linden (void) immu_dvma_device_setup(dip, 0);
1553a634bfcSVikram Hegde
1563a634bfcSVikram Hegde memlist_read_lock();
1573a634bfcSVikram Hegde
1583a634bfcSVikram Hegde mp = bios_rsvd;
1593a634bfcSVikram Hegde while (mp != NULL) {
160e03dceedSVikram Hegde memrng_t mrng = {0};
1613a634bfcSVikram Hegde
16250200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Mapping BIOS rsvd range "
1633a634bfcSVikram Hegde "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address,
1643a634bfcSVikram Hegde mp->ml_address + mp->ml_size);
1653a634bfcSVikram Hegde
166e03dceedSVikram Hegde mrng.mrng_start = IMMU_ROUNDOWN(mp->ml_address);
167e03dceedSVikram Hegde mrng.mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE;
1683a634bfcSVikram Hegde
16950200e77SFrank Van Der Linden (void) immu_map_memrange(dip, &mrng);
1703a634bfcSVikram Hegde
1713a634bfcSVikram Hegde mp = mp->ml_next;
1723a634bfcSVikram Hegde }
1733a634bfcSVikram Hegde
1743a634bfcSVikram Hegde memlist_read_unlock();
1753a634bfcSVikram Hegde }
1763a634bfcSVikram Hegde
177e03dceedSVikram Hegde
178e03dceedSVikram Hegde /*
1799e986f0eSFrank Van Der Linden * Check if the driver requests a specific type of mapping.
180e03dceedSVikram Hegde */
181e03dceedSVikram Hegde /*ARGSUSED*/
182e03dceedSVikram Hegde static void
check_conf(dev_info_t * dip,void * arg)1839e986f0eSFrank Van Der Linden check_conf(dev_info_t *dip, void *arg)
184e03dceedSVikram Hegde {
1859e986f0eSFrank Van Der Linden immu_devi_t *immu_devi;
1869e986f0eSFrank Van Der Linden const char *dname;
1879e986f0eSFrank Van Der Linden uint_t i;
18850200e77SFrank Van Der Linden int hasmapprop = 0, haspreprop = 0;
18950200e77SFrank Van Der Linden boolean_t old_premap;
190e03dceedSVikram Hegde
191e03dceedSVikram Hegde /*
1929e986f0eSFrank Van Der Linden * Only PCI devices can use an IOMMU. Legacy ISA devices
1939e986f0eSFrank Van Der Linden * are handled in check_lpc.
194e03dceedSVikram Hegde */
1959e986f0eSFrank Van Der Linden if (!DEVI_IS_PCI(dip))
1969e986f0eSFrank Van Der Linden return;
197e03dceedSVikram Hegde
1989e986f0eSFrank Van Der Linden dname = ddi_driver_name(dip);
1999e986f0eSFrank Van Der Linden if (dname == NULL)
2009e986f0eSFrank Van Der Linden return;
2019e986f0eSFrank Van Der Linden immu_devi = immu_devi_get(dip);
2029e986f0eSFrank Van Der Linden
2039e986f0eSFrank Van Der Linden for (i = 0; i < nunity; i++) {
2049e986f0eSFrank Van Der Linden if (strcmp(unity_driver_array[i], dname) == 0) {
20550200e77SFrank Van Der Linden hasmapprop = 1;
2069e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
207e03dceedSVikram Hegde }
208e03dceedSVikram Hegde }
2099e986f0eSFrank Van Der Linden
2109e986f0eSFrank Van Der Linden for (i = 0; i < nxlate; i++) {
2119e986f0eSFrank Van Der Linden if (strcmp(xlate_driver_array[i], dname) == 0) {
21250200e77SFrank Van Der Linden hasmapprop = 1;
2139e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags &= ~IMMU_FLAGS_UNITY;
2149e986f0eSFrank Van Der Linden }
2159e986f0eSFrank Van Der Linden }
2169e986f0eSFrank Van Der Linden
21750200e77SFrank Van Der Linden old_premap = immu_devi->imd_use_premap;
21850200e77SFrank Van Der Linden
21950200e77SFrank Van Der Linden for (i = 0; i < nnopremap; i++) {
22050200e77SFrank Van Der Linden if (strcmp(nopremap_driver_array[i], dname) == 0) {
22150200e77SFrank Van Der Linden haspreprop = 1;
22250200e77SFrank Van Der Linden immu_devi->imd_use_premap = B_FALSE;
22350200e77SFrank Van Der Linden }
22450200e77SFrank Van Der Linden }
22550200e77SFrank Van Der Linden
22650200e77SFrank Van Der Linden for (i = 0; i < npremap; i++) {
22750200e77SFrank Van Der Linden if (strcmp(premap_driver_array[i], dname) == 0) {
22850200e77SFrank Van Der Linden haspreprop = 1;
22950200e77SFrank Van Der Linden immu_devi->imd_use_premap = B_TRUE;
23050200e77SFrank Van Der Linden }
23150200e77SFrank Van Der Linden }
23250200e77SFrank Van Der Linden
2339e986f0eSFrank Van Der Linden /*
2349e986f0eSFrank Van Der Linden * Report if we changed the value from the default.
2359e986f0eSFrank Van Der Linden */
23650200e77SFrank Van Der Linden if (hasmapprop && (immu_devi->imd_dvma_flags ^ immu_global_dvma_flags))
2379e986f0eSFrank Van Der Linden ddi_err(DER_LOG, dip, "using %s DVMA mapping",
2389e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY ?
2399e986f0eSFrank Van Der Linden DDI_DVMA_MAPTYPE_UNITY : DDI_DVMA_MAPTYPE_XLATE);
24050200e77SFrank Van Der Linden
24150200e77SFrank Van Der Linden if (haspreprop && (immu_devi->imd_use_premap != old_premap))
24250200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "%susing premapped DVMA space",
24350200e77SFrank Van Der Linden immu_devi->imd_use_premap ? "" : "not ");
244e03dceedSVikram Hegde }
245e03dceedSVikram Hegde
2463a634bfcSVikram Hegde /*
2473a634bfcSVikram Hegde * Check if the device is USB controller
2483a634bfcSVikram Hegde */
2493a634bfcSVikram Hegde /*ARGSUSED*/
2503a634bfcSVikram Hegde static void
check_usb(dev_info_t * dip,void * arg)2513a634bfcSVikram Hegde check_usb(dev_info_t *dip, void *arg)
2523a634bfcSVikram Hegde {
2533a634bfcSVikram Hegde const char *drv = ddi_driver_name(dip);
2549e986f0eSFrank Van Der Linden immu_devi_t *immu_devi;
2559e986f0eSFrank Van Der Linden
2563a634bfcSVikram Hegde
2573a634bfcSVikram Hegde if (drv == NULL ||
2583a634bfcSVikram Hegde (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 &&
2593a634bfcSVikram Hegde strcmp(drv, "ehci") != 0)) {
2603a634bfcSVikram Hegde return;
2613a634bfcSVikram Hegde }
2623a634bfcSVikram Hegde
2639e986f0eSFrank Van Der Linden immu_devi = immu_devi_get(dip);
2649e986f0eSFrank Van Der Linden
2659e986f0eSFrank Van Der Linden /*
2669e986f0eSFrank Van Der Linden * If unit mappings are already specified, globally or
2679e986f0eSFrank Van Der Linden * locally, we're done here, since that covers both
2689e986f0eSFrank Van Der Linden * quirks below.
2699e986f0eSFrank Van Der Linden */
2709e986f0eSFrank Van Der Linden if (immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY)
2719e986f0eSFrank Van Der Linden return;
2729e986f0eSFrank Van Der Linden
2733a634bfcSVikram Hegde /* This must come first since it does unity mapping */
2743a634bfcSVikram Hegde if (immu_quirk_usbfullpa == B_TRUE) {
2759e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
2769e986f0eSFrank Van Der Linden } else if (immu_quirk_usbrmrr == B_TRUE) {
2773a634bfcSVikram Hegde ddi_err(DER_LOG, dip, "Applying USB RMRR quirk");
2783a634bfcSVikram Hegde map_bios_rsvd_mem(dip);
2793a634bfcSVikram Hegde }
2803a634bfcSVikram Hegde }
2813a634bfcSVikram Hegde
2823a634bfcSVikram Hegde /*
2833a634bfcSVikram Hegde * Check if the device is a LPC device
2843a634bfcSVikram Hegde */
2853a634bfcSVikram Hegde /*ARGSUSED*/
2863a634bfcSVikram Hegde static void
check_lpc(dev_info_t * dip,void * arg)2873a634bfcSVikram Hegde check_lpc(dev_info_t *dip, void *arg)
2883a634bfcSVikram Hegde {
2893a634bfcSVikram Hegde immu_devi_t *immu_devi;
2903a634bfcSVikram Hegde
2913a634bfcSVikram Hegde immu_devi = immu_devi_get(dip);
2923a634bfcSVikram Hegde if (immu_devi->imd_lpc == B_TRUE) {
29350200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Found LPC device");
2943a634bfcSVikram Hegde /* This will put the immu_devi on the LPC "specials" list */
29550200e77SFrank Van Der Linden (void) immu_dvma_device_setup(dip, IMMU_FLAGS_SLEEP);
2963a634bfcSVikram Hegde }
2973a634bfcSVikram Hegde }
2983a634bfcSVikram Hegde
2993a634bfcSVikram Hegde /*
3003a634bfcSVikram Hegde * Check if the device is a GFX device
3013a634bfcSVikram Hegde */
3023a634bfcSVikram Hegde /*ARGSUSED*/
3033a634bfcSVikram Hegde static void
check_gfx(dev_info_t * dip,void * arg)3043a634bfcSVikram Hegde check_gfx(dev_info_t *dip, void *arg)
3053a634bfcSVikram Hegde {
3063a634bfcSVikram Hegde immu_devi_t *immu_devi;
3073a634bfcSVikram Hegde
3083a634bfcSVikram Hegde immu_devi = immu_devi_get(dip);
3093a634bfcSVikram Hegde if (immu_devi->imd_display == B_TRUE) {
3109e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
31150200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Found GFX device");
3123a634bfcSVikram Hegde /* This will put the immu_devi on the GFX "specials" list */
3133a634bfcSVikram Hegde (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP);
3143a634bfcSVikram Hegde }
3153a634bfcSVikram Hegde }
3163a634bfcSVikram Hegde
3173a634bfcSVikram Hegde static void
walk_tree(int (* f)(dev_info_t *,void *),void * arg)3183a634bfcSVikram Hegde walk_tree(int (*f)(dev_info_t *, void *), void *arg)
3193a634bfcSVikram Hegde {
3203a634bfcSVikram Hegde int count;
3213a634bfcSVikram Hegde
3223a634bfcSVikram Hegde ndi_devi_enter(root_devinfo, &count);
3233a634bfcSVikram Hegde ddi_walk_devs(ddi_get_child(root_devinfo), f, arg);
3243a634bfcSVikram Hegde ndi_devi_exit(root_devinfo, count);
3253a634bfcSVikram Hegde }
3263a634bfcSVikram Hegde
3273a634bfcSVikram Hegde static int
check_pre_setup_quirks(dev_info_t * dip,void * arg)3283a634bfcSVikram Hegde check_pre_setup_quirks(dev_info_t *dip, void *arg)
3293a634bfcSVikram Hegde {
3303a634bfcSVikram Hegde /* just 1 check right now */
3313a634bfcSVikram Hegde return (check_mobile4(dip, arg));
3323a634bfcSVikram Hegde }
3333a634bfcSVikram Hegde
3343a634bfcSVikram Hegde static int
check_pre_startup_quirks(dev_info_t * dip,void * arg)3353a634bfcSVikram Hegde check_pre_startup_quirks(dev_info_t *dip, void *arg)
3363a634bfcSVikram Hegde {
3373a634bfcSVikram Hegde if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) {
3383a634bfcSVikram Hegde ddi_err(DER_PANIC, dip, "Failed to get immu_devi");
3393a634bfcSVikram Hegde }
3403a634bfcSVikram Hegde
3413a634bfcSVikram Hegde check_gfx(dip, arg);
3423a634bfcSVikram Hegde
3433a634bfcSVikram Hegde check_lpc(dip, arg);
3443a634bfcSVikram Hegde
3459e986f0eSFrank Van Der Linden check_conf(dip, arg);
3463a634bfcSVikram Hegde
3479e986f0eSFrank Van Der Linden check_usb(dip, arg);
348e03dceedSVikram Hegde
3493a634bfcSVikram Hegde return (DDI_WALK_CONTINUE);
3503a634bfcSVikram Hegde }
3513a634bfcSVikram Hegde
3523a634bfcSVikram Hegde static void
pre_setup_quirks(void)3533a634bfcSVikram Hegde pre_setup_quirks(void)
3543a634bfcSVikram Hegde {
3553a634bfcSVikram Hegde walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4);
3563a634bfcSVikram Hegde }
3573a634bfcSVikram Hegde
3583a634bfcSVikram Hegde static void
pre_startup_quirks(void)3593a634bfcSVikram Hegde pre_startup_quirks(void)
3603a634bfcSVikram Hegde {
3613a634bfcSVikram Hegde walk_tree(check_pre_startup_quirks, NULL);
3623a634bfcSVikram Hegde
3633a634bfcSVikram Hegde immu_dmar_rmrr_map();
3643a634bfcSVikram Hegde }
3653a634bfcSVikram Hegde
3669e986f0eSFrank Van Der Linden static int
get_conf_str(char * bopt,char ** val)3679e986f0eSFrank Van Der Linden get_conf_str(char *bopt, char **val)
3689e986f0eSFrank Van Der Linden {
3699e986f0eSFrank Van Der Linden int ret;
3709e986f0eSFrank Van Der Linden
3719e986f0eSFrank Van Der Linden /*
3729e986f0eSFrank Van Der Linden * Check the rootnex.conf property
3739e986f0eSFrank Van Der Linden * Fake up a dev_t since searching the global
3749e986f0eSFrank Van Der Linden * property list needs it
3759e986f0eSFrank Van Der Linden */
3769e986f0eSFrank Van Der Linden ret = ddi_prop_lookup_string(
3779e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0),
3789e986f0eSFrank Van Der Linden root_devinfo, DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
3799e986f0eSFrank Van Der Linden bopt, val);
3809e986f0eSFrank Van Der Linden
3819e986f0eSFrank Van Der Linden return (ret);
3829e986f0eSFrank Van Der Linden }
3839e986f0eSFrank Van Der Linden
3843a634bfcSVikram Hegde /*
3853adb2334SVikram Hegde * get_conf_opt()
3863adb2334SVikram Hegde * get a rootnex.conf setting (always a boolean)
3873adb2334SVikram Hegde */
3883adb2334SVikram Hegde static void
get_conf_opt(char * bopt,boolean_t * kvar)3893adb2334SVikram Hegde get_conf_opt(char *bopt, boolean_t *kvar)
3903adb2334SVikram Hegde {
3913adb2334SVikram Hegde char *val = NULL;
3923adb2334SVikram Hegde
3933adb2334SVikram Hegde /*
3943adb2334SVikram Hegde * Check the rootnex.conf property
3953adb2334SVikram Hegde * Fake up a dev_t since searching the global
3963adb2334SVikram Hegde * property list needs it
3973adb2334SVikram Hegde */
3983adb2334SVikram Hegde
3999e986f0eSFrank Van Der Linden if (get_conf_str(bopt, &val) != DDI_PROP_SUCCESS)
4009e986f0eSFrank Van Der Linden return;
4019e986f0eSFrank Van Der Linden
4023adb2334SVikram Hegde if (strcmp(val, "true") == 0) {
4033adb2334SVikram Hegde *kvar = B_TRUE;
4043adb2334SVikram Hegde } else if (strcmp(val, "false") == 0) {
4053adb2334SVikram Hegde *kvar = B_FALSE;
4063adb2334SVikram Hegde } else {
4073adb2334SVikram Hegde ddi_err(DER_WARN, NULL, "rootnex.conf switch %s=\"%s\" ",
4083adb2334SVikram Hegde "is not set to true or false. Ignoring option.",
4093adb2334SVikram Hegde bopt, val);
4103adb2334SVikram Hegde }
4113adb2334SVikram Hegde ddi_prop_free(val);
4123adb2334SVikram Hegde }
4133adb2334SVikram Hegde
4143adb2334SVikram Hegde /*
4153a634bfcSVikram Hegde * get_bootopt()
4163a634bfcSVikram Hegde * check a boot option (always a boolean)
4173a634bfcSVikram Hegde */
4189e986f0eSFrank Van Der Linden static int
get_boot_str(char * bopt,char ** val)4199e986f0eSFrank Van Der Linden get_boot_str(char *bopt, char **val)
4209e986f0eSFrank Van Der Linden {
4219e986f0eSFrank Van Der Linden int ret;
4229e986f0eSFrank Van Der Linden
4239e986f0eSFrank Van Der Linden ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo,
4249e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS, bopt, val);
4259e986f0eSFrank Van Der Linden
4269e986f0eSFrank Van Der Linden return (ret);
4279e986f0eSFrank Van Der Linden }
4289e986f0eSFrank Van Der Linden
4293a634bfcSVikram Hegde static void
get_bootopt(char * bopt,boolean_t * kvar)4303a634bfcSVikram Hegde get_bootopt(char *bopt, boolean_t *kvar)
4313a634bfcSVikram Hegde {
4323a634bfcSVikram Hegde char *val = NULL;
4333a634bfcSVikram Hegde
4343a634bfcSVikram Hegde /*
4353a634bfcSVikram Hegde * All boot options set at the GRUB menu become
4363a634bfcSVikram Hegde * properties on the rootnex.
4373a634bfcSVikram Hegde */
4389e986f0eSFrank Van Der Linden if (get_boot_str(bopt, &val) != DDI_PROP_SUCCESS)
4399e986f0eSFrank Van Der Linden return;
4409e986f0eSFrank Van Der Linden
4413a634bfcSVikram Hegde if (strcmp(val, "true") == 0) {
4423a634bfcSVikram Hegde *kvar = B_TRUE;
4433a634bfcSVikram Hegde } else if (strcmp(val, "false") == 0) {
4443a634bfcSVikram Hegde *kvar = B_FALSE;
4453a634bfcSVikram Hegde } else {
4463a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ",
4473a634bfcSVikram Hegde "is not set to true or false. Ignoring option.",
4483a634bfcSVikram Hegde bopt, val);
4493a634bfcSVikram Hegde }
4503a634bfcSVikram Hegde ddi_prop_free(val);
4513a634bfcSVikram Hegde }
4529e986f0eSFrank Van Der Linden
4539e986f0eSFrank Van Der Linden static void
get_boot_dvma_mode(void)4549e986f0eSFrank Van Der Linden get_boot_dvma_mode(void)
4559e986f0eSFrank Van Der Linden {
4569e986f0eSFrank Van Der Linden char *val = NULL;
4579e986f0eSFrank Van Der Linden
4589e986f0eSFrank Van Der Linden if (get_boot_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
4599e986f0eSFrank Van Der Linden != DDI_PROP_SUCCESS)
4609e986f0eSFrank Van Der Linden return;
4619e986f0eSFrank Van Der Linden
4629e986f0eSFrank Van Der Linden if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
4639e986f0eSFrank Van Der Linden immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
4649e986f0eSFrank Van Der Linden } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
4659e986f0eSFrank Van Der Linden immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
4669e986f0eSFrank Van Der Linden } else {
4679e986f0eSFrank Van Der Linden ddi_err(DER_WARN, NULL, "bad value \"%s\" for boot option %s",
4689e986f0eSFrank Van Der Linden val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
4693a634bfcSVikram Hegde }
4709e986f0eSFrank Van Der Linden ddi_prop_free(val);
4719e986f0eSFrank Van Der Linden }
4729e986f0eSFrank Van Der Linden
4739e986f0eSFrank Van Der Linden static void
get_conf_dvma_mode(void)4749e986f0eSFrank Van Der Linden get_conf_dvma_mode(void)
4759e986f0eSFrank Van Der Linden {
4769e986f0eSFrank Van Der Linden char *val = NULL;
4779e986f0eSFrank Van Der Linden
4789e986f0eSFrank Van Der Linden if (get_conf_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
4799e986f0eSFrank Van Der Linden != DDI_PROP_SUCCESS)
4809e986f0eSFrank Van Der Linden return;
4819e986f0eSFrank Van Der Linden
4829e986f0eSFrank Van Der Linden if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
4839e986f0eSFrank Van Der Linden immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
4849e986f0eSFrank Van Der Linden } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
4859e986f0eSFrank Van Der Linden immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
4869e986f0eSFrank Van Der Linden } else {
4879e986f0eSFrank Van Der Linden ddi_err(DER_WARN, NULL, "bad value \"%s\" for rootnex "
4889e986f0eSFrank Van Der Linden "option %s", val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
4899e986f0eSFrank Van Der Linden }
4909e986f0eSFrank Van Der Linden ddi_prop_free(val);
4919e986f0eSFrank Van Der Linden }
4929e986f0eSFrank Van Der Linden
4933a634bfcSVikram Hegde
4943a634bfcSVikram Hegde static void
get_conf_tunables(char * bopt,int64_t * ivar)4953adb2334SVikram Hegde get_conf_tunables(char *bopt, int64_t *ivar)
496e03dceedSVikram Hegde {
497e03dceedSVikram Hegde int64_t *iarray;
498e03dceedSVikram Hegde uint_t n;
499e03dceedSVikram Hegde
500e03dceedSVikram Hegde /*
501e03dceedSVikram Hegde * Check the rootnex.conf property
502e03dceedSVikram Hegde * Fake up a dev_t since searching the global
503e03dceedSVikram Hegde * property list needs it
504e03dceedSVikram Hegde */
505e03dceedSVikram Hegde if (ddi_prop_lookup_int64_array(
506e03dceedSVikram Hegde makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
507e03dceedSVikram Hegde DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, bopt,
508e03dceedSVikram Hegde &iarray, &n) != DDI_PROP_SUCCESS) {
509e03dceedSVikram Hegde return;
510e03dceedSVikram Hegde }
511e03dceedSVikram Hegde
512e03dceedSVikram Hegde if (n != 1) {
513e03dceedSVikram Hegde ddi_err(DER_WARN, NULL, "More than one value specified for "
514e03dceedSVikram Hegde "%s property. Ignoring and using default",
515e03dceedSVikram Hegde "immu-flush-gran");
516e03dceedSVikram Hegde ddi_prop_free(iarray);
517e03dceedSVikram Hegde return;
518e03dceedSVikram Hegde }
519e03dceedSVikram Hegde
520e03dceedSVikram Hegde if (iarray[0] < 0) {
521e03dceedSVikram Hegde ddi_err(DER_WARN, NULL, "Negative value specified for "
522e03dceedSVikram Hegde "%s property. Inoring and Using default value",
523e03dceedSVikram Hegde "immu-flush-gran");
524e03dceedSVikram Hegde ddi_prop_free(iarray);
525e03dceedSVikram Hegde return;
526e03dceedSVikram Hegde }
527e03dceedSVikram Hegde
528e03dceedSVikram Hegde *ivar = iarray[0];
529e03dceedSVikram Hegde
530e03dceedSVikram Hegde ddi_prop_free(iarray);
531e03dceedSVikram Hegde }
532e03dceedSVikram Hegde
533e03dceedSVikram Hegde static void
read_conf_options(void)5343adb2334SVikram Hegde read_conf_options(void)
5353adb2334SVikram Hegde {
5363adb2334SVikram Hegde /* enable/disable options */
5373adb2334SVikram Hegde get_conf_opt("immu-enable", &immu_enable);
5383adb2334SVikram Hegde get_conf_opt("immu-dvma-enable", &immu_dvma_enable);
5393adb2334SVikram Hegde get_conf_opt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
5403adb2334SVikram Hegde get_conf_opt("immu-intrmap-enable", &immu_intrmap_enable);
5413adb2334SVikram Hegde get_conf_opt("immu-qinv-enable", &immu_qinv_enable);
5423adb2334SVikram Hegde
5433adb2334SVikram Hegde /* workaround switches */
5443adb2334SVikram Hegde get_conf_opt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
5453adb2334SVikram Hegde get_conf_opt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
5463adb2334SVikram Hegde get_conf_opt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
5473adb2334SVikram Hegde
5483adb2334SVikram Hegde /* debug printing */
5493adb2334SVikram Hegde get_conf_opt("immu-dmar-print", &immu_dmar_print);
5503adb2334SVikram Hegde
5513adb2334SVikram Hegde /* get tunables */
5523adb2334SVikram Hegde get_conf_tunables("immu-flush-gran", &immu_flush_gran);
5539e986f0eSFrank Van Der Linden
5549e986f0eSFrank Van Der Linden get_conf_dvma_mode();
5553adb2334SVikram Hegde }
5563adb2334SVikram Hegde
5573adb2334SVikram Hegde static void
read_boot_options(void)5583a634bfcSVikram Hegde read_boot_options(void)
5593a634bfcSVikram Hegde {
5603a634bfcSVikram Hegde /* enable/disable options */
5613a634bfcSVikram Hegde get_bootopt("immu-enable", &immu_enable);
5623a634bfcSVikram Hegde get_bootopt("immu-dvma-enable", &immu_dvma_enable);
5633a634bfcSVikram Hegde get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
5643a634bfcSVikram Hegde get_bootopt("immu-intrmap-enable", &immu_intrmap_enable);
5653a634bfcSVikram Hegde get_bootopt("immu-qinv-enable", &immu_qinv_enable);
5663a634bfcSVikram Hegde
5673a634bfcSVikram Hegde /* workaround switches */
5683a634bfcSVikram Hegde get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
5693a634bfcSVikram Hegde get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
5703a634bfcSVikram Hegde get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
5713a634bfcSVikram Hegde
5723a634bfcSVikram Hegde /* debug printing */
5733a634bfcSVikram Hegde get_bootopt("immu-dmar-print", &immu_dmar_print);
5749e986f0eSFrank Van Der Linden
5759e986f0eSFrank Van Der Linden get_boot_dvma_mode();
5769e986f0eSFrank Van Der Linden }
5779e986f0eSFrank Van Der Linden
5789e986f0eSFrank Van Der Linden static void
mapping_list_setup(void)5799e986f0eSFrank Van Der Linden mapping_list_setup(void)
5809e986f0eSFrank Van Der Linden {
5819e986f0eSFrank Van Der Linden char **string_array;
5829e986f0eSFrank Van Der Linden uint_t nstrings;
5839e986f0eSFrank Van Der Linden
5849e986f0eSFrank Van Der Linden if (ddi_prop_lookup_string_array(
5859e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
5869e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
5879e986f0eSFrank Van Der Linden "immu-dvma-unity-drivers",
5889e986f0eSFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
5899e986f0eSFrank Van Der Linden unity_driver_array = string_array;
5909e986f0eSFrank Van Der Linden nunity = nstrings;
5919e986f0eSFrank Van Der Linden }
5929e986f0eSFrank Van Der Linden
5939e986f0eSFrank Van Der Linden if (ddi_prop_lookup_string_array(
5949e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
5959e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
5969e986f0eSFrank Van Der Linden "immu-dvma-xlate-drivers",
5979e986f0eSFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
5989e986f0eSFrank Van Der Linden xlate_driver_array = string_array;
5999e986f0eSFrank Van Der Linden nxlate = nstrings;
6009e986f0eSFrank Van Der Linden }
60150200e77SFrank Van Der Linden
60250200e77SFrank Van Der Linden if (ddi_prop_lookup_string_array(
60350200e77SFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
60450200e77SFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
60550200e77SFrank Van Der Linden "immu-dvma-premap-drivers",
60650200e77SFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
60750200e77SFrank Van Der Linden premap_driver_array = string_array;
60850200e77SFrank Van Der Linden npremap = nstrings;
60950200e77SFrank Van Der Linden }
61050200e77SFrank Van Der Linden
61150200e77SFrank Van Der Linden if (ddi_prop_lookup_string_array(
61250200e77SFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
61350200e77SFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
61450200e77SFrank Van Der Linden "immu-dvma-nopremap-drivers",
61550200e77SFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
61650200e77SFrank Van Der Linden nopremap_driver_array = string_array;
61750200e77SFrank Van Der Linden nnopremap = nstrings;
61850200e77SFrank Van Der Linden }
6193a634bfcSVikram Hegde }
6203a634bfcSVikram Hegde
6213a634bfcSVikram Hegde /*
6223a634bfcSVikram Hegde * Note, this will not catch hardware not enumerated
6233a634bfcSVikram Hegde * in early boot
6243a634bfcSVikram Hegde */
6253a634bfcSVikram Hegde static boolean_t
blacklisted_driver(void)6263a634bfcSVikram Hegde blacklisted_driver(void)
6273a634bfcSVikram Hegde {
6283a634bfcSVikram Hegde char **strptr;
6293a634bfcSVikram Hegde int i;
6303a634bfcSVikram Hegde major_t maj;
6313a634bfcSVikram Hegde
6323a634bfcSVikram Hegde /* need at least 2 strings */
6333a634bfcSVikram Hegde if (nblacks < 2) {
6343a634bfcSVikram Hegde return (B_FALSE);
6353a634bfcSVikram Hegde }
6363a634bfcSVikram Hegde
6373a634bfcSVikram Hegde for (i = 0; nblacks - i > 1; i++) {
638e03dceedSVikram Hegde strptr = &black_array[i];
6393a634bfcSVikram Hegde if (strcmp(*strptr++, "DRIVER") == 0) {
6403a634bfcSVikram Hegde if ((maj = ddi_name_to_major(*strptr++))
6413a634bfcSVikram Hegde != DDI_MAJOR_T_NONE) {
6423a634bfcSVikram Hegde /* is there hardware bound to this drvr */
6433a634bfcSVikram Hegde if (devnamesp[maj].dn_head != NULL) {
6443a634bfcSVikram Hegde return (B_TRUE);
6453a634bfcSVikram Hegde }
6463a634bfcSVikram Hegde }
6473a634bfcSVikram Hegde i += 1; /* for loop adds 1, so add only 1 here */
6483a634bfcSVikram Hegde }
6493a634bfcSVikram Hegde }
6503a634bfcSVikram Hegde
6513a634bfcSVikram Hegde return (B_FALSE);
6523a634bfcSVikram Hegde }
6533a634bfcSVikram Hegde
6543a634bfcSVikram Hegde static boolean_t
blacklisted_smbios(void)6553a634bfcSVikram Hegde blacklisted_smbios(void)
6563a634bfcSVikram Hegde {
6573a634bfcSVikram Hegde id_t smid;
6583a634bfcSVikram Hegde smbios_hdl_t *smhdl;
6593a634bfcSVikram Hegde smbios_info_t sminf;
6603a634bfcSVikram Hegde smbios_system_t smsys;
6613a634bfcSVikram Hegde char *mfg, *product, *version;
6623a634bfcSVikram Hegde char **strptr;
6633a634bfcSVikram Hegde int i;
6643a634bfcSVikram Hegde
6653a634bfcSVikram Hegde /* need at least 4 strings for this setting */
6663a634bfcSVikram Hegde if (nblacks < 4) {
6673a634bfcSVikram Hegde return (B_FALSE);
6683a634bfcSVikram Hegde }
6693a634bfcSVikram Hegde
6703a634bfcSVikram Hegde smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL);
6713a634bfcSVikram Hegde if (smhdl == NULL ||
6723a634bfcSVikram Hegde (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR ||
6733a634bfcSVikram Hegde smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) {
6743a634bfcSVikram Hegde return (B_FALSE);
6753a634bfcSVikram Hegde }
6763a634bfcSVikram Hegde
6773a634bfcSVikram Hegde mfg = (char *)sminf.smbi_manufacturer;
6783a634bfcSVikram Hegde product = (char *)sminf.smbi_product;
6793a634bfcSVikram Hegde version = (char *)sminf.smbi_version;
6803a634bfcSVikram Hegde
6813a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n");
6823a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg);
6833a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product);
6843a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version);
6853a634bfcSVikram Hegde
6863a634bfcSVikram Hegde for (i = 0; nblacks - i > 3; i++) {
687e03dceedSVikram Hegde strptr = &black_array[i];
6883a634bfcSVikram Hegde if (strcmp(*strptr++, "SMBIOS") == 0) {
6893a634bfcSVikram Hegde if (strcmp(*strptr++, mfg) == 0 &&
6903a634bfcSVikram Hegde ((char *)strptr == '\0' ||
6913a634bfcSVikram Hegde strcmp(*strptr++, product) == 0) &&
6923a634bfcSVikram Hegde ((char *)strptr == '\0' ||
6933a634bfcSVikram Hegde strcmp(*strptr++, version) == 0)) {
6943a634bfcSVikram Hegde return (B_TRUE);
6953a634bfcSVikram Hegde }
6963a634bfcSVikram Hegde i += 3;
6973a634bfcSVikram Hegde }
6983a634bfcSVikram Hegde }
6993a634bfcSVikram Hegde
7003a634bfcSVikram Hegde return (B_FALSE);
7013a634bfcSVikram Hegde }
7023a634bfcSVikram Hegde
7033a634bfcSVikram Hegde static boolean_t
blacklisted_acpi(void)7043a634bfcSVikram Hegde blacklisted_acpi(void)
7053a634bfcSVikram Hegde {
7063a634bfcSVikram Hegde if (nblacks == 0) {
7073a634bfcSVikram Hegde return (B_FALSE);
7083a634bfcSVikram Hegde }
7093a634bfcSVikram Hegde
7103a634bfcSVikram Hegde return (immu_dmar_blacklisted(black_array, nblacks));
7113a634bfcSVikram Hegde }
7123a634bfcSVikram Hegde
7133a634bfcSVikram Hegde /*
7143a634bfcSVikram Hegde * Check if system is blacklisted by Intel IOMMU driver
7153a634bfcSVikram Hegde * i.e. should Intel IOMMU be disabled on this system
7163a634bfcSVikram Hegde * Currently a system can be blacklistd based on the
7173a634bfcSVikram Hegde * following bases:
7183a634bfcSVikram Hegde *
7193a634bfcSVikram Hegde * 1. DMAR ACPI table information.
7203a634bfcSVikram Hegde * This information includes things like
7213a634bfcSVikram Hegde * manufacturer and revision number. If rootnex.conf
7223a634bfcSVikram Hegde * has matching info set in its blacklist property
7233a634bfcSVikram Hegde * then Intel IOMMu will be disabled
7243a634bfcSVikram Hegde *
7253a634bfcSVikram Hegde * 2. SMBIOS information
7263a634bfcSVikram Hegde *
7273a634bfcSVikram Hegde * 3. Driver installed - useful if a particular
7283a634bfcSVikram Hegde * driver or hardware is toxic if Intel IOMMU
7293a634bfcSVikram Hegde * is turned on.
7303a634bfcSVikram Hegde */
7313a634bfcSVikram Hegde
7323a634bfcSVikram Hegde static void
blacklist_setup(void)7333a634bfcSVikram Hegde blacklist_setup(void)
7343a634bfcSVikram Hegde {
7353a634bfcSVikram Hegde char **string_array;
7363a634bfcSVikram Hegde uint_t nstrings;
7373a634bfcSVikram Hegde
7383a634bfcSVikram Hegde /*
7393a634bfcSVikram Hegde * Check the rootnex.conf blacklist property.
7403a634bfcSVikram Hegde * Fake up a dev_t since searching the global
7413a634bfcSVikram Hegde * property list needs it
7423a634bfcSVikram Hegde */
7433a634bfcSVikram Hegde if (ddi_prop_lookup_string_array(
7443a634bfcSVikram Hegde makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
7453a634bfcSVikram Hegde DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist",
7463a634bfcSVikram Hegde &string_array, &nstrings) != DDI_PROP_SUCCESS) {
7473a634bfcSVikram Hegde return;
7483a634bfcSVikram Hegde }
7493a634bfcSVikram Hegde
7503a634bfcSVikram Hegde /* smallest blacklist criteria works with multiples of 2 */
7513a634bfcSVikram Hegde if (nstrings % 2 != 0) {
7523a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist "
7533a634bfcSVikram Hegde "rootnex.conf: number of strings must be a "
7543a634bfcSVikram Hegde "multiple of 2");
7553a634bfcSVikram Hegde ddi_prop_free(string_array);
7563a634bfcSVikram Hegde return;
7573a634bfcSVikram Hegde }
7583a634bfcSVikram Hegde
7593a634bfcSVikram Hegde black_array = string_array;
7603a634bfcSVikram Hegde nblacks = nstrings;
7613a634bfcSVikram Hegde }
7623a634bfcSVikram Hegde
7633a634bfcSVikram Hegde static void
blacklist_destroy(void)7643a634bfcSVikram Hegde blacklist_destroy(void)
7653a634bfcSVikram Hegde {
7663a634bfcSVikram Hegde if (black_array) {
7673a634bfcSVikram Hegde ddi_prop_free(black_array);
7683a634bfcSVikram Hegde black_array = NULL;
7693a634bfcSVikram Hegde nblacks = 0;
7703a634bfcSVikram Hegde }
77150200e77SFrank Van Der Linden }
7723a634bfcSVikram Hegde
77350200e77SFrank Van Der Linden static char *
immu_alloc_name(const char * str,int instance)77450200e77SFrank Van Der Linden immu_alloc_name(const char *str, int instance)
77550200e77SFrank Van Der Linden {
77650200e77SFrank Van Der Linden size_t slen;
77750200e77SFrank Van Der Linden char *s;
77850200e77SFrank Van Der Linden
77950200e77SFrank Van Der Linden slen = strlen(str) + IMMU_ISTRLEN + 1;
78050200e77SFrank Van Der Linden s = kmem_zalloc(slen, VM_SLEEP);
78150200e77SFrank Van Der Linden if (s != NULL)
78250200e77SFrank Van Der Linden (void) snprintf(s, slen, "%s%d", str, instance);
78350200e77SFrank Van Der Linden
78450200e77SFrank Van Der Linden return (s);
7853a634bfcSVikram Hegde }
7863a634bfcSVikram Hegde
7873a634bfcSVikram Hegde
7883a634bfcSVikram Hegde /*
7893a634bfcSVikram Hegde * Now set all the fields in the order they are defined
7903a634bfcSVikram Hegde * We do this only as a defensive-coding practice, it is
7913a634bfcSVikram Hegde * not a correctness issue.
7923a634bfcSVikram Hegde */
7933a634bfcSVikram Hegde static void *
immu_state_alloc(int seg,void * dmar_unit)7943a634bfcSVikram Hegde immu_state_alloc(int seg, void *dmar_unit)
7953a634bfcSVikram Hegde {
7963a634bfcSVikram Hegde immu_t *immu;
79750200e77SFrank Van Der Linden char *nodename, *hcachename, *pcachename;
79850200e77SFrank Van Der Linden int instance;
7993a634bfcSVikram Hegde
8003a634bfcSVikram Hegde dmar_unit = immu_dmar_walk_units(seg, dmar_unit);
8013a634bfcSVikram Hegde if (dmar_unit == NULL) {
8023a634bfcSVikram Hegde /* No more IOMMUs in this segment */
8033a634bfcSVikram Hegde return (NULL);
8043a634bfcSVikram Hegde }
8053a634bfcSVikram Hegde
8063a634bfcSVikram Hegde immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP);
8073a634bfcSVikram Hegde
8083a634bfcSVikram Hegde mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL);
8093a634bfcSVikram Hegde
8103a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
8113a634bfcSVikram Hegde
8123a634bfcSVikram Hegde immu->immu_dmar_unit = dmar_unit;
8133a634bfcSVikram Hegde immu->immu_dip = immu_dmar_unit_dip(dmar_unit);
8143a634bfcSVikram Hegde
81550200e77SFrank Van Der Linden nodename = ddi_node_name(immu->immu_dip);
81650200e77SFrank Van Der Linden instance = ddi_get_instance(immu->immu_dip);
81750200e77SFrank Van Der Linden
81850200e77SFrank Van Der Linden immu->immu_name = immu_alloc_name(nodename, instance);
81950200e77SFrank Van Der Linden if (immu->immu_name == NULL)
82050200e77SFrank Van Der Linden return (NULL);
82150200e77SFrank Van Der Linden
8223a634bfcSVikram Hegde /*
8233a634bfcSVikram Hegde * the immu_intr_lock mutex is grabbed by the IOMMU
8243a634bfcSVikram Hegde * unit's interrupt handler so we need to use an
8253a634bfcSVikram Hegde * interrupt cookie for the mutex
8263a634bfcSVikram Hegde */
8273a634bfcSVikram Hegde mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER,
8283a634bfcSVikram Hegde (void *)ipltospl(IMMU_INTR_IPL));
8293a634bfcSVikram Hegde
8303a634bfcSVikram Hegde /* IOMMU regs related */
8313a634bfcSVikram Hegde mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL);
832e03dceedSVikram Hegde cv_init(&(immu->immu_regs_cv), NULL, CV_DEFAULT, NULL);
833e03dceedSVikram Hegde immu->immu_regs_busy = B_FALSE;
8343a634bfcSVikram Hegde
8353a634bfcSVikram Hegde /* DVMA related */
8363a634bfcSVikram Hegde immu->immu_dvma_coherent = B_FALSE;
8373a634bfcSVikram Hegde
8383a634bfcSVikram Hegde /* DVMA context related */
8393a634bfcSVikram Hegde rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL);
8403a634bfcSVikram Hegde
8413a634bfcSVikram Hegde /* DVMA domain related */
8423a634bfcSVikram Hegde list_create(&(immu->immu_domain_list), sizeof (domain_t),
8433a634bfcSVikram Hegde offsetof(domain_t, dom_immu_node));
8443a634bfcSVikram Hegde
8453a634bfcSVikram Hegde /* DVMA special device lists */
8463a634bfcSVikram Hegde immu->immu_dvma_gfx_only = B_FALSE;
8473a634bfcSVikram Hegde list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t),
8483a634bfcSVikram Hegde offsetof(immu_devi_t, imd_spc_node));
8493a634bfcSVikram Hegde list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t),
8503a634bfcSVikram Hegde offsetof(immu_devi_t, imd_spc_node));
8513a634bfcSVikram Hegde
8523a634bfcSVikram Hegde /* interrupt remapping related */
8533a634bfcSVikram Hegde mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL);
8543a634bfcSVikram Hegde
8553a634bfcSVikram Hegde /* qinv related */
8563a634bfcSVikram Hegde mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL);
8573a634bfcSVikram Hegde
8583a634bfcSVikram Hegde /*
8593a634bfcSVikram Hegde * insert this immu unit into the system-wide list
8603a634bfcSVikram Hegde */
8613a634bfcSVikram Hegde list_insert_tail(&immu_list, immu);
8623a634bfcSVikram Hegde
86350200e77SFrank Van Der Linden pcachename = immu_alloc_name("immu_pgtable_cache", instance);
86450200e77SFrank Van Der Linden if (pcachename == NULL)
86550200e77SFrank Van Der Linden return (NULL);
86650200e77SFrank Van Der Linden
86750200e77SFrank Van Der Linden hcachename = immu_alloc_name("immu_hdl_cache", instance);
86850200e77SFrank Van Der Linden if (hcachename == NULL)
86950200e77SFrank Van Der Linden return (NULL);
87050200e77SFrank Van Der Linden
87150200e77SFrank Van Der Linden immu->immu_pgtable_cache = kmem_cache_create(pcachename,
87250200e77SFrank Van Der Linden sizeof (pgtable_t), 0, pgtable_ctor, pgtable_dtor, NULL, immu,
87350200e77SFrank Van Der Linden NULL, 0);
87450200e77SFrank Van Der Linden immu->immu_hdl_cache = kmem_cache_create(hcachename,
87550200e77SFrank Van Der Linden sizeof (immu_hdl_priv_t), 64, immu_hdl_priv_ctor,
87650200e77SFrank Van Der Linden NULL, NULL, immu, NULL, 0);
87750200e77SFrank Van Der Linden
8783a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
8793a634bfcSVikram Hegde
88050200e77SFrank Van Der Linden ddi_err(DER_LOG, immu->immu_dip, "unit setup");
8813a634bfcSVikram Hegde
8823a634bfcSVikram Hegde immu_dmar_set_immu(dmar_unit, immu);
8833a634bfcSVikram Hegde
8843a634bfcSVikram Hegde return (dmar_unit);
8853a634bfcSVikram Hegde }
8863a634bfcSVikram Hegde
8873a634bfcSVikram Hegde static void
immu_subsystems_setup(void)8883a634bfcSVikram Hegde immu_subsystems_setup(void)
8893a634bfcSVikram Hegde {
8903a634bfcSVikram Hegde int seg;
8913a634bfcSVikram Hegde void *unit_hdl;
8923a634bfcSVikram Hegde
8933a634bfcSVikram Hegde ddi_err(DER_VERB, NULL,
89450200e77SFrank Van Der Linden "Creating state structures for Intel IOMMU units");
8953a634bfcSVikram Hegde
8963a634bfcSVikram Hegde mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL);
8973a634bfcSVikram Hegde list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node));
8983a634bfcSVikram Hegde
8993a634bfcSVikram Hegde mutex_enter(&immu_lock);
9003a634bfcSVikram Hegde
9013a634bfcSVikram Hegde unit_hdl = NULL;
9023a634bfcSVikram Hegde for (seg = 0; seg < IMMU_MAXSEG; seg++) {
9033a634bfcSVikram Hegde while (unit_hdl = immu_state_alloc(seg, unit_hdl)) {
9043a634bfcSVikram Hegde ;
9053a634bfcSVikram Hegde }
9063a634bfcSVikram Hegde }
9073a634bfcSVikram Hegde
9083a634bfcSVikram Hegde immu_regs_setup(&immu_list); /* subsequent code needs this first */
9093a634bfcSVikram Hegde immu_dvma_setup(&immu_list);
910d2256d26SFrank Van Der Linden if (immu_qinv_setup(&immu_list) == DDI_SUCCESS)
9113a634bfcSVikram Hegde immu_intrmap_setup(&immu_list);
912d2256d26SFrank Van Der Linden else
913d2256d26SFrank Van Der Linden immu_intrmap_enable = B_FALSE;
9143a634bfcSVikram Hegde
9153a634bfcSVikram Hegde mutex_exit(&immu_lock);
9163a634bfcSVikram Hegde }
9173a634bfcSVikram Hegde
9183a634bfcSVikram Hegde /*
9193a634bfcSVikram Hegde * immu_subsystems_startup()
9203a634bfcSVikram Hegde * startup all units that were setup
9213a634bfcSVikram Hegde */
9223a634bfcSVikram Hegde static void
immu_subsystems_startup(void)9233a634bfcSVikram Hegde immu_subsystems_startup(void)
9243a634bfcSVikram Hegde {
9253a634bfcSVikram Hegde immu_t *immu;
92650200e77SFrank Van Der Linden iommulib_ops_t *iommulib_ops;
9273a634bfcSVikram Hegde
9283a634bfcSVikram Hegde mutex_enter(&immu_lock);
9293a634bfcSVikram Hegde
9303a634bfcSVikram Hegde immu_dmar_startup();
9313a634bfcSVikram Hegde
9323a634bfcSVikram Hegde immu = list_head(&immu_list);
9333a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
9343a634bfcSVikram Hegde
9353a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
9363a634bfcSVikram Hegde
9373a634bfcSVikram Hegde immu_intr_register(immu);
9383a634bfcSVikram Hegde immu_dvma_startup(immu);
9393a634bfcSVikram Hegde immu_intrmap_startup(immu);
9403a634bfcSVikram Hegde immu_qinv_startup(immu);
9413a634bfcSVikram Hegde
9423a634bfcSVikram Hegde /*
9433a634bfcSVikram Hegde * Set IOMMU unit's regs to do
9443a634bfcSVikram Hegde * the actual startup. This will
9453a634bfcSVikram Hegde * set immu->immu_running field
9463a634bfcSVikram Hegde * if the unit is successfully
9473a634bfcSVikram Hegde * started
9483a634bfcSVikram Hegde */
9493a634bfcSVikram Hegde immu_regs_startup(immu);
9503a634bfcSVikram Hegde
9513a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
95250200e77SFrank Van Der Linden
95350200e77SFrank Van Der Linden iommulib_ops = kmem_alloc(sizeof (iommulib_ops_t), KM_SLEEP);
95450200e77SFrank Van Der Linden *iommulib_ops = immulib_ops;
95550200e77SFrank Van Der Linden iommulib_ops->ilops_data = (void *)immu;
95650200e77SFrank Van Der Linden (void) iommulib_iommu_register(immu->immu_dip, iommulib_ops,
95750200e77SFrank Van Der Linden &immu->immu_iommulib_handle);
9583a634bfcSVikram Hegde }
9593a634bfcSVikram Hegde
9603a634bfcSVikram Hegde mutex_exit(&immu_lock);
9613a634bfcSVikram Hegde }
9623a634bfcSVikram Hegde
9633a634bfcSVikram Hegde /* ################## Intel IOMMU internal interfaces ###################### */
9643a634bfcSVikram Hegde
9653a634bfcSVikram Hegde /*
9663a634bfcSVikram Hegde * Internal interfaces for IOMMU code (i.e. not exported to rootnex
9673a634bfcSVikram Hegde * or rest of system)
9683a634bfcSVikram Hegde */
9693a634bfcSVikram Hegde
9703a634bfcSVikram Hegde /*
9713a634bfcSVikram Hegde * ddip can be NULL, in which case we walk up until we find the root dip
9723a634bfcSVikram Hegde * NOTE: We never visit the root dip since its not a hardware node
9733a634bfcSVikram Hegde */
9743a634bfcSVikram Hegde int
immu_walk_ancestor(dev_info_t * rdip,dev_info_t * ddip,int (* func)(dev_info_t *,void * arg),void * arg,int * lvlp,immu_flags_t immu_flags)9753a634bfcSVikram Hegde immu_walk_ancestor(
9763a634bfcSVikram Hegde dev_info_t *rdip,
9773a634bfcSVikram Hegde dev_info_t *ddip,
9783a634bfcSVikram Hegde int (*func)(dev_info_t *, void *arg),
9793a634bfcSVikram Hegde void *arg,
9803a634bfcSVikram Hegde int *lvlp,
9813a634bfcSVikram Hegde immu_flags_t immu_flags)
9823a634bfcSVikram Hegde {
9833a634bfcSVikram Hegde dev_info_t *pdip;
9843a634bfcSVikram Hegde int level;
9853a634bfcSVikram Hegde int error = DDI_SUCCESS;
9863a634bfcSVikram Hegde
9873a634bfcSVikram Hegde /* ddip and immu can be NULL */
9883a634bfcSVikram Hegde
9893a634bfcSVikram Hegde /* Hold rdip so that branch is not detached */
9903a634bfcSVikram Hegde ndi_hold_devi(rdip);
9913a634bfcSVikram Hegde for (pdip = rdip, level = 1; pdip && pdip != root_devinfo;
9923a634bfcSVikram Hegde pdip = ddi_get_parent(pdip), level++) {
9933a634bfcSVikram Hegde
9943a634bfcSVikram Hegde if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) {
9953a634bfcSVikram Hegde error = DDI_FAILURE;
9963a634bfcSVikram Hegde break;
9973a634bfcSVikram Hegde }
9983a634bfcSVikram Hegde if (func(pdip, arg) == DDI_WALK_TERMINATE) {
9993a634bfcSVikram Hegde break;
10003a634bfcSVikram Hegde }
10013a634bfcSVikram Hegde if (immu_flags & IMMU_FLAGS_DONTPASS) {
10023a634bfcSVikram Hegde break;
10033a634bfcSVikram Hegde }
10043a634bfcSVikram Hegde if (pdip == ddip) {
10053a634bfcSVikram Hegde break;
10063a634bfcSVikram Hegde }
10073a634bfcSVikram Hegde }
10083a634bfcSVikram Hegde
10093a634bfcSVikram Hegde ndi_rele_devi(rdip);
10103a634bfcSVikram Hegde
10113a634bfcSVikram Hegde if (lvlp)
10123a634bfcSVikram Hegde *lvlp = level;
10133a634bfcSVikram Hegde
10143a634bfcSVikram Hegde return (error);
10153a634bfcSVikram Hegde }
10163a634bfcSVikram Hegde
10173a634bfcSVikram Hegde /* ######################## Intel IOMMU entry points ####################### */
10183a634bfcSVikram Hegde /*
10193a634bfcSVikram Hegde * immu_init()
10203a634bfcSVikram Hegde * called from rootnex_attach(). setup but don't startup the Intel IOMMU
10213a634bfcSVikram Hegde * This is the first function called in Intel IOMMU code
10223a634bfcSVikram Hegde */
10233a634bfcSVikram Hegde void
immu_init(void)10243a634bfcSVikram Hegde immu_init(void)
10253a634bfcSVikram Hegde {
10263a634bfcSVikram Hegde char *phony_reg = "A thing of beauty is a joy forever";
10273a634bfcSVikram Hegde
10283a634bfcSVikram Hegde /* Set some global shorthands that are needed by all of IOMMU code */
10293a634bfcSVikram Hegde root_devinfo = ddi_root_node();
10303a634bfcSVikram Hegde
10313a634bfcSVikram Hegde /*
10323a634bfcSVikram Hegde * Intel IOMMU only supported only if MMU(CPU) page size is ==
10333a634bfcSVikram Hegde * IOMMU pages size.
10343a634bfcSVikram Hegde */
10353a634bfcSVikram Hegde /*LINTED*/
10363a634bfcSVikram Hegde if (MMU_PAGESIZE != IMMU_PAGESIZE) {
10373a634bfcSVikram Hegde ddi_err(DER_WARN, NULL,
10383a634bfcSVikram Hegde "MMU page size (%d) is not equal to\n"
10393a634bfcSVikram Hegde "IOMMU page size (%d). "
10403a634bfcSVikram Hegde "Disabling Intel IOMMU. ",
10413a634bfcSVikram Hegde MMU_PAGESIZE, IMMU_PAGESIZE);
10423a634bfcSVikram Hegde immu_enable = B_FALSE;
10433a634bfcSVikram Hegde return;
10443a634bfcSVikram Hegde }
10453a634bfcSVikram Hegde
10463a634bfcSVikram Hegde /*
10473adb2334SVikram Hegde * Read rootnex.conf options. Do this before
10483adb2334SVikram Hegde * boot options so boot options can override .conf options.
10493adb2334SVikram Hegde */
10503adb2334SVikram Hegde read_conf_options();
10513adb2334SVikram Hegde
10523adb2334SVikram Hegde /*
10533a634bfcSVikram Hegde * retrieve the Intel IOMMU boot options.
10543a634bfcSVikram Hegde * Do this before parsing immu ACPI table
10553a634bfcSVikram Hegde * as a boot option could potentially affect
10563a634bfcSVikram Hegde * ACPI parsing.
10573a634bfcSVikram Hegde */
10583a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n");
10593a634bfcSVikram Hegde read_boot_options();
10603a634bfcSVikram Hegde
10613a634bfcSVikram Hegde /*
10623a634bfcSVikram Hegde * Check the IOMMU enable boot-option first.
10633a634bfcSVikram Hegde * This is so that we can skip parsing the ACPI table
10643a634bfcSVikram Hegde * if necessary because that may cause problems in
10653a634bfcSVikram Hegde * systems with buggy BIOS or ACPI tables
10663a634bfcSVikram Hegde */
10673a634bfcSVikram Hegde if (immu_enable == B_FALSE) {
10683a634bfcSVikram Hegde return;
10693a634bfcSVikram Hegde }
10703a634bfcSVikram Hegde
1071c94adbf9SFrank Van Der Linden if (immu_intrmap_enable == B_TRUE)
1072c94adbf9SFrank Van Der Linden immu_qinv_enable = B_TRUE;
1073c94adbf9SFrank Van Der Linden
10743a634bfcSVikram Hegde /*
10753a634bfcSVikram Hegde * Next, check if the system even has an Intel IOMMU
10763a634bfcSVikram Hegde * We use the presence or absence of the IOMMU ACPI
10773a634bfcSVikram Hegde * table to detect Intel IOMMU.
10783a634bfcSVikram Hegde */
10793a634bfcSVikram Hegde if (immu_dmar_setup() != DDI_SUCCESS) {
10803a634bfcSVikram Hegde immu_enable = B_FALSE;
10813a634bfcSVikram Hegde return;
10823a634bfcSVikram Hegde }
10833a634bfcSVikram Hegde
10849e986f0eSFrank Van Der Linden mapping_list_setup();
10859e986f0eSFrank Van Der Linden
10863a634bfcSVikram Hegde /*
10873a634bfcSVikram Hegde * Check blacklists
10883a634bfcSVikram Hegde */
10893a634bfcSVikram Hegde blacklist_setup();
10903a634bfcSVikram Hegde
10913a634bfcSVikram Hegde if (blacklisted_smbios() == B_TRUE) {
10923a634bfcSVikram Hegde blacklist_destroy();
10933a634bfcSVikram Hegde immu_enable = B_FALSE;
10943a634bfcSVikram Hegde return;
10953a634bfcSVikram Hegde }
10963a634bfcSVikram Hegde
10973a634bfcSVikram Hegde if (blacklisted_driver() == B_TRUE) {
10983a634bfcSVikram Hegde blacklist_destroy();
10993a634bfcSVikram Hegde immu_enable = B_FALSE;
11003a634bfcSVikram Hegde return;
11013a634bfcSVikram Hegde }
11023a634bfcSVikram Hegde
11033a634bfcSVikram Hegde /*
11043a634bfcSVikram Hegde * Read the "raw" DMAR ACPI table to get information
11053a634bfcSVikram Hegde * and convert into a form we can use.
11063a634bfcSVikram Hegde */
11073a634bfcSVikram Hegde if (immu_dmar_parse() != DDI_SUCCESS) {
11083a634bfcSVikram Hegde blacklist_destroy();
11093a634bfcSVikram Hegde immu_enable = B_FALSE;
11103a634bfcSVikram Hegde return;
11113a634bfcSVikram Hegde }
11123a634bfcSVikram Hegde
11133a634bfcSVikram Hegde /*
11143a634bfcSVikram Hegde * now that we have processed the ACPI table
11153a634bfcSVikram Hegde * check if we need to blacklist this system
11163a634bfcSVikram Hegde * based on ACPI info
11173a634bfcSVikram Hegde */
11183a634bfcSVikram Hegde if (blacklisted_acpi() == B_TRUE) {
11193a634bfcSVikram Hegde immu_dmar_destroy();
11203a634bfcSVikram Hegde blacklist_destroy();
11213a634bfcSVikram Hegde immu_enable = B_FALSE;
11223a634bfcSVikram Hegde return;
11233a634bfcSVikram Hegde }
11243a634bfcSVikram Hegde
11253a634bfcSVikram Hegde blacklist_destroy();
11263a634bfcSVikram Hegde
11273a634bfcSVikram Hegde /*
11283a634bfcSVikram Hegde * Check if system has HW quirks.
11293a634bfcSVikram Hegde */
11303a634bfcSVikram Hegde pre_setup_quirks();
11313a634bfcSVikram Hegde
11323a634bfcSVikram Hegde /* Now do the rest of the setup */
11333a634bfcSVikram Hegde immu_subsystems_setup();
11343a634bfcSVikram Hegde
11353a634bfcSVikram Hegde /*
11363a634bfcSVikram Hegde * Now that the IMMU is setup, create a phony
11373a634bfcSVikram Hegde * reg prop so that suspend/resume works
11383a634bfcSVikram Hegde */
11393a634bfcSVikram Hegde if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg",
11403a634bfcSVikram Hegde (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) {
11413a634bfcSVikram Hegde ddi_err(DER_PANIC, NULL, "Failed to create reg prop for "
11423a634bfcSVikram Hegde "rootnex node");
11433a634bfcSVikram Hegde /*NOTREACHED*/
11443a634bfcSVikram Hegde }
11453a634bfcSVikram Hegde
11463a634bfcSVikram Hegde immu_setup = B_TRUE;
11473a634bfcSVikram Hegde }
11483a634bfcSVikram Hegde
11493a634bfcSVikram Hegde /*
11503a634bfcSVikram Hegde * immu_startup()
11513a634bfcSVikram Hegde * called directly by boot code to startup
11523a634bfcSVikram Hegde * all units of the IOMMU
11533a634bfcSVikram Hegde */
11543a634bfcSVikram Hegde void
immu_startup(void)11553a634bfcSVikram Hegde immu_startup(void)
11563a634bfcSVikram Hegde {
11573a634bfcSVikram Hegde /*
11583a634bfcSVikram Hegde * If IOMMU is disabled, do nothing
11593a634bfcSVikram Hegde */
11603a634bfcSVikram Hegde if (immu_enable == B_FALSE) {
11613a634bfcSVikram Hegde return;
11623a634bfcSVikram Hegde }
11633a634bfcSVikram Hegde
11643a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
11653a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, "
116650200e77SFrank Van Der Linden "skipping IOMMU startup");
11673a634bfcSVikram Hegde return;
11683a634bfcSVikram Hegde }
11693a634bfcSVikram Hegde
11703a634bfcSVikram Hegde pre_startup_quirks();
11713a634bfcSVikram Hegde
11723a634bfcSVikram Hegde ddi_err(DER_CONT, NULL,
11733a634bfcSVikram Hegde "?Starting Intel IOMMU (dmar) units...\n");
11743a634bfcSVikram Hegde
11753a634bfcSVikram Hegde immu_subsystems_startup();
11763a634bfcSVikram Hegde
11773a634bfcSVikram Hegde immu_running = B_TRUE;
11783a634bfcSVikram Hegde }
11793a634bfcSVikram Hegde
11803a634bfcSVikram Hegde /*
11813a634bfcSVikram Hegde * Hook to notify IOMMU code of device tree changes
11823a634bfcSVikram Hegde */
11833a634bfcSVikram Hegde void
immu_device_tree_changed(void)11843a634bfcSVikram Hegde immu_device_tree_changed(void)
11853a634bfcSVikram Hegde {
11863a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
11873a634bfcSVikram Hegde return;
11883a634bfcSVikram Hegde }
11893a634bfcSVikram Hegde
11903a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Intel IOMMU currently "
11913a634bfcSVikram Hegde "does not use device tree updates");
11923a634bfcSVikram Hegde }
11933a634bfcSVikram Hegde
11943a634bfcSVikram Hegde /*
11953a634bfcSVikram Hegde * Hook to notify IOMMU code of memory changes
11963a634bfcSVikram Hegde */
11973a634bfcSVikram Hegde void
immu_physmem_update(uint64_t addr,uint64_t size)11983a634bfcSVikram Hegde immu_physmem_update(uint64_t addr, uint64_t size)
11993a634bfcSVikram Hegde {
12003a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
12013a634bfcSVikram Hegde return;
12023a634bfcSVikram Hegde }
12033a634bfcSVikram Hegde immu_dvma_physmem_update(addr, size);
12043a634bfcSVikram Hegde }
12053a634bfcSVikram Hegde
12063a634bfcSVikram Hegde /*
12073a634bfcSVikram Hegde * immu_quiesce()
12083a634bfcSVikram Hegde * quiesce all units that are running
12093a634bfcSVikram Hegde */
12103a634bfcSVikram Hegde int
immu_quiesce(void)12113a634bfcSVikram Hegde immu_quiesce(void)
12123a634bfcSVikram Hegde {
12133a634bfcSVikram Hegde immu_t *immu;
12143a634bfcSVikram Hegde int ret = DDI_SUCCESS;
12153a634bfcSVikram Hegde
12163a634bfcSVikram Hegde mutex_enter(&immu_lock);
12173a634bfcSVikram Hegde
1218*96992ee7SEthindra Ramamurthy if (immu_running == B_FALSE) {
1219*96992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12203a634bfcSVikram Hegde return (DDI_SUCCESS);
1221*96992ee7SEthindra Ramamurthy }
12223a634bfcSVikram Hegde
12233a634bfcSVikram Hegde immu = list_head(&immu_list);
12243a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
12253a634bfcSVikram Hegde
12263a634bfcSVikram Hegde /* if immu is not running, we dont quiesce */
12273a634bfcSVikram Hegde if (immu->immu_regs_running == B_FALSE)
12283a634bfcSVikram Hegde continue;
12293a634bfcSVikram Hegde
12303a634bfcSVikram Hegde /* flush caches */
12313a634bfcSVikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
123250200e77SFrank Van Der Linden immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
123350200e77SFrank Van Der Linden immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
12343a634bfcSVikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
12353a634bfcSVikram Hegde immu_regs_wbf_flush(immu);
12363a634bfcSVikram Hegde
12373a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
12383a634bfcSVikram Hegde
12393a634bfcSVikram Hegde /*
12403a634bfcSVikram Hegde * Set IOMMU unit's regs to do
12413a634bfcSVikram Hegde * the actual shutdown.
12423a634bfcSVikram Hegde */
12433a634bfcSVikram Hegde immu_regs_shutdown(immu);
12443a634bfcSVikram Hegde immu_regs_suspend(immu);
12453a634bfcSVikram Hegde
12463a634bfcSVikram Hegde /* if immu is still running, we failed */
12473a634bfcSVikram Hegde if (immu->immu_regs_running == B_TRUE)
12483a634bfcSVikram Hegde ret = DDI_FAILURE;
12493a634bfcSVikram Hegde else
12503a634bfcSVikram Hegde immu->immu_regs_quiesced = B_TRUE;
12513a634bfcSVikram Hegde
12523a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
12533a634bfcSVikram Hegde }
12543a634bfcSVikram Hegde
12553a634bfcSVikram Hegde if (ret == DDI_SUCCESS) {
12563a634bfcSVikram Hegde immu_running = B_FALSE;
12573a634bfcSVikram Hegde immu_quiesced = B_TRUE;
12583a634bfcSVikram Hegde }
1259*96992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12603a634bfcSVikram Hegde
12613a634bfcSVikram Hegde return (ret);
12623a634bfcSVikram Hegde }
12633a634bfcSVikram Hegde
12643a634bfcSVikram Hegde /*
12653a634bfcSVikram Hegde * immu_unquiesce()
12663a634bfcSVikram Hegde * unquiesce all units
12673a634bfcSVikram Hegde */
12683a634bfcSVikram Hegde int
immu_unquiesce(void)12693a634bfcSVikram Hegde immu_unquiesce(void)
12703a634bfcSVikram Hegde {
12713a634bfcSVikram Hegde immu_t *immu;
12723a634bfcSVikram Hegde int ret = DDI_SUCCESS;
12733a634bfcSVikram Hegde
12743a634bfcSVikram Hegde mutex_enter(&immu_lock);
12753a634bfcSVikram Hegde
1276*96992ee7SEthindra Ramamurthy if (immu_quiesced == B_FALSE) {
1277*96992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12783a634bfcSVikram Hegde return (DDI_SUCCESS);
1279*96992ee7SEthindra Ramamurthy }
12803a634bfcSVikram Hegde
12813a634bfcSVikram Hegde immu = list_head(&immu_list);
12823a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
12833a634bfcSVikram Hegde
12843a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
12853a634bfcSVikram Hegde
12863a634bfcSVikram Hegde /* if immu was not quiesced, i.e was not running before */
1287e03dceedSVikram Hegde if (immu->immu_regs_quiesced == B_FALSE) {
1288e03dceedSVikram Hegde mutex_exit(&(immu->immu_lock));
12893a634bfcSVikram Hegde continue;
1290e03dceedSVikram Hegde }
12913a634bfcSVikram Hegde
12923a634bfcSVikram Hegde if (immu_regs_resume(immu) != DDI_SUCCESS) {
12933a634bfcSVikram Hegde ret = DDI_FAILURE;
1294e03dceedSVikram Hegde mutex_exit(&(immu->immu_lock));
12953a634bfcSVikram Hegde continue;
12963a634bfcSVikram Hegde }
12973a634bfcSVikram Hegde
12983a634bfcSVikram Hegde /* flush caches before unquiesce */
12993a634bfcSVikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
130050200e77SFrank Van Der Linden immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
130150200e77SFrank Van Der Linden immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
13023a634bfcSVikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
13033a634bfcSVikram Hegde
13043a634bfcSVikram Hegde /*
13053a634bfcSVikram Hegde * Set IOMMU unit's regs to do
13063a634bfcSVikram Hegde * the actual startup. This will
13073a634bfcSVikram Hegde * set immu->immu_regs_running field
13083a634bfcSVikram Hegde * if the unit is successfully
13093a634bfcSVikram Hegde * started
13103a634bfcSVikram Hegde */
13113a634bfcSVikram Hegde immu_regs_startup(immu);
13123a634bfcSVikram Hegde
13133a634bfcSVikram Hegde if (immu->immu_regs_running == B_FALSE) {
13143a634bfcSVikram Hegde ret = DDI_FAILURE;
13153a634bfcSVikram Hegde } else {
13163a634bfcSVikram Hegde immu_quiesced = B_TRUE;
13173a634bfcSVikram Hegde immu_running = B_TRUE;
13183a634bfcSVikram Hegde immu->immu_regs_quiesced = B_FALSE;
13193a634bfcSVikram Hegde }
13203a634bfcSVikram Hegde
13213a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
13223a634bfcSVikram Hegde }
13233a634bfcSVikram Hegde
13243a634bfcSVikram Hegde mutex_exit(&immu_lock);
13253a634bfcSVikram Hegde
13263a634bfcSVikram Hegde return (ret);
13273a634bfcSVikram Hegde }
13283a634bfcSVikram Hegde
132950200e77SFrank Van Der Linden void
immu_init_inv_wait(immu_inv_wait_t * iwp,const char * name,boolean_t sync)133050200e77SFrank Van Der Linden immu_init_inv_wait(immu_inv_wait_t *iwp, const char *name, boolean_t sync)
133150200e77SFrank Van Der Linden {
133250200e77SFrank Van Der Linden caddr_t vaddr;
133350200e77SFrank Van Der Linden uint64_t paddr;
133450200e77SFrank Van Der Linden
133550200e77SFrank Van Der Linden iwp->iwp_sync = sync;
133650200e77SFrank Van Der Linden
133750200e77SFrank Van Der Linden vaddr = (caddr_t)&iwp->iwp_vstatus;
133850200e77SFrank Van Der Linden paddr = pfn_to_pa(hat_getpfnum(kas.a_hat, vaddr));
133950200e77SFrank Van Der Linden paddr += ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
134050200e77SFrank Van Der Linden
134150200e77SFrank Van Der Linden iwp->iwp_pstatus = paddr;
134250200e77SFrank Van Der Linden iwp->iwp_name = name;
134350200e77SFrank Van Der Linden }
134450200e77SFrank Van Der Linden
13453a634bfcSVikram Hegde /* ############## END Intel IOMMU entry points ################## */
1346