1*11600SVikram.Hegde@Sun.COM /* 2*11600SVikram.Hegde@Sun.COM * CDDL HEADER START 3*11600SVikram.Hegde@Sun.COM * 4*11600SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the 5*11600SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License"). 6*11600SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License. 7*11600SVikram.Hegde@Sun.COM * 8*11600SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*11600SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*11600SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions 11*11600SVikram.Hegde@Sun.COM * and limitations under the License. 12*11600SVikram.Hegde@Sun.COM * 13*11600SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*11600SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*11600SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*11600SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*11600SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*11600SVikram.Hegde@Sun.COM * 19*11600SVikram.Hegde@Sun.COM * CDDL HEADER END 20*11600SVikram.Hegde@Sun.COM */ 21*11600SVikram.Hegde@Sun.COM /* 22*11600SVikram.Hegde@Sun.COM * Portions Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*11600SVikram.Hegde@Sun.COM * Use is subject to license terms. 24*11600SVikram.Hegde@Sun.COM */ 25*11600SVikram.Hegde@Sun.COM /* 26*11600SVikram.Hegde@Sun.COM * Copyright (c) 2009, Intel Corporation. 27*11600SVikram.Hegde@Sun.COM * All rights reserved. 28*11600SVikram.Hegde@Sun.COM */ 29*11600SVikram.Hegde@Sun.COM 30*11600SVikram.Hegde@Sun.COM /* 31*11600SVikram.Hegde@Sun.COM * Intel IOMMU implementation 32*11600SVikram.Hegde@Sun.COM * This file contains Intel IOMMU code exported 33*11600SVikram.Hegde@Sun.COM * to the rest of the system and code that deals 34*11600SVikram.Hegde@Sun.COM * with the Intel IOMMU as a whole. 35*11600SVikram.Hegde@Sun.COM */ 36*11600SVikram.Hegde@Sun.COM 37*11600SVikram.Hegde@Sun.COM #include <sys/conf.h> 38*11600SVikram.Hegde@Sun.COM #include <sys/modctl.h> 39*11600SVikram.Hegde@Sun.COM #include <sys/pci.h> 40*11600SVikram.Hegde@Sun.COM #include <sys/pci_impl.h> 41*11600SVikram.Hegde@Sun.COM #include <sys/sysmacros.h> 42*11600SVikram.Hegde@Sun.COM #include <sys/ddi.h> 43*11600SVikram.Hegde@Sun.COM #include <sys/ddidmareq.h> 44*11600SVikram.Hegde@Sun.COM #include <sys/ddi_impldefs.h> 45*11600SVikram.Hegde@Sun.COM #include <sys/ddifm.h> 46*11600SVikram.Hegde@Sun.COM #include <sys/sunndi.h> 47*11600SVikram.Hegde@Sun.COM #include <sys/debug.h> 48*11600SVikram.Hegde@Sun.COM #include <sys/fm/protocol.h> 49*11600SVikram.Hegde@Sun.COM #include <sys/note.h> 50*11600SVikram.Hegde@Sun.COM #include <sys/apic.h> 51*11600SVikram.Hegde@Sun.COM #include <vm/hat_i86.h> 52*11600SVikram.Hegde@Sun.COM #include <sys/smp_impldefs.h> 53*11600SVikram.Hegde@Sun.COM #include <sys/spl.h> 54*11600SVikram.Hegde@Sun.COM #include <sys/archsystm.h> 55*11600SVikram.Hegde@Sun.COM #include <sys/x86_archext.h> 56*11600SVikram.Hegde@Sun.COM #include <sys/rootnex.h> 57*11600SVikram.Hegde@Sun.COM #include <sys/avl.h> 58*11600SVikram.Hegde@Sun.COM #include <sys/bootconf.h> 59*11600SVikram.Hegde@Sun.COM #include <sys/bootinfo.h> 60*11600SVikram.Hegde@Sun.COM #include <sys/atomic.h> 61*11600SVikram.Hegde@Sun.COM #include <sys/immu.h> 62*11600SVikram.Hegde@Sun.COM 63*11600SVikram.Hegde@Sun.COM /* ########################### Globals and tunables ######################## */ 64*11600SVikram.Hegde@Sun.COM /* 65*11600SVikram.Hegde@Sun.COM * Global switches (boolean) that can be toggled either via boot options 66*11600SVikram.Hegde@Sun.COM * or via /etc/system or kmdb 67*11600SVikram.Hegde@Sun.COM */ 68*11600SVikram.Hegde@Sun.COM 69*11600SVikram.Hegde@Sun.COM /* Various features */ 70*11600SVikram.Hegde@Sun.COM boolean_t immu_enable = B_TRUE; 71*11600SVikram.Hegde@Sun.COM boolean_t immu_dvma_enable = B_TRUE; 72*11600SVikram.Hegde@Sun.COM 73*11600SVikram.Hegde@Sun.COM /* accessed in other files so not static */ 74*11600SVikram.Hegde@Sun.COM boolean_t immu_gfxdvma_enable = B_TRUE; 75*11600SVikram.Hegde@Sun.COM boolean_t immu_intrmap_enable = B_FALSE; 76*11600SVikram.Hegde@Sun.COM boolean_t immu_qinv_enable = B_FALSE; 77*11600SVikram.Hegde@Sun.COM 78*11600SVikram.Hegde@Sun.COM /* various quirks that need working around */ 79*11600SVikram.Hegde@Sun.COM 80*11600SVikram.Hegde@Sun.COM /* XXX We always map page 0 read/write for now */ 81*11600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbpage0 = B_TRUE; 82*11600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbrmrr = B_TRUE; 83*11600SVikram.Hegde@Sun.COM boolean_t immu_quirk_usbfullpa; 84*11600SVikram.Hegde@Sun.COM boolean_t immu_quirk_mobile4; 85*11600SVikram.Hegde@Sun.COM 86*11600SVikram.Hegde@Sun.COM boolean_t immu_mmio_safe = B_TRUE; 87*11600SVikram.Hegde@Sun.COM 88*11600SVikram.Hegde@Sun.COM /* debug messages */ 89*11600SVikram.Hegde@Sun.COM boolean_t immu_dmar_print; 90*11600SVikram.Hegde@Sun.COM 91*11600SVikram.Hegde@Sun.COM /* ############ END OPTIONS section ################ */ 92*11600SVikram.Hegde@Sun.COM 93*11600SVikram.Hegde@Sun.COM /* 94*11600SVikram.Hegde@Sun.COM * Global used internally by Intel IOMMU code 95*11600SVikram.Hegde@Sun.COM */ 96*11600SVikram.Hegde@Sun.COM dev_info_t *root_devinfo; 97*11600SVikram.Hegde@Sun.COM kmutex_t immu_lock; 98*11600SVikram.Hegde@Sun.COM list_t immu_list; 99*11600SVikram.Hegde@Sun.COM boolean_t immu_setup; 100*11600SVikram.Hegde@Sun.COM boolean_t immu_running; 101*11600SVikram.Hegde@Sun.COM boolean_t immu_quiesced; 102*11600SVikram.Hegde@Sun.COM 103*11600SVikram.Hegde@Sun.COM /* ######################## END Globals and tunables ###################### */ 104*11600SVikram.Hegde@Sun.COM /* Globals used only in this file */ 105*11600SVikram.Hegde@Sun.COM static char **black_array; 106*11600SVikram.Hegde@Sun.COM static uint_t nblacks; 107*11600SVikram.Hegde@Sun.COM /* ###################### Utility routines ############################# */ 108*11600SVikram.Hegde@Sun.COM 109*11600SVikram.Hegde@Sun.COM /* 110*11600SVikram.Hegde@Sun.COM * Check if the device has mobile 4 chipset 111*11600SVikram.Hegde@Sun.COM */ 112*11600SVikram.Hegde@Sun.COM static int 113*11600SVikram.Hegde@Sun.COM check_mobile4(dev_info_t *dip, void *arg) 114*11600SVikram.Hegde@Sun.COM { 115*11600SVikram.Hegde@Sun.COM _NOTE(ARGUNUSED(arg)); 116*11600SVikram.Hegde@Sun.COM int vendor, device; 117*11600SVikram.Hegde@Sun.COM int *ip = (int *)arg; 118*11600SVikram.Hegde@Sun.COM 119*11600SVikram.Hegde@Sun.COM ASSERT(arg); 120*11600SVikram.Hegde@Sun.COM 121*11600SVikram.Hegde@Sun.COM vendor = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 122*11600SVikram.Hegde@Sun.COM "vendor-id", -1); 123*11600SVikram.Hegde@Sun.COM device = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 124*11600SVikram.Hegde@Sun.COM "device-id", -1); 125*11600SVikram.Hegde@Sun.COM 126*11600SVikram.Hegde@Sun.COM if (vendor == 0x8086 && device == 0x2a40) { 127*11600SVikram.Hegde@Sun.COM *ip = B_TRUE; 128*11600SVikram.Hegde@Sun.COM ddi_err(DER_NOTE, dip, "IMMU: Mobile 4 chipset detected. " 129*11600SVikram.Hegde@Sun.COM "Force setting IOMMU write buffer"); 130*11600SVikram.Hegde@Sun.COM return (DDI_WALK_TERMINATE); 131*11600SVikram.Hegde@Sun.COM } else { 132*11600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE); 133*11600SVikram.Hegde@Sun.COM } 134*11600SVikram.Hegde@Sun.COM } 135*11600SVikram.Hegde@Sun.COM 136*11600SVikram.Hegde@Sun.COM static void 137*11600SVikram.Hegde@Sun.COM map_bios_rsvd_mem(dev_info_t *dip) 138*11600SVikram.Hegde@Sun.COM { 139*11600SVikram.Hegde@Sun.COM struct memlist *mp; 140*11600SVikram.Hegde@Sun.COM int e; 141*11600SVikram.Hegde@Sun.COM 142*11600SVikram.Hegde@Sun.COM memlist_read_lock(); 143*11600SVikram.Hegde@Sun.COM 144*11600SVikram.Hegde@Sun.COM mp = bios_rsvd; 145*11600SVikram.Hegde@Sun.COM while (mp != NULL) { 146*11600SVikram.Hegde@Sun.COM memrng_t *mrng = {0}; 147*11600SVikram.Hegde@Sun.COM 148*11600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, dip, "IMMU: Mapping BIOS rsvd range " 149*11600SVikram.Hegde@Sun.COM "[0x%" PRIx64 " - 0x%"PRIx64 "]\n", mp->ml_address, 150*11600SVikram.Hegde@Sun.COM mp->ml_address + mp->ml_size); 151*11600SVikram.Hegde@Sun.COM 152*11600SVikram.Hegde@Sun.COM mrng->mrng_start = IMMU_ROUNDOWN(mp->ml_address); 153*11600SVikram.Hegde@Sun.COM mrng->mrng_npages = IMMU_ROUNDUP(mp->ml_size) / IMMU_PAGESIZE; 154*11600SVikram.Hegde@Sun.COM 155*11600SVikram.Hegde@Sun.COM e = immu_dvma_map(NULL, NULL, mrng, 0, dip, IMMU_FLAGS_MEMRNG); 156*11600SVikram.Hegde@Sun.COM ASSERT(e == DDI_DMA_MAPPED || e == DDI_DMA_USE_PHYSICAL); 157*11600SVikram.Hegde@Sun.COM 158*11600SVikram.Hegde@Sun.COM mp = mp->ml_next; 159*11600SVikram.Hegde@Sun.COM } 160*11600SVikram.Hegde@Sun.COM 161*11600SVikram.Hegde@Sun.COM memlist_read_unlock(); 162*11600SVikram.Hegde@Sun.COM } 163*11600SVikram.Hegde@Sun.COM 164*11600SVikram.Hegde@Sun.COM /* 165*11600SVikram.Hegde@Sun.COM * Check if the device is USB controller 166*11600SVikram.Hegde@Sun.COM */ 167*11600SVikram.Hegde@Sun.COM /*ARGSUSED*/ 168*11600SVikram.Hegde@Sun.COM static void 169*11600SVikram.Hegde@Sun.COM check_usb(dev_info_t *dip, void *arg) 170*11600SVikram.Hegde@Sun.COM { 171*11600SVikram.Hegde@Sun.COM const char *drv = ddi_driver_name(dip); 172*11600SVikram.Hegde@Sun.COM 173*11600SVikram.Hegde@Sun.COM if (drv == NULL || 174*11600SVikram.Hegde@Sun.COM (strcmp(drv, "uhci") != 0 && strcmp(drv, "ohci") != 0 && 175*11600SVikram.Hegde@Sun.COM strcmp(drv, "ehci") != 0)) { 176*11600SVikram.Hegde@Sun.COM return; 177*11600SVikram.Hegde@Sun.COM } 178*11600SVikram.Hegde@Sun.COM 179*11600SVikram.Hegde@Sun.COM /* This must come first since it does unity mapping */ 180*11600SVikram.Hegde@Sun.COM if (immu_quirk_usbfullpa == B_TRUE) { 181*11600SVikram.Hegde@Sun.COM int e; 182*11600SVikram.Hegde@Sun.COM ddi_err(DER_NOTE, dip, "Applying USB FULL PA quirk"); 183*11600SVikram.Hegde@Sun.COM e = immu_dvma_map(NULL, NULL, NULL, 0, dip, IMMU_FLAGS_UNITY); 184*11600SVikram.Hegde@Sun.COM /* for unity mode, map will return USE_PHYSICAL */ 185*11600SVikram.Hegde@Sun.COM ASSERT(e == DDI_DMA_USE_PHYSICAL); 186*11600SVikram.Hegde@Sun.COM } 187*11600SVikram.Hegde@Sun.COM 188*11600SVikram.Hegde@Sun.COM if (immu_quirk_usbrmrr == B_TRUE) { 189*11600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, dip, "Applying USB RMRR quirk"); 190*11600SVikram.Hegde@Sun.COM map_bios_rsvd_mem(dip); 191*11600SVikram.Hegde@Sun.COM } 192*11600SVikram.Hegde@Sun.COM } 193*11600SVikram.Hegde@Sun.COM 194*11600SVikram.Hegde@Sun.COM /* 195*11600SVikram.Hegde@Sun.COM * Check if the device is a LPC device 196*11600SVikram.Hegde@Sun.COM */ 197*11600SVikram.Hegde@Sun.COM /*ARGSUSED*/ 198*11600SVikram.Hegde@Sun.COM static void 199*11600SVikram.Hegde@Sun.COM check_lpc(dev_info_t *dip, void *arg) 200*11600SVikram.Hegde@Sun.COM { 201*11600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi; 202*11600SVikram.Hegde@Sun.COM 203*11600SVikram.Hegde@Sun.COM immu_devi = immu_devi_get(dip); 204*11600SVikram.Hegde@Sun.COM ASSERT(immu_devi); 205*11600SVikram.Hegde@Sun.COM if (immu_devi->imd_lpc == B_TRUE) { 206*11600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, dip, "IMMU: Found LPC device"); 207*11600SVikram.Hegde@Sun.COM /* This will put the immu_devi on the LPC "specials" list */ 208*11600SVikram.Hegde@Sun.COM (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP); 209*11600SVikram.Hegde@Sun.COM } 210*11600SVikram.Hegde@Sun.COM } 211*11600SVikram.Hegde@Sun.COM 212*11600SVikram.Hegde@Sun.COM /* 213*11600SVikram.Hegde@Sun.COM * Check if the device is a GFX device 214*11600SVikram.Hegde@Sun.COM */ 215*11600SVikram.Hegde@Sun.COM /*ARGSUSED*/ 216*11600SVikram.Hegde@Sun.COM static void 217*11600SVikram.Hegde@Sun.COM check_gfx(dev_info_t *dip, void *arg) 218*11600SVikram.Hegde@Sun.COM { 219*11600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi; 220*11600SVikram.Hegde@Sun.COM int e; 221*11600SVikram.Hegde@Sun.COM 222*11600SVikram.Hegde@Sun.COM immu_devi = immu_devi_get(dip); 223*11600SVikram.Hegde@Sun.COM ASSERT(immu_devi); 224*11600SVikram.Hegde@Sun.COM if (immu_devi->imd_display == B_TRUE) { 225*11600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, dip, "IMMU: Found GFX device"); 226*11600SVikram.Hegde@Sun.COM /* This will put the immu_devi on the GFX "specials" list */ 227*11600SVikram.Hegde@Sun.COM (void) immu_dvma_get_immu(dip, IMMU_FLAGS_SLEEP); 228*11600SVikram.Hegde@Sun.COM e = immu_dvma_map(NULL, NULL, NULL, 0, dip, IMMU_FLAGS_UNITY); 229*11600SVikram.Hegde@Sun.COM /* for unity mode, map will return USE_PHYSICAL */ 230*11600SVikram.Hegde@Sun.COM ASSERT(e == DDI_DMA_USE_PHYSICAL); 231*11600SVikram.Hegde@Sun.COM } 232*11600SVikram.Hegde@Sun.COM } 233*11600SVikram.Hegde@Sun.COM 234*11600SVikram.Hegde@Sun.COM static void 235*11600SVikram.Hegde@Sun.COM walk_tree(int (*f)(dev_info_t *, void *), void *arg) 236*11600SVikram.Hegde@Sun.COM { 237*11600SVikram.Hegde@Sun.COM int count; 238*11600SVikram.Hegde@Sun.COM 239*11600SVikram.Hegde@Sun.COM ndi_devi_enter(root_devinfo, &count); 240*11600SVikram.Hegde@Sun.COM ddi_walk_devs(ddi_get_child(root_devinfo), f, arg); 241*11600SVikram.Hegde@Sun.COM ndi_devi_exit(root_devinfo, count); 242*11600SVikram.Hegde@Sun.COM } 243*11600SVikram.Hegde@Sun.COM 244*11600SVikram.Hegde@Sun.COM static int 245*11600SVikram.Hegde@Sun.COM check_pre_setup_quirks(dev_info_t *dip, void *arg) 246*11600SVikram.Hegde@Sun.COM { 247*11600SVikram.Hegde@Sun.COM /* just 1 check right now */ 248*11600SVikram.Hegde@Sun.COM return (check_mobile4(dip, arg)); 249*11600SVikram.Hegde@Sun.COM } 250*11600SVikram.Hegde@Sun.COM 251*11600SVikram.Hegde@Sun.COM static int 252*11600SVikram.Hegde@Sun.COM check_pre_startup_quirks(dev_info_t *dip, void *arg) 253*11600SVikram.Hegde@Sun.COM { 254*11600SVikram.Hegde@Sun.COM if (immu_devi_set(dip, IMMU_FLAGS_SLEEP) != DDI_SUCCESS) { 255*11600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, dip, "Failed to get immu_devi"); 256*11600SVikram.Hegde@Sun.COM } 257*11600SVikram.Hegde@Sun.COM 258*11600SVikram.Hegde@Sun.COM check_gfx(dip, arg); 259*11600SVikram.Hegde@Sun.COM 260*11600SVikram.Hegde@Sun.COM check_lpc(dip, arg); 261*11600SVikram.Hegde@Sun.COM 262*11600SVikram.Hegde@Sun.COM check_usb(dip, arg); 263*11600SVikram.Hegde@Sun.COM 264*11600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE); 265*11600SVikram.Hegde@Sun.COM } 266*11600SVikram.Hegde@Sun.COM 267*11600SVikram.Hegde@Sun.COM static void 268*11600SVikram.Hegde@Sun.COM pre_setup_quirks(void) 269*11600SVikram.Hegde@Sun.COM { 270*11600SVikram.Hegde@Sun.COM walk_tree(check_pre_setup_quirks, &immu_quirk_mobile4); 271*11600SVikram.Hegde@Sun.COM } 272*11600SVikram.Hegde@Sun.COM 273*11600SVikram.Hegde@Sun.COM static void 274*11600SVikram.Hegde@Sun.COM pre_startup_quirks(void) 275*11600SVikram.Hegde@Sun.COM { 276*11600SVikram.Hegde@Sun.COM walk_tree(check_pre_startup_quirks, NULL); 277*11600SVikram.Hegde@Sun.COM 278*11600SVikram.Hegde@Sun.COM immu_dmar_rmrr_map(); 279*11600SVikram.Hegde@Sun.COM } 280*11600SVikram.Hegde@Sun.COM 281*11600SVikram.Hegde@Sun.COM /* 282*11600SVikram.Hegde@Sun.COM * get_bootopt() 283*11600SVikram.Hegde@Sun.COM * check a boot option (always a boolean) 284*11600SVikram.Hegde@Sun.COM */ 285*11600SVikram.Hegde@Sun.COM static void 286*11600SVikram.Hegde@Sun.COM get_bootopt(char *bopt, boolean_t *kvar) 287*11600SVikram.Hegde@Sun.COM { 288*11600SVikram.Hegde@Sun.COM char *val = NULL; 289*11600SVikram.Hegde@Sun.COM 290*11600SVikram.Hegde@Sun.COM ASSERT(bopt); 291*11600SVikram.Hegde@Sun.COM ASSERT(kvar); 292*11600SVikram.Hegde@Sun.COM 293*11600SVikram.Hegde@Sun.COM /* 294*11600SVikram.Hegde@Sun.COM * All boot options set at the GRUB menu become 295*11600SVikram.Hegde@Sun.COM * properties on the rootnex. 296*11600SVikram.Hegde@Sun.COM */ 297*11600SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, root_devinfo, 298*11600SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS, bopt, &val) == DDI_SUCCESS) { 299*11600SVikram.Hegde@Sun.COM ASSERT(val); 300*11600SVikram.Hegde@Sun.COM if (strcmp(val, "true") == 0) { 301*11600SVikram.Hegde@Sun.COM *kvar = B_TRUE; 302*11600SVikram.Hegde@Sun.COM } else if (strcmp(val, "false") == 0) { 303*11600SVikram.Hegde@Sun.COM *kvar = B_FALSE; 304*11600SVikram.Hegde@Sun.COM } else { 305*11600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "boot option %s=\"%s\" ", 306*11600SVikram.Hegde@Sun.COM "is not set to true or false. Ignoring option.", 307*11600SVikram.Hegde@Sun.COM bopt, val); 308*11600SVikram.Hegde@Sun.COM } 309*11600SVikram.Hegde@Sun.COM ddi_prop_free(val); 310*11600SVikram.Hegde@Sun.COM } 311*11600SVikram.Hegde@Sun.COM } 312*11600SVikram.Hegde@Sun.COM 313*11600SVikram.Hegde@Sun.COM static void 314*11600SVikram.Hegde@Sun.COM read_boot_options(void) 315*11600SVikram.Hegde@Sun.COM { 316*11600SVikram.Hegde@Sun.COM /* enable/disable options */ 317*11600SVikram.Hegde@Sun.COM get_bootopt("immu-enable", &immu_enable); 318*11600SVikram.Hegde@Sun.COM get_bootopt("immu-dvma-enable", &immu_dvma_enable); 319*11600SVikram.Hegde@Sun.COM get_bootopt("immu-gfxdvma-enable", &immu_gfxdvma_enable); 320*11600SVikram.Hegde@Sun.COM get_bootopt("immu-intrmap-enable", &immu_intrmap_enable); 321*11600SVikram.Hegde@Sun.COM get_bootopt("immu-qinv-enable", &immu_qinv_enable); 322*11600SVikram.Hegde@Sun.COM get_bootopt("immu-mmio-safe", &immu_mmio_safe); 323*11600SVikram.Hegde@Sun.COM 324*11600SVikram.Hegde@Sun.COM /* workaround switches */ 325*11600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbpage0", &immu_quirk_usbpage0); 326*11600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbfullpa", &immu_quirk_usbfullpa); 327*11600SVikram.Hegde@Sun.COM get_bootopt("immu-quirk-usbrmrr", &immu_quirk_usbrmrr); 328*11600SVikram.Hegde@Sun.COM 329*11600SVikram.Hegde@Sun.COM /* debug printing */ 330*11600SVikram.Hegde@Sun.COM get_bootopt("immu-dmar-print", &immu_dmar_print); 331*11600SVikram.Hegde@Sun.COM } 332*11600SVikram.Hegde@Sun.COM 333*11600SVikram.Hegde@Sun.COM /* 334*11600SVikram.Hegde@Sun.COM * Note, this will not catch hardware not enumerated 335*11600SVikram.Hegde@Sun.COM * in early boot 336*11600SVikram.Hegde@Sun.COM */ 337*11600SVikram.Hegde@Sun.COM static boolean_t 338*11600SVikram.Hegde@Sun.COM blacklisted_driver(void) 339*11600SVikram.Hegde@Sun.COM { 340*11600SVikram.Hegde@Sun.COM char **strptr; 341*11600SVikram.Hegde@Sun.COM int i; 342*11600SVikram.Hegde@Sun.COM major_t maj; 343*11600SVikram.Hegde@Sun.COM 344*11600SVikram.Hegde@Sun.COM ASSERT((black_array == NULL) ^ (nblacks != 0)); 345*11600SVikram.Hegde@Sun.COM 346*11600SVikram.Hegde@Sun.COM /* need at least 2 strings */ 347*11600SVikram.Hegde@Sun.COM if (nblacks < 2) { 348*11600SVikram.Hegde@Sun.COM return (B_FALSE); 349*11600SVikram.Hegde@Sun.COM } 350*11600SVikram.Hegde@Sun.COM 351*11600SVikram.Hegde@Sun.COM strptr = black_array; 352*11600SVikram.Hegde@Sun.COM for (i = 0; nblacks - i > 1; i++) { 353*11600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, "DRIVER") == 0) { 354*11600SVikram.Hegde@Sun.COM if ((maj = ddi_name_to_major(*strptr++)) 355*11600SVikram.Hegde@Sun.COM != DDI_MAJOR_T_NONE) { 356*11600SVikram.Hegde@Sun.COM /* is there hardware bound to this drvr */ 357*11600SVikram.Hegde@Sun.COM if (devnamesp[maj].dn_head != NULL) { 358*11600SVikram.Hegde@Sun.COM return (B_TRUE); 359*11600SVikram.Hegde@Sun.COM } 360*11600SVikram.Hegde@Sun.COM } 361*11600SVikram.Hegde@Sun.COM i += 1; /* for loop adds 1, so add only 1 here */ 362*11600SVikram.Hegde@Sun.COM } 363*11600SVikram.Hegde@Sun.COM } 364*11600SVikram.Hegde@Sun.COM 365*11600SVikram.Hegde@Sun.COM return (B_FALSE); 366*11600SVikram.Hegde@Sun.COM } 367*11600SVikram.Hegde@Sun.COM 368*11600SVikram.Hegde@Sun.COM static boolean_t 369*11600SVikram.Hegde@Sun.COM blacklisted_smbios(void) 370*11600SVikram.Hegde@Sun.COM { 371*11600SVikram.Hegde@Sun.COM id_t smid; 372*11600SVikram.Hegde@Sun.COM smbios_hdl_t *smhdl; 373*11600SVikram.Hegde@Sun.COM smbios_info_t sminf; 374*11600SVikram.Hegde@Sun.COM smbios_system_t smsys; 375*11600SVikram.Hegde@Sun.COM char *mfg, *product, *version; 376*11600SVikram.Hegde@Sun.COM char **strptr; 377*11600SVikram.Hegde@Sun.COM int i; 378*11600SVikram.Hegde@Sun.COM 379*11600SVikram.Hegde@Sun.COM ASSERT((black_array == NULL) ^ (nblacks != 0)); 380*11600SVikram.Hegde@Sun.COM 381*11600SVikram.Hegde@Sun.COM /* need at least 4 strings for this setting */ 382*11600SVikram.Hegde@Sun.COM if (nblacks < 4) { 383*11600SVikram.Hegde@Sun.COM return (B_FALSE); 384*11600SVikram.Hegde@Sun.COM } 385*11600SVikram.Hegde@Sun.COM 386*11600SVikram.Hegde@Sun.COM smhdl = smbios_open(NULL, SMB_VERSION, ksmbios_flags, NULL); 387*11600SVikram.Hegde@Sun.COM if (smhdl == NULL || 388*11600SVikram.Hegde@Sun.COM (smid = smbios_info_system(smhdl, &smsys)) == SMB_ERR || 389*11600SVikram.Hegde@Sun.COM smbios_info_common(smhdl, smid, &sminf) == SMB_ERR) { 390*11600SVikram.Hegde@Sun.COM return (B_FALSE); 391*11600SVikram.Hegde@Sun.COM } 392*11600SVikram.Hegde@Sun.COM 393*11600SVikram.Hegde@Sun.COM mfg = (char *)sminf.smbi_manufacturer; 394*11600SVikram.Hegde@Sun.COM product = (char *)sminf.smbi_product; 395*11600SVikram.Hegde@Sun.COM version = (char *)sminf.smbi_version; 396*11600SVikram.Hegde@Sun.COM 397*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?System SMBIOS information:\n"); 398*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Manufacturer = <%s>\n", mfg); 399*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Product = <%s>\n", product); 400*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Version = <%s>\n", version); 401*11600SVikram.Hegde@Sun.COM 402*11600SVikram.Hegde@Sun.COM strptr = black_array; 403*11600SVikram.Hegde@Sun.COM for (i = 0; nblacks - i > 3; i++) { 404*11600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, "SMBIOS") == 0) { 405*11600SVikram.Hegde@Sun.COM if (strcmp(*strptr++, mfg) == 0 && 406*11600SVikram.Hegde@Sun.COM ((char *)strptr == '\0' || 407*11600SVikram.Hegde@Sun.COM strcmp(*strptr++, product) == 0) && 408*11600SVikram.Hegde@Sun.COM ((char *)strptr == '\0' || 409*11600SVikram.Hegde@Sun.COM strcmp(*strptr++, version) == 0)) { 410*11600SVikram.Hegde@Sun.COM return (B_TRUE); 411*11600SVikram.Hegde@Sun.COM } 412*11600SVikram.Hegde@Sun.COM i += 3; 413*11600SVikram.Hegde@Sun.COM } 414*11600SVikram.Hegde@Sun.COM } 415*11600SVikram.Hegde@Sun.COM 416*11600SVikram.Hegde@Sun.COM return (B_FALSE); 417*11600SVikram.Hegde@Sun.COM } 418*11600SVikram.Hegde@Sun.COM 419*11600SVikram.Hegde@Sun.COM static boolean_t 420*11600SVikram.Hegde@Sun.COM blacklisted_acpi(void) 421*11600SVikram.Hegde@Sun.COM { 422*11600SVikram.Hegde@Sun.COM ASSERT((black_array == NULL) ^ (nblacks != 0)); 423*11600SVikram.Hegde@Sun.COM if (nblacks == 0) { 424*11600SVikram.Hegde@Sun.COM return (B_FALSE); 425*11600SVikram.Hegde@Sun.COM } 426*11600SVikram.Hegde@Sun.COM 427*11600SVikram.Hegde@Sun.COM return (immu_dmar_blacklisted(black_array, nblacks)); 428*11600SVikram.Hegde@Sun.COM } 429*11600SVikram.Hegde@Sun.COM 430*11600SVikram.Hegde@Sun.COM /* 431*11600SVikram.Hegde@Sun.COM * Check if system is blacklisted by Intel IOMMU driver 432*11600SVikram.Hegde@Sun.COM * i.e. should Intel IOMMU be disabled on this system 433*11600SVikram.Hegde@Sun.COM * Currently a system can be blacklistd based on the 434*11600SVikram.Hegde@Sun.COM * following bases: 435*11600SVikram.Hegde@Sun.COM * 436*11600SVikram.Hegde@Sun.COM * 1. DMAR ACPI table information. 437*11600SVikram.Hegde@Sun.COM * This information includes things like 438*11600SVikram.Hegde@Sun.COM * manufacturer and revision number. If rootnex.conf 439*11600SVikram.Hegde@Sun.COM * has matching info set in its blacklist property 440*11600SVikram.Hegde@Sun.COM * then Intel IOMMu will be disabled 441*11600SVikram.Hegde@Sun.COM * 442*11600SVikram.Hegde@Sun.COM * 2. SMBIOS information 443*11600SVikram.Hegde@Sun.COM * 444*11600SVikram.Hegde@Sun.COM * 3. Driver installed - useful if a particular 445*11600SVikram.Hegde@Sun.COM * driver or hardware is toxic if Intel IOMMU 446*11600SVikram.Hegde@Sun.COM * is turned on. 447*11600SVikram.Hegde@Sun.COM */ 448*11600SVikram.Hegde@Sun.COM 449*11600SVikram.Hegde@Sun.COM static void 450*11600SVikram.Hegde@Sun.COM blacklist_setup(void) 451*11600SVikram.Hegde@Sun.COM { 452*11600SVikram.Hegde@Sun.COM char **string_array; 453*11600SVikram.Hegde@Sun.COM uint_t nstrings; 454*11600SVikram.Hegde@Sun.COM 455*11600SVikram.Hegde@Sun.COM /* 456*11600SVikram.Hegde@Sun.COM * Check the rootnex.conf blacklist property. 457*11600SVikram.Hegde@Sun.COM * Fake up a dev_t since searching the global 458*11600SVikram.Hegde@Sun.COM * property list needs it 459*11600SVikram.Hegde@Sun.COM */ 460*11600SVikram.Hegde@Sun.COM if (ddi_prop_lookup_string_array( 461*11600SVikram.Hegde@Sun.COM makedevice(ddi_name_to_major("rootnex"), 0), root_devinfo, 462*11600SVikram.Hegde@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_ROOTNEX_GLOBAL, "immu-blacklist", 463*11600SVikram.Hegde@Sun.COM &string_array, &nstrings) != DDI_PROP_SUCCESS) { 464*11600SVikram.Hegde@Sun.COM return; 465*11600SVikram.Hegde@Sun.COM } 466*11600SVikram.Hegde@Sun.COM 467*11600SVikram.Hegde@Sun.COM /* smallest blacklist criteria works with multiples of 2 */ 468*11600SVikram.Hegde@Sun.COM if (nstrings % 2 != 0) { 469*11600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Invalid IOMMU blacklist " 470*11600SVikram.Hegde@Sun.COM "rootnex.conf: number of strings must be a " 471*11600SVikram.Hegde@Sun.COM "multiple of 2"); 472*11600SVikram.Hegde@Sun.COM ddi_prop_free(string_array); 473*11600SVikram.Hegde@Sun.COM return; 474*11600SVikram.Hegde@Sun.COM } 475*11600SVikram.Hegde@Sun.COM 476*11600SVikram.Hegde@Sun.COM black_array = string_array; 477*11600SVikram.Hegde@Sun.COM nblacks = nstrings; 478*11600SVikram.Hegde@Sun.COM } 479*11600SVikram.Hegde@Sun.COM 480*11600SVikram.Hegde@Sun.COM static void 481*11600SVikram.Hegde@Sun.COM blacklist_destroy(void) 482*11600SVikram.Hegde@Sun.COM { 483*11600SVikram.Hegde@Sun.COM if (black_array) { 484*11600SVikram.Hegde@Sun.COM ddi_prop_free(black_array); 485*11600SVikram.Hegde@Sun.COM black_array = NULL; 486*11600SVikram.Hegde@Sun.COM nblacks = 0; 487*11600SVikram.Hegde@Sun.COM } 488*11600SVikram.Hegde@Sun.COM 489*11600SVikram.Hegde@Sun.COM ASSERT(black_array == NULL); 490*11600SVikram.Hegde@Sun.COM ASSERT(nblacks == 0); 491*11600SVikram.Hegde@Sun.COM } 492*11600SVikram.Hegde@Sun.COM 493*11600SVikram.Hegde@Sun.COM 494*11600SVikram.Hegde@Sun.COM /* 495*11600SVikram.Hegde@Sun.COM * Now set all the fields in the order they are defined 496*11600SVikram.Hegde@Sun.COM * We do this only as a defensive-coding practice, it is 497*11600SVikram.Hegde@Sun.COM * not a correctness issue. 498*11600SVikram.Hegde@Sun.COM */ 499*11600SVikram.Hegde@Sun.COM static void * 500*11600SVikram.Hegde@Sun.COM immu_state_alloc(int seg, void *dmar_unit) 501*11600SVikram.Hegde@Sun.COM { 502*11600SVikram.Hegde@Sun.COM immu_t *immu; 503*11600SVikram.Hegde@Sun.COM 504*11600SVikram.Hegde@Sun.COM dmar_unit = immu_dmar_walk_units(seg, dmar_unit); 505*11600SVikram.Hegde@Sun.COM if (dmar_unit == NULL) { 506*11600SVikram.Hegde@Sun.COM /* No more IOMMUs in this segment */ 507*11600SVikram.Hegde@Sun.COM return (NULL); 508*11600SVikram.Hegde@Sun.COM } 509*11600SVikram.Hegde@Sun.COM 510*11600SVikram.Hegde@Sun.COM immu = kmem_zalloc(sizeof (immu_t), KM_SLEEP); 511*11600SVikram.Hegde@Sun.COM 512*11600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_lock), NULL, MUTEX_DRIVER, NULL); 513*11600SVikram.Hegde@Sun.COM 514*11600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock)); 515*11600SVikram.Hegde@Sun.COM 516*11600SVikram.Hegde@Sun.COM immu->immu_dmar_unit = dmar_unit; 517*11600SVikram.Hegde@Sun.COM immu->immu_name = ddi_strdup(immu_dmar_unit_name(dmar_unit), 518*11600SVikram.Hegde@Sun.COM KM_SLEEP); 519*11600SVikram.Hegde@Sun.COM immu->immu_dip = immu_dmar_unit_dip(dmar_unit); 520*11600SVikram.Hegde@Sun.COM 521*11600SVikram.Hegde@Sun.COM /* 522*11600SVikram.Hegde@Sun.COM * the immu_intr_lock mutex is grabbed by the IOMMU 523*11600SVikram.Hegde@Sun.COM * unit's interrupt handler so we need to use an 524*11600SVikram.Hegde@Sun.COM * interrupt cookie for the mutex 525*11600SVikram.Hegde@Sun.COM */ 526*11600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_intr_lock), NULL, MUTEX_DRIVER, 527*11600SVikram.Hegde@Sun.COM (void *)ipltospl(IMMU_INTR_IPL)); 528*11600SVikram.Hegde@Sun.COM 529*11600SVikram.Hegde@Sun.COM /* IOMMU regs related */ 530*11600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_regs_lock), NULL, MUTEX_DEFAULT, NULL); 531*11600SVikram.Hegde@Sun.COM 532*11600SVikram.Hegde@Sun.COM /* DVMA related */ 533*11600SVikram.Hegde@Sun.COM immu->immu_dvma_coherent = B_FALSE; 534*11600SVikram.Hegde@Sun.COM 535*11600SVikram.Hegde@Sun.COM /* DVMA context related */ 536*11600SVikram.Hegde@Sun.COM rw_init(&(immu->immu_ctx_rwlock), NULL, RW_DEFAULT, NULL); 537*11600SVikram.Hegde@Sun.COM 538*11600SVikram.Hegde@Sun.COM /* DVMA domain related */ 539*11600SVikram.Hegde@Sun.COM list_create(&(immu->immu_domain_list), sizeof (domain_t), 540*11600SVikram.Hegde@Sun.COM offsetof(domain_t, dom_immu_node)); 541*11600SVikram.Hegde@Sun.COM 542*11600SVikram.Hegde@Sun.COM /* DVMA special device lists */ 543*11600SVikram.Hegde@Sun.COM immu->immu_dvma_gfx_only = B_FALSE; 544*11600SVikram.Hegde@Sun.COM list_create(&(immu->immu_dvma_lpc_list), sizeof (immu_devi_t), 545*11600SVikram.Hegde@Sun.COM offsetof(immu_devi_t, imd_spc_node)); 546*11600SVikram.Hegde@Sun.COM list_create(&(immu->immu_dvma_gfx_list), sizeof (immu_devi_t), 547*11600SVikram.Hegde@Sun.COM offsetof(immu_devi_t, imd_spc_node)); 548*11600SVikram.Hegde@Sun.COM 549*11600SVikram.Hegde@Sun.COM /* interrupt remapping related */ 550*11600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_intrmap_lock), NULL, MUTEX_DEFAULT, NULL); 551*11600SVikram.Hegde@Sun.COM 552*11600SVikram.Hegde@Sun.COM /* qinv related */ 553*11600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_qinv_lock), NULL, MUTEX_DEFAULT, NULL); 554*11600SVikram.Hegde@Sun.COM 555*11600SVikram.Hegde@Sun.COM /* 556*11600SVikram.Hegde@Sun.COM * insert this immu unit into the system-wide list 557*11600SVikram.Hegde@Sun.COM */ 558*11600SVikram.Hegde@Sun.COM list_insert_tail(&immu_list, immu); 559*11600SVikram.Hegde@Sun.COM 560*11600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock)); 561*11600SVikram.Hegde@Sun.COM 562*11600SVikram.Hegde@Sun.COM ddi_err(DER_LOG, immu->immu_dip, "IMMU: unit setup"); 563*11600SVikram.Hegde@Sun.COM 564*11600SVikram.Hegde@Sun.COM immu_dmar_set_immu(dmar_unit, immu); 565*11600SVikram.Hegde@Sun.COM 566*11600SVikram.Hegde@Sun.COM return (dmar_unit); 567*11600SVikram.Hegde@Sun.COM } 568*11600SVikram.Hegde@Sun.COM 569*11600SVikram.Hegde@Sun.COM static void 570*11600SVikram.Hegde@Sun.COM immu_subsystems_setup(void) 571*11600SVikram.Hegde@Sun.COM { 572*11600SVikram.Hegde@Sun.COM int seg; 573*11600SVikram.Hegde@Sun.COM void *unit_hdl; 574*11600SVikram.Hegde@Sun.COM 575*11600SVikram.Hegde@Sun.COM ddi_err(DER_VERB, NULL, 576*11600SVikram.Hegde@Sun.COM "Creating state structures for Intel IOMMU units\n"); 577*11600SVikram.Hegde@Sun.COM 578*11600SVikram.Hegde@Sun.COM ASSERT(immu_setup == B_FALSE); 579*11600SVikram.Hegde@Sun.COM ASSERT(immu_running == B_FALSE); 580*11600SVikram.Hegde@Sun.COM 581*11600SVikram.Hegde@Sun.COM mutex_init(&immu_lock, NULL, MUTEX_DEFAULT, NULL); 582*11600SVikram.Hegde@Sun.COM list_create(&immu_list, sizeof (immu_t), offsetof(immu_t, immu_node)); 583*11600SVikram.Hegde@Sun.COM 584*11600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock); 585*11600SVikram.Hegde@Sun.COM 586*11600SVikram.Hegde@Sun.COM unit_hdl = NULL; 587*11600SVikram.Hegde@Sun.COM for (seg = 0; seg < IMMU_MAXSEG; seg++) { 588*11600SVikram.Hegde@Sun.COM while (unit_hdl = immu_state_alloc(seg, unit_hdl)) { 589*11600SVikram.Hegde@Sun.COM ; 590*11600SVikram.Hegde@Sun.COM } 591*11600SVikram.Hegde@Sun.COM } 592*11600SVikram.Hegde@Sun.COM 593*11600SVikram.Hegde@Sun.COM immu_regs_setup(&immu_list); /* subsequent code needs this first */ 594*11600SVikram.Hegde@Sun.COM immu_dvma_setup(&immu_list); 595*11600SVikram.Hegde@Sun.COM immu_intrmap_setup(&immu_list); 596*11600SVikram.Hegde@Sun.COM immu_qinv_setup(&immu_list); 597*11600SVikram.Hegde@Sun.COM 598*11600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock); 599*11600SVikram.Hegde@Sun.COM } 600*11600SVikram.Hegde@Sun.COM 601*11600SVikram.Hegde@Sun.COM /* 602*11600SVikram.Hegde@Sun.COM * immu_subsystems_startup() 603*11600SVikram.Hegde@Sun.COM * startup all units that were setup 604*11600SVikram.Hegde@Sun.COM */ 605*11600SVikram.Hegde@Sun.COM static void 606*11600SVikram.Hegde@Sun.COM immu_subsystems_startup(void) 607*11600SVikram.Hegde@Sun.COM { 608*11600SVikram.Hegde@Sun.COM immu_t *immu; 609*11600SVikram.Hegde@Sun.COM 610*11600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock); 611*11600SVikram.Hegde@Sun.COM 612*11600SVikram.Hegde@Sun.COM ASSERT(immu_setup == B_TRUE); 613*11600SVikram.Hegde@Sun.COM ASSERT(immu_running == B_FALSE); 614*11600SVikram.Hegde@Sun.COM 615*11600SVikram.Hegde@Sun.COM immu_dmar_startup(); 616*11600SVikram.Hegde@Sun.COM 617*11600SVikram.Hegde@Sun.COM immu = list_head(&immu_list); 618*11600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) { 619*11600SVikram.Hegde@Sun.COM 620*11600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock)); 621*11600SVikram.Hegde@Sun.COM 622*11600SVikram.Hegde@Sun.COM immu_intr_register(immu); 623*11600SVikram.Hegde@Sun.COM immu_dvma_startup(immu); 624*11600SVikram.Hegde@Sun.COM immu_intrmap_startup(immu); 625*11600SVikram.Hegde@Sun.COM immu_qinv_startup(immu); 626*11600SVikram.Hegde@Sun.COM 627*11600SVikram.Hegde@Sun.COM /* 628*11600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do 629*11600SVikram.Hegde@Sun.COM * the actual startup. This will 630*11600SVikram.Hegde@Sun.COM * set immu->immu_running field 631*11600SVikram.Hegde@Sun.COM * if the unit is successfully 632*11600SVikram.Hegde@Sun.COM * started 633*11600SVikram.Hegde@Sun.COM */ 634*11600SVikram.Hegde@Sun.COM immu_regs_startup(immu); 635*11600SVikram.Hegde@Sun.COM 636*11600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock)); 637*11600SVikram.Hegde@Sun.COM } 638*11600SVikram.Hegde@Sun.COM 639*11600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock); 640*11600SVikram.Hegde@Sun.COM } 641*11600SVikram.Hegde@Sun.COM 642*11600SVikram.Hegde@Sun.COM /* ################## Intel IOMMU internal interfaces ###################### */ 643*11600SVikram.Hegde@Sun.COM 644*11600SVikram.Hegde@Sun.COM /* 645*11600SVikram.Hegde@Sun.COM * Internal interfaces for IOMMU code (i.e. not exported to rootnex 646*11600SVikram.Hegde@Sun.COM * or rest of system) 647*11600SVikram.Hegde@Sun.COM */ 648*11600SVikram.Hegde@Sun.COM 649*11600SVikram.Hegde@Sun.COM /* 650*11600SVikram.Hegde@Sun.COM * ddip can be NULL, in which case we walk up until we find the root dip 651*11600SVikram.Hegde@Sun.COM * NOTE: We never visit the root dip since its not a hardware node 652*11600SVikram.Hegde@Sun.COM */ 653*11600SVikram.Hegde@Sun.COM int 654*11600SVikram.Hegde@Sun.COM immu_walk_ancestor( 655*11600SVikram.Hegde@Sun.COM dev_info_t *rdip, 656*11600SVikram.Hegde@Sun.COM dev_info_t *ddip, 657*11600SVikram.Hegde@Sun.COM int (*func)(dev_info_t *, void *arg), 658*11600SVikram.Hegde@Sun.COM void *arg, 659*11600SVikram.Hegde@Sun.COM int *lvlp, 660*11600SVikram.Hegde@Sun.COM immu_flags_t immu_flags) 661*11600SVikram.Hegde@Sun.COM { 662*11600SVikram.Hegde@Sun.COM dev_info_t *pdip; 663*11600SVikram.Hegde@Sun.COM int level; 664*11600SVikram.Hegde@Sun.COM int error = DDI_SUCCESS; 665*11600SVikram.Hegde@Sun.COM 666*11600SVikram.Hegde@Sun.COM ASSERT(root_devinfo); 667*11600SVikram.Hegde@Sun.COM ASSERT(rdip); 668*11600SVikram.Hegde@Sun.COM ASSERT(rdip != root_devinfo); 669*11600SVikram.Hegde@Sun.COM ASSERT(func); 670*11600SVikram.Hegde@Sun.COM 671*11600SVikram.Hegde@Sun.COM /* ddip and immu can be NULL */ 672*11600SVikram.Hegde@Sun.COM 673*11600SVikram.Hegde@Sun.COM /* Hold rdip so that branch is not detached */ 674*11600SVikram.Hegde@Sun.COM ndi_hold_devi(rdip); 675*11600SVikram.Hegde@Sun.COM for (pdip = rdip, level = 1; pdip && pdip != root_devinfo; 676*11600SVikram.Hegde@Sun.COM pdip = ddi_get_parent(pdip), level++) { 677*11600SVikram.Hegde@Sun.COM 678*11600SVikram.Hegde@Sun.COM if (immu_devi_set(pdip, immu_flags) != DDI_SUCCESS) { 679*11600SVikram.Hegde@Sun.COM error = DDI_FAILURE; 680*11600SVikram.Hegde@Sun.COM break; 681*11600SVikram.Hegde@Sun.COM } 682*11600SVikram.Hegde@Sun.COM if (func(pdip, arg) == DDI_WALK_TERMINATE) { 683*11600SVikram.Hegde@Sun.COM break; 684*11600SVikram.Hegde@Sun.COM } 685*11600SVikram.Hegde@Sun.COM if (immu_flags & IMMU_FLAGS_DONTPASS) { 686*11600SVikram.Hegde@Sun.COM break; 687*11600SVikram.Hegde@Sun.COM } 688*11600SVikram.Hegde@Sun.COM if (pdip == ddip) { 689*11600SVikram.Hegde@Sun.COM break; 690*11600SVikram.Hegde@Sun.COM } 691*11600SVikram.Hegde@Sun.COM } 692*11600SVikram.Hegde@Sun.COM 693*11600SVikram.Hegde@Sun.COM ndi_rele_devi(rdip); 694*11600SVikram.Hegde@Sun.COM 695*11600SVikram.Hegde@Sun.COM if (lvlp) 696*11600SVikram.Hegde@Sun.COM *lvlp = level; 697*11600SVikram.Hegde@Sun.COM 698*11600SVikram.Hegde@Sun.COM return (error); 699*11600SVikram.Hegde@Sun.COM } 700*11600SVikram.Hegde@Sun.COM 701*11600SVikram.Hegde@Sun.COM /* ######################## Intel IOMMU entry points ####################### */ 702*11600SVikram.Hegde@Sun.COM /* 703*11600SVikram.Hegde@Sun.COM * immu_init() 704*11600SVikram.Hegde@Sun.COM * called from rootnex_attach(). setup but don't startup the Intel IOMMU 705*11600SVikram.Hegde@Sun.COM * This is the first function called in Intel IOMMU code 706*11600SVikram.Hegde@Sun.COM */ 707*11600SVikram.Hegde@Sun.COM void 708*11600SVikram.Hegde@Sun.COM immu_init(void) 709*11600SVikram.Hegde@Sun.COM { 710*11600SVikram.Hegde@Sun.COM char *phony_reg = "A thing of beauty is a joy forever"; 711*11600SVikram.Hegde@Sun.COM 712*11600SVikram.Hegde@Sun.COM /* Set some global shorthands that are needed by all of IOMMU code */ 713*11600SVikram.Hegde@Sun.COM ASSERT(root_devinfo == NULL); 714*11600SVikram.Hegde@Sun.COM root_devinfo = ddi_root_node(); 715*11600SVikram.Hegde@Sun.COM 716*11600SVikram.Hegde@Sun.COM /* 717*11600SVikram.Hegde@Sun.COM * Intel IOMMU only supported only if MMU(CPU) page size is == 718*11600SVikram.Hegde@Sun.COM * IOMMU pages size. 719*11600SVikram.Hegde@Sun.COM */ 720*11600SVikram.Hegde@Sun.COM /*LINTED*/ 721*11600SVikram.Hegde@Sun.COM if (MMU_PAGESIZE != IMMU_PAGESIZE) { 722*11600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, 723*11600SVikram.Hegde@Sun.COM "MMU page size (%d) is not equal to\n" 724*11600SVikram.Hegde@Sun.COM "IOMMU page size (%d). " 725*11600SVikram.Hegde@Sun.COM "Disabling Intel IOMMU. ", 726*11600SVikram.Hegde@Sun.COM MMU_PAGESIZE, IMMU_PAGESIZE); 727*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 728*11600SVikram.Hegde@Sun.COM return; 729*11600SVikram.Hegde@Sun.COM } 730*11600SVikram.Hegde@Sun.COM 731*11600SVikram.Hegde@Sun.COM /* 732*11600SVikram.Hegde@Sun.COM * retrieve the Intel IOMMU boot options. 733*11600SVikram.Hegde@Sun.COM * Do this before parsing immu ACPI table 734*11600SVikram.Hegde@Sun.COM * as a boot option could potentially affect 735*11600SVikram.Hegde@Sun.COM * ACPI parsing. 736*11600SVikram.Hegde@Sun.COM */ 737*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, "?Reading Intel IOMMU boot options\n"); 738*11600SVikram.Hegde@Sun.COM read_boot_options(); 739*11600SVikram.Hegde@Sun.COM 740*11600SVikram.Hegde@Sun.COM /* 741*11600SVikram.Hegde@Sun.COM * Check the IOMMU enable boot-option first. 742*11600SVikram.Hegde@Sun.COM * This is so that we can skip parsing the ACPI table 743*11600SVikram.Hegde@Sun.COM * if necessary because that may cause problems in 744*11600SVikram.Hegde@Sun.COM * systems with buggy BIOS or ACPI tables 745*11600SVikram.Hegde@Sun.COM */ 746*11600SVikram.Hegde@Sun.COM if (immu_enable == B_FALSE) { 747*11600SVikram.Hegde@Sun.COM return; 748*11600SVikram.Hegde@Sun.COM } 749*11600SVikram.Hegde@Sun.COM 750*11600SVikram.Hegde@Sun.COM /* 751*11600SVikram.Hegde@Sun.COM * Next, check if the system even has an Intel IOMMU 752*11600SVikram.Hegde@Sun.COM * We use the presence or absence of the IOMMU ACPI 753*11600SVikram.Hegde@Sun.COM * table to detect Intel IOMMU. 754*11600SVikram.Hegde@Sun.COM */ 755*11600SVikram.Hegde@Sun.COM if (immu_dmar_setup() != DDI_SUCCESS) { 756*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 757*11600SVikram.Hegde@Sun.COM return; 758*11600SVikram.Hegde@Sun.COM } 759*11600SVikram.Hegde@Sun.COM 760*11600SVikram.Hegde@Sun.COM /* 761*11600SVikram.Hegde@Sun.COM * Check blacklists 762*11600SVikram.Hegde@Sun.COM */ 763*11600SVikram.Hegde@Sun.COM blacklist_setup(); 764*11600SVikram.Hegde@Sun.COM 765*11600SVikram.Hegde@Sun.COM if (blacklisted_smbios() == B_TRUE) { 766*11600SVikram.Hegde@Sun.COM blacklist_destroy(); 767*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 768*11600SVikram.Hegde@Sun.COM return; 769*11600SVikram.Hegde@Sun.COM } 770*11600SVikram.Hegde@Sun.COM 771*11600SVikram.Hegde@Sun.COM if (blacklisted_driver() == B_TRUE) { 772*11600SVikram.Hegde@Sun.COM blacklist_destroy(); 773*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 774*11600SVikram.Hegde@Sun.COM return; 775*11600SVikram.Hegde@Sun.COM } 776*11600SVikram.Hegde@Sun.COM 777*11600SVikram.Hegde@Sun.COM /* 778*11600SVikram.Hegde@Sun.COM * Read the "raw" DMAR ACPI table to get information 779*11600SVikram.Hegde@Sun.COM * and convert into a form we can use. 780*11600SVikram.Hegde@Sun.COM */ 781*11600SVikram.Hegde@Sun.COM if (immu_dmar_parse() != DDI_SUCCESS) { 782*11600SVikram.Hegde@Sun.COM blacklist_destroy(); 783*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 784*11600SVikram.Hegde@Sun.COM return; 785*11600SVikram.Hegde@Sun.COM } 786*11600SVikram.Hegde@Sun.COM 787*11600SVikram.Hegde@Sun.COM /* 788*11600SVikram.Hegde@Sun.COM * now that we have processed the ACPI table 789*11600SVikram.Hegde@Sun.COM * check if we need to blacklist this system 790*11600SVikram.Hegde@Sun.COM * based on ACPI info 791*11600SVikram.Hegde@Sun.COM */ 792*11600SVikram.Hegde@Sun.COM if (blacklisted_acpi() == B_TRUE) { 793*11600SVikram.Hegde@Sun.COM immu_dmar_destroy(); 794*11600SVikram.Hegde@Sun.COM blacklist_destroy(); 795*11600SVikram.Hegde@Sun.COM immu_enable = B_FALSE; 796*11600SVikram.Hegde@Sun.COM return; 797*11600SVikram.Hegde@Sun.COM } 798*11600SVikram.Hegde@Sun.COM 799*11600SVikram.Hegde@Sun.COM blacklist_destroy(); 800*11600SVikram.Hegde@Sun.COM 801*11600SVikram.Hegde@Sun.COM /* 802*11600SVikram.Hegde@Sun.COM * Check if system has HW quirks. 803*11600SVikram.Hegde@Sun.COM */ 804*11600SVikram.Hegde@Sun.COM pre_setup_quirks(); 805*11600SVikram.Hegde@Sun.COM 806*11600SVikram.Hegde@Sun.COM /* Now do the rest of the setup */ 807*11600SVikram.Hegde@Sun.COM immu_subsystems_setup(); 808*11600SVikram.Hegde@Sun.COM 809*11600SVikram.Hegde@Sun.COM /* 810*11600SVikram.Hegde@Sun.COM * Now that the IMMU is setup, create a phony 811*11600SVikram.Hegde@Sun.COM * reg prop so that suspend/resume works 812*11600SVikram.Hegde@Sun.COM */ 813*11600SVikram.Hegde@Sun.COM if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, root_devinfo, "reg", 814*11600SVikram.Hegde@Sun.COM (uchar_t *)phony_reg, strlen(phony_reg) + 1) != DDI_PROP_SUCCESS) { 815*11600SVikram.Hegde@Sun.COM ddi_err(DER_PANIC, NULL, "Failed to create reg prop for " 816*11600SVikram.Hegde@Sun.COM "rootnex node"); 817*11600SVikram.Hegde@Sun.COM /*NOTREACHED*/ 818*11600SVikram.Hegde@Sun.COM } 819*11600SVikram.Hegde@Sun.COM 820*11600SVikram.Hegde@Sun.COM immu_setup = B_TRUE; 821*11600SVikram.Hegde@Sun.COM } 822*11600SVikram.Hegde@Sun.COM 823*11600SVikram.Hegde@Sun.COM /* 824*11600SVikram.Hegde@Sun.COM * immu_startup() 825*11600SVikram.Hegde@Sun.COM * called directly by boot code to startup 826*11600SVikram.Hegde@Sun.COM * all units of the IOMMU 827*11600SVikram.Hegde@Sun.COM */ 828*11600SVikram.Hegde@Sun.COM void 829*11600SVikram.Hegde@Sun.COM immu_startup(void) 830*11600SVikram.Hegde@Sun.COM { 831*11600SVikram.Hegde@Sun.COM /* 832*11600SVikram.Hegde@Sun.COM * If IOMMU is disabled, do nothing 833*11600SVikram.Hegde@Sun.COM */ 834*11600SVikram.Hegde@Sun.COM if (immu_enable == B_FALSE) { 835*11600SVikram.Hegde@Sun.COM return; 836*11600SVikram.Hegde@Sun.COM } 837*11600SVikram.Hegde@Sun.COM 838*11600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) { 839*11600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Intel IOMMU not setup, " 840*11600SVikram.Hegde@Sun.COM "skipping IOMU startup"); 841*11600SVikram.Hegde@Sun.COM return; 842*11600SVikram.Hegde@Sun.COM } 843*11600SVikram.Hegde@Sun.COM 844*11600SVikram.Hegde@Sun.COM pre_startup_quirks(); 845*11600SVikram.Hegde@Sun.COM 846*11600SVikram.Hegde@Sun.COM ddi_err(DER_CONT, NULL, 847*11600SVikram.Hegde@Sun.COM "?Starting Intel IOMMU (dmar) units...\n"); 848*11600SVikram.Hegde@Sun.COM 849*11600SVikram.Hegde@Sun.COM immu_subsystems_startup(); 850*11600SVikram.Hegde@Sun.COM 851*11600SVikram.Hegde@Sun.COM immu_running = B_TRUE; 852*11600SVikram.Hegde@Sun.COM } 853*11600SVikram.Hegde@Sun.COM 854*11600SVikram.Hegde@Sun.COM /* 855*11600SVikram.Hegde@Sun.COM * immu_map_sgl() 856*11600SVikram.Hegde@Sun.COM * called from rootnex_coredma_bindhdl() when Intel 857*11600SVikram.Hegde@Sun.COM * IOMMU is enabled to build DVMA cookies and map them. 858*11600SVikram.Hegde@Sun.COM */ 859*11600SVikram.Hegde@Sun.COM int 860*11600SVikram.Hegde@Sun.COM immu_map_sgl(ddi_dma_impl_t *hp, struct ddi_dma_req *dmareq, 861*11600SVikram.Hegde@Sun.COM int prealloc_count, dev_info_t *rdip) 862*11600SVikram.Hegde@Sun.COM { 863*11600SVikram.Hegde@Sun.COM if (immu_running == B_FALSE) { 864*11600SVikram.Hegde@Sun.COM return (DDI_DMA_USE_PHYSICAL); 865*11600SVikram.Hegde@Sun.COM } 866*11600SVikram.Hegde@Sun.COM 867*11600SVikram.Hegde@Sun.COM return (immu_dvma_map(hp, dmareq, NULL, prealloc_count, rdip, 868*11600SVikram.Hegde@Sun.COM IMMU_FLAGS_DMAHDL)); 869*11600SVikram.Hegde@Sun.COM } 870*11600SVikram.Hegde@Sun.COM 871*11600SVikram.Hegde@Sun.COM /* 872*11600SVikram.Hegde@Sun.COM * immu_unmap_sgl() 873*11600SVikram.Hegde@Sun.COM * called from rootnex_coredma_unbindhdl(), to unmap DVMA 874*11600SVikram.Hegde@Sun.COM * cookies and free them 875*11600SVikram.Hegde@Sun.COM */ 876*11600SVikram.Hegde@Sun.COM int 877*11600SVikram.Hegde@Sun.COM immu_unmap_sgl(ddi_dma_impl_t *hp, dev_info_t *rdip) 878*11600SVikram.Hegde@Sun.COM { 879*11600SVikram.Hegde@Sun.COM if (immu_running == B_FALSE) { 880*11600SVikram.Hegde@Sun.COM return (DDI_DMA_USE_PHYSICAL); 881*11600SVikram.Hegde@Sun.COM } 882*11600SVikram.Hegde@Sun.COM 883*11600SVikram.Hegde@Sun.COM return (immu_dvma_unmap(hp, rdip)); 884*11600SVikram.Hegde@Sun.COM } 885*11600SVikram.Hegde@Sun.COM 886*11600SVikram.Hegde@Sun.COM /* 887*11600SVikram.Hegde@Sun.COM * Hook to notify IOMMU code of device tree changes 888*11600SVikram.Hegde@Sun.COM */ 889*11600SVikram.Hegde@Sun.COM void 890*11600SVikram.Hegde@Sun.COM immu_device_tree_changed(void) 891*11600SVikram.Hegde@Sun.COM { 892*11600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) { 893*11600SVikram.Hegde@Sun.COM return; 894*11600SVikram.Hegde@Sun.COM } 895*11600SVikram.Hegde@Sun.COM 896*11600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, NULL, "Intel IOMMU currently " 897*11600SVikram.Hegde@Sun.COM "does not use device tree updates"); 898*11600SVikram.Hegde@Sun.COM } 899*11600SVikram.Hegde@Sun.COM 900*11600SVikram.Hegde@Sun.COM /* 901*11600SVikram.Hegde@Sun.COM * Hook to notify IOMMU code of memory changes 902*11600SVikram.Hegde@Sun.COM */ 903*11600SVikram.Hegde@Sun.COM void 904*11600SVikram.Hegde@Sun.COM immu_physmem_update(uint64_t addr, uint64_t size) 905*11600SVikram.Hegde@Sun.COM { 906*11600SVikram.Hegde@Sun.COM if (immu_setup == B_FALSE) { 907*11600SVikram.Hegde@Sun.COM return; 908*11600SVikram.Hegde@Sun.COM } 909*11600SVikram.Hegde@Sun.COM immu_dvma_physmem_update(addr, size); 910*11600SVikram.Hegde@Sun.COM } 911*11600SVikram.Hegde@Sun.COM 912*11600SVikram.Hegde@Sun.COM /* 913*11600SVikram.Hegde@Sun.COM * immu_quiesce() 914*11600SVikram.Hegde@Sun.COM * quiesce all units that are running 915*11600SVikram.Hegde@Sun.COM */ 916*11600SVikram.Hegde@Sun.COM int 917*11600SVikram.Hegde@Sun.COM immu_quiesce(void) 918*11600SVikram.Hegde@Sun.COM { 919*11600SVikram.Hegde@Sun.COM immu_t *immu; 920*11600SVikram.Hegde@Sun.COM int ret = DDI_SUCCESS; 921*11600SVikram.Hegde@Sun.COM 922*11600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock); 923*11600SVikram.Hegde@Sun.COM 924*11600SVikram.Hegde@Sun.COM if (immu_running == B_FALSE) 925*11600SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 926*11600SVikram.Hegde@Sun.COM 927*11600SVikram.Hegde@Sun.COM ASSERT(immu_setup == B_TRUE); 928*11600SVikram.Hegde@Sun.COM 929*11600SVikram.Hegde@Sun.COM immu = list_head(&immu_list); 930*11600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) { 931*11600SVikram.Hegde@Sun.COM 932*11600SVikram.Hegde@Sun.COM /* if immu is not running, we dont quiesce */ 933*11600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_FALSE) 934*11600SVikram.Hegde@Sun.COM continue; 935*11600SVikram.Hegde@Sun.COM 936*11600SVikram.Hegde@Sun.COM /* flush caches */ 937*11600SVikram.Hegde@Sun.COM rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER); 938*11600SVikram.Hegde@Sun.COM immu_regs_context_flush(immu, 0, 0, 0, CONTEXT_GLOBAL); 939*11600SVikram.Hegde@Sun.COM rw_exit(&(immu->immu_ctx_rwlock)); 940*11600SVikram.Hegde@Sun.COM immu_regs_iotlb_flush(immu, 0, 0, 0, 0, IOTLB_GLOBAL); 941*11600SVikram.Hegde@Sun.COM immu_regs_wbf_flush(immu); 942*11600SVikram.Hegde@Sun.COM 943*11600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock)); 944*11600SVikram.Hegde@Sun.COM 945*11600SVikram.Hegde@Sun.COM /* 946*11600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do 947*11600SVikram.Hegde@Sun.COM * the actual shutdown. 948*11600SVikram.Hegde@Sun.COM */ 949*11600SVikram.Hegde@Sun.COM immu_regs_shutdown(immu); 950*11600SVikram.Hegde@Sun.COM immu_regs_suspend(immu); 951*11600SVikram.Hegde@Sun.COM 952*11600SVikram.Hegde@Sun.COM /* if immu is still running, we failed */ 953*11600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_TRUE) 954*11600SVikram.Hegde@Sun.COM ret = DDI_FAILURE; 955*11600SVikram.Hegde@Sun.COM else 956*11600SVikram.Hegde@Sun.COM immu->immu_regs_quiesced = B_TRUE; 957*11600SVikram.Hegde@Sun.COM 958*11600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock)); 959*11600SVikram.Hegde@Sun.COM } 960*11600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock); 961*11600SVikram.Hegde@Sun.COM 962*11600SVikram.Hegde@Sun.COM if (ret == DDI_SUCCESS) { 963*11600SVikram.Hegde@Sun.COM immu_running = B_FALSE; 964*11600SVikram.Hegde@Sun.COM immu_quiesced = B_TRUE; 965*11600SVikram.Hegde@Sun.COM } 966*11600SVikram.Hegde@Sun.COM 967*11600SVikram.Hegde@Sun.COM return (ret); 968*11600SVikram.Hegde@Sun.COM } 969*11600SVikram.Hegde@Sun.COM 970*11600SVikram.Hegde@Sun.COM /* 971*11600SVikram.Hegde@Sun.COM * immu_unquiesce() 972*11600SVikram.Hegde@Sun.COM * unquiesce all units 973*11600SVikram.Hegde@Sun.COM */ 974*11600SVikram.Hegde@Sun.COM int 975*11600SVikram.Hegde@Sun.COM immu_unquiesce(void) 976*11600SVikram.Hegde@Sun.COM { 977*11600SVikram.Hegde@Sun.COM immu_t *immu; 978*11600SVikram.Hegde@Sun.COM int ret = DDI_SUCCESS; 979*11600SVikram.Hegde@Sun.COM 980*11600SVikram.Hegde@Sun.COM mutex_enter(&immu_lock); 981*11600SVikram.Hegde@Sun.COM 982*11600SVikram.Hegde@Sun.COM if (immu_quiesced == B_FALSE) 983*11600SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 984*11600SVikram.Hegde@Sun.COM 985*11600SVikram.Hegde@Sun.COM ASSERT(immu_setup == B_TRUE); 986*11600SVikram.Hegde@Sun.COM ASSERT(immu_running == B_FALSE); 987*11600SVikram.Hegde@Sun.COM 988*11600SVikram.Hegde@Sun.COM immu = list_head(&immu_list); 989*11600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) { 990*11600SVikram.Hegde@Sun.COM 991*11600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_lock)); 992*11600SVikram.Hegde@Sun.COM 993*11600SVikram.Hegde@Sun.COM /* if immu was not quiesced, i.e was not running before */ 994*11600SVikram.Hegde@Sun.COM if (immu->immu_regs_quiesced == B_FALSE) 995*11600SVikram.Hegde@Sun.COM continue; 996*11600SVikram.Hegde@Sun.COM 997*11600SVikram.Hegde@Sun.COM if (immu_regs_resume(immu) != DDI_SUCCESS) { 998*11600SVikram.Hegde@Sun.COM ret = DDI_FAILURE; 999*11600SVikram.Hegde@Sun.COM continue; 1000*11600SVikram.Hegde@Sun.COM } 1001*11600SVikram.Hegde@Sun.COM 1002*11600SVikram.Hegde@Sun.COM /* flush caches before unquiesce */ 1003*11600SVikram.Hegde@Sun.COM rw_enter(&(immu->immu_ctx_rwlock), RW_WRITER); 1004*11600SVikram.Hegde@Sun.COM immu_regs_context_flush(immu, 0, 0, 0, CONTEXT_GLOBAL); 1005*11600SVikram.Hegde@Sun.COM rw_exit(&(immu->immu_ctx_rwlock)); 1006*11600SVikram.Hegde@Sun.COM immu_regs_iotlb_flush(immu, 0, 0, 0, 0, IOTLB_GLOBAL); 1007*11600SVikram.Hegde@Sun.COM 1008*11600SVikram.Hegde@Sun.COM /* 1009*11600SVikram.Hegde@Sun.COM * Set IOMMU unit's regs to do 1010*11600SVikram.Hegde@Sun.COM * the actual startup. This will 1011*11600SVikram.Hegde@Sun.COM * set immu->immu_regs_running field 1012*11600SVikram.Hegde@Sun.COM * if the unit is successfully 1013*11600SVikram.Hegde@Sun.COM * started 1014*11600SVikram.Hegde@Sun.COM */ 1015*11600SVikram.Hegde@Sun.COM immu_regs_startup(immu); 1016*11600SVikram.Hegde@Sun.COM 1017*11600SVikram.Hegde@Sun.COM if (immu->immu_regs_running == B_FALSE) { 1018*11600SVikram.Hegde@Sun.COM ret = DDI_FAILURE; 1019*11600SVikram.Hegde@Sun.COM } else { 1020*11600SVikram.Hegde@Sun.COM immu_quiesced = B_TRUE; 1021*11600SVikram.Hegde@Sun.COM immu_running = B_TRUE; 1022*11600SVikram.Hegde@Sun.COM immu->immu_regs_quiesced = B_FALSE; 1023*11600SVikram.Hegde@Sun.COM } 1024*11600SVikram.Hegde@Sun.COM 1025*11600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_lock)); 1026*11600SVikram.Hegde@Sun.COM } 1027*11600SVikram.Hegde@Sun.COM 1028*11600SVikram.Hegde@Sun.COM mutex_exit(&immu_lock); 1029*11600SVikram.Hegde@Sun.COM 1030*11600SVikram.Hegde@Sun.COM return (ret); 1031*11600SVikram.Hegde@Sun.COM } 1032*11600SVikram.Hegde@Sun.COM 1033*11600SVikram.Hegde@Sun.COM /* ############## END Intel IOMMU entry points ################## */ 1034