111600SVikram.Hegde@Sun.COM /*
211600SVikram.Hegde@Sun.COM * CDDL HEADER START
311600SVikram.Hegde@Sun.COM *
411600SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the
511600SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License").
611600SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License.
711600SVikram.Hegde@Sun.COM *
811600SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911600SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011600SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions
1111600SVikram.Hegde@Sun.COM * and limitations under the License.
1211600SVikram.Hegde@Sun.COM *
1311600SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411600SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511600SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611600SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711600SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811600SVikram.Hegde@Sun.COM *
1911600SVikram.Hegde@Sun.COM * CDDL HEADER END
2011600SVikram.Hegde@Sun.COM */
2111600SVikram.Hegde@Sun.COM /*
2212465Sfrank.van.der.linden@oracle.com * Portions Copyright (c) 2010, Oracle and/or its affiliates.
2312465Sfrank.van.der.linden@oracle.com * All rights reserved.
2411600SVikram.Hegde@Sun.COM */
2511600SVikram.Hegde@Sun.COM /*
2611600SVikram.Hegde@Sun.COM * Copyright (c) 2009, Intel Corporation.
2711600SVikram.Hegde@Sun.COM * All rights reserved.
2811600SVikram.Hegde@Sun.COM */
2911600SVikram.Hegde@Sun.COM
3011600SVikram.Hegde@Sun.COM /*
3111600SVikram.Hegde@Sun.COM * Intel IOMMU implementation
3211600SVikram.Hegde@Sun.COM * This file contains Intel IOMMU code exported
3311600SVikram.Hegde@Sun.COM * to the rest of the system and code that deals
3411600SVikram.Hegde@Sun.COM * with the Intel IOMMU as a whole.
3511600SVikram.Hegde@Sun.COM */
3611600SVikram.Hegde@Sun.COM
3711600SVikram.Hegde@Sun.COM #include <sys/conf.h>
3811600SVikram.Hegde@Sun.COM #include <sys/modctl.h>
3911600SVikram.Hegde@Sun.COM #include <sys/pci.h>
4011600SVikram.Hegde@Sun.COM #include <sys/pci_impl.h>
4111600SVikram.Hegde@Sun.COM #include <sys/sysmacros.h>
4211600SVikram.Hegde@Sun.COM #include <sys/ddi.h>
4311600SVikram.Hegde@Sun.COM #include <sys/ddidmareq.h>
4411600SVikram.Hegde@Sun.COM #include <sys/ddi_impldefs.h>
4511600SVikram.Hegde@Sun.COM #include <sys/ddifm.h>
4611600SVikram.Hegde@Sun.COM #include <sys/sunndi.h>
4711600SVikram.Hegde@Sun.COM #include <sys/debug.h>
4811600SVikram.Hegde@Sun.COM #include <sys/fm/protocol.h>
4911600SVikram.Hegde@Sun.COM #include <sys/note.h>
5011600SVikram.Hegde@Sun.COM #include <sys/apic.h>
5111600SVikram.Hegde@Sun.COM #include <vm/hat_i86.h>
5211600SVikram.Hegde@Sun.COM #include <sys/smp_impldefs.h>
5311600SVikram.Hegde@Sun.COM #include <sys/spl.h>
5411600SVikram.Hegde@Sun.COM #include <sys/archsystm.h>
5511600SVikram.Hegde@Sun.COM #include <sys/x86_archext.h>
5611600SVikram.Hegde@Sun.COM #include <sys/avl.h>
5711600SVikram.Hegde@Sun.COM #include <sys/bootconf.h>
5811600SVikram.Hegde@Sun.COM #include <sys/bootinfo.h>
5911600SVikram.Hegde@Sun.COM #include <sys/atomic.h>
6011600SVikram.Hegde@Sun.COM #include <sys/immu.h>
6111600SVikram.Hegde@Sun.COM /* ########################### Globals and tunables ######################## */
6211600SVikram.Hegde@Sun.COM /*
6311600SVikram.Hegde@Sun.COM * Global switches (boolean) that can be toggled either via boot options
6411600SVikram.Hegde@Sun.COM * or via /etc/system or kmdb
6511600SVikram.Hegde@Sun.COM */
6611600SVikram.Hegde@Sun.COM
6711600SVikram.Hegde@Sun.COM /* Various features */
6811749SVikram.Hegde@Sun.COM boolean_t immu_enable = B_TRUE;
6911600SVikram.Hegde@Sun.COM boolean_t immu_dvma_enable = B_TRUE;
7011600SVikram.Hegde@Sun.COM
7111600SVikram.Hegde@Sun.COM /* accessed in other files so not static */
7211600SVikram.Hegde@Sun.COM boolean_t immu_gfxdvma_enable = B_TRUE;
7311600SVikram.Hegde@Sun.COM boolean_t immu_intrmap_enable = B_FALSE;
7413050Sfrank.van.der.linden@oracle.com boolean_t immu_qinv_enable = B_TRUE;
7511600SVikram.Hegde@Sun.COM
7611600SVikram.Hegde@Sun.COM /* various quirks that need working around */
7711600SVikram.Hegde@Sun.COM
7811600SVikram.Hegde@Sun.COM /* XXX We always map page 0 read/write for now */
7911600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbpage0 = B_TRUE;
8011600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbrmrr = B_TRUE;
8111600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbfullpa;
8211600SVikram.Hegde@Sun.COM boolean_t immu_quirk_mobile4;
8311600SVikram.Hegde@Sun.COM
8411600SVikram.Hegde@Sun.COM /* debug messages */
8511600SVikram.Hegde@Sun.COM boolean_t immu_dmar_print;
8611600SVikram.Hegde@Sun.COM
8711658SVikram.Hegde@Sun.COM /* Tunables */
8811658SVikram.Hegde@Sun.COM int64_t immu_flush_gran = 5;
8911658SVikram.Hegde@Sun.COM
9012465Sfrank.van.der.linden@oracle.com immu_flags_t immu_global_dvma_flags;
9112465Sfrank.van.der.linden@oracle.com
9211600SVikram.Hegde@Sun.COM /* ############ END OPTIONS section ################ */
9311600SVikram.Hegde@Sun.COM
9411600SVikram.Hegde@Sun.COM /*
9511600SVikram.Hegde@Sun.COM * Global used internally by Intel IOMMU code
9611600SVikram.Hegde@Sun.COM */
9711600SVikram.Hegde@Sun.COM dev_info_t *root_devinfo;
9811600SVikram.Hegde@Sun.COM kmutex_t immu_lock;
9911600SVikram.Hegde@Sun.COM list_t immu_list;
10011600SVikram.Hegde@Sun.COM boolean_t immu_setup;
10111600SVikram.Hegde@Sun.COM boolean_t immu_running;
10211600SVikram.Hegde@Sun.COM boolean_t immu_quiesced;
10311600SVikram.Hegde@Sun.COM
10411600SVikram.Hegde@Sun.COM /* ######################## END Globals and tunables ###################### */
10511600SVikram.Hegde@Sun.COM /* Globals used only in this file */
10611600SVikram.Hegde@Sun.COM static char **black_array;
10711600SVikram.Hegde@Sun.COM static uint_t nblacks;
10812465Sfrank.van.der.linden@oracle.com
10912465Sfrank.van.der.linden@oracle.com static char **unity_driver_array;
11012465Sfrank.van.der.linden@oracle.com static uint_t nunity;
11112465Sfrank.van.der.linden@oracle.com static char **xlate_driver_array;
11212465Sfrank.van.der.linden@oracle.com static uint_t nxlate;
11313050Sfrank.van.der.linden@oracle.com
11413050Sfrank.van.der.linden@oracle.com static char **premap_driver_array;
11513050Sfrank.van.der.linden@oracle.com static uint_t npremap;
11613050Sfrank.van.der.linden@oracle.com static char **nopremap_driver_array;
11713050Sfrank.van.der.linden@oracle.com static uint_t nnopremap;
11811600SVikram.Hegde@Sun.COM /* ###################### Utility routines ############################# */
11911600SVikram.Hegde@Sun.COM
12011600SVikram.Hegde@Sun.COM /*
12111600SVikram.Hegde@Sun.COM * Check if the device has mobile 4 chipset
12211600SVikram.Hegde@Sun.COM */
12311600SVikram.Hegde@Sun.COM static int
check_mobile4(dev_info_t * dip,void * arg)12411600SVikram.Hegde@Sun.COM check_mobile4(dev_info_t *dip, void *arg)
12511600SVikram.Hegde@Sun.COM {
12611600SVikram.Hegde@Sun.COM _NOTE(ARGUNUSED(arg));
12711600SVikram.Hegde@Sun.COM int vendor, device;
12811600SVikram.Hegde@Sun.COM int *ip = (int *)arg;
12911600SVikram.Hegde@Sun.COM
13011600SVikram.Hegde@Sun.COM vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
13111600SVikram.Hegde@Sun.COM "vendor-id", -1);
13211600SVikram.Hegde@Sun.COM device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
13311600SVikram.Hegde@Sun.COM "device-id", -1);
13411600SVikram.Hegde@Sun.COM
13511600SVikram.Hegde@Sun.COM if (vendor == 0x8086 && device == 0x2a40) {
13611600SVikram.Hegde@Sun.COM *ip = B_TRUE;
13713050Sfrank.van.der.linden@oracle.com ddi_err(DER_NOTE, dip, "iommu: Mobile 4 chipset detected. "
13811600SVikram.Hegde@Sun.COM "Force setting IOMMU write buffer");
13911600SVikram.Hegde@Sun.COM return (DDI_WALK_TERMINATE);
14011600SVikram.Hegde@Sun.COM } else {
14111600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE);
14211600SVikram.Hegde@Sun.COM }
14311600SVikram.Hegde@Sun.COM }
14411600SVikram.Hegde@Sun.COM
14511600SVikram.Hegde@Sun.COM static void
map_bios_rsvd_mem(dev_info_t * dip)14611600SVikram.Hegde@Sun.COM map_bios_rsvd_mem(dev_info_t *dip)
14711600SVikram.Hegde@Sun.COM {
14811600SVikram.Hegde@Sun.COM struct memlist *mp;
14913050Sfrank.van.der.linden@oracle.com
15013050Sfrank.van.der.linden@oracle.com /*
15113050Sfrank.van.der.linden@oracle.com * Make sure the domain for the device is set up before
15213050Sfrank.van.der.linden@oracle.com * mapping anything.
15313050Sfrank.van.der.linden@oracle.com */
15413050Sfrank.van.der.linden@oracle.com (void) immu_dvma_device_setup(dip, 0);
15511600SVikram.Hegde@Sun.COM
15611600SVikram.Hegde@Sun.COM memlist_read_lock();
15711600SVikram.Hegde@Sun.COM
15811600SVikram.Hegde@Sun.COM mp = bios_rsvd;
15911600SVikram.Hegde@Sun.COM while (mp != NULL) {
16011658SVikram.Hegde@Sun.COM memrng_t mrng = {0};
16111600SVikram.Hegde@Sun.COM
16213050Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, dip, "iommu: Mapping BIOS rsvd range "
16311600SVikram.Hegde@Sun.COM "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address,
16411600SVikram.Hegde@Sun.COM mp->ml_address + mp->ml_size);
16511600SVikram.Hegde@Sun.COM
16611658SVikram.Hegde@Sun.COM mrng.mrng_start = IMMU_ROUNDOWN(mp->ml_address);
16711658SVikram.Hegde@Sun.COM mrng.mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE;
16811600SVikram.Hegde@Sun.COM
16913050Sfrank.van.der.linden@oracle.com (void) immu_map_memrange(dip, &mrng);
17011600SVikram.Hegde@Sun.COM
17111600SVikram.Hegde@Sun.COM mp = mp->ml_next;
17211600SVikram.Hegde@Sun.COM }
17311600SVikram.Hegde@Sun.COM
17411600SVikram.Hegde@Sun.COM memlist_read_unlock();
17511600SVikram.Hegde@Sun.COM }
17611600SVikram.Hegde@Sun.COM
17711658SVikram.Hegde@Sun.COM
17811658SVikram.Hegde@Sun.COM /*
17912465Sfrank.van.der.linden@oracle.com * Check if the driver requests a specific type of mapping.
18011658SVikram.Hegde@Sun.COM */
18111658SVikram.Hegde@Sun.COM /*ARGSUSED*/
18211658SVikram.Hegde@Sun.COM static void
check_conf(dev_info_t * dip,void * arg)18312465Sfrank.van.der.linden@oracle.com check_conf(dev_info_t *dip, void *arg)
18411658SVikram.Hegde@Sun.COM {
18512465Sfrank.van.der.linden@oracle.com immu_devi_t *immu_devi;
18612465Sfrank.van.der.linden@oracle.com const char *dname;
18712465Sfrank.van.der.linden@oracle.com uint_t i;
18813050Sfrank.van.der.linden@oracle.com int hasmapprop = 0, haspreprop = 0;
18913050Sfrank.van.der.linden@oracle.com boolean_t old_premap;
19011658SVikram.Hegde@Sun.COM
19111658SVikram.Hegde@Sun.COM /*
19212465Sfrank.van.der.linden@oracle.com * Only PCI devices can use an IOMMU. Legacy ISA devices
19312465Sfrank.van.der.linden@oracle.com * are handled in check_lpc.
19411658SVikram.Hegde@Sun.COM */
19512465Sfrank.van.der.linden@oracle.com if (!DEVI_IS_PCI(dip))
19612465Sfrank.van.der.linden@oracle.com return;
19712465Sfrank.van.der.linden@oracle.com
19812465Sfrank.van.der.linden@oracle.com dname = ddi_driver_name(dip);
19912465Sfrank.van.der.linden@oracle.com if (dname == NULL)
20012465Sfrank.van.der.linden@oracle.com return;
20112465Sfrank.van.der.linden@oracle.com immu_devi = immu_devi_get(dip);
20212465Sfrank.van.der.linden@oracle.com
20312465Sfrank.van.der.linden@oracle.com for (i = 0; i < nunity; i++) {
20412465Sfrank.van.der.linden@oracle.com if (strcmp(unity_driver_array[i], dname) == 0) {
20513050Sfrank.van.der.linden@oracle.com hasmapprop = 1;
20612465Sfrank.van.der.linden@oracle.com immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
20712465Sfrank.van.der.linden@oracle.com }
20812465Sfrank.van.der.linden@oracle.com }
20911658SVikram.Hegde@Sun.COM
21012465Sfrank.van.der.linden@oracle.com for (i = 0; i < nxlate; i++) {
21112465Sfrank.van.der.linden@oracle.com if (strcmp(xlate_driver_array[i], dname) == 0) {
21213050Sfrank.van.der.linden@oracle.com hasmapprop = 1;
21312465Sfrank.van.der.linden@oracle.com immu_devi->imd_dvma_flags &= ~IMMU_FLAGS_UNITY;
21411658SVikram.Hegde@Sun.COM }
21511658SVikram.Hegde@Sun.COM }
21612465Sfrank.van.der.linden@oracle.com
21713050Sfrank.van.der.linden@oracle.com old_premap = immu_devi->imd_use_premap;
21813050Sfrank.van.der.linden@oracle.com
21913050Sfrank.van.der.linden@oracle.com for (i = 0; i < nnopremap; i++) {
22013050Sfrank.van.der.linden@oracle.com if (strcmp(nopremap_driver_array[i], dname) == 0) {
22113050Sfrank.van.der.linden@oracle.com haspreprop = 1;
22213050Sfrank.van.der.linden@oracle.com immu_devi->imd_use_premap = B_FALSE;
22313050Sfrank.van.der.linden@oracle.com }
22413050Sfrank.van.der.linden@oracle.com }
22513050Sfrank.van.der.linden@oracle.com
22613050Sfrank.van.der.linden@oracle.com for (i = 0; i < npremap; i++) {
22713050Sfrank.van.der.linden@oracle.com if (strcmp(premap_driver_array[i], dname) == 0) {
22813050Sfrank.van.der.linden@oracle.com haspreprop = 1;
22913050Sfrank.van.der.linden@oracle.com immu_devi->imd_use_premap = B_TRUE;
23013050Sfrank.van.der.linden@oracle.com }
23113050Sfrank.van.der.linden@oracle.com }
23213050Sfrank.van.der.linden@oracle.com
23312465Sfrank.van.der.linden@oracle.com /*
23412465Sfrank.van.der.linden@oracle.com * Report if we changed the value from the default.
23512465Sfrank.van.der.linden@oracle.com */
23613050Sfrank.van.der.linden@oracle.com if (hasmapprop && (immu_devi->imd_dvma_flags ^ immu_global_dvma_flags))
23712465Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, dip, "using %s DVMA mapping",
23812465Sfrank.van.der.linden@oracle.com immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY ?
23912465Sfrank.van.der.linden@oracle.com DDI_DVMA_MAPTYPE_UNITY : DDI_DVMA_MAPTYPE_XLATE);
24013050Sfrank.van.der.linden@oracle.com
24113050Sfrank.van.der.linden@oracle.com if (haspreprop && (immu_devi->imd_use_premap != old_premap))
24213050Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, dip, "%susing premapped DVMA space",
24313050Sfrank.van.der.linden@oracle.com immu_devi->imd_use_premap ? "" : "not ");
24411658SVikram.Hegde@Sun.COM }
24511658SVikram.Hegde@Sun.COM
24611600SVikram.Hegde@Sun.COM /*
24711600SVikram.Hegde@Sun.COM * Check if the device is USB controller
24811600SVikram.Hegde@Sun.COM */
24911600SVikram.Hegde@Sun.COM /*ARGSUSED*/
25011600SVikram.Hegde@Sun.COM static void
check_usb(dev_info_t * dip,void * arg)25111600SVikram.Hegde@Sun.COM check_usb(dev_info_t *dip, void *arg)
25211600SVikram.Hegde@Sun.COM {
25311600SVikram.Hegde@Sun.COM const char *drv = ddi_driver_name(dip);
25412465Sfrank.van.der.linden@oracle.com immu_devi_t *immu_devi;
25512465Sfrank.van.der.linden@oracle.com
25611600SVikram.Hegde@Sun.COM
25711600SVikram.Hegde@Sun.COM if (drv == NULL ||
25811600SVikram.Hegde@Sun.COM (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 &&
25911600SVikram.Hegde@Sun.COM strcmp(drv, "ehci") != 0)) {
26011600SVikram.Hegde@Sun.COM return;
26111600SVikram.Hegde@Sun.COM }
26211600SVikram.Hegde@Sun.COM
26312465Sfrank.van.der.linden@oracle.com immu_devi = immu_devi_get(dip);
26412465Sfrank.van.der.linden@oracle.com
26512465Sfrank.van.der.linden@oracle.com /*
26612465Sfrank.van.der.linden@oracle.com * If unit mappings are already specified, globally or
26712465Sfrank.van.der.linden@oracle.com * locally, we're done here, since that covers both
26812465Sfrank.van.der.linden@oracle.com * quirks below.
26912465Sfrank.van.der.linden@oracle.com */
27012465Sfrank.van.der.linden@oracle.com if (immu_devi->imd_dvma_flags & IMMU_FLAGS_UNITY)
27112465Sfrank.van.der.linden@oracle.com return;
27212465Sfrank.van.der.linden@oracle.com
27311600SVikram.Hegde@Sun.COM /* This must come first since it does unity mapping */
27411600SVikram.Hegde@Sun.COM if (immu_quirk_usbfullpa == B_TRUE) {
27512465Sfrank.van.der.linden@oracle.com immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
27612465Sfrank.van.der.linden@oracle.com } else if (immu_quirk_usbrmrr == B_TRUE) {
27711600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, dip, "Applying USB RMRR quirk");
27811600SVikram.Hegde@Sun.COM map_bios_rsvd_mem(dip);
27911600SVikram.Hegde@Sun.COM }
28011600SVikram.Hegde@Sun.COM }
28111600SVikram.Hegde@Sun.COM
28211600SVikram.Hegde@Sun.COM /*
28311600SVikram.Hegde@Sun.COM * Check if the device is a LPC device
28411600SVikram.Hegde@Sun.COM */
28511600SVikram.Hegde@Sun.COM /*ARGSUSED*/
28611600SVikram.Hegde@Sun.COM static void
check_lpc(dev_info_t * dip,void * arg)28711600SVikram.Hegde@Sun.COM check_lpc(dev_info_t *dip, void *arg)
28811600SVikram.Hegde@Sun.COM {
28911600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi;
29011600SVikram.Hegde@Sun.COM
29111600SVikram.Hegde@Sun.COM immu_devi = immu_devi_get(dip);
29211600SVikram.Hegde@Sun.COM if (immu_devi->imd_lpc == B_TRUE) {
29313050Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, dip, "iommu: Found LPC device");
29411600SVikram.Hegde@Sun.COM /* This will put the immu_devi on the LPC "specials" list */
29513050Sfrank.van.der.linden@oracle.com (void) immu_dvma_device_setup(dip, IMMU_FLAGS_SLEEP);
29611600SVikram.Hegde@Sun.COM }
29711600SVikram.Hegde@Sun.COM }
29811600SVikram.Hegde@Sun.COM
29911600SVikram.Hegde@Sun.COM /*
30011600SVikram.Hegde@Sun.COM * Check if the device is a GFX device
30111600SVikram.Hegde@Sun.COM */
30211600SVikram.Hegde@Sun.COM /*ARGSUSED*/
30311600SVikram.Hegde@Sun.COM static void
check_gfx(dev_info_t * dip,void * arg)30411600SVikram.Hegde@Sun.COM check_gfx(dev_info_t *dip, void *arg)
30511600SVikram.Hegde@Sun.COM {
30611600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi;
30711600SVikram.Hegde@Sun.COM
30811600SVikram.Hegde@Sun.COM immu_devi = immu_devi_get(dip);
30911600SVikram.Hegde@Sun.COM if (immu_devi->imd_display == B_TRUE) {
31012465Sfrank.van.der.linden@oracle.com immu_devi->imd_dvma_flags |= IMMU_FLAGS_UNITY;
31113050Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, dip, "iommu: Found GFX device");
31211600SVikram.Hegde@Sun.COM /* This will put the immu_devi on the GFX "specials" list */
31311600SVikram.Hegde@Sun.COM (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP);
31411600SVikram.Hegde@Sun.COM }
31511600SVikram.Hegde@Sun.COM }
31611600SVikram.Hegde@Sun.COM
31711600SVikram.Hegde@Sun.COM static void
walk_tree(int (* f)(dev_info_t *,void *),void * arg)31811600SVikram.Hegde@Sun.COM walk_tree(int (*f)(dev_info_t *, void *), void *arg)
31911600SVikram.Hegde@Sun.COM {
32011600SVikram.Hegde@Sun.COM int count;
32111600SVikram.Hegde@Sun.COM
32211600SVikram.Hegde@Sun.COM ndi_devi_enter(root_devinfo, &count);
32311600SVikram.Hegde@Sun.COM ddi_walk_devs(ddi_get_child(root_devinfo), f, arg);
32411600SVikram.Hegde@Sun.COM ndi_devi_exit(root_devinfo, count);
32511600SVikram.Hegde@Sun.COM }
32611600SVikram.Hegde@Sun.COM
32711600SVikram.Hegde@Sun.COM static int
check_pre_setup_quirks(dev_info_t * dip,void * arg)32811600SVikram.Hegde@Sun.COM check_pre_setup_quirks(dev_info_t *dip, void *arg)
32911600SVikram.Hegde@Sun.COM {
33011600SVikram.Hegde@Sun.COM /* just 1 check right now */
33111600SVikram.Hegde@Sun.COM return (check_mobile4(dip, arg));
33211600SVikram.Hegde@Sun.COM }
33311600SVikram.Hegde@Sun.COM
33411600SVikram.Hegde@Sun.COM static int
check_pre_startup_quirks(dev_info_t * dip,void * arg)33511600SVikram.Hegde@Sun.COM check_pre_startup_quirks(dev_info_t *dip, void *arg)
33611600SVikram.Hegde@Sun.COM {
33711600SVikram.Hegde@Sun.COM if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) {
33811600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, dip, "Failed to get immu_devi");
33911600SVikram.Hegde@Sun.COM }
34011600SVikram.Hegde@Sun.COM
34111600SVikram.Hegde@Sun.COM check_gfx(dip, arg);
34211600SVikram.Hegde@Sun.COM
34311600SVikram.Hegde@Sun.COM check_lpc(dip, arg);
34411600SVikram.Hegde@Sun.COM
34512465Sfrank.van.der.linden@oracle.com check_conf(dip, arg);
34611600SVikram.Hegde@Sun.COM
34712465Sfrank.van.der.linden@oracle.com check_usb(dip, arg);
34811658SVikram.Hegde@Sun.COM
34911600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE);
35011600SVikram.Hegde@Sun.COM }
35111600SVikram.Hegde@Sun.COM
35211600SVikram.Hegde@Sun.COM static void
pre_setup_quirks(void)35311600SVikram.Hegde@Sun.COM pre_setup_quirks(void)
35411600SVikram.Hegde@Sun.COM {
35511600SVikram.Hegde@Sun.COM walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4);
35611600SVikram.Hegde@Sun.COM }
35711600SVikram.Hegde@Sun.COM
35811600SVikram.Hegde@Sun.COM static void
pre_startup_quirks(void)35911600SVikram.Hegde@Sun.COM pre_startup_quirks(void)
36011600SVikram.Hegde@Sun.COM {
36111600SVikram.Hegde@Sun.COM walk_tree(check_pre_startup_quirks, NULL);
36211600SVikram.Hegde@Sun.COM
36311600SVikram.Hegde@Sun.COM immu_dmar_rmrr_map();
36411600SVikram.Hegde@Sun.COM }
36511600SVikram.Hegde@Sun.COM
36612465Sfrank.van.der.linden@oracle.com static int
get_conf_str(char * bopt,char ** val)36712465Sfrank.van.der.linden@oracle.com get_conf_str(char *bopt, char **val)
36812465Sfrank.van.der.linden@oracle.com {
36912465Sfrank.van.der.linden@oracle.com int ret;
37012465Sfrank.van.der.linden@oracle.com
37112465Sfrank.van.der.linden@oracle.com /*
37212465Sfrank.van.der.linden@oracle.com * Check the rootnex.conf property
37312465Sfrank.van.der.linden@oracle.com * Fake up a dev_t since searching the global
37412465Sfrank.van.der.linden@oracle.com * property list needs it
37512465Sfrank.van.der.linden@oracle.com */
37612465Sfrank.van.der.linden@oracle.com ret = ddi_prop_lookup_string(
37712465Sfrank.van.der.linden@oracle.com makedevice(ddi_name_to_major("rootnex"), 0),
37812465Sfrank.van.der.linden@oracle.com root_devinfo, DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
37912465Sfrank.van.der.linden@oracle.com bopt, val);
38012465Sfrank.van.der.linden@oracle.com
38112465Sfrank.van.der.linden@oracle.com return (ret);
38212465Sfrank.van.der.linden@oracle.com }
38312465Sfrank.van.der.linden@oracle.com
38411600SVikram.Hegde@Sun.COM /*
38511749SVikram.Hegde@Sun.COM * get_conf_opt()
38611749SVikram.Hegde@Sun.COM * get a rootnex.conf setting (always a boolean)
38711749SVikram.Hegde@Sun.COM */
38811749SVikram.Hegde@Sun.COM static void
get_conf_opt(char * bopt,boolean_t * kvar)38911749SVikram.Hegde@Sun.COM get_conf_opt(char *bopt, boolean_t *kvar)
39011749SVikram.Hegde@Sun.COM {
39111749SVikram.Hegde@Sun.COM char *val = NULL;
39211749SVikram.Hegde@Sun.COM
39311749SVikram.Hegde@Sun.COM /*
39411749SVikram.Hegde@Sun.COM * Check the rootnex.conf property
39511749SVikram.Hegde@Sun.COM * Fake up a dev_t since searching the global
39611749SVikram.Hegde@Sun.COM * property list needs it
39711749SVikram.Hegde@Sun.COM */
39812465Sfrank.van.der.linden@oracle.com
39912465Sfrank.van.der.linden@oracle.com if (get_conf_str(bopt, &val) != DDI_PROP_SUCCESS)
40011749SVikram.Hegde@Sun.COM return;
40111749SVikram.Hegde@Sun.COM
40211749SVikram.Hegde@Sun.COM if (strcmp(val, "true") == 0) {
40311749SVikram.Hegde@Sun.COM *kvar = B_TRUE;
40411749SVikram.Hegde@Sun.COM } else if (strcmp(val, "false") == 0) {
40511749SVikram.Hegde@Sun.COM *kvar = B_FALSE;
40611749SVikram.Hegde@Sun.COM } else {
40711749SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "rootnex.conf switch %s=\"%s\" ",
40811749SVikram.Hegde@Sun.COM "is not set to true or false. Ignoring option.",
40911749SVikram.Hegde@Sun.COM bopt, val);
41011749SVikram.Hegde@Sun.COM }
41111749SVikram.Hegde@Sun.COM ddi_prop_free(val);
41211749SVikram.Hegde@Sun.COM }
41311749SVikram.Hegde@Sun.COM
41411749SVikram.Hegde@Sun.COM /*
41511600SVikram.Hegde@Sun.COM * get_bootopt()
41611600SVikram.Hegde@Sun.COM * check a boot option (always a boolean)
41711600SVikram.Hegde@Sun.COM */
41812465Sfrank.van.der.linden@oracle.com static int
get_boot_str(char * bopt,char ** val)41912465Sfrank.van.der.linden@oracle.com get_boot_str(char *bopt, char **val)
42012465Sfrank.van.der.linden@oracle.com {
42112465Sfrank.van.der.linden@oracle.com int ret;
42212465Sfrank.van.der.linden@oracle.com
42312465Sfrank.van.der.linden@oracle.com ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo,
42412465Sfrank.van.der.linden@oracle.com DDI_PROP_DONTPASS, bopt, val);
42512465Sfrank.van.der.linden@oracle.com
42612465Sfrank.van.der.linden@oracle.com return (ret);
42712465Sfrank.van.der.linden@oracle.com }
42812465Sfrank.van.der.linden@oracle.com
42911600SVikram.Hegde@Sun.COM static void
get_bootopt(char * bopt,boolean_t * kvar)43011600SVikram.Hegde@Sun.COM get_bootopt(char *bopt, boolean_t *kvar)
43111600SVikram.Hegde@Sun.COM {
43211600SVikram.Hegde@Sun.COM char *val = NULL;
43311600SVikram.Hegde@Sun.COM
43411600SVikram.Hegde@Sun.COM /*
43511600SVikram.Hegde@Sun.COM * All boot options set at the GRUB menu become
43611600SVikram.Hegde@Sun.COM * properties on the rootnex.
43711600SVikram.Hegde@Sun.COM */
43812465Sfrank.van.der.linden@oracle.com if (get_boot_str(bopt, &val) != DDI_PROP_SUCCESS)
43912465Sfrank.van.der.linden@oracle.com return;
44012465Sfrank.van.der.linden@oracle.com
44112465Sfrank.van.der.linden@oracle.com if (strcmp(val, "true") == 0) {
44212465Sfrank.van.der.linden@oracle.com *kvar = B_TRUE;
44312465Sfrank.van.der.linden@oracle.com } else if (strcmp(val, "false") == 0) {
44412465Sfrank.van.der.linden@oracle.com *kvar = B_FALSE;
44512465Sfrank.van.der.linden@oracle.com } else {
44612465Sfrank.van.der.linden@oracle.com ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ",
44712465Sfrank.van.der.linden@oracle.com "is not set to true or false. Ignoring option.",
44812465Sfrank.van.der.linden@oracle.com bopt, val);
44911600SVikram.Hegde@Sun.COM }
45012465Sfrank.van.der.linden@oracle.com ddi_prop_free(val);
45111600SVikram.Hegde@Sun.COM }
45211600SVikram.Hegde@Sun.COM
45311600SVikram.Hegde@Sun.COM static void
get_boot_dvma_mode(void)45412465Sfrank.van.der.linden@oracle.com get_boot_dvma_mode(void)
45512465Sfrank.van.der.linden@oracle.com {
45612465Sfrank.van.der.linden@oracle.com char *val = NULL;
45712465Sfrank.van.der.linden@oracle.com
45812465Sfrank.van.der.linden@oracle.com if (get_boot_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
45912465Sfrank.van.der.linden@oracle.com != DDI_PROP_SUCCESS)
46012465Sfrank.van.der.linden@oracle.com return;
46112465Sfrank.van.der.linden@oracle.com
46212465Sfrank.van.der.linden@oracle.com if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
46312465Sfrank.van.der.linden@oracle.com immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
46412465Sfrank.van.der.linden@oracle.com } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
46512465Sfrank.van.der.linden@oracle.com immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
46612465Sfrank.van.der.linden@oracle.com } else {
46712465Sfrank.van.der.linden@oracle.com ddi_err(DER_WARN, NULL, "bad value \"%s\" for boot option %s",
46812465Sfrank.van.der.linden@oracle.com val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
46912465Sfrank.van.der.linden@oracle.com }
47012465Sfrank.van.der.linden@oracle.com ddi_prop_free(val);
47112465Sfrank.van.der.linden@oracle.com }
47212465Sfrank.van.der.linden@oracle.com
47312465Sfrank.van.der.linden@oracle.com static void
get_conf_dvma_mode(void)47412465Sfrank.van.der.linden@oracle.com get_conf_dvma_mode(void)
47512465Sfrank.van.der.linden@oracle.com {
47612465Sfrank.van.der.linden@oracle.com char *val = NULL;
47712465Sfrank.van.der.linden@oracle.com
47812465Sfrank.van.der.linden@oracle.com if (get_conf_str(DDI_DVMA_MAPTYPE_ROOTNEX_PROP, &val)
47912465Sfrank.van.der.linden@oracle.com != DDI_PROP_SUCCESS)
48012465Sfrank.van.der.linden@oracle.com return;
48112465Sfrank.van.der.linden@oracle.com
48212465Sfrank.van.der.linden@oracle.com if (strcmp(val, DDI_DVMA_MAPTYPE_UNITY) == 0) {
48312465Sfrank.van.der.linden@oracle.com immu_global_dvma_flags |= IMMU_FLAGS_UNITY;
48412465Sfrank.van.der.linden@oracle.com } else if (strcmp(val, DDI_DVMA_MAPTYPE_XLATE) == 0) {
48512465Sfrank.van.der.linden@oracle.com immu_global_dvma_flags &= ~IMMU_FLAGS_UNITY;
48612465Sfrank.van.der.linden@oracle.com } else {
48712465Sfrank.van.der.linden@oracle.com ddi_err(DER_WARN, NULL, "bad value \"%s\" for rootnex "
48812465Sfrank.van.der.linden@oracle.com "option %s", val, DDI_DVMA_MAPTYPE_ROOTNEX_PROP);
48912465Sfrank.van.der.linden@oracle.com }
49012465Sfrank.van.der.linden@oracle.com ddi_prop_free(val);
49112465Sfrank.van.der.linden@oracle.com }
49212465Sfrank.van.der.linden@oracle.com
49312465Sfrank.van.der.linden@oracle.com
49412465Sfrank.van.der.linden@oracle.com static void
get_conf_tunables(char * bopt,int64_t * ivar)49511749SVikram.Hegde@Sun.COM get_conf_tunables(char *bopt, int64_t *ivar)
49611658SVikram.Hegde@Sun.COM {
49711658SVikram.Hegde@Sun.COM int64_t *iarray;
49811658SVikram.Hegde@Sun.COM uint_t n;
49911658SVikram.Hegde@Sun.COM
50011658SVikram.Hegde@Sun.COM /*
50111658SVikram.Hegde@Sun.COM * Check the rootnex.conf property
50211658SVikram.Hegde@Sun.COM * Fake up a dev_t since searching the global
50311658SVikram.Hegde@Sun.COM * property list needs it
50411658SVikram.Hegde@Sun.COM */
50511658SVikram.Hegde@Sun.COM if (ddi_prop_lookup_int64_array(
50611658SVikram.Hegde@Sun.COM makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
50711658SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, bopt,
50811658SVikram.Hegde@Sun.COM &iarray, &n) != DDI_PROP_SUCCESS) {
50911658SVikram.Hegde@Sun.COM return;
51011658SVikram.Hegde@Sun.COM }
51111658SVikram.Hegde@Sun.COM
51211658SVikram.Hegde@Sun.COM if (n != 1) {
51311658SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "More than one value specified for "
51411658SVikram.Hegde@Sun.COM "%s property. Ignoring and using default",
51511658SVikram.Hegde@Sun.COM "immu-flush-gran");
51611658SVikram.Hegde@Sun.COM ddi_prop_free(iarray);
51711658SVikram.Hegde@Sun.COM return;
51811658SVikram.Hegde@Sun.COM }
51911658SVikram.Hegde@Sun.COM
52011658SVikram.Hegde@Sun.COM if (iarray[0] < 0) {
52111658SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Negative value specified for "
52211658SVikram.Hegde@Sun.COM "%s property. Inoring and Using default value",
52311658SVikram.Hegde@Sun.COM "immu-flush-gran");
52411658SVikram.Hegde@Sun.COM ddi_prop_free(iarray);
52511658SVikram.Hegde@Sun.COM return;
52611658SVikram.Hegde@Sun.COM }
52711658SVikram.Hegde@Sun.COM
52811658SVikram.Hegde@Sun.COM *ivar = iarray[0];
52911658SVikram.Hegde@Sun.COM
53011658SVikram.Hegde@Sun.COM ddi_prop_free(iarray);
53111658SVikram.Hegde@Sun.COM }
53211658SVikram.Hegde@Sun.COM
53311658SVikram.Hegde@Sun.COM static void
read_conf_options(void)53411749SVikram.Hegde@Sun.COM read_conf_options(void)
53511749SVikram.Hegde@Sun.COM {
53611749SVikram.Hegde@Sun.COM /* enable/disable options */
53711749SVikram.Hegde@Sun.COM get_conf_opt("immu-enable", &immu_enable);
53811749SVikram.Hegde@Sun.COM get_conf_opt("immu-dvma-enable", &immu_dvma_enable);
53911749SVikram.Hegde@Sun.COM get_conf_opt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
54011749SVikram.Hegde@Sun.COM get_conf_opt("immu-intrmap-enable", &immu_intrmap_enable);
54111749SVikram.Hegde@Sun.COM get_conf_opt("immu-qinv-enable", &immu_qinv_enable);
54211749SVikram.Hegde@Sun.COM
54311749SVikram.Hegde@Sun.COM /* workaround switches */
54411749SVikram.Hegde@Sun.COM get_conf_opt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
54511749SVikram.Hegde@Sun.COM get_conf_opt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
54611749SVikram.Hegde@Sun.COM get_conf_opt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
54711749SVikram.Hegde@Sun.COM
54811749SVikram.Hegde@Sun.COM /* debug printing */
54911749SVikram.Hegde@Sun.COM get_conf_opt("immu-dmar-print", &immu_dmar_print);
55011749SVikram.Hegde@Sun.COM
55111749SVikram.Hegde@Sun.COM /* get tunables */
55211749SVikram.Hegde@Sun.COM get_conf_tunables("immu-flush-gran", &immu_flush_gran);
55312465Sfrank.van.der.linden@oracle.com
55412465Sfrank.van.der.linden@oracle.com get_conf_dvma_mode();
55511749SVikram.Hegde@Sun.COM }
55611749SVikram.Hegde@Sun.COM
55711749SVikram.Hegde@Sun.COM static void
read_boot_options(void)55811600SVikram.Hegde@Sun.COM read_boot_options(void)
55911600SVikram.Hegde@Sun.COM {
56011600SVikram.Hegde@Sun.COM /* enable/disable options */
56111600SVikram.Hegde@Sun.COM get_bootopt("immu-enable", &immu_enable);
56211600SVikram.Hegde@Sun.COM get_bootopt("immu-dvma-enable", &immu_dvma_enable);
56311600SVikram.Hegde@Sun.COM get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable);
56411600SVikram.Hegde@Sun.COM get_bootopt("immu-intrmap-enable", &immu_intrmap_enable);
56511600SVikram.Hegde@Sun.COM get_bootopt("immu-qinv-enable", &immu_qinv_enable);
56611600SVikram.Hegde@Sun.COM
56711600SVikram.Hegde@Sun.COM /* workaround switches */
56811600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0);
56911600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa);
57011600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr);
57111600SVikram.Hegde@Sun.COM
57211600SVikram.Hegde@Sun.COM /* debug printing */
57311600SVikram.Hegde@Sun.COM get_bootopt("immu-dmar-print", &immu_dmar_print);
57412465Sfrank.van.der.linden@oracle.com
57512465Sfrank.van.der.linden@oracle.com get_boot_dvma_mode();
57612465Sfrank.van.der.linden@oracle.com }
57712465Sfrank.van.der.linden@oracle.com
57812465Sfrank.van.der.linden@oracle.com static void
mapping_list_setup(void)57912465Sfrank.van.der.linden@oracle.com mapping_list_setup(void)
58012465Sfrank.van.der.linden@oracle.com {
58112465Sfrank.van.der.linden@oracle.com char **string_array;
58212465Sfrank.van.der.linden@oracle.com uint_t nstrings;
58312465Sfrank.van.der.linden@oracle.com
58412465Sfrank.van.der.linden@oracle.com if (ddi_prop_lookup_string_array(
58512465Sfrank.van.der.linden@oracle.com makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
58612465Sfrank.van.der.linden@oracle.com DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
58712465Sfrank.van.der.linden@oracle.com "immu-dvma-unity-drivers",
58812465Sfrank.van.der.linden@oracle.com &string_array, &nstrings) == DDI_PROP_SUCCESS) {
58912465Sfrank.van.der.linden@oracle.com unity_driver_array = string_array;
59012465Sfrank.van.der.linden@oracle.com nunity = nstrings;
59112465Sfrank.van.der.linden@oracle.com }
59212465Sfrank.van.der.linden@oracle.com
59312465Sfrank.van.der.linden@oracle.com if (ddi_prop_lookup_string_array(
59412465Sfrank.van.der.linden@oracle.com makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
59512465Sfrank.van.der.linden@oracle.com DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
59612465Sfrank.van.der.linden@oracle.com "immu-dvma-xlate-drivers",
59712465Sfrank.van.der.linden@oracle.com &string_array, &nstrings) == DDI_PROP_SUCCESS) {
59812465Sfrank.van.der.linden@oracle.com xlate_driver_array = string_array;
59912465Sfrank.van.der.linden@oracle.com nxlate = nstrings;
60012465Sfrank.van.der.linden@oracle.com }
60113050Sfrank.van.der.linden@oracle.com
60213050Sfrank.van.der.linden@oracle.com if (ddi_prop_lookup_string_array(
60313050Sfrank.van.der.linden@oracle.com makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
60413050Sfrank.van.der.linden@oracle.com DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
60513050Sfrank.van.der.linden@oracle.com "immu-dvma-premap-drivers",
60613050Sfrank.van.der.linden@oracle.com &string_array, &nstrings) == DDI_PROP_SUCCESS) {
60713050Sfrank.van.der.linden@oracle.com premap_driver_array = string_array;
60813050Sfrank.van.der.linden@oracle.com npremap = nstrings;
60913050Sfrank.van.der.linden@oracle.com }
61013050Sfrank.van.der.linden@oracle.com
61113050Sfrank.van.der.linden@oracle.com if (ddi_prop_lookup_string_array(
61213050Sfrank.van.der.linden@oracle.com makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
61313050Sfrank.van.der.linden@oracle.com DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL,
61413050Sfrank.van.der.linden@oracle.com "immu-dvma-nopremap-drivers",
61513050Sfrank.van.der.linden@oracle.com &string_array, &nstrings) == DDI_PROP_SUCCESS) {
61613050Sfrank.van.der.linden@oracle.com nopremap_driver_array = string_array;
61713050Sfrank.van.der.linden@oracle.com nnopremap = nstrings;
61813050Sfrank.van.der.linden@oracle.com }
61911600SVikram.Hegde@Sun.COM }
62011600SVikram.Hegde@Sun.COM
62111600SVikram.Hegde@Sun.COM /*
62211600SVikram.Hegde@Sun.COM * Note, this will not catch hardware not enumerated
62311600SVikram.Hegde@Sun.COM * in early boot
62411600SVikram.Hegde@Sun.COM */
62511600SVikram.Hegde@Sun.COM static boolean_t
blacklisted_driver(void)62611600SVikram.Hegde@Sun.COM blacklisted_driver(void)
62711600SVikram.Hegde@Sun.COM {
62811600SVikram.Hegde@Sun.COM char **strptr;
62911600SVikram.Hegde@Sun.COM int i;
63011600SVikram.Hegde@Sun.COM major_t maj;
63111600SVikram.Hegde@Sun.COM
63211600SVikram.Hegde@Sun.COM /* need at least 2 strings */
63311600SVikram.Hegde@Sun.COM if (nblacks < 2) {
63411600SVikram.Hegde@Sun.COM return (B_FALSE);
63511600SVikram.Hegde@Sun.COM }
63611600SVikram.Hegde@Sun.COM
63711600SVikram.Hegde@Sun.COM for (i = 0; nblacks - i > 1; i++) {
63811658SVikram.Hegde@Sun.COM strptr = &black_array[i];
63911600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, "DRIVER") == 0) {
64011600SVikram.Hegde@Sun.COM if ((maj = ddi_name_to_major(*strptr++))
64111600SVikram.Hegde@Sun.COM != DDI_MAJOR_T_NONE) {
64211600SVikram.Hegde@Sun.COM /* is there hardware bound to this drvr */
64311600SVikram.Hegde@Sun.COM if (devnamesp[maj].dn_head != NULL) {
64411600SVikram.Hegde@Sun.COM return (B_TRUE);
64511600SVikram.Hegde@Sun.COM }
64611600SVikram.Hegde@Sun.COM }
64711600SVikram.Hegde@Sun.COM i += 1; /* for loop adds 1, so add only 1 here */
64811600SVikram.Hegde@Sun.COM }
64911600SVikram.Hegde@Sun.COM }
65011600SVikram.Hegde@Sun.COM
65111600SVikram.Hegde@Sun.COM return (B_FALSE);
65211600SVikram.Hegde@Sun.COM }
65311600SVikram.Hegde@Sun.COM
65411600SVikram.Hegde@Sun.COM static boolean_t
blacklisted_smbios(void)65511600SVikram.Hegde@Sun.COM blacklisted_smbios(void)
65611600SVikram.Hegde@Sun.COM {
65711600SVikram.Hegde@Sun.COM id_t smid;
65811600SVikram.Hegde@Sun.COM smbios_hdl_t *smhdl;
65911600SVikram.Hegde@Sun.COM smbios_info_t sminf;
66011600SVikram.Hegde@Sun.COM smbios_system_t smsys;
66111600SVikram.Hegde@Sun.COM char *mfg, *product, *version;
66211600SVikram.Hegde@Sun.COM char **strptr;
66311600SVikram.Hegde@Sun.COM int i;
66411600SVikram.Hegde@Sun.COM
66511600SVikram.Hegde@Sun.COM /* need at least 4 strings for this setting */
66611600SVikram.Hegde@Sun.COM if (nblacks < 4) {
66711600SVikram.Hegde@Sun.COM return (B_FALSE);
66811600SVikram.Hegde@Sun.COM }
66911600SVikram.Hegde@Sun.COM
67011600SVikram.Hegde@Sun.COM smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL);
67111600SVikram.Hegde@Sun.COM if (smhdl == NULL ||
67211600SVikram.Hegde@Sun.COM (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR ||
67311600SVikram.Hegde@Sun.COM smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) {
67411600SVikram.Hegde@Sun.COM return (B_FALSE);
67511600SVikram.Hegde@Sun.COM }
67611600SVikram.Hegde@Sun.COM
67711600SVikram.Hegde@Sun.COM mfg = (char *)sminf.smbi_manufacturer;
67811600SVikram.Hegde@Sun.COM product = (char *)sminf.smbi_product;
67911600SVikram.Hegde@Sun.COM version = (char *)sminf.smbi_version;
68011600SVikram.Hegde@Sun.COM
68111600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n");
68211600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg);
68311600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product);
68411600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version);
68511600SVikram.Hegde@Sun.COM
68611600SVikram.Hegde@Sun.COM for (i = 0; nblacks - i > 3; i++) {
68711658SVikram.Hegde@Sun.COM strptr = &black_array[i];
68811600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, "SMBIOS") == 0) {
68911600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, mfg) == 0 &&
69011600SVikram.Hegde@Sun.COM ((char *)strptr == '\0' ||
69111600SVikram.Hegde@Sun.COM strcmp(*strptr++, product) == 0) &&
69211600SVikram.Hegde@Sun.COM ((char *)strptr == '\0' ||
69311600SVikram.Hegde@Sun.COM strcmp(*strptr++, version) == 0)) {
69411600SVikram.Hegde@Sun.COM return (B_TRUE);
69511600SVikram.Hegde@Sun.COM }
69611600SVikram.Hegde@Sun.COM i += 3;
69711600SVikram.Hegde@Sun.COM }
69811600SVikram.Hegde@Sun.COM }
69911600SVikram.Hegde@Sun.COM
70011600SVikram.Hegde@Sun.COM return (B_FALSE);
70111600SVikram.Hegde@Sun.COM }
70211600SVikram.Hegde@Sun.COM
70311600SVikram.Hegde@Sun.COM static boolean_t
blacklisted_acpi(void)70411600SVikram.Hegde@Sun.COM blacklisted_acpi(void)
70511600SVikram.Hegde@Sun.COM {
70611600SVikram.Hegde@Sun.COM if (nblacks == 0) {
70711600SVikram.Hegde@Sun.COM return (B_FALSE);
70811600SVikram.Hegde@Sun.COM }
70911600SVikram.Hegde@Sun.COM
71011600SVikram.Hegde@Sun.COM return (immu_dmar_blacklisted(black_array, nblacks));
71111600SVikram.Hegde@Sun.COM }
71211600SVikram.Hegde@Sun.COM
71311600SVikram.Hegde@Sun.COM /*
71411600SVikram.Hegde@Sun.COM * Check if system is blacklisted by Intel IOMMU driver
71511600SVikram.Hegde@Sun.COM * i.e. should Intel IOMMU be disabled on this system
71611600SVikram.Hegde@Sun.COM * Currently a system can be blacklistd based on the
71711600SVikram.Hegde@Sun.COM * following bases:
71811600SVikram.Hegde@Sun.COM *
71911600SVikram.Hegde@Sun.COM * 1. DMAR ACPI table information.
72011600SVikram.Hegde@Sun.COM * This information includes things like
72111600SVikram.Hegde@Sun.COM * manufacturer and revision number. If rootnex.conf
72211600SVikram.Hegde@Sun.COM * has matching info set in its blacklist property
72311600SVikram.Hegde@Sun.COM * then Intel IOMMu will be disabled
72411600SVikram.Hegde@Sun.COM *
72511600SVikram.Hegde@Sun.COM * 2. SMBIOS information
72611600SVikram.Hegde@Sun.COM *
72711600SVikram.Hegde@Sun.COM * 3. Driver installed - useful if a particular
72811600SVikram.Hegde@Sun.COM * driver or hardware is toxic if Intel IOMMU
72911600SVikram.Hegde@Sun.COM * is turned on.
73011600SVikram.Hegde@Sun.COM */
73111600SVikram.Hegde@Sun.COM
73211600SVikram.Hegde@Sun.COM static void
blacklist_setup(void)73311600SVikram.Hegde@Sun.COM blacklist_setup(void)
73411600SVikram.Hegde@Sun.COM {
73511600SVikram.Hegde@Sun.COM char **string_array;
73611600SVikram.Hegde@Sun.COM uint_t nstrings;
73711600SVikram.Hegde@Sun.COM
73811600SVikram.Hegde@Sun.COM /*
73911600SVikram.Hegde@Sun.COM * Check the rootnex.conf blacklist property.
74011600SVikram.Hegde@Sun.COM * Fake up a dev_t since searching the global
74111600SVikram.Hegde@Sun.COM * property list needs it
74211600SVikram.Hegde@Sun.COM */
74311600SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string_array(
74411600SVikram.Hegde@Sun.COM makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo,
74511600SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist",
74611600SVikram.Hegde@Sun.COM &string_array, &nstrings) != DDI_PROP_SUCCESS) {
74711600SVikram.Hegde@Sun.COM return;
74811600SVikram.Hegde@Sun.COM }
74911600SVikram.Hegde@Sun.COM
75011600SVikram.Hegde@Sun.COM /* smallest blacklist criteria works with multiples of 2 */
75111600SVikram.Hegde@Sun.COM if (nstrings % 2 != 0) {
75211600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist "
75311600SVikram.Hegde@Sun.COM "rootnex.conf: number of strings must be a "
75411600SVikram.Hegde@Sun.COM "multiple of 2");
75511600SVikram.Hegde@Sun.COM ddi_prop_free(string_array);
75611600SVikram.Hegde@Sun.COM return;
75711600SVikram.Hegde@Sun.COM }
75811600SVikram.Hegde@Sun.COM
75911600SVikram.Hegde@Sun.COM black_array = string_array;
76011600SVikram.Hegde@Sun.COM nblacks = nstrings;
76111600SVikram.Hegde@Sun.COM }
76211600SVikram.Hegde@Sun.COM
76311600SVikram.Hegde@Sun.COM static void
blacklist_destroy(void)76411600SVikram.Hegde@Sun.COM blacklist_destroy(void)
76511600SVikram.Hegde@Sun.COM {
76611600SVikram.Hegde@Sun.COM if (black_array) {
76711600SVikram.Hegde@Sun.COM ddi_prop_free(black_array);
76811600SVikram.Hegde@Sun.COM black_array = NULL;
76911600SVikram.Hegde@Sun.COM nblacks = 0;
77011600SVikram.Hegde@Sun.COM }
77113050Sfrank.van.der.linden@oracle.com }
77211600SVikram.Hegde@Sun.COM
77313050Sfrank.van.der.linden@oracle.com static char *
immu_alloc_name(const char * str,int instance)77413050Sfrank.van.der.linden@oracle.com immu_alloc_name(const char *str, int instance)
77513050Sfrank.van.der.linden@oracle.com {
77613050Sfrank.van.der.linden@oracle.com size_t slen;
77713050Sfrank.van.der.linden@oracle.com char *s;
77813050Sfrank.van.der.linden@oracle.com
77913050Sfrank.van.der.linden@oracle.com slen = strlen(str) + IMMU_ISTRLEN + 1;
78013050Sfrank.van.der.linden@oracle.com s = kmem_zalloc(slen, VM_SLEEP);
78113050Sfrank.van.der.linden@oracle.com if (s != NULL)
78213050Sfrank.van.der.linden@oracle.com (void) snprintf(s, slen, "%s%d", str, instance);
78313050Sfrank.van.der.linden@oracle.com
78413050Sfrank.van.der.linden@oracle.com return (s);
78511600SVikram.Hegde@Sun.COM }
78611600SVikram.Hegde@Sun.COM
78711600SVikram.Hegde@Sun.COM
78811600SVikram.Hegde@Sun.COM /*
78911600SVikram.Hegde@Sun.COM * Now set all the fields in the order they are defined
79011600SVikram.Hegde@Sun.COM * We do this only as a defensive-coding practice, it is
79111600SVikram.Hegde@Sun.COM * not a correctness issue.
79211600SVikram.Hegde@Sun.COM */
79311600SVikram.Hegde@Sun.COM static void *
immu_state_alloc(int seg,void * dmar_unit)79411600SVikram.Hegde@Sun.COM immu_state_alloc(int seg, void *dmar_unit)
79511600SVikram.Hegde@Sun.COM {
79611600SVikram.Hegde@Sun.COM immu_t *immu;
79713050Sfrank.van.der.linden@oracle.com char *nodename, *hcachename, *pcachename;
79813050Sfrank.van.der.linden@oracle.com int instance;
79911600SVikram.Hegde@Sun.COM
80011600SVikram.Hegde@Sun.COM dmar_unit = immu_dmar_walk_units(seg, dmar_unit);
80111600SVikram.Hegde@Sun.COM if (dmar_unit == NULL) {
80211600SVikram.Hegde@Sun.COM /* No more IOMMUs in this segment */
80311600SVikram.Hegde@Sun.COM return (NULL);
80411600SVikram.Hegde@Sun.COM }
80511600SVikram.Hegde@Sun.COM
80611600SVikram.Hegde@Sun.COM immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP);
80711600SVikram.Hegde@Sun.COM
80811600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL);
80911600SVikram.Hegde@Sun.COM
81011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock));
81111600SVikram.Hegde@Sun.COM
81211600SVikram.Hegde@Sun.COM immu->immu_dmar_unit = dmar_unit;
81311600SVikram.Hegde@Sun.COM immu->immu_dip = immu_dmar_unit_dip(dmar_unit);
81411600SVikram.Hegde@Sun.COM
81513050Sfrank.van.der.linden@oracle.com nodename = ddi_node_name(immu->immu_dip);
81613050Sfrank.van.der.linden@oracle.com instance = ddi_get_instance(immu->immu_dip);
81713050Sfrank.van.der.linden@oracle.com
81813050Sfrank.van.der.linden@oracle.com immu->immu_name = immu_alloc_name(nodename, instance);
81913050Sfrank.van.der.linden@oracle.com if (immu->immu_name == NULL)
82013050Sfrank.van.der.linden@oracle.com return (NULL);
82113050Sfrank.van.der.linden@oracle.com
82211600SVikram.Hegde@Sun.COM /*
82311600SVikram.Hegde@Sun.COM * the immu_intr_lock mutex is grabbed by the IOMMU
82411600SVikram.Hegde@Sun.COM * unit's interrupt handler so we need to use an
82511600SVikram.Hegde@Sun.COM * interrupt cookie for the mutex
82611600SVikram.Hegde@Sun.COM */
82711600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER,
82811600SVikram.Hegde@Sun.COM (void *)ipltospl(IMMU_INTR_IPL));
82911600SVikram.Hegde@Sun.COM
83011600SVikram.Hegde@Sun.COM /* IOMMU regs related */
83111600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL);
83211658SVikram.Hegde@Sun.COM cv_init(&(immu->immu_regs_cv), NULL, CV_DEFAULT, NULL);
83311658SVikram.Hegde@Sun.COM immu->immu_regs_busy = B_FALSE;
83411600SVikram.Hegde@Sun.COM
83511600SVikram.Hegde@Sun.COM /* DVMA related */
83611600SVikram.Hegde@Sun.COM immu->immu_dvma_coherent = B_FALSE;
83711600SVikram.Hegde@Sun.COM
83811600SVikram.Hegde@Sun.COM /* DVMA context related */
83911600SVikram.Hegde@Sun.COM rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL);
84011600SVikram.Hegde@Sun.COM
84111600SVikram.Hegde@Sun.COM /* DVMA domain related */
84211600SVikram.Hegde@Sun.COM list_create(&(immu->immu_domain_list), sizeof (domain_t),
84311600SVikram.Hegde@Sun.COM offsetof(domain_t, dom_immu_node));
84411600SVikram.Hegde@Sun.COM
84511600SVikram.Hegde@Sun.COM /* DVMA special device lists */
84611600SVikram.Hegde@Sun.COM immu->immu_dvma_gfx_only = B_FALSE;
84711600SVikram.Hegde@Sun.COM list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t),
84811600SVikram.Hegde@Sun.COM offsetof(immu_devi_t, imd_spc_node));
84911600SVikram.Hegde@Sun.COM list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t),
85011600SVikram.Hegde@Sun.COM offsetof(immu_devi_t, imd_spc_node));
85111600SVikram.Hegde@Sun.COM
85211600SVikram.Hegde@Sun.COM /* interrupt remapping related */
85311600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL);
85411600SVikram.Hegde@Sun.COM
85511600SVikram.Hegde@Sun.COM /* qinv related */
85611600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL);
85711600SVikram.Hegde@Sun.COM
85811600SVikram.Hegde@Sun.COM /*
85911600SVikram.Hegde@Sun.COM * insert this immu unit into the system-wide list
86011600SVikram.Hegde@Sun.COM */
86111600SVikram.Hegde@Sun.COM list_insert_tail(&immu_list, immu);
86211600SVikram.Hegde@Sun.COM
86313050Sfrank.van.der.linden@oracle.com pcachename = immu_alloc_name("immu_pgtable_cache", instance);
86413050Sfrank.van.der.linden@oracle.com if (pcachename == NULL)
86513050Sfrank.van.der.linden@oracle.com return (NULL);
86613050Sfrank.van.der.linden@oracle.com
86713050Sfrank.van.der.linden@oracle.com hcachename = immu_alloc_name("immu_hdl_cache", instance);
86813050Sfrank.van.der.linden@oracle.com if (hcachename == NULL)
86913050Sfrank.van.der.linden@oracle.com return (NULL);
87013050Sfrank.van.der.linden@oracle.com
87113050Sfrank.van.der.linden@oracle.com immu->immu_pgtable_cache = kmem_cache_create(pcachename,
87213050Sfrank.van.der.linden@oracle.com sizeof (pgtable_t), 0, pgtable_ctor, pgtable_dtor, NULL, immu,
87313050Sfrank.van.der.linden@oracle.com NULL, 0);
87413050Sfrank.van.der.linden@oracle.com immu->immu_hdl_cache = kmem_cache_create(hcachename,
87513050Sfrank.van.der.linden@oracle.com sizeof (immu_hdl_priv_t), 64, immu_hdl_priv_ctor,
87613050Sfrank.van.der.linden@oracle.com NULL, NULL, immu, NULL, 0);
87713050Sfrank.van.der.linden@oracle.com
87811600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
87911600SVikram.Hegde@Sun.COM
88013050Sfrank.van.der.linden@oracle.com ddi_err(DER_LOG, immu->immu_dip, "unit setup");
88111600SVikram.Hegde@Sun.COM
88211600SVikram.Hegde@Sun.COM immu_dmar_set_immu(dmar_unit, immu);
88311600SVikram.Hegde@Sun.COM
88411600SVikram.Hegde@Sun.COM return (dmar_unit);
88511600SVikram.Hegde@Sun.COM }
88611600SVikram.Hegde@Sun.COM
88711600SVikram.Hegde@Sun.COM static void
immu_subsystems_setup(void)88811600SVikram.Hegde@Sun.COM immu_subsystems_setup(void)
88911600SVikram.Hegde@Sun.COM {
89011600SVikram.Hegde@Sun.COM int seg;
89111600SVikram.Hegde@Sun.COM void *unit_hdl;
89211600SVikram.Hegde@Sun.COM
89311600SVikram.Hegde@Sun.COM ddi_err(DER_VERB, NULL,
89413050Sfrank.van.der.linden@oracle.com "Creating state structures for Intel IOMMU units");
89511600SVikram.Hegde@Sun.COM
89611600SVikram.Hegde@Sun.COM mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL);
89711600SVikram.Hegde@Sun.COM list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node));
89811600SVikram.Hegde@Sun.COM
89911600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock);
90011600SVikram.Hegde@Sun.COM
90111600SVikram.Hegde@Sun.COM unit_hdl = NULL;
90211600SVikram.Hegde@Sun.COM for (seg = 0; seg < IMMU_MAXSEG; seg++) {
90311600SVikram.Hegde@Sun.COM while (unit_hdl = immu_state_alloc(seg, unit_hdl)) {
90411600SVikram.Hegde@Sun.COM ;
90511600SVikram.Hegde@Sun.COM }
90611600SVikram.Hegde@Sun.COM }
90711600SVikram.Hegde@Sun.COM
90811600SVikram.Hegde@Sun.COM immu_regs_setup(&immu_list); /* subsequent code needs this first */
90911600SVikram.Hegde@Sun.COM immu_dvma_setup(&immu_list);
91012716Sfrank.van.der.linden@oracle.com if (immu_qinv_setup(&immu_list) == DDI_SUCCESS)
91112716Sfrank.van.der.linden@oracle.com immu_intrmap_setup(&immu_list);
91212716Sfrank.van.der.linden@oracle.com else
91312716Sfrank.van.der.linden@oracle.com immu_intrmap_enable = B_FALSE;
91411600SVikram.Hegde@Sun.COM
91511600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock);
91611600SVikram.Hegde@Sun.COM }
91711600SVikram.Hegde@Sun.COM
91811600SVikram.Hegde@Sun.COM /*
91911600SVikram.Hegde@Sun.COM * immu_subsystems_startup()
92011600SVikram.Hegde@Sun.COM * startup all units that were setup
92111600SVikram.Hegde@Sun.COM */
92211600SVikram.Hegde@Sun.COM static void
immu_subsystems_startup(void)92311600SVikram.Hegde@Sun.COM immu_subsystems_startup(void)
92411600SVikram.Hegde@Sun.COM {
92511600SVikram.Hegde@Sun.COM immu_t *immu;
92613050Sfrank.van.der.linden@oracle.com iommulib_ops_t *iommulib_ops;
92711600SVikram.Hegde@Sun.COM
92811600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock);
92911600SVikram.Hegde@Sun.COM
93011600SVikram.Hegde@Sun.COM immu_dmar_startup();
93111600SVikram.Hegde@Sun.COM
93211600SVikram.Hegde@Sun.COM immu = list_head(&immu_list);
93311600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) {
93411600SVikram.Hegde@Sun.COM
93511600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock));
93611600SVikram.Hegde@Sun.COM
93711600SVikram.Hegde@Sun.COM immu_intr_register(immu);
93811600SVikram.Hegde@Sun.COM immu_dvma_startup(immu);
93911600SVikram.Hegde@Sun.COM immu_intrmap_startup(immu);
94011600SVikram.Hegde@Sun.COM immu_qinv_startup(immu);
94111600SVikram.Hegde@Sun.COM
94211600SVikram.Hegde@Sun.COM /*
94311600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do
94411600SVikram.Hegde@Sun.COM * the actual startup. This will
94511600SVikram.Hegde@Sun.COM * set immu->immu_running field
94611600SVikram.Hegde@Sun.COM * if the unit is successfully
94711600SVikram.Hegde@Sun.COM * started
94811600SVikram.Hegde@Sun.COM */
94911600SVikram.Hegde@Sun.COM immu_regs_startup(immu);
95011600SVikram.Hegde@Sun.COM
95111600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
95213050Sfrank.van.der.linden@oracle.com
95313050Sfrank.van.der.linden@oracle.com iommulib_ops = kmem_alloc(sizeof (iommulib_ops_t), KM_SLEEP);
95413050Sfrank.van.der.linden@oracle.com *iommulib_ops = immulib_ops;
95513050Sfrank.van.der.linden@oracle.com iommulib_ops->ilops_data = (void *)immu;
95613050Sfrank.van.der.linden@oracle.com (void) iommulib_iommu_register(immu->immu_dip, iommulib_ops,
95713050Sfrank.van.der.linden@oracle.com &immu->immu_iommulib_handle);
95811600SVikram.Hegde@Sun.COM }
95911600SVikram.Hegde@Sun.COM
96011600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock);
96111600SVikram.Hegde@Sun.COM }
96211600SVikram.Hegde@Sun.COM
96311600SVikram.Hegde@Sun.COM /* ################## Intel IOMMU internal interfaces ###################### */
96411600SVikram.Hegde@Sun.COM
96511600SVikram.Hegde@Sun.COM /*
96611600SVikram.Hegde@Sun.COM * Internal interfaces for IOMMU code (i.e. not exported to rootnex
96711600SVikram.Hegde@Sun.COM * or rest of system)
96811600SVikram.Hegde@Sun.COM */
96911600SVikram.Hegde@Sun.COM
97011600SVikram.Hegde@Sun.COM /*
97111600SVikram.Hegde@Sun.COM * ddip can be NULL, in which case we walk up until we find the root dip
97211600SVikram.Hegde@Sun.COM * NOTE: We never visit the root dip since its not a hardware node
97311600SVikram.Hegde@Sun.COM */
97411600SVikram.Hegde@Sun.COM 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)97511600SVikram.Hegde@Sun.COM immu_walk_ancestor(
97611600SVikram.Hegde@Sun.COM dev_info_t *rdip,
97711600SVikram.Hegde@Sun.COM dev_info_t *ddip,
97811600SVikram.Hegde@Sun.COM int (*func)(dev_info_t *, void *arg),
97911600SVikram.Hegde@Sun.COM void *arg,
98011600SVikram.Hegde@Sun.COM int *lvlp,
98111600SVikram.Hegde@Sun.COM immu_flags_t immu_flags)
98211600SVikram.Hegde@Sun.COM {
98311600SVikram.Hegde@Sun.COM dev_info_t *pdip;
98411600SVikram.Hegde@Sun.COM int level;
98511600SVikram.Hegde@Sun.COM int error = DDI_SUCCESS;
98611600SVikram.Hegde@Sun.COM
98711600SVikram.Hegde@Sun.COM /* ddip and immu can be NULL */
98811600SVikram.Hegde@Sun.COM
98911600SVikram.Hegde@Sun.COM /* Hold rdip so that branch is not detached */
99011600SVikram.Hegde@Sun.COM ndi_hold_devi(rdip);
99111600SVikram.Hegde@Sun.COM for (pdip = rdip, level = 1; pdip && pdip != root_devinfo;
99211600SVikram.Hegde@Sun.COM pdip = ddi_get_parent(pdip), level++) {
99311600SVikram.Hegde@Sun.COM
99411600SVikram.Hegde@Sun.COM if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) {
99511600SVikram.Hegde@Sun.COM error = DDI_FAILURE;
99611600SVikram.Hegde@Sun.COM break;
99711600SVikram.Hegde@Sun.COM }
99811600SVikram.Hegde@Sun.COM if (func(pdip, arg) == DDI_WALK_TERMINATE) {
99911600SVikram.Hegde@Sun.COM break;
100011600SVikram.Hegde@Sun.COM }
100111600SVikram.Hegde@Sun.COM if (immu_flags & IMMU_FLAGS_DONTPASS) {
100211600SVikram.Hegde@Sun.COM break;
100311600SVikram.Hegde@Sun.COM }
100411600SVikram.Hegde@Sun.COM if (pdip == ddip) {
100511600SVikram.Hegde@Sun.COM break;
100611600SVikram.Hegde@Sun.COM }
100711600SVikram.Hegde@Sun.COM }
100811600SVikram.Hegde@Sun.COM
100911600SVikram.Hegde@Sun.COM ndi_rele_devi(rdip);
101011600SVikram.Hegde@Sun.COM
101111600SVikram.Hegde@Sun.COM if (lvlp)
101211600SVikram.Hegde@Sun.COM *lvlp = level;
101311600SVikram.Hegde@Sun.COM
101411600SVikram.Hegde@Sun.COM return (error);
101511600SVikram.Hegde@Sun.COM }
101611600SVikram.Hegde@Sun.COM
101711600SVikram.Hegde@Sun.COM /* ######################## Intel IOMMU entry points ####################### */
101811600SVikram.Hegde@Sun.COM /*
101911600SVikram.Hegde@Sun.COM * immu_init()
102011600SVikram.Hegde@Sun.COM * called from rootnex_attach(). setup but don't startup the Intel IOMMU
102111600SVikram.Hegde@Sun.COM * This is the first function called in Intel IOMMU code
102211600SVikram.Hegde@Sun.COM */
102311600SVikram.Hegde@Sun.COM void
immu_init(void)102411600SVikram.Hegde@Sun.COM immu_init(void)
102511600SVikram.Hegde@Sun.COM {
102611600SVikram.Hegde@Sun.COM char *phony_reg = "A thing of beauty is a joy forever";
102711600SVikram.Hegde@Sun.COM
102811600SVikram.Hegde@Sun.COM /* Set some global shorthands that are needed by all of IOMMU code */
102911600SVikram.Hegde@Sun.COM root_devinfo = ddi_root_node();
103011600SVikram.Hegde@Sun.COM
103111600SVikram.Hegde@Sun.COM /*
103211600SVikram.Hegde@Sun.COM * Intel IOMMU only supported only if MMU(CPU) page size is ==
103311600SVikram.Hegde@Sun.COM * IOMMU pages size.
103411600SVikram.Hegde@Sun.COM */
103511600SVikram.Hegde@Sun.COM /*LINTED*/
103611600SVikram.Hegde@Sun.COM if (MMU_PAGESIZE != IMMU_PAGESIZE) {
103711600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL,
103811600SVikram.Hegde@Sun.COM "MMU page size (%d) is not equal to\n"
103911600SVikram.Hegde@Sun.COM "IOMMU page size (%d). "
104011600SVikram.Hegde@Sun.COM "Disabling Intel IOMMU. ",
104111600SVikram.Hegde@Sun.COM MMU_PAGESIZE, IMMU_PAGESIZE);
104211600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
104311600SVikram.Hegde@Sun.COM return;
104411600SVikram.Hegde@Sun.COM }
104511600SVikram.Hegde@Sun.COM
104611600SVikram.Hegde@Sun.COM /*
104711749SVikram.Hegde@Sun.COM * Read rootnex.conf options. Do this before
104811749SVikram.Hegde@Sun.COM * boot options so boot options can override .conf options.
104911749SVikram.Hegde@Sun.COM */
105011749SVikram.Hegde@Sun.COM read_conf_options();
105111749SVikram.Hegde@Sun.COM
105211749SVikram.Hegde@Sun.COM /*
105311600SVikram.Hegde@Sun.COM * retrieve the Intel IOMMU boot options.
105411600SVikram.Hegde@Sun.COM * Do this before parsing immu ACPI table
105511600SVikram.Hegde@Sun.COM * as a boot option could potentially affect
105611600SVikram.Hegde@Sun.COM * ACPI parsing.
105711600SVikram.Hegde@Sun.COM */
105811600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n");
105911600SVikram.Hegde@Sun.COM read_boot_options();
106011600SVikram.Hegde@Sun.COM
106111600SVikram.Hegde@Sun.COM /*
106211600SVikram.Hegde@Sun.COM * Check the IOMMU enable boot-option first.
106311600SVikram.Hegde@Sun.COM * This is so that we can skip parsing the ACPI table
106411600SVikram.Hegde@Sun.COM * if necessary because that may cause problems in
106511600SVikram.Hegde@Sun.COM * systems with buggy BIOS or ACPI tables
106611600SVikram.Hegde@Sun.COM */
106711600SVikram.Hegde@Sun.COM if (immu_enable == B_FALSE) {
106811600SVikram.Hegde@Sun.COM return;
106911600SVikram.Hegde@Sun.COM }
107011600SVikram.Hegde@Sun.COM
107112513Sfrank.van.der.linden@oracle.com if (immu_intrmap_enable == B_TRUE)
107212513Sfrank.van.der.linden@oracle.com immu_qinv_enable = B_TRUE;
107312513Sfrank.van.der.linden@oracle.com
107411600SVikram.Hegde@Sun.COM /*
107511600SVikram.Hegde@Sun.COM * Next, check if the system even has an Intel IOMMU
107611600SVikram.Hegde@Sun.COM * We use the presence or absence of the IOMMU ACPI
107711600SVikram.Hegde@Sun.COM * table to detect Intel IOMMU.
107811600SVikram.Hegde@Sun.COM */
107911600SVikram.Hegde@Sun.COM if (immu_dmar_setup() != DDI_SUCCESS) {
108011600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
108111600SVikram.Hegde@Sun.COM return;
108211600SVikram.Hegde@Sun.COM }
108311600SVikram.Hegde@Sun.COM
108412465Sfrank.van.der.linden@oracle.com mapping_list_setup();
108512465Sfrank.van.der.linden@oracle.com
108611600SVikram.Hegde@Sun.COM /*
108711600SVikram.Hegde@Sun.COM * Check blacklists
108811600SVikram.Hegde@Sun.COM */
108911600SVikram.Hegde@Sun.COM blacklist_setup();
109011600SVikram.Hegde@Sun.COM
109111600SVikram.Hegde@Sun.COM if (blacklisted_smbios() == B_TRUE) {
109211600SVikram.Hegde@Sun.COM blacklist_destroy();
109311600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
109411600SVikram.Hegde@Sun.COM return;
109511600SVikram.Hegde@Sun.COM }
109611600SVikram.Hegde@Sun.COM
109711600SVikram.Hegde@Sun.COM if (blacklisted_driver() == B_TRUE) {
109811600SVikram.Hegde@Sun.COM blacklist_destroy();
109911600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
110011600SVikram.Hegde@Sun.COM return;
110111600SVikram.Hegde@Sun.COM }
110211600SVikram.Hegde@Sun.COM
110311600SVikram.Hegde@Sun.COM /*
110411600SVikram.Hegde@Sun.COM * Read the "raw" DMAR ACPI table to get information
110511600SVikram.Hegde@Sun.COM * and convert into a form we can use.
110611600SVikram.Hegde@Sun.COM */
110711600SVikram.Hegde@Sun.COM if (immu_dmar_parse() != DDI_SUCCESS) {
110811600SVikram.Hegde@Sun.COM blacklist_destroy();
110911600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
111011600SVikram.Hegde@Sun.COM return;
111111600SVikram.Hegde@Sun.COM }
111211600SVikram.Hegde@Sun.COM
111311600SVikram.Hegde@Sun.COM /*
111411600SVikram.Hegde@Sun.COM * now that we have processed the ACPI table
111511600SVikram.Hegde@Sun.COM * check if we need to blacklist this system
111611600SVikram.Hegde@Sun.COM * based on ACPI info
111711600SVikram.Hegde@Sun.COM */
111811600SVikram.Hegde@Sun.COM if (blacklisted_acpi() == B_TRUE) {
111911600SVikram.Hegde@Sun.COM immu_dmar_destroy();
112011600SVikram.Hegde@Sun.COM blacklist_destroy();
112111600SVikram.Hegde@Sun.COM immu_enable = B_FALSE;
112211600SVikram.Hegde@Sun.COM return;
112311600SVikram.Hegde@Sun.COM }
112411600SVikram.Hegde@Sun.COM
112511600SVikram.Hegde@Sun.COM blacklist_destroy();
112611600SVikram.Hegde@Sun.COM
112711600SVikram.Hegde@Sun.COM /*
112811600SVikram.Hegde@Sun.COM * Check if system has HW quirks.
112911600SVikram.Hegde@Sun.COM */
113011600SVikram.Hegde@Sun.COM pre_setup_quirks();
113111600SVikram.Hegde@Sun.COM
113211600SVikram.Hegde@Sun.COM /* Now do the rest of the setup */
113311600SVikram.Hegde@Sun.COM immu_subsystems_setup();
113411600SVikram.Hegde@Sun.COM
113511600SVikram.Hegde@Sun.COM /*
113611600SVikram.Hegde@Sun.COM * Now that the IMMU is setup, create a phony
113711600SVikram.Hegde@Sun.COM * reg prop so that suspend/resume works
113811600SVikram.Hegde@Sun.COM */
113911600SVikram.Hegde@Sun.COM if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg",
114011600SVikram.Hegde@Sun.COM (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) {
114111600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, NULL, "Failed to create reg prop for "
114211600SVikram.Hegde@Sun.COM "rootnex node");
114311600SVikram.Hegde@Sun.COM /*NOTREACHED*/
114411600SVikram.Hegde@Sun.COM }
114511600SVikram.Hegde@Sun.COM
114611600SVikram.Hegde@Sun.COM immu_setup = B_TRUE;
114711600SVikram.Hegde@Sun.COM }
114811600SVikram.Hegde@Sun.COM
114911600SVikram.Hegde@Sun.COM /*
115011600SVikram.Hegde@Sun.COM * immu_startup()
115111600SVikram.Hegde@Sun.COM * called directly by boot code to startup
115211600SVikram.Hegde@Sun.COM * all units of the IOMMU
115311600SVikram.Hegde@Sun.COM */
115411600SVikram.Hegde@Sun.COM void
immu_startup(void)115511600SVikram.Hegde@Sun.COM immu_startup(void)
115611600SVikram.Hegde@Sun.COM {
115711600SVikram.Hegde@Sun.COM /*
115811600SVikram.Hegde@Sun.COM * If IOMMU is disabled, do nothing
115911600SVikram.Hegde@Sun.COM */
116011600SVikram.Hegde@Sun.COM if (immu_enable == B_FALSE) {
116111600SVikram.Hegde@Sun.COM return;
116211600SVikram.Hegde@Sun.COM }
116311600SVikram.Hegde@Sun.COM
116411600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) {
116511600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, "
116613050Sfrank.van.der.linden@oracle.com "skipping IOMMU startup");
116711600SVikram.Hegde@Sun.COM return;
116811600SVikram.Hegde@Sun.COM }
116911600SVikram.Hegde@Sun.COM
117011600SVikram.Hegde@Sun.COM pre_startup_quirks();
117111600SVikram.Hegde@Sun.COM
117211600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL,
117311600SVikram.Hegde@Sun.COM "?Starting Intel IOMMU (dmar) units...\n");
117411600SVikram.Hegde@Sun.COM
117511600SVikram.Hegde@Sun.COM immu_subsystems_startup();
117611600SVikram.Hegde@Sun.COM
117711600SVikram.Hegde@Sun.COM immu_running = B_TRUE;
117811600SVikram.Hegde@Sun.COM }
117911600SVikram.Hegde@Sun.COM
118011600SVikram.Hegde@Sun.COM /*
118111600SVikram.Hegde@Sun.COM * Hook to notify IOMMU code of device tree changes
118211600SVikram.Hegde@Sun.COM */
118311600SVikram.Hegde@Sun.COM void
immu_device_tree_changed(void)118411600SVikram.Hegde@Sun.COM immu_device_tree_changed(void)
118511600SVikram.Hegde@Sun.COM {
118611600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) {
118711600SVikram.Hegde@Sun.COM return;
118811600SVikram.Hegde@Sun.COM }
118911600SVikram.Hegde@Sun.COM
119011600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Intel IOMMU currently "
119111600SVikram.Hegde@Sun.COM "does not use device tree updates");
119211600SVikram.Hegde@Sun.COM }
119311600SVikram.Hegde@Sun.COM
119411600SVikram.Hegde@Sun.COM /*
119511600SVikram.Hegde@Sun.COM * Hook to notify IOMMU code of memory changes
119611600SVikram.Hegde@Sun.COM */
119711600SVikram.Hegde@Sun.COM void
immu_physmem_update(uint64_t addr,uint64_t size)119811600SVikram.Hegde@Sun.COM immu_physmem_update(uint64_t addr, uint64_t size)
119911600SVikram.Hegde@Sun.COM {
120011600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) {
120111600SVikram.Hegde@Sun.COM return;
120211600SVikram.Hegde@Sun.COM }
120311600SVikram.Hegde@Sun.COM immu_dvma_physmem_update(addr, size);
120411600SVikram.Hegde@Sun.COM }
120511600SVikram.Hegde@Sun.COM
120611600SVikram.Hegde@Sun.COM /*
120711600SVikram.Hegde@Sun.COM * immu_quiesce()
120811600SVikram.Hegde@Sun.COM * quiesce all units that are running
120911600SVikram.Hegde@Sun.COM */
121011600SVikram.Hegde@Sun.COM int
immu_quiesce(void)121111600SVikram.Hegde@Sun.COM immu_quiesce(void)
121211600SVikram.Hegde@Sun.COM {
121311600SVikram.Hegde@Sun.COM immu_t *immu;
121411600SVikram.Hegde@Sun.COM int ret = DDI_SUCCESS;
121511600SVikram.Hegde@Sun.COM
121611600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock);
121711600SVikram.Hegde@Sun.COM
1218*13070SEthindra.Ramamurthy@Sun.COM if (immu_running == B_FALSE) {
1219*13070SEthindra.Ramamurthy@Sun.COM mutex_exit(&immu_lock);
122011600SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
1221*13070SEthindra.Ramamurthy@Sun.COM }
122211600SVikram.Hegde@Sun.COM
122311600SVikram.Hegde@Sun.COM immu = list_head(&immu_list);
122411600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) {
122511600SVikram.Hegde@Sun.COM
122611600SVikram.Hegde@Sun.COM /* if immu is not running, we dont quiesce */
122711600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_FALSE)
122811600SVikram.Hegde@Sun.COM continue;
122911600SVikram.Hegde@Sun.COM
123011600SVikram.Hegde@Sun.COM /* flush caches */
123111600SVikram.Hegde@Sun.COM rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
123213050Sfrank.van.der.linden@oracle.com immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
123313050Sfrank.van.der.linden@oracle.com immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
123411600SVikram.Hegde@Sun.COM rw_exit(&(immu->immu_ctx_rwlock));
123511600SVikram.Hegde@Sun.COM immu_regs_wbf_flush(immu);
123611600SVikram.Hegde@Sun.COM
123711600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock));
123811600SVikram.Hegde@Sun.COM
123911600SVikram.Hegde@Sun.COM /*
124011600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do
124111600SVikram.Hegde@Sun.COM * the actual shutdown.
124211600SVikram.Hegde@Sun.COM */
124311600SVikram.Hegde@Sun.COM immu_regs_shutdown(immu);
124411600SVikram.Hegde@Sun.COM immu_regs_suspend(immu);
124511600SVikram.Hegde@Sun.COM
124611600SVikram.Hegde@Sun.COM /* if immu is still running, we failed */
124711600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_TRUE)
124811600SVikram.Hegde@Sun.COM ret = DDI_FAILURE;
124911600SVikram.Hegde@Sun.COM else
125011600SVikram.Hegde@Sun.COM immu->immu_regs_quiesced = B_TRUE;
125111600SVikram.Hegde@Sun.COM
125211600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
125311600SVikram.Hegde@Sun.COM }
125411600SVikram.Hegde@Sun.COM
125511600SVikram.Hegde@Sun.COM if (ret == DDI_SUCCESS) {
125611600SVikram.Hegde@Sun.COM immu_running = B_FALSE;
125711600SVikram.Hegde@Sun.COM immu_quiesced = B_TRUE;
125811600SVikram.Hegde@Sun.COM }
1259*13070SEthindra.Ramamurthy@Sun.COM mutex_exit(&immu_lock);
126011600SVikram.Hegde@Sun.COM
126111600SVikram.Hegde@Sun.COM return (ret);
126211600SVikram.Hegde@Sun.COM }
126311600SVikram.Hegde@Sun.COM
126411600SVikram.Hegde@Sun.COM /*
126511600SVikram.Hegde@Sun.COM * immu_unquiesce()
126611600SVikram.Hegde@Sun.COM * unquiesce all units
126711600SVikram.Hegde@Sun.COM */
126811600SVikram.Hegde@Sun.COM int
immu_unquiesce(void)126911600SVikram.Hegde@Sun.COM immu_unquiesce(void)
127011600SVikram.Hegde@Sun.COM {
127111600SVikram.Hegde@Sun.COM immu_t *immu;
127211600SVikram.Hegde@Sun.COM int ret = DDI_SUCCESS;
127311600SVikram.Hegde@Sun.COM
127411600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock);
127511600SVikram.Hegde@Sun.COM
1276*13070SEthindra.Ramamurthy@Sun.COM if (immu_quiesced == B_FALSE) {
1277*13070SEthindra.Ramamurthy@Sun.COM mutex_exit(&immu_lock);
127811600SVikram.Hegde@Sun.COM return (DDI_SUCCESS);
1279*13070SEthindra.Ramamurthy@Sun.COM }
128011600SVikram.Hegde@Sun.COM
128111600SVikram.Hegde@Sun.COM immu = list_head(&immu_list);
128211600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) {
128311600SVikram.Hegde@Sun.COM
128411600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock));
128511600SVikram.Hegde@Sun.COM
128611600SVikram.Hegde@Sun.COM /* if immu was not quiesced, i.e was not running before */
128711658SVikram.Hegde@Sun.COM if (immu->immu_regs_quiesced == B_FALSE) {
128811658SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
128911600SVikram.Hegde@Sun.COM continue;
129011658SVikram.Hegde@Sun.COM }
129111600SVikram.Hegde@Sun.COM
129211600SVikram.Hegde@Sun.COM if (immu_regs_resume(immu) != DDI_SUCCESS) {
129311600SVikram.Hegde@Sun.COM ret = DDI_FAILURE;
129411658SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
129511600SVikram.Hegde@Sun.COM continue;
129611600SVikram.Hegde@Sun.COM }
129711600SVikram.Hegde@Sun.COM
129811600SVikram.Hegde@Sun.COM /* flush caches before unquiesce */
129911600SVikram.Hegde@Sun.COM rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER);
130013050Sfrank.van.der.linden@oracle.com immu_flush_context_gbl(immu, &immu->immu_ctx_inv_wait);
130113050Sfrank.van.der.linden@oracle.com immu_flush_iotlb_gbl(immu, &immu->immu_ctx_inv_wait);
130211600SVikram.Hegde@Sun.COM rw_exit(&(immu->immu_ctx_rwlock));
130311600SVikram.Hegde@Sun.COM
130411600SVikram.Hegde@Sun.COM /*
130511600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do
130611600SVikram.Hegde@Sun.COM * the actual startup. This will
130711600SVikram.Hegde@Sun.COM * set immu->immu_regs_running field
130811600SVikram.Hegde@Sun.COM * if the unit is successfully
130911600SVikram.Hegde@Sun.COM * started
131011600SVikram.Hegde@Sun.COM */
131111600SVikram.Hegde@Sun.COM immu_regs_startup(immu);
131211600SVikram.Hegde@Sun.COM
131311600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_FALSE) {
131411600SVikram.Hegde@Sun.COM ret = DDI_FAILURE;
131511600SVikram.Hegde@Sun.COM } else {
131611600SVikram.Hegde@Sun.COM immu_quiesced = B_TRUE;
131711600SVikram.Hegde@Sun.COM immu_running = B_TRUE;
131811600SVikram.Hegde@Sun.COM immu->immu_regs_quiesced = B_FALSE;
131911600SVikram.Hegde@Sun.COM }
132011600SVikram.Hegde@Sun.COM
132111600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock));
132211600SVikram.Hegde@Sun.COM }
132311600SVikram.Hegde@Sun.COM
132411600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock);
132511600SVikram.Hegde@Sun.COM
132611600SVikram.Hegde@Sun.COM return (ret);
132711600SVikram.Hegde@Sun.COM }
132811600SVikram.Hegde@Sun.COM
132913050Sfrank.van.der.linden@oracle.com void
immu_init_inv_wait(immu_inv_wait_t * iwp,const char * name,boolean_t sync)133013050Sfrank.van.der.linden@oracle.com immu_init_inv_wait(immu_inv_wait_t *iwp, const char *name, boolean_t sync)
133113050Sfrank.van.der.linden@oracle.com {
133213050Sfrank.van.der.linden@oracle.com caddr_t vaddr;
133313050Sfrank.van.der.linden@oracle.com uint64_t paddr;
133413050Sfrank.van.der.linden@oracle.com
133513050Sfrank.van.der.linden@oracle.com iwp->iwp_sync = sync;
133613050Sfrank.van.der.linden@oracle.com
133713050Sfrank.van.der.linden@oracle.com vaddr = (caddr_t)&iwp->iwp_vstatus;
133813050Sfrank.van.der.linden@oracle.com paddr = pfn_to_pa(hat_getpfnum(kas.a_hat, vaddr));
133913050Sfrank.van.der.linden@oracle.com paddr += ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
134013050Sfrank.van.der.linden@oracle.com
134113050Sfrank.van.der.linden@oracle.com iwp->iwp_pstatus = paddr;
134213050Sfrank.van.der.linden@oracle.com iwp->iwp_name = name;
134313050Sfrank.van.der.linden@oracle.com }
134413050Sfrank.van.der.linden@oracle.com
134511600SVikram.Hegde@Sun.COM /* ############## END Intel IOMMU entry points ################## */
1346