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
303fe80ca4SDan Cross /*
313fe80ca4SDan Cross * Copyright 2023 Oxide Computer Company
323fe80ca4SDan Cross */
333fe80ca4SDan Cross
343a634bfcSVikram Hegde /*
353a634bfcSVikram Hegde * Intel IOMMU implementation
363a634bfcSVikram Hegde * This file contains Intel IOMMU code exported
373a634bfcSVikram Hegde * to the rest of the system and code that deals
383a634bfcSVikram Hegde * with the Intel IOMMU as a whole.
393a634bfcSVikram Hegde */
403a634bfcSVikram Hegde
413a634bfcSVikram Hegde #include <sys/conf.h>
423a634bfcSVikram Hegde #include <sys/modctl.h>
433a634bfcSVikram Hegde #include <sys/pci.h>
443a634bfcSVikram Hegde #include <sys/pci_impl.h>
453a634bfcSVikram Hegde #include <sys/sysmacros.h>
463a634bfcSVikram Hegde #include <sys/ddi.h>
473a634bfcSVikram Hegde #include <sys/ddidmareq.h>
483a634bfcSVikram Hegde #include <sys/ddi_impldefs.h>
493a634bfcSVikram Hegde #include <sys/ddifm.h>
503a634bfcSVikram Hegde #include <sys/sunndi.h>
513a634bfcSVikram Hegde #include <sys/debug.h>
523a634bfcSVikram Hegde #include <sys/fm/protocol.h>
533a634bfcSVikram Hegde #include <sys/note.h>
543a634bfcSVikram Hegde #include <sys/apic.h>
553a634bfcSVikram Hegde #include <vm/hat_i86.h>
563a634bfcSVikram Hegde #include <sys/smp_impldefs.h>
573a634bfcSVikram Hegde #include <sys/spl.h>
583a634bfcSVikram Hegde #include <sys/archsystm.h>
593a634bfcSVikram Hegde #include <sys/x86_archext.h>
603a634bfcSVikram Hegde #include <sys/avl.h>
613a634bfcSVikram Hegde #include <sys/bootconf.h>
623a634bfcSVikram Hegde #include <sys/bootinfo.h>
633a634bfcSVikram Hegde #include <sys/atomic.h>
643a634bfcSVikram Hegde #include <sys/immu.h>
653a634bfcSVikram Hegde /* ########################### Globals and tunables ######################## */
663a634bfcSVikram Hegde /*
673a634bfcSVikram Hegde * Global switches (boolean) that can be toggled either via boot options
683a634bfcSVikram Hegde * or via /etc/system or kmdb
693a634bfcSVikram Hegde */
703a634bfcSVikram Hegde
713a634bfcSVikram Hegde /* Various features */
723adb2334SVikram Hegde boolean_t immu_enable = B_TRUE;
733a634bfcSVikram Hegde boolean_t immu_dvma_enable = B_TRUE;
743a634bfcSVikram Hegde
753a634bfcSVikram Hegde /* accessed in other files so not static */
763a634bfcSVikram Hegde boolean_t immu_gfxdvma_enable = B_TRUE;
773a634bfcSVikram Hegde boolean_t immu_intrmap_enable = B_FALSE;
7850200e77SFrank Van Der Linden boolean_t immu_qinv_enable = B_TRUE;
793a634bfcSVikram Hegde
803a634bfcSVikram Hegde /* various quirks that need working around */
813a634bfcSVikram Hegde
823a634bfcSVikram Hegde /* XXX We always map page 0 read/write for now */
833a634bfcSVikram Hegde boolean_t immu_quirk_usbpage0 = B_TRUE;
843a634bfcSVikram Hegde boolean_t immu_quirk_usbrmrr = B_TRUE;
853a634bfcSVikram Hegde boolean_t immu_quirk_usbfullpa;
863a634bfcSVikram Hegde boolean_t immu_quirk_mobile4;
873a634bfcSVikram Hegde
883a634bfcSVikram Hegde /* debug messages */
893a634bfcSVikram Hegde boolean_t immu_dmar_print;
903a634bfcSVikram Hegde
91e03dceedSVikram Hegde /* Tunables */
92e03dceedSVikram Hegde int64_t immu_flush_gran = 5;
93e03dceedSVikram Hegde
949e986f0eSFrank Van Der Linden immu_flags_t immu_global_dvma_flags;
959e986f0eSFrank Van Der Linden
963a634bfcSVikram Hegde /* ############ END OPTIONS section ################ */
973a634bfcSVikram Hegde
983a634bfcSVikram Hegde /*
993a634bfcSVikram Hegde * Global used internally by Intel IOMMU code
1003a634bfcSVikram Hegde */
1013a634bfcSVikram Hegde dev_info_t *root_devinfo;
1023a634bfcSVikram Hegde kmutex_t immu_lock;
1033a634bfcSVikram Hegde list_t immu_list;
1043a634bfcSVikram Hegde boolean_t immu_setup;
1053a634bfcSVikram Hegde boolean_t immu_running;
1063a634bfcSVikram Hegde boolean_t immu_quiesced;
1073a634bfcSVikram Hegde
1083a634bfcSVikram Hegde /* ######################## END Globals and tunables ###################### */
1093a634bfcSVikram Hegde /* Globals used only in this file */
1103a634bfcSVikram Hegde static char **black_array;
1113a634bfcSVikram Hegde static uint_t nblacks;
1129e986f0eSFrank Van Der Linden
1139e986f0eSFrank Van Der Linden static char **unity_driver_array;
1149e986f0eSFrank Van Der Linden static uint_t nunity;
1159e986f0eSFrank Van Der Linden static char **xlate_driver_array;
1169e986f0eSFrank Van Der Linden static uint_t nxlate;
11750200e77SFrank Van Der Linden
11850200e77SFrank Van Der Linden static char **premap_driver_array;
11950200e77SFrank Van Der Linden static uint_t npremap;
12050200e77SFrank Van Der Linden static char **nopremap_driver_array;
12150200e77SFrank Van Der Linden static uint_t nnopremap;
1223a634bfcSVikram Hegde /* ###################### Utility routines ############################# */
1233a634bfcSVikram Hegde
1243a634bfcSVikram Hegde /*
1253a634bfcSVikram Hegde * Check if the device has mobile 4 chipset
1263a634bfcSVikram Hegde */
1273a634bfcSVikram Hegde static int
check_mobile4(dev_info_t * dip,void * arg)1283a634bfcSVikram Hegde check_mobile4(dev_info_t *dip, void *arg)
1293a634bfcSVikram Hegde {
1303a634bfcSVikram Hegde _NOTE(ARGUNUSED(arg));
1313a634bfcSVikram Hegde int vendor, device;
1323a634bfcSVikram Hegde int *ip = (int *)arg;
1333a634bfcSVikram Hegde
1343a634bfcSVikram Hegde vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1353a634bfcSVikram Hegde "vendor-id", -1);
1363a634bfcSVikram Hegde device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1373a634bfcSVikram Hegde "device-id", -1);
1383a634bfcSVikram Hegde
1393a634bfcSVikram Hegde if (vendor == 0x8086 && device == 0x2a40) {
1403a634bfcSVikram Hegde *ip = B_TRUE;
14150200e77SFrank Van Der Linden ddi_err(DER_NOTE, dip, "iommu: Mobile 4 chipset detected. "
1423a634bfcSVikram Hegde "Force setting IOMMU write buffer");
1433a634bfcSVikram Hegde return (DDI_WALK_TERMINATE);
1443a634bfcSVikram Hegde } else {
1453a634bfcSVikram Hegde return (DDI_WALK_CONTINUE);
1463a634bfcSVikram Hegde }
1473a634bfcSVikram Hegde }
1483a634bfcSVikram Hegde
1493a634bfcSVikram Hegde static void
map_bios_rsvd_mem(dev_info_t * dip)1503a634bfcSVikram Hegde map_bios_rsvd_mem(dev_info_t *dip)
1513a634bfcSVikram Hegde {
1523a634bfcSVikram Hegde struct memlist *mp;
15350200e77SFrank Van Der Linden
15450200e77SFrank Van Der Linden /*
15550200e77SFrank Van Der Linden * Make sure the domain for the device is set up before
15650200e77SFrank Van Der Linden * mapping anything.
15750200e77SFrank Van Der Linden */
15850200e77SFrank Van Der Linden (void) immu_dvma_device_setup(dip, 0);
1593a634bfcSVikram Hegde
1603a634bfcSVikram Hegde memlist_read_lock();
1613a634bfcSVikram Hegde
1623a634bfcSVikram Hegde mp = bios_rsvd;
1633a634bfcSVikram Hegde while (mp != NULL) {
164e03dceedSVikram Hegde memrng_t mrng = {0};
1653a634bfcSVikram Hegde
16650200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Mapping BIOS rsvd range "
1673a634bfcSVikram Hegde "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address,
1683a634bfcSVikram Hegde mp->ml_address + mp->ml_size);
1693a634bfcSVikram Hegde
170e03dceedSVikram Hegde mrng.mrng_start = IMMU_ROUNDOWN(mp->ml_address);
171e03dceedSVikram Hegde mrng.mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE;
1723a634bfcSVikram Hegde
17350200e77SFrank Van Der Linden (void) immu_map_memrange(dip, &mrng);
1743a634bfcSVikram Hegde
1753a634bfcSVikram Hegde mp = mp->ml_next;
1763a634bfcSVikram Hegde }
1773a634bfcSVikram Hegde
1783a634bfcSVikram Hegde memlist_read_unlock();
1793a634bfcSVikram Hegde }
1803a634bfcSVikram Hegde
181e03dceedSVikram Hegde
182e03dceedSVikram Hegde /*
1839e986f0eSFrank Van Der Linden * Check if the driver requests a specific type of mapping.
184e03dceedSVikram Hegde */
185e03dceedSVikram Hegde /*ARGSUSED*/
186e03dceedSVikram Hegde static void
check_conf(dev_info_t * dip,void * arg)1879e986f0eSFrank Van Der Linden check_conf(dev_info_t *dip, void *arg)
188e03dceedSVikram Hegde {
1899e986f0eSFrank Van Der Linden immu_devi_t *immu_devi;
1909e986f0eSFrank Van Der Linden const char *dname;
1919e986f0eSFrank Van Der Linden uint_t i;
19250200e77SFrank Van Der Linden int hasmapprop = 0, haspreprop = 0;
19350200e77SFrank Van Der Linden boolean_t old_premap;
194e03dceedSVikram Hegde
195e03dceedSVikram Hegde /*
1969e986f0eSFrank Van Der Linden * Only PCI devices can use an IOMMU. Legacy ISA devices
1979e986f0eSFrank Van Der Linden * are handled in check_lpc.
198e03dceedSVikram Hegde */
1999e986f0eSFrank Van Der Linden if (!DEVI_IS_PCI(dip))
2009e986f0eSFrank Van Der Linden return;
2019e986f0eSFrank Van Der Linden
2029e986f0eSFrank Van Der Linden dname = ddi_driver_name(dip);
2039e986f0eSFrank Van Der Linden if (dname == NULL)
2049e986f0eSFrank Van Der Linden return;
2059e986f0eSFrank Van Der Linden immu_devi = immu_devi_get(dip);
2069e986f0eSFrank Van Der Linden
2079e986f0eSFrank Van Der Linden for (i = 0; i < nunity; i++) {
2089e986f0eSFrank Van Der Linden if (strcmp(unity_driver_array[i], dname) == 0) {
20950200e77SFrank Van Der Linden hasmapprop = 1;
2109e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
2119e986f0eSFrank Van Der Linden }
2129e986f0eSFrank Van Der Linden }
2139e986f0eSFrank Van Der Linden
2149e986f0eSFrank Van Der Linden for (i = 0; i < nxlate; i++) {
2159e986f0eSFrank Van Der Linden if (strcmp(xlate_driver_array[i], dname) == 0) {
21650200e77SFrank Van Der Linden hasmapprop = 1;
2179e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags &= ~IMMU_FLAGS_UNITY;
218e03dceedSVikram Hegde }
219e03dceedSVikram Hegde }
2209e986f0eSFrank Van Der Linden
22150200e77SFrank Van Der Linden old_premap = immu_devi->imd_use_premap;
22250200e77SFrank Van Der Linden
22350200e77SFrank Van Der Linden for (i = 0; i < nnopremap; i++) {
22450200e77SFrank Van Der Linden if (strcmp(nopremap_driver_array[i], dname) == 0) {
22550200e77SFrank Van Der Linden haspreprop = 1;
22650200e77SFrank Van Der Linden immu_devi->imd_use_premap = B_FALSE;
22750200e77SFrank Van Der Linden }
22850200e77SFrank Van Der Linden }
22950200e77SFrank Van Der Linden
23050200e77SFrank Van Der Linden for (i = 0; i < npremap; i++) {
23150200e77SFrank Van Der Linden if (strcmp(premap_driver_array[i], dname) == 0) {
23250200e77SFrank Van Der Linden haspreprop = 1;
23350200e77SFrank Van Der Linden immu_devi->imd_use_premap = B_TRUE;
23450200e77SFrank Van Der Linden }
23550200e77SFrank Van Der Linden }
23650200e77SFrank Van Der Linden
2379e986f0eSFrank Van Der Linden /*
2389e986f0eSFrank Van Der Linden * Report if we changed the value from the default.
2399e986f0eSFrank Van Der Linden */
24050200e77SFrank Van Der Linden if (hasmapprop && (immu_devi->imd_dvma_flags ^ immu_global_dvma_flags))
2419e986f0eSFrank Van Der Linden ddi_err(DER_LOG, dip, "using %s DVMA mapping",
2429e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY ?
2439e986f0eSFrank Van Der Linden DDI_DVMA_MAPTYPE_UNITY : DDI_DVMA_MAPTYPE_XLATE);
24450200e77SFrank Van Der Linden
24550200e77SFrank Van Der Linden if (haspreprop && (immu_devi->imd_use_premap != old_premap))
24650200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "%susing premapped DVMA space",
24750200e77SFrank Van Der Linden immu_devi->imd_use_premap ? "" : "not ");
248e03dceedSVikram Hegde }
249e03dceedSVikram Hegde
2503a634bfcSVikram Hegde /*
2513a634bfcSVikram Hegde * Check if the device is USB controller
2523a634bfcSVikram Hegde */
2533a634bfcSVikram Hegde /*ARGSUSED*/
2543a634bfcSVikram Hegde static void
check_usb(dev_info_t * dip,void * arg)2553a634bfcSVikram Hegde check_usb(dev_info_t *dip, void *arg)
2563a634bfcSVikram Hegde {
2573a634bfcSVikram Hegde const char *drv = ddi_driver_name(dip);
2589e986f0eSFrank Van Der Linden immu_devi_t *immu_devi;
2599e986f0eSFrank Van Der Linden
2603a634bfcSVikram Hegde
261993e3fafSRobert Mustacchi /*
262993e3fafSRobert Mustacchi * It's not clear if xHCI really needs these quirks; however, to be on
263993e3fafSRobert Mustacchi * the safe side until we know for certain we add it to the list below.
264993e3fafSRobert Mustacchi */
2653a634bfcSVikram Hegde if (drv == NULL ||
2663a634bfcSVikram Hegde (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 &&
267993e3fafSRobert Mustacchi strcmp(drv, "ehci") != 0 && strcmp(drv, "xhci") != 0)) {
2683a634bfcSVikram Hegde return;
2693a634bfcSVikram Hegde }
2703a634bfcSVikram Hegde
2719e986f0eSFrank Van Der Linden immu_devi = immu_devi_get(dip);
2729e986f0eSFrank Van Der Linden
2739e986f0eSFrank Van Der Linden /*
2749e986f0eSFrank Van Der Linden * If unit mappings are already specified, globally or
2759e986f0eSFrank Van Der Linden * locally, we're done here, since that covers both
2769e986f0eSFrank Van Der Linden * quirks below.
2779e986f0eSFrank Van Der Linden */
2789e986f0eSFrank Van Der Linden if (immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY)
2799e986f0eSFrank Van Der Linden return;
2809e986f0eSFrank Van Der Linden
2813a634bfcSVikram Hegde /* This must come first since it does unity mapping */
2823a634bfcSVikram Hegde if (immu_quirk_usbfullpa == B_TRUE) {
2839e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
2849e986f0eSFrank Van Der Linden } else if (immu_quirk_usbrmrr == B_TRUE) {
2853a634bfcSVikram Hegde ddi_err(DER_LOG, dip, "Applying USB RMRR quirk");
2863a634bfcSVikram Hegde map_bios_rsvd_mem(dip);
2873a634bfcSVikram Hegde }
2883a634bfcSVikram Hegde }
2893a634bfcSVikram Hegde
2903a634bfcSVikram Hegde /*
2913a634bfcSVikram Hegde * Check if the device is a LPC device
2923a634bfcSVikram Hegde */
2933a634bfcSVikram Hegde /*ARGSUSED*/
2943a634bfcSVikram Hegde static void
check_lpc(dev_info_t * dip,void * arg)2953a634bfcSVikram Hegde check_lpc(dev_info_t *dip, void *arg)
2963a634bfcSVikram Hegde {
2973a634bfcSVikram Hegde immu_devi_t *immu_devi;
2983a634bfcSVikram Hegde
2993a634bfcSVikram Hegde immu_devi = immu_devi_get(dip);
3003a634bfcSVikram Hegde if (immu_devi->imd_lpc == B_TRUE) {
30150200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Found LPC device");
3023a634bfcSVikram Hegde /* This will put the immu_devi on the LPC "specials" list */
30350200e77SFrank Van Der Linden (void) immu_dvma_device_setup(dip, IMMU_FLAGS_SLEEP);
3043a634bfcSVikram Hegde }
3053a634bfcSVikram Hegde }
3063a634bfcSVikram Hegde
3073a634bfcSVikram Hegde /*
3083a634bfcSVikram Hegde * Check if the device is a GFX device
3093a634bfcSVikram Hegde */
3103a634bfcSVikram Hegde /*ARGSUSED*/
3113a634bfcSVikram Hegde static void
check_gfx(dev_info_t * dip,void * arg)3123a634bfcSVikram Hegde check_gfx(dev_info_t *dip, void *arg)
3133a634bfcSVikram Hegde {
3143a634bfcSVikram Hegde immu_devi_t *immu_devi;
3153a634bfcSVikram Hegde
3163a634bfcSVikram Hegde immu_devi = immu_devi_get(dip);
3173a634bfcSVikram Hegde if (immu_devi->imd_display == B_TRUE) {
3189e986f0eSFrank Van Der Linden immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
31950200e77SFrank Van Der Linden ddi_err(DER_LOG, dip, "iommu: Found GFX device");
3203a634bfcSVikram Hegde /* This will put the immu_devi on the GFX "specials" list */
3213a634bfcSVikram Hegde (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP);
3223a634bfcSVikram Hegde }
3233a634bfcSVikram Hegde }
3243a634bfcSVikram Hegde
3253a634bfcSVikram Hegde static void
walk_tree(int (* f)(dev_info_t *,void *),void * arg)3263a634bfcSVikram Hegde walk_tree(int (*f)(dev_info_t *, void *), void *arg)
3273a634bfcSVikram Hegde {
3283fe80ca4SDan Cross ndi_devi_enter(root_devinfo);
3293a634bfcSVikram Hegde ddi_walk_devs(ddi_get_child(root_devinfo), f, arg);
3303fe80ca4SDan Cross ndi_devi_exit(root_devinfo);
3313a634bfcSVikram Hegde }
3323a634bfcSVikram Hegde
3333a634bfcSVikram Hegde static int
check_pre_setup_quirks(dev_info_t * dip,void * arg)3343a634bfcSVikram Hegde check_pre_setup_quirks(dev_info_t *dip, void *arg)
3353a634bfcSVikram Hegde {
3363a634bfcSVikram Hegde /* just 1 check right now */
3373a634bfcSVikram Hegde return (check_mobile4(dip, arg));
3383a634bfcSVikram Hegde }
3393a634bfcSVikram Hegde
3403a634bfcSVikram Hegde static int
check_pre_startup_quirks(dev_info_t * dip,void * arg)3413a634bfcSVikram Hegde check_pre_startup_quirks(dev_info_t *dip, void *arg)
3423a634bfcSVikram Hegde {
3433a634bfcSVikram Hegde if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) {
3443a634bfcSVikram Hegde ddi_err(DER_PANIC, dip, "Failed to get immu_devi");
3453a634bfcSVikram Hegde }
3463a634bfcSVikram Hegde
3473a634bfcSVikram Hegde check_gfx(dip, arg);
3483a634bfcSVikram Hegde
3493a634bfcSVikram Hegde check_lpc(dip, arg);
3503a634bfcSVikram Hegde
3519e986f0eSFrank Van Der Linden check_conf(dip, arg);
3523a634bfcSVikram Hegde
3539e986f0eSFrank Van Der Linden check_usb(dip, arg);
354e03dceedSVikram Hegde
3553a634bfcSVikram Hegde return (DDI_WALK_CONTINUE);
3563a634bfcSVikram Hegde }
3573a634bfcSVikram Hegde
3583a634bfcSVikram Hegde static void
pre_setup_quirks(void)3593a634bfcSVikram Hegde pre_setup_quirks(void)
3603a634bfcSVikram Hegde {
3613a634bfcSVikram Hegde walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4);
3623a634bfcSVikram Hegde }
3633a634bfcSVikram Hegde
3643a634bfcSVikram Hegde static void
pre_startup_quirks(void)3653a634bfcSVikram Hegde pre_startup_quirks(void)
3663a634bfcSVikram Hegde {
3673a634bfcSVikram Hegde walk_tree(check_pre_startup_quirks, NULL);
3683a634bfcSVikram Hegde
3693a634bfcSVikram Hegde immu_dmar_rmrr_map();
3703a634bfcSVikram Hegde }
3713a634bfcSVikram Hegde
3729e986f0eSFrank Van Der Linden static int
get_conf_str(char * bopt,char ** val)3739e986f0eSFrank Van Der Linden get_conf_str(char *bopt, char **val)
3749e986f0eSFrank Van Der Linden {
3759e986f0eSFrank Van Der Linden int ret;
3769e986f0eSFrank Van Der Linden
3779e986f0eSFrank Van Der Linden /*
3789e986f0eSFrank Van Der Linden * Check the rootnex.conf property
3799e986f0eSFrank Van Der Linden * Fake up a dev_t since searching the global
3809e986f0eSFrank Van Der Linden * property list needs it
3819e986f0eSFrank Van Der Linden */
3829e986f0eSFrank Van Der Linden ret = ddi_prop_lookup_string(
3839e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0),
3849e986f0eSFrank Van Der Linden root_devinfo, DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
3859e986f0eSFrank Van Der Linden bopt, val);
3869e986f0eSFrank Van Der Linden
3879e986f0eSFrank Van Der Linden return (ret);
3889e986f0eSFrank Van Der Linden }
3899e986f0eSFrank Van Der Linden
3903adb2334SVikram Hegde /*
3913adb2334SVikram Hegde * get_conf_opt()
392*d5ebc493SDan Cross * get a rootnex.conf setting (always a boolean)
3933adb2334SVikram Hegde */
3943adb2334SVikram Hegde static void
get_conf_opt(char * bopt,boolean_t * kvar)3953adb2334SVikram Hegde get_conf_opt(char *bopt, boolean_t *kvar)
3963adb2334SVikram Hegde {
3973adb2334SVikram Hegde char *val = NULL;
3983adb2334SVikram Hegde
3993adb2334SVikram Hegde /*
4003adb2334SVikram Hegde * Check the rootnex.conf property
4013adb2334SVikram Hegde * Fake up a dev_t since searching the global
4023adb2334SVikram Hegde * property list needs it
4033adb2334SVikram Hegde */
4049e986f0eSFrank Van Der Linden
4059e986f0eSFrank Van Der Linden if (get_conf_str(bopt, &val) != DDI_PROP_SUCCESS)
4063adb2334SVikram Hegde return;
4073adb2334SVikram Hegde
4083adb2334SVikram Hegde if (strcmp(val, "true") == 0) {
4093adb2334SVikram Hegde *kvar = B_TRUE;
4103adb2334SVikram Hegde } else if (strcmp(val, "false") == 0) {
4113adb2334SVikram Hegde *kvar = B_FALSE;
4123adb2334SVikram Hegde } else {
4133adb2334SVikram Hegde ddi_err(DER_WARN, NULL, "rootnex.conf switch %s=\"%s\" ",
4143adb2334SVikram Hegde "is not set to true or false. Ignoring option.",
4153adb2334SVikram Hegde bopt, val);
4163adb2334SVikram Hegde }
4173adb2334SVikram Hegde ddi_prop_free(val);
4183adb2334SVikram Hegde }
4193adb2334SVikram Hegde
4203a634bfcSVikram Hegde /*
4213a634bfcSVikram Hegde * get_bootopt()
422*d5ebc493SDan Cross * check a boot option (always a boolean)
4233a634bfcSVikram Hegde */
4249e986f0eSFrank Van Der Linden static int
get_boot_str(char * bopt,char ** val)4259e986f0eSFrank Van Der Linden get_boot_str(char *bopt, char **val)
4269e986f0eSFrank Van Der Linden {
4279e986f0eSFrank Van Der Linden int ret;
4289e986f0eSFrank Van Der Linden
4299e986f0eSFrank Van Der Linden ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo,
4309e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS, bopt, val);
4319e986f0eSFrank Van Der Linden
4329e986f0eSFrank Van Der Linden return (ret);
4339e986f0eSFrank Van Der Linden }
4349e986f0eSFrank Van Der Linden
4353a634bfcSVikram Hegde static void
get_bootopt(char * bopt,boolean_t * kvar)4363a634bfcSVikram Hegde get_bootopt(char *bopt, boolean_t *kvar)
4373a634bfcSVikram Hegde {
4383a634bfcSVikram Hegde char *val = NULL;
4393a634bfcSVikram Hegde
4403a634bfcSVikram Hegde /*
4413a634bfcSVikram Hegde * All boot options set at the GRUB menu become
4423a634bfcSVikram Hegde * properties on the rootnex.
4433a634bfcSVikram Hegde */
4449e986f0eSFrank Van Der Linden if (get_boot_str(bopt, &val) != DDI_PROP_SUCCESS)
4459e986f0eSFrank Van Der Linden return;
4469e986f0eSFrank Van Der Linden
4479e986f0eSFrank Van Der Linden if (strcmp(val, "true") == 0) {
4489e986f0eSFrank Van Der Linden *kvar = B_TRUE;
4499e986f0eSFrank Van Der Linden } else if (strcmp(val, "false") == 0) {
4509e986f0eSFrank Van Der Linden *kvar = B_FALSE;
4519e986f0eSFrank Van Der Linden } else {
4529e986f0eSFrank Van Der Linden ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ",
4539e986f0eSFrank Van Der Linden "is not set to true or false. Ignoring option.",
4549e986f0eSFrank Van Der Linden bopt, val);
4559e986f0eSFrank Van Der Linden }
4569e986f0eSFrank Van Der Linden ddi_prop_free(val);
4579e986f0eSFrank Van Der Linden }
4589e986f0eSFrank Van Der Linden
4599e986f0eSFrank Van Der Linden static void
get_boot_dvma_mode(void)4609e986f0eSFrank Van Der Linden get_boot_dvma_mode(void)
4619e986f0eSFrank Van Der Linden {
4629e986f0eSFrank Van Der Linden char *val = NULL;
4639e986f0eSFrank Van Der Linden
4649e986f0eSFrank Van Der Linden if (get_boot_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
4659e986f0eSFrank Van Der Linden != DDI_PROP_SUCCESS)
4669e986f0eSFrank Van Der Linden return;
4679e986f0eSFrank Van Der Linden
4689e986f0eSFrank Van Der Linden if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
4699e986f0eSFrank Van Der Linden immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
4709e986f0eSFrank Van Der Linden } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
4719e986f0eSFrank Van Der Linden immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
4729e986f0eSFrank Van Der Linden } else {
4739e986f0eSFrank Van Der Linden ddi_err(DER_WARN, NULL, "bad value \"%s\" for boot option %s",
4749e986f0eSFrank Van Der Linden val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
4753a634bfcSVikram Hegde }
4769e986f0eSFrank Van Der Linden ddi_prop_free(val);
4773a634bfcSVikram Hegde }
4783a634bfcSVikram Hegde
4799e986f0eSFrank Van Der Linden static void
get_conf_dvma_mode(void)4809e986f0eSFrank Van Der Linden get_conf_dvma_mode(void)
4819e986f0eSFrank Van Der Linden {
4829e986f0eSFrank Van Der Linden char *val = NULL;
4839e986f0eSFrank Van Der Linden
4849e986f0eSFrank Van Der Linden if (get_conf_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
4859e986f0eSFrank Van Der Linden != DDI_PROP_SUCCESS)
4869e986f0eSFrank Van Der Linden return;
4879e986f0eSFrank Van Der Linden
4889e986f0eSFrank Van Der Linden if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
4899e986f0eSFrank Van Der Linden immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
4909e986f0eSFrank Van Der Linden } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
4919e986f0eSFrank Van Der Linden immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
4929e986f0eSFrank Van Der Linden } else {
4939e986f0eSFrank Van Der Linden ddi_err(DER_WARN, NULL, "bad value \"%s\" for rootnex "
4949e986f0eSFrank Van Der Linden "option %s", val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
4959e986f0eSFrank Van Der Linden }
4969e986f0eSFrank Van Der Linden ddi_prop_free(val);
4979e986f0eSFrank Van Der Linden }
4989e986f0eSFrank Van Der Linden
4999e986f0eSFrank Van Der Linden
500e03dceedSVikram Hegde static void
get_conf_tunables(char * bopt,int64_t * ivar)5013adb2334SVikram Hegde get_conf_tunables(char *bopt, int64_t *ivar)
502e03dceedSVikram Hegde {
503e03dceedSVikram Hegde int64_t *iarray;
504e03dceedSVikram Hegde uint_t n;
505e03dceedSVikram Hegde
506e03dceedSVikram Hegde /*
507e03dceedSVikram Hegde * Check the rootnex.conf property
508e03dceedSVikram Hegde * Fake up a dev_t since searching the global
509e03dceedSVikram Hegde * property list needs it
510e03dceedSVikram Hegde */
511e03dceedSVikram Hegde if (ddi_prop_lookup_int64_array(
512e03dceedSVikram Hegde makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
513e03dceedSVikram Hegde DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, bopt,
514e03dceedSVikram Hegde &iarray, &n) != DDI_PROP_SUCCESS) {
515e03dceedSVikram Hegde return;
516e03dceedSVikram Hegde }
517e03dceedSVikram Hegde
518e03dceedSVikram Hegde if (n != 1) {
519e03dceedSVikram Hegde ddi_err(DER_WARN, NULL, "More than one value specified for "
520e03dceedSVikram Hegde "%s property. Ignoring and using default",
521e03dceedSVikram Hegde "immu-flush-gran");
522e03dceedSVikram Hegde ddi_prop_free(iarray);
523e03dceedSVikram Hegde return;
524e03dceedSVikram Hegde }
525e03dceedSVikram Hegde
526e03dceedSVikram Hegde if (iarray[0] < 0) {
527e03dceedSVikram Hegde ddi_err(DER_WARN, NULL, "Negative value specified for "
528e03dceedSVikram Hegde "%s property. Inoring and Using default value",
529e03dceedSVikram Hegde "immu-flush-gran");
530e03dceedSVikram Hegde ddi_prop_free(iarray);
531e03dceedSVikram Hegde return;
532e03dceedSVikram Hegde }
533e03dceedSVikram Hegde
534e03dceedSVikram Hegde *ivar = iarray[0];
535e03dceedSVikram Hegde
536e03dceedSVikram Hegde ddi_prop_free(iarray);
537e03dceedSVikram Hegde }
538e03dceedSVikram Hegde
5393adb2334SVikram Hegde static void
read_conf_options(void)5403adb2334SVikram Hegde read_conf_options(void)
5413adb2334SVikram Hegde {
5423adb2334SVikram Hegde /* enable/disable options */
5433adb2334SVikram Hegde get_conf_opt("immu-enable", &immu_enable);
5443adb2334SVikram Hegde get_conf_opt("immu-dvma-enable", &immu_dvma_enable);
5453adb2334SVikram Hegde get_conf_opt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
5463adb2334SVikram Hegde get_conf_opt("immu-intrmap-enable", &immu_intrmap_enable);
5473adb2334SVikram Hegde get_conf_opt("immu-qinv-enable", &immu_qinv_enable);
5483adb2334SVikram Hegde
5493adb2334SVikram Hegde /* workaround switches */
5503adb2334SVikram Hegde get_conf_opt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
5513adb2334SVikram Hegde get_conf_opt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
5523adb2334SVikram Hegde get_conf_opt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
5533adb2334SVikram Hegde
5543adb2334SVikram Hegde /* debug printing */
5553adb2334SVikram Hegde get_conf_opt("immu-dmar-print", &immu_dmar_print);
5563adb2334SVikram Hegde
5573adb2334SVikram Hegde /* get tunables */
5583adb2334SVikram Hegde get_conf_tunables("immu-flush-gran", &immu_flush_gran);
5599e986f0eSFrank Van Der Linden
5609e986f0eSFrank Van Der Linden get_conf_dvma_mode();
5613adb2334SVikram Hegde }
5623adb2334SVikram Hegde
5633a634bfcSVikram Hegde static void
read_boot_options(void)5643a634bfcSVikram Hegde read_boot_options(void)
5653a634bfcSVikram Hegde {
5663a634bfcSVikram Hegde /* enable/disable options */
5673a634bfcSVikram Hegde get_bootopt("immu-enable", &immu_enable);
5683a634bfcSVikram Hegde get_bootopt("immu-dvma-enable", &immu_dvma_enable);
5693a634bfcSVikram Hegde get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
5703a634bfcSVikram Hegde get_bootopt("immu-intrmap-enable", &immu_intrmap_enable);
5713a634bfcSVikram Hegde get_bootopt("immu-qinv-enable", &immu_qinv_enable);
5723a634bfcSVikram Hegde
5733a634bfcSVikram Hegde /* workaround switches */
5743a634bfcSVikram Hegde get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
5753a634bfcSVikram Hegde get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
5763a634bfcSVikram Hegde get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
5773a634bfcSVikram Hegde
5783a634bfcSVikram Hegde /* debug printing */
5793a634bfcSVikram Hegde get_bootopt("immu-dmar-print", &immu_dmar_print);
5809e986f0eSFrank Van Der Linden
5819e986f0eSFrank Van Der Linden get_boot_dvma_mode();
5829e986f0eSFrank Van Der Linden }
5839e986f0eSFrank Van Der Linden
5849e986f0eSFrank Van Der Linden static void
mapping_list_setup(void)5859e986f0eSFrank Van Der Linden mapping_list_setup(void)
5869e986f0eSFrank Van Der Linden {
5879e986f0eSFrank Van Der Linden char **string_array;
5889e986f0eSFrank Van Der Linden uint_t nstrings;
5899e986f0eSFrank Van Der Linden
5909e986f0eSFrank Van Der Linden if (ddi_prop_lookup_string_array(
5919e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
5929e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
5939e986f0eSFrank Van Der Linden "immu-dvma-unity-drivers",
5949e986f0eSFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
5959e986f0eSFrank Van Der Linden unity_driver_array = string_array;
5969e986f0eSFrank Van Der Linden nunity = nstrings;
5979e986f0eSFrank Van Der Linden }
5989e986f0eSFrank Van Der Linden
5999e986f0eSFrank Van Der Linden if (ddi_prop_lookup_string_array(
6009e986f0eSFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
6019e986f0eSFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
6029e986f0eSFrank Van Der Linden "immu-dvma-xlate-drivers",
6039e986f0eSFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
6049e986f0eSFrank Van Der Linden xlate_driver_array = string_array;
6059e986f0eSFrank Van Der Linden nxlate = nstrings;
6069e986f0eSFrank Van Der Linden }
60750200e77SFrank Van Der Linden
60850200e77SFrank Van Der Linden if (ddi_prop_lookup_string_array(
60950200e77SFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
61050200e77SFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
61150200e77SFrank Van Der Linden "immu-dvma-premap-drivers",
61250200e77SFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
61350200e77SFrank Van Der Linden premap_driver_array = string_array;
61450200e77SFrank Van Der Linden npremap = nstrings;
61550200e77SFrank Van Der Linden }
61650200e77SFrank Van Der Linden
61750200e77SFrank Van Der Linden if (ddi_prop_lookup_string_array(
61850200e77SFrank Van Der Linden makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
61950200e77SFrank Van Der Linden DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
62050200e77SFrank Van Der Linden "immu-dvma-nopremap-drivers",
62150200e77SFrank Van Der Linden &string_array, &nstrings) == DDI_PROP_SUCCESS) {
62250200e77SFrank Van Der Linden nopremap_driver_array = string_array;
62350200e77SFrank Van Der Linden nnopremap = nstrings;
62450200e77SFrank Van Der Linden }
6253a634bfcSVikram Hegde }
6263a634bfcSVikram Hegde
6273a634bfcSVikram Hegde /*
6283a634bfcSVikram Hegde * Note, this will not catch hardware not enumerated
6293a634bfcSVikram Hegde * in early boot
6303a634bfcSVikram Hegde */
6313a634bfcSVikram Hegde static boolean_t
blacklisted_driver(void)6323a634bfcSVikram Hegde blacklisted_driver(void)
6333a634bfcSVikram Hegde {
6343a634bfcSVikram Hegde char **strptr;
6353a634bfcSVikram Hegde int i;
6363a634bfcSVikram Hegde major_t maj;
6373a634bfcSVikram Hegde
6383a634bfcSVikram Hegde /* need at least 2 strings */
6393a634bfcSVikram Hegde if (nblacks < 2) {
6403a634bfcSVikram Hegde return (B_FALSE);
6413a634bfcSVikram Hegde }
6423a634bfcSVikram Hegde
6433a634bfcSVikram Hegde for (i = 0; nblacks - i > 1; i++) {
644e03dceedSVikram Hegde strptr = &black_array[i];
6453a634bfcSVikram Hegde if (strcmp(*strptr++, "DRIVER") == 0) {
6463a634bfcSVikram Hegde if ((maj = ddi_name_to_major(*strptr++))
6473a634bfcSVikram Hegde != DDI_MAJOR_T_NONE) {
6483a634bfcSVikram Hegde /* is there hardware bound to this drvr */
6493a634bfcSVikram Hegde if (devnamesp[maj].dn_head != NULL) {
6503a634bfcSVikram Hegde return (B_TRUE);
6513a634bfcSVikram Hegde }
6523a634bfcSVikram Hegde }
6533a634bfcSVikram Hegde i += 1; /* for loop adds 1, so add only 1 here */
6543a634bfcSVikram Hegde }
6553a634bfcSVikram Hegde }
6563a634bfcSVikram Hegde
6573a634bfcSVikram Hegde return (B_FALSE);
6583a634bfcSVikram Hegde }
6593a634bfcSVikram Hegde
6603a634bfcSVikram Hegde static boolean_t
blacklisted_smbios(void)6613a634bfcSVikram Hegde blacklisted_smbios(void)
6623a634bfcSVikram Hegde {
6633a634bfcSVikram Hegde id_t smid;
6643a634bfcSVikram Hegde smbios_hdl_t *smhdl;
6653a634bfcSVikram Hegde smbios_info_t sminf;
6663a634bfcSVikram Hegde smbios_system_t smsys;
6673a634bfcSVikram Hegde char *mfg, *product, *version;
6683a634bfcSVikram Hegde char **strptr;
6693a634bfcSVikram Hegde int i;
6703a634bfcSVikram Hegde
6713a634bfcSVikram Hegde /* need at least 4 strings for this setting */
6723a634bfcSVikram Hegde if (nblacks < 4) {
6733a634bfcSVikram Hegde return (B_FALSE);
6743a634bfcSVikram Hegde }
6753a634bfcSVikram Hegde
6763a634bfcSVikram Hegde smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL);
6773a634bfcSVikram Hegde if (smhdl == NULL ||
6783a634bfcSVikram Hegde (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR ||
6793a634bfcSVikram Hegde smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) {
6803a634bfcSVikram Hegde return (B_FALSE);
6813a634bfcSVikram Hegde }
6823a634bfcSVikram Hegde
6833a634bfcSVikram Hegde mfg = (char *)sminf.smbi_manufacturer;
6843a634bfcSVikram Hegde product = (char *)sminf.smbi_product;
6853a634bfcSVikram Hegde version = (char *)sminf.smbi_version;
6863a634bfcSVikram Hegde
6873a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n");
6883a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg);
6893a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product);
6903a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version);
6913a634bfcSVikram Hegde
6923a634bfcSVikram Hegde for (i = 0; nblacks - i > 3; i++) {
693e03dceedSVikram Hegde strptr = &black_array[i];
6943a634bfcSVikram Hegde if (strcmp(*strptr++, "SMBIOS") == 0) {
6953a634bfcSVikram Hegde if (strcmp(*strptr++, mfg) == 0 &&
696243bebc0SToomas Soome (*strptr[0] == '\0' ||
6973a634bfcSVikram Hegde strcmp(*strptr++, product) == 0) &&
698243bebc0SToomas Soome (*strptr[0] == '\0' ||
6993a634bfcSVikram Hegde strcmp(*strptr++, version) == 0)) {
7003a634bfcSVikram Hegde return (B_TRUE);
7013a634bfcSVikram Hegde }
7023a634bfcSVikram Hegde i += 3;
7033a634bfcSVikram Hegde }
7043a634bfcSVikram Hegde }
7053a634bfcSVikram Hegde
7063a634bfcSVikram Hegde return (B_FALSE);
7073a634bfcSVikram Hegde }
7083a634bfcSVikram Hegde
7093a634bfcSVikram Hegde static boolean_t
blacklisted_acpi(void)7103a634bfcSVikram Hegde blacklisted_acpi(void)
7113a634bfcSVikram Hegde {
7123a634bfcSVikram Hegde if (nblacks == 0) {
7133a634bfcSVikram Hegde return (B_FALSE);
7143a634bfcSVikram Hegde }
7153a634bfcSVikram Hegde
7163a634bfcSVikram Hegde return (immu_dmar_blacklisted(black_array, nblacks));
7173a634bfcSVikram Hegde }
7183a634bfcSVikram Hegde
7193a634bfcSVikram Hegde /*
7203a634bfcSVikram Hegde * Check if system is blacklisted by Intel IOMMU driver
7213a634bfcSVikram Hegde * i.e. should Intel IOMMU be disabled on this system
7223a634bfcSVikram Hegde * Currently a system can be blacklistd based on the
7233a634bfcSVikram Hegde * following bases:
7243a634bfcSVikram Hegde *
7253a634bfcSVikram Hegde * 1. DMAR ACPI table information.
7263a634bfcSVikram Hegde * This information includes things like
7273a634bfcSVikram Hegde * manufacturer and revision number. If rootnex.conf
7283a634bfcSVikram Hegde * has matching info set in its blacklist property
7293a634bfcSVikram Hegde * then Intel IOMMu will be disabled
7303a634bfcSVikram Hegde *
7313a634bfcSVikram Hegde * 2. SMBIOS information
7323a634bfcSVikram Hegde *
7333a634bfcSVikram Hegde * 3. Driver installed - useful if a particular
7343a634bfcSVikram Hegde * driver or hardware is toxic if Intel IOMMU
7353a634bfcSVikram Hegde * is turned on.
7363a634bfcSVikram Hegde */
7373a634bfcSVikram Hegde
7383a634bfcSVikram Hegde static void
blacklist_setup(void)7393a634bfcSVikram Hegde blacklist_setup(void)
7403a634bfcSVikram Hegde {
7413a634bfcSVikram Hegde char **string_array;
7423a634bfcSVikram Hegde uint_t nstrings;
7433a634bfcSVikram Hegde
7443a634bfcSVikram Hegde /*
7453a634bfcSVikram Hegde * Check the rootnex.conf blacklist property.
7463a634bfcSVikram Hegde * Fake up a dev_t since searching the global
7473a634bfcSVikram Hegde * property list needs it
7483a634bfcSVikram Hegde */
7493a634bfcSVikram Hegde if (ddi_prop_lookup_string_array(
7503a634bfcSVikram Hegde makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
7513a634bfcSVikram Hegde DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist",
7523a634bfcSVikram Hegde &string_array, &nstrings) != DDI_PROP_SUCCESS) {
7533a634bfcSVikram Hegde return;
7543a634bfcSVikram Hegde }
7553a634bfcSVikram Hegde
7563a634bfcSVikram Hegde /* smallest blacklist criteria works with multiples of 2 */
7573a634bfcSVikram Hegde if (nstrings % 2 != 0) {
7583a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist "
7593a634bfcSVikram Hegde "rootnex.conf: number of strings must be a "
7603a634bfcSVikram Hegde "multiple of 2");
7613a634bfcSVikram Hegde ddi_prop_free(string_array);
7623a634bfcSVikram Hegde return;
7633a634bfcSVikram Hegde }
7643a634bfcSVikram Hegde
7653a634bfcSVikram Hegde black_array = string_array;
7663a634bfcSVikram Hegde nblacks = nstrings;
7673a634bfcSVikram Hegde }
7683a634bfcSVikram Hegde
7693a634bfcSVikram Hegde static void
blacklist_destroy(void)7703a634bfcSVikram Hegde blacklist_destroy(void)
7713a634bfcSVikram Hegde {
7723a634bfcSVikram Hegde if (black_array) {
7733a634bfcSVikram Hegde ddi_prop_free(black_array);
7743a634bfcSVikram Hegde black_array = NULL;
7753a634bfcSVikram Hegde nblacks = 0;
7763a634bfcSVikram Hegde }
77750200e77SFrank Van Der Linden }
77850200e77SFrank Van Der Linden
77950200e77SFrank Van Der Linden static char *
immu_alloc_name(const char * str,int instance)78050200e77SFrank Van Der Linden immu_alloc_name(const char *str, int instance)
78150200e77SFrank Van Der Linden {
78250200e77SFrank Van Der Linden size_t slen;
78350200e77SFrank Van Der Linden char *s;
7843a634bfcSVikram Hegde
78550200e77SFrank Van Der Linden slen = strlen(str) + IMMU_ISTRLEN + 1;
78650200e77SFrank Van Der Linden s = kmem_zalloc(slen, VM_SLEEP);
78750200e77SFrank Van Der Linden if (s != NULL)
78850200e77SFrank Van Der Linden (void) snprintf(s, slen, "%s%d", str, instance);
78950200e77SFrank Van Der Linden
79050200e77SFrank Van Der Linden return (s);
7913a634bfcSVikram Hegde }
7923a634bfcSVikram Hegde
7933a634bfcSVikram Hegde
7943a634bfcSVikram Hegde /*
7953a634bfcSVikram Hegde * Now set all the fields in the order they are defined
7963a634bfcSVikram Hegde * We do this only as a defensive-coding practice, it is
7973a634bfcSVikram Hegde * not a correctness issue.
7983a634bfcSVikram Hegde */
7993a634bfcSVikram Hegde static void *
immu_state_alloc(int seg,void * dmar_unit)8003a634bfcSVikram Hegde immu_state_alloc(int seg, void *dmar_unit)
8013a634bfcSVikram Hegde {
8023a634bfcSVikram Hegde immu_t *immu;
80350200e77SFrank Van Der Linden char *nodename, *hcachename, *pcachename;
80450200e77SFrank Van Der Linden int instance;
8053a634bfcSVikram Hegde
8063a634bfcSVikram Hegde dmar_unit = immu_dmar_walk_units(seg, dmar_unit);
8073a634bfcSVikram Hegde if (dmar_unit == NULL) {
8083a634bfcSVikram Hegde /* No more IOMMUs in this segment */
8093a634bfcSVikram Hegde return (NULL);
8103a634bfcSVikram Hegde }
8113a634bfcSVikram Hegde
8123a634bfcSVikram Hegde immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP);
8133a634bfcSVikram Hegde
8143a634bfcSVikram Hegde mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL);
8153a634bfcSVikram Hegde
8163a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
8173a634bfcSVikram Hegde
8183a634bfcSVikram Hegde immu->immu_dmar_unit = dmar_unit;
8193a634bfcSVikram Hegde immu->immu_dip = immu_dmar_unit_dip(dmar_unit);
8203a634bfcSVikram Hegde
82150200e77SFrank Van Der Linden nodename = ddi_node_name(immu->immu_dip);
82250200e77SFrank Van Der Linden instance = ddi_get_instance(immu->immu_dip);
82350200e77SFrank Van Der Linden
82450200e77SFrank Van Der Linden immu->immu_name = immu_alloc_name(nodename, instance);
82550200e77SFrank Van Der Linden if (immu->immu_name == NULL)
82650200e77SFrank Van Der Linden return (NULL);
82750200e77SFrank Van Der Linden
8283a634bfcSVikram Hegde /*
8293a634bfcSVikram Hegde * the immu_intr_lock mutex is grabbed by the IOMMU
8303a634bfcSVikram Hegde * unit's interrupt handler so we need to use an
8313a634bfcSVikram Hegde * interrupt cookie for the mutex
8323a634bfcSVikram Hegde */
8333a634bfcSVikram Hegde mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER,
8343a634bfcSVikram Hegde (void *)ipltospl(IMMU_INTR_IPL));
8353a634bfcSVikram Hegde
8363a634bfcSVikram Hegde /* IOMMU regs related */
8373a634bfcSVikram Hegde mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL);
838e03dceedSVikram Hegde cv_init(&(immu->immu_regs_cv), NULL, CV_DEFAULT, NULL);
839e03dceedSVikram Hegde immu->immu_regs_busy = B_FALSE;
8403a634bfcSVikram Hegde
8413a634bfcSVikram Hegde /* DVMA related */
8423a634bfcSVikram Hegde immu->immu_dvma_coherent = B_FALSE;
8433a634bfcSVikram Hegde
8443a634bfcSVikram Hegde /* DVMA context related */
8453a634bfcSVikram Hegde rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL);
8463a634bfcSVikram Hegde
8473a634bfcSVikram Hegde /* DVMA domain related */
8483a634bfcSVikram Hegde list_create(&(immu->immu_domain_list), sizeof (domain_t),
8493a634bfcSVikram Hegde offsetof(domain_t, dom_immu_node));
8503a634bfcSVikram Hegde
8513a634bfcSVikram Hegde /* DVMA special device lists */
8523a634bfcSVikram Hegde immu->immu_dvma_gfx_only = B_FALSE;
8533a634bfcSVikram Hegde list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t),
8543a634bfcSVikram Hegde offsetof(immu_devi_t, imd_spc_node));
8553a634bfcSVikram Hegde list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t),
8563a634bfcSVikram Hegde offsetof(immu_devi_t, imd_spc_node));
8573a634bfcSVikram Hegde
8583a634bfcSVikram Hegde /* interrupt remapping related */
8593a634bfcSVikram Hegde mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL);
8603a634bfcSVikram Hegde
8613a634bfcSVikram Hegde /* qinv related */
8623a634bfcSVikram Hegde mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL);
8633a634bfcSVikram Hegde
8643a634bfcSVikram Hegde /*
8653a634bfcSVikram Hegde * insert this immu unit into the system-wide list
8663a634bfcSVikram Hegde */
8673a634bfcSVikram Hegde list_insert_tail(&immu_list, immu);
8683a634bfcSVikram Hegde
86950200e77SFrank Van Der Linden pcachename = immu_alloc_name("immu_pgtable_cache", instance);
87050200e77SFrank Van Der Linden if (pcachename == NULL)
87150200e77SFrank Van Der Linden return (NULL);
87250200e77SFrank Van Der Linden
87350200e77SFrank Van Der Linden hcachename = immu_alloc_name("immu_hdl_cache", instance);
87450200e77SFrank Van Der Linden if (hcachename == NULL)
87550200e77SFrank Van Der Linden return (NULL);
87650200e77SFrank Van Der Linden
87750200e77SFrank Van Der Linden immu->immu_pgtable_cache = kmem_cache_create(pcachename,
87850200e77SFrank Van Der Linden sizeof (pgtable_t), 0, pgtable_ctor, pgtable_dtor, NULL, immu,
87950200e77SFrank Van Der Linden NULL, 0);
88050200e77SFrank Van Der Linden immu->immu_hdl_cache = kmem_cache_create(hcachename,
88150200e77SFrank Van Der Linden sizeof (immu_hdl_priv_t), 64, immu_hdl_priv_ctor,
88250200e77SFrank Van Der Linden NULL, NULL, immu, NULL, 0);
88350200e77SFrank Van Der Linden
8843a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
8853a634bfcSVikram Hegde
88650200e77SFrank Van Der Linden ddi_err(DER_LOG, immu->immu_dip, "unit setup");
8873a634bfcSVikram Hegde
8883a634bfcSVikram Hegde immu_dmar_set_immu(dmar_unit, immu);
8893a634bfcSVikram Hegde
8903a634bfcSVikram Hegde return (dmar_unit);
8913a634bfcSVikram Hegde }
8923a634bfcSVikram Hegde
8933a634bfcSVikram Hegde static void
immu_subsystems_setup(void)8943a634bfcSVikram Hegde immu_subsystems_setup(void)
8953a634bfcSVikram Hegde {
8963a634bfcSVikram Hegde int seg;
8973a634bfcSVikram Hegde void *unit_hdl;
8983a634bfcSVikram Hegde
8993a634bfcSVikram Hegde ddi_err(DER_VERB, NULL,
90050200e77SFrank Van Der Linden "Creating state structures for Intel IOMMU units");
9013a634bfcSVikram Hegde
9023a634bfcSVikram Hegde mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL);
9033a634bfcSVikram Hegde list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node));
9043a634bfcSVikram Hegde
9053a634bfcSVikram Hegde mutex_enter(&immu_lock);
9063a634bfcSVikram Hegde
9073a634bfcSVikram Hegde unit_hdl = NULL;
9083a634bfcSVikram Hegde for (seg = 0; seg < IMMU_MAXSEG; seg++) {
9093a634bfcSVikram Hegde while (unit_hdl = immu_state_alloc(seg, unit_hdl)) {
9103a634bfcSVikram Hegde ;
9113a634bfcSVikram Hegde }
9123a634bfcSVikram Hegde }
9133a634bfcSVikram Hegde
9143a634bfcSVikram Hegde immu_regs_setup(&immu_list); /* subsequent code needs this first */
9153a634bfcSVikram Hegde immu_dvma_setup(&immu_list);
916d2256d26SFrank Van Der Linden if (immu_qinv_setup(&immu_list) == DDI_SUCCESS)
917d2256d26SFrank Van Der Linden immu_intrmap_setup(&immu_list);
918d2256d26SFrank Van Der Linden else
919d2256d26SFrank Van Der Linden immu_intrmap_enable = B_FALSE;
9203a634bfcSVikram Hegde
9213a634bfcSVikram Hegde mutex_exit(&immu_lock);
9223a634bfcSVikram Hegde }
9233a634bfcSVikram Hegde
9243a634bfcSVikram Hegde /*
9253a634bfcSVikram Hegde * immu_subsystems_startup()
926*d5ebc493SDan Cross * startup all units that were setup
9273a634bfcSVikram Hegde */
9283a634bfcSVikram Hegde static void
immu_subsystems_startup(void)9293a634bfcSVikram Hegde immu_subsystems_startup(void)
9303a634bfcSVikram Hegde {
9313a634bfcSVikram Hegde immu_t *immu;
93250200e77SFrank Van Der Linden iommulib_ops_t *iommulib_ops;
9333a634bfcSVikram Hegde
9343a634bfcSVikram Hegde mutex_enter(&immu_lock);
9353a634bfcSVikram Hegde
9363a634bfcSVikram Hegde immu_dmar_startup();
9373a634bfcSVikram Hegde
9383a634bfcSVikram Hegde immu = list_head(&immu_list);
9393a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
9403a634bfcSVikram Hegde
9413a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
9423a634bfcSVikram Hegde
9433a634bfcSVikram Hegde immu_intr_register(immu);
9443a634bfcSVikram Hegde immu_dvma_startup(immu);
9453a634bfcSVikram Hegde immu_intrmap_startup(immu);
9463a634bfcSVikram Hegde immu_qinv_startup(immu);
9473a634bfcSVikram Hegde
9483a634bfcSVikram Hegde /*
9493a634bfcSVikram Hegde * Set IOMMU unit's regs to do
9503a634bfcSVikram Hegde * the actual startup. This will
9513a634bfcSVikram Hegde * set immu->immu_running field
9523a634bfcSVikram Hegde * if the unit is successfully
9533a634bfcSVikram Hegde * started
9543a634bfcSVikram Hegde */
9553a634bfcSVikram Hegde immu_regs_startup(immu);
9563a634bfcSVikram Hegde
9573a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
95850200e77SFrank Van Der Linden
95950200e77SFrank Van Der Linden iommulib_ops = kmem_alloc(sizeof (iommulib_ops_t), KM_SLEEP);
96050200e77SFrank Van Der Linden *iommulib_ops = immulib_ops;
96150200e77SFrank Van Der Linden iommulib_ops->ilops_data = (void *)immu;
96250200e77SFrank Van Der Linden (void) iommulib_iommu_register(immu->immu_dip, iommulib_ops,
96350200e77SFrank Van Der Linden &immu->immu_iommulib_handle);
9643a634bfcSVikram Hegde }
9653a634bfcSVikram Hegde
9663a634bfcSVikram Hegde mutex_exit(&immu_lock);
9673a634bfcSVikram Hegde }
9683a634bfcSVikram Hegde
9693a634bfcSVikram Hegde /* ################## Intel IOMMU internal interfaces ###################### */
9703a634bfcSVikram Hegde
9713a634bfcSVikram Hegde /*
9723a634bfcSVikram Hegde * Internal interfaces for IOMMU code (i.e. not exported to rootnex
9733a634bfcSVikram Hegde * or rest of system)
9743a634bfcSVikram Hegde */
9753a634bfcSVikram Hegde
9763a634bfcSVikram Hegde /*
9773a634bfcSVikram Hegde * ddip can be NULL, in which case we walk up until we find the root dip
9783a634bfcSVikram Hegde * NOTE: We never visit the root dip since its not a hardware node
9793a634bfcSVikram Hegde */
9803a634bfcSVikram 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)9813a634bfcSVikram Hegde immu_walk_ancestor(
9823a634bfcSVikram Hegde dev_info_t *rdip,
9833a634bfcSVikram Hegde dev_info_t *ddip,
9843a634bfcSVikram Hegde int (*func)(dev_info_t *, void *arg),
9853a634bfcSVikram Hegde void *arg,
9863a634bfcSVikram Hegde int *lvlp,
9873a634bfcSVikram Hegde immu_flags_t immu_flags)
9883a634bfcSVikram Hegde {
9893a634bfcSVikram Hegde dev_info_t *pdip;
9903a634bfcSVikram Hegde int level;
9913a634bfcSVikram Hegde int error = DDI_SUCCESS;
9923a634bfcSVikram Hegde
9933a634bfcSVikram Hegde /* ddip and immu can be NULL */
9943a634bfcSVikram Hegde
9953a634bfcSVikram Hegde /* Hold rdip so that branch is not detached */
9963a634bfcSVikram Hegde ndi_hold_devi(rdip);
9973a634bfcSVikram Hegde for (pdip = rdip, level = 1; pdip && pdip != root_devinfo;
9983a634bfcSVikram Hegde pdip = ddi_get_parent(pdip), level++) {
9993a634bfcSVikram Hegde
10003a634bfcSVikram Hegde if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) {
10013a634bfcSVikram Hegde error = DDI_FAILURE;
10023a634bfcSVikram Hegde break;
10033a634bfcSVikram Hegde }
10043a634bfcSVikram Hegde if (func(pdip, arg) == DDI_WALK_TERMINATE) {
10053a634bfcSVikram Hegde break;
10063a634bfcSVikram Hegde }
10073a634bfcSVikram Hegde if (immu_flags & IMMU_FLAGS_DONTPASS) {
10083a634bfcSVikram Hegde break;
10093a634bfcSVikram Hegde }
10103a634bfcSVikram Hegde if (pdip == ddip) {
10113a634bfcSVikram Hegde break;
10123a634bfcSVikram Hegde }
10133a634bfcSVikram Hegde }
10143a634bfcSVikram Hegde
10153a634bfcSVikram Hegde ndi_rele_devi(rdip);
10163a634bfcSVikram Hegde
10173a634bfcSVikram Hegde if (lvlp)
10183a634bfcSVikram Hegde *lvlp = level;
10193a634bfcSVikram Hegde
10203a634bfcSVikram Hegde return (error);
10213a634bfcSVikram Hegde }
10223a634bfcSVikram Hegde
10233a634bfcSVikram Hegde /* ######################## Intel IOMMU entry points ####################### */
10243a634bfcSVikram Hegde /*
10253a634bfcSVikram Hegde * immu_init()
10263a634bfcSVikram Hegde * called from rootnex_attach(). setup but don't startup the Intel IOMMU
10273a634bfcSVikram Hegde * This is the first function called in Intel IOMMU code
10283a634bfcSVikram Hegde */
10293a634bfcSVikram Hegde void
immu_init(void)10303a634bfcSVikram Hegde immu_init(void)
10313a634bfcSVikram Hegde {
10323a634bfcSVikram Hegde char *phony_reg = "A thing of beauty is a joy forever";
10333a634bfcSVikram Hegde
10343a634bfcSVikram Hegde /* Set some global shorthands that are needed by all of IOMMU code */
10353a634bfcSVikram Hegde root_devinfo = ddi_root_node();
10363a634bfcSVikram Hegde
10373a634bfcSVikram Hegde /*
10383a634bfcSVikram Hegde * Intel IOMMU only supported only if MMU(CPU) page size is ==
10393a634bfcSVikram Hegde * IOMMU pages size.
10403a634bfcSVikram Hegde */
10413a634bfcSVikram Hegde /*LINTED*/
10423a634bfcSVikram Hegde if (MMU_PAGESIZE != IMMU_PAGESIZE) {
10433a634bfcSVikram Hegde ddi_err(DER_WARN, NULL,
10443a634bfcSVikram Hegde "MMU page size (%d) is not equal to\n"
10453a634bfcSVikram Hegde "IOMMU page size (%d). "
10463a634bfcSVikram Hegde "Disabling Intel IOMMU. ",
10473a634bfcSVikram Hegde MMU_PAGESIZE, IMMU_PAGESIZE);
10483a634bfcSVikram Hegde immu_enable = B_FALSE;
10493a634bfcSVikram Hegde return;
10503a634bfcSVikram Hegde }
10513a634bfcSVikram Hegde
10523adb2334SVikram Hegde /*
10533adb2334SVikram Hegde * Read rootnex.conf options. Do this before
10543adb2334SVikram Hegde * boot options so boot options can override .conf options.
10553adb2334SVikram Hegde */
10563adb2334SVikram Hegde read_conf_options();
10573adb2334SVikram Hegde
10583a634bfcSVikram Hegde /*
10593a634bfcSVikram Hegde * retrieve the Intel IOMMU boot options.
10603a634bfcSVikram Hegde * Do this before parsing immu ACPI table
10613a634bfcSVikram Hegde * as a boot option could potentially affect
10623a634bfcSVikram Hegde * ACPI parsing.
10633a634bfcSVikram Hegde */
10643a634bfcSVikram Hegde ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n");
10653a634bfcSVikram Hegde read_boot_options();
10663a634bfcSVikram Hegde
10673a634bfcSVikram Hegde /*
10683a634bfcSVikram Hegde * Check the IOMMU enable boot-option first.
10693a634bfcSVikram Hegde * This is so that we can skip parsing the ACPI table
10703a634bfcSVikram Hegde * if necessary because that may cause problems in
10713a634bfcSVikram Hegde * systems with buggy BIOS or ACPI tables
10723a634bfcSVikram Hegde */
10733a634bfcSVikram Hegde if (immu_enable == B_FALSE) {
10743a634bfcSVikram Hegde return;
10753a634bfcSVikram Hegde }
10763a634bfcSVikram Hegde
1077c94adbf9SFrank Van Der Linden if (immu_intrmap_enable == B_TRUE)
1078c94adbf9SFrank Van Der Linden immu_qinv_enable = B_TRUE;
1079c94adbf9SFrank Van Der Linden
10803a634bfcSVikram Hegde /*
10813a634bfcSVikram Hegde * Next, check if the system even has an Intel IOMMU
10823a634bfcSVikram Hegde * We use the presence or absence of the IOMMU ACPI
10833a634bfcSVikram Hegde * table to detect Intel IOMMU.
10843a634bfcSVikram Hegde */
10853a634bfcSVikram Hegde if (immu_dmar_setup() != DDI_SUCCESS) {
10863a634bfcSVikram Hegde immu_enable = B_FALSE;
10873a634bfcSVikram Hegde return;
10883a634bfcSVikram Hegde }
10893a634bfcSVikram Hegde
10909e986f0eSFrank Van Der Linden mapping_list_setup();
10919e986f0eSFrank Van Der Linden
10923a634bfcSVikram Hegde /*
10933a634bfcSVikram Hegde * Check blacklists
10943a634bfcSVikram Hegde */
10953a634bfcSVikram Hegde blacklist_setup();
10963a634bfcSVikram Hegde
10973a634bfcSVikram Hegde if (blacklisted_smbios() == B_TRUE) {
10983a634bfcSVikram Hegde blacklist_destroy();
10993a634bfcSVikram Hegde immu_enable = B_FALSE;
11003a634bfcSVikram Hegde return;
11013a634bfcSVikram Hegde }
11023a634bfcSVikram Hegde
11033a634bfcSVikram Hegde if (blacklisted_driver() == B_TRUE) {
11043a634bfcSVikram Hegde blacklist_destroy();
11053a634bfcSVikram Hegde immu_enable = B_FALSE;
11063a634bfcSVikram Hegde return;
11073a634bfcSVikram Hegde }
11083a634bfcSVikram Hegde
11093a634bfcSVikram Hegde /*
11103a634bfcSVikram Hegde * Read the "raw" DMAR ACPI table to get information
11113a634bfcSVikram Hegde * and convert into a form we can use.
11123a634bfcSVikram Hegde */
11133a634bfcSVikram Hegde if (immu_dmar_parse() != DDI_SUCCESS) {
11143a634bfcSVikram Hegde blacklist_destroy();
11153a634bfcSVikram Hegde immu_enable = B_FALSE;
11163a634bfcSVikram Hegde return;
11173a634bfcSVikram Hegde }
11183a634bfcSVikram Hegde
11193a634bfcSVikram Hegde /*
11203a634bfcSVikram Hegde * now that we have processed the ACPI table
11213a634bfcSVikram Hegde * check if we need to blacklist this system
11223a634bfcSVikram Hegde * based on ACPI info
11233a634bfcSVikram Hegde */
11243a634bfcSVikram Hegde if (blacklisted_acpi() == B_TRUE) {
11253a634bfcSVikram Hegde immu_dmar_destroy();
11263a634bfcSVikram Hegde blacklist_destroy();
11273a634bfcSVikram Hegde immu_enable = B_FALSE;
11283a634bfcSVikram Hegde return;
11293a634bfcSVikram Hegde }
11303a634bfcSVikram Hegde
11313a634bfcSVikram Hegde blacklist_destroy();
11323a634bfcSVikram Hegde
11333a634bfcSVikram Hegde /*
11343a634bfcSVikram Hegde * Check if system has HW quirks.
11353a634bfcSVikram Hegde */
11363a634bfcSVikram Hegde pre_setup_quirks();
11373a634bfcSVikram Hegde
11383a634bfcSVikram Hegde /* Now do the rest of the setup */
11393a634bfcSVikram Hegde immu_subsystems_setup();
11403a634bfcSVikram Hegde
11413a634bfcSVikram Hegde /*
11423a634bfcSVikram Hegde * Now that the IMMU is setup, create a phony
11433a634bfcSVikram Hegde * reg prop so that suspend/resume works
11443a634bfcSVikram Hegde */
11453a634bfcSVikram Hegde if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg",
11463a634bfcSVikram Hegde (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) {
11473a634bfcSVikram Hegde ddi_err(DER_PANIC, NULL, "Failed to create reg prop for "
11483a634bfcSVikram Hegde "rootnex node");
11493a634bfcSVikram Hegde /*NOTREACHED*/
11503a634bfcSVikram Hegde }
11513a634bfcSVikram Hegde
11523a634bfcSVikram Hegde immu_setup = B_TRUE;
11533a634bfcSVikram Hegde }
11543a634bfcSVikram Hegde
11553a634bfcSVikram Hegde /*
11563a634bfcSVikram Hegde * immu_startup()
1157*d5ebc493SDan Cross * called directly by boot code to startup
1158*d5ebc493SDan Cross * all units of the IOMMU
11593a634bfcSVikram Hegde */
11603a634bfcSVikram Hegde void
immu_startup(void)11613a634bfcSVikram Hegde immu_startup(void)
11623a634bfcSVikram Hegde {
11633a634bfcSVikram Hegde /*
11643a634bfcSVikram Hegde * If IOMMU is disabled, do nothing
11653a634bfcSVikram Hegde */
11663a634bfcSVikram Hegde if (immu_enable == B_FALSE) {
11673a634bfcSVikram Hegde return;
11683a634bfcSVikram Hegde }
11693a634bfcSVikram Hegde
11703a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
11713a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, "
117250200e77SFrank Van Der Linden "skipping IOMMU startup");
11733a634bfcSVikram Hegde return;
11743a634bfcSVikram Hegde }
11753a634bfcSVikram Hegde
11763a634bfcSVikram Hegde pre_startup_quirks();
11773a634bfcSVikram Hegde
11783a634bfcSVikram Hegde ddi_err(DER_CONT, NULL,
11793a634bfcSVikram Hegde "?Starting Intel IOMMU (dmar) units...\n");
11803a634bfcSVikram Hegde
11813a634bfcSVikram Hegde immu_subsystems_startup();
11823a634bfcSVikram Hegde
11833a634bfcSVikram Hegde immu_running = B_TRUE;
11843a634bfcSVikram Hegde }
11853a634bfcSVikram Hegde
11863a634bfcSVikram Hegde /*
11873a634bfcSVikram Hegde * Hook to notify IOMMU code of device tree changes
11883a634bfcSVikram Hegde */
11893a634bfcSVikram Hegde void
immu_device_tree_changed(void)11903a634bfcSVikram Hegde immu_device_tree_changed(void)
11913a634bfcSVikram Hegde {
11923a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
11933a634bfcSVikram Hegde return;
11943a634bfcSVikram Hegde }
11953a634bfcSVikram Hegde
11963a634bfcSVikram Hegde ddi_err(DER_WARN, NULL, "Intel IOMMU currently "
11973a634bfcSVikram Hegde "does not use device tree updates");
11983a634bfcSVikram Hegde }
11993a634bfcSVikram Hegde
12003a634bfcSVikram Hegde /*
12013a634bfcSVikram Hegde * Hook to notify IOMMU code of memory changes
12023a634bfcSVikram Hegde */
12033a634bfcSVikram Hegde void
immu_physmem_update(uint64_t addr,uint64_t size)12043a634bfcSVikram Hegde immu_physmem_update(uint64_t addr, uint64_t size)
12053a634bfcSVikram Hegde {
12063a634bfcSVikram Hegde if (immu_setup == B_FALSE) {
12073a634bfcSVikram Hegde return;
12083a634bfcSVikram Hegde }
12093a634bfcSVikram Hegde immu_dvma_physmem_update(addr, size);
12103a634bfcSVikram Hegde }
12113a634bfcSVikram Hegde
12123a634bfcSVikram Hegde /*
12133a634bfcSVikram Hegde * immu_quiesce()
1214*d5ebc493SDan Cross * quiesce all units that are running
12153a634bfcSVikram Hegde */
12163a634bfcSVikram Hegde int
immu_quiesce(void)12173a634bfcSVikram Hegde immu_quiesce(void)
12183a634bfcSVikram Hegde {
12193a634bfcSVikram Hegde immu_t *immu;
12203a634bfcSVikram Hegde int ret = DDI_SUCCESS;
12213a634bfcSVikram Hegde
12223a634bfcSVikram Hegde mutex_enter(&immu_lock);
12233a634bfcSVikram Hegde
122496992ee7SEthindra Ramamurthy if (immu_running == B_FALSE) {
122596992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12263a634bfcSVikram Hegde return (DDI_SUCCESS);
122796992ee7SEthindra Ramamurthy }
12283a634bfcSVikram Hegde
12293a634bfcSVikram Hegde immu = list_head(&immu_list);
12303a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
12313a634bfcSVikram Hegde
12323a634bfcSVikram Hegde /* if immu is not running, we dont quiesce */
12333a634bfcSVikram Hegde if (immu->immu_regs_running == B_FALSE)
12343a634bfcSVikram Hegde continue;
12353a634bfcSVikram Hegde
12363a634bfcSVikram Hegde /* flush caches */
12373a634bfcSVikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
123850200e77SFrank Van Der Linden immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
123950200e77SFrank Van Der Linden immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
12403a634bfcSVikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
12413a634bfcSVikram Hegde immu_regs_wbf_flush(immu);
12423a634bfcSVikram Hegde
12433a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
12443a634bfcSVikram Hegde
12453a634bfcSVikram Hegde /*
12463a634bfcSVikram Hegde * Set IOMMU unit's regs to do
12473a634bfcSVikram Hegde * the actual shutdown.
12483a634bfcSVikram Hegde */
12493a634bfcSVikram Hegde immu_regs_shutdown(immu);
12503a634bfcSVikram Hegde immu_regs_suspend(immu);
12513a634bfcSVikram Hegde
12523a634bfcSVikram Hegde /* if immu is still running, we failed */
12533a634bfcSVikram Hegde if (immu->immu_regs_running == B_TRUE)
12543a634bfcSVikram Hegde ret = DDI_FAILURE;
12553a634bfcSVikram Hegde else
12563a634bfcSVikram Hegde immu->immu_regs_quiesced = B_TRUE;
12573a634bfcSVikram Hegde
12583a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
12593a634bfcSVikram Hegde }
12603a634bfcSVikram Hegde
12613a634bfcSVikram Hegde if (ret == DDI_SUCCESS) {
12623a634bfcSVikram Hegde immu_running = B_FALSE;
12633a634bfcSVikram Hegde immu_quiesced = B_TRUE;
12643a634bfcSVikram Hegde }
126596992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12663a634bfcSVikram Hegde
12673a634bfcSVikram Hegde return (ret);
12683a634bfcSVikram Hegde }
12693a634bfcSVikram Hegde
12703a634bfcSVikram Hegde /*
12713a634bfcSVikram Hegde * immu_unquiesce()
1272*d5ebc493SDan Cross * unquiesce all units
12733a634bfcSVikram Hegde */
12743a634bfcSVikram Hegde int
immu_unquiesce(void)12753a634bfcSVikram Hegde immu_unquiesce(void)
12763a634bfcSVikram Hegde {
12773a634bfcSVikram Hegde immu_t *immu;
12783a634bfcSVikram Hegde int ret = DDI_SUCCESS;
12793a634bfcSVikram Hegde
12803a634bfcSVikram Hegde mutex_enter(&immu_lock);
12813a634bfcSVikram Hegde
128296992ee7SEthindra Ramamurthy if (immu_quiesced == B_FALSE) {
128396992ee7SEthindra Ramamurthy mutex_exit(&immu_lock);
12843a634bfcSVikram Hegde return (DDI_SUCCESS);
128596992ee7SEthindra Ramamurthy }
12863a634bfcSVikram Hegde
12873a634bfcSVikram Hegde immu = list_head(&immu_list);
12883a634bfcSVikram Hegde for (; immu; immu = list_next(&immu_list, immu)) {
12893a634bfcSVikram Hegde
12903a634bfcSVikram Hegde mutex_enter(&(immu->immu_lock));
12913a634bfcSVikram Hegde
12923a634bfcSVikram Hegde /* if immu was not quiesced, i.e was not running before */
1293e03dceedSVikram Hegde if (immu->immu_regs_quiesced == B_FALSE) {
1294e03dceedSVikram Hegde mutex_exit(&(immu->immu_lock));
12953a634bfcSVikram Hegde continue;
1296e03dceedSVikram Hegde }
12973a634bfcSVikram Hegde
12983a634bfcSVikram Hegde if (immu_regs_resume(immu) != DDI_SUCCESS) {
12993a634bfcSVikram Hegde ret = DDI_FAILURE;
1300e03dceedSVikram Hegde mutex_exit(&(immu->immu_lock));
13013a634bfcSVikram Hegde continue;
13023a634bfcSVikram Hegde }
13033a634bfcSVikram Hegde
13043a634bfcSVikram Hegde /* flush caches before unquiesce */
13053a634bfcSVikram Hegde rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
130650200e77SFrank Van Der Linden immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
130750200e77SFrank Van Der Linden immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
13083a634bfcSVikram Hegde rw_exit(&(immu->immu_ctx_rwlock));
13093a634bfcSVikram Hegde
13103a634bfcSVikram Hegde /*
13113a634bfcSVikram Hegde * Set IOMMU unit's regs to do
13123a634bfcSVikram Hegde * the actual startup. This will
13133a634bfcSVikram Hegde * set immu->immu_regs_running field
13143a634bfcSVikram Hegde * if the unit is successfully
13153a634bfcSVikram Hegde * started
13163a634bfcSVikram Hegde */
13173a634bfcSVikram Hegde immu_regs_startup(immu);
13183a634bfcSVikram Hegde
13193a634bfcSVikram Hegde if (immu->immu_regs_running == B_FALSE) {
13203a634bfcSVikram Hegde ret = DDI_FAILURE;
13213a634bfcSVikram Hegde } else {
13223a634bfcSVikram Hegde immu_quiesced = B_TRUE;
13233a634bfcSVikram Hegde immu_running = B_TRUE;
13243a634bfcSVikram Hegde immu->immu_regs_quiesced = B_FALSE;
13253a634bfcSVikram Hegde }
13263a634bfcSVikram Hegde
13273a634bfcSVikram Hegde mutex_exit(&(immu->immu_lock));
13283a634bfcSVikram Hegde }
13293a634bfcSVikram Hegde
13303a634bfcSVikram Hegde mutex_exit(&immu_lock);
13313a634bfcSVikram Hegde
13323a634bfcSVikram Hegde return (ret);
13333a634bfcSVikram Hegde }
13343a634bfcSVikram Hegde
133550200e77SFrank Van Der Linden void
immu_init_inv_wait(immu_inv_wait_t * iwp,const char * name,boolean_t sync)133650200e77SFrank Van Der Linden immu_init_inv_wait(immu_inv_wait_t *iwp, const char *name, boolean_t sync)
133750200e77SFrank Van Der Linden {
133850200e77SFrank Van Der Linden caddr_t vaddr;
133950200e77SFrank Van Der Linden uint64_t paddr;
134050200e77SFrank Van Der Linden
134150200e77SFrank Van Der Linden iwp->iwp_sync = sync;
134250200e77SFrank Van Der Linden
134350200e77SFrank Van Der Linden vaddr = (caddr_t)&iwp->iwp_vstatus;
134450200e77SFrank Van Der Linden paddr = pfn_to_pa(hat_getpfnum(kas.a_hat, vaddr));
134550200e77SFrank Van Der Linden paddr += ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
134650200e77SFrank Van Der Linden
134750200e77SFrank Van Der Linden iwp->iwp_pstatus = paddr;
134850200e77SFrank Van Der Linden iwp->iwp_name = name;
134950200e77SFrank Van Der Linden }
135050200e77SFrank Van Der Linden
13513a634bfcSVikram Hegde /* ############## END Intel IOMMU entry points ################## */
1352