17d87efajmcp/*
27d87efajmcp * CDDL HEADER START
37d87efajmcp *
47d87efajmcp * The contents of this file are subject to the terms of the
57d87efajmcp * Common Development and Distribution License (the "License").
67d87efajmcp * You may not use this file except in compliance with the License.
77d87efajmcp *
87d87efajmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97d87efajmcp * or http://www.opensolaris.org/os/licensing.
107d87efajmcp * See the License for the specific language governing permissions
117d87efajmcp * and limitations under the License.
127d87efajmcp *
137d87efajmcp * When distributing Covered Code, include this CDDL HEADER in each
147d87efajmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157d87efajmcp * If applicable, add the following below this CDDL HEADER, with the
167d87efajmcp * fields enclosed by brackets "[]" replaced with your own identifying
177d87efajmcp * information: Portions Copyright [yyyy] [name of copyright owner]
187d87efajmcp *
197d87efajmcp * CDDL HEADER END
207d87efajmcp */
217d87efajmcp
227d87efajmcp/*
237d87efajmcp * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247d87efajmcp * Use is subject to license terms.
257d87efajmcp */
267d87efajmcp
277d87efajmcp#include <sys/types.h>
287d87efajmcp#include <sys/file.h>
297d87efajmcp#include <sys/errno.h>
307d87efajmcp#include <sys/open.h>
317d87efajmcp#include <sys/stat.h>
327d87efajmcp#include <sys/cred.h>
337d87efajmcp#include <sys/modctl.h>
347d87efajmcp#include <sys/conf.h>
357d87efajmcp#include <sys/devops.h>
367d87efajmcp#include <sys/ddi.h>
376732dbbVikram Hegde#include <sys/x86_archext.h>
387d87efajmcp
397d87efajmcp#include <sys/amd_iommu.h>
407d87efajmcp#include "amd_iommu_impl.h"
417d87efajmcp#include "amd_iommu_acpi.h"
427d87efajmcp
437d87efajmcp
447d87efajmcp#define	AMD_IOMMU_MINOR2INST(x)	(x)
457d87efajmcp#define	AMD_IOMMU_INST2MINOR(x)	(x)
467d87efajmcp#define	AMD_IOMMU_NODETYPE	"ddi_iommu"
477d87efajmcp#define	AMD_IOMMU_MINOR_NAME	"amd-iommu"
487d87efajmcp
497d87efajmcpstatic int amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
507d87efajmcp    void **result);
517d87efajmcpstatic int amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
527d87efajmcpstatic int amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
537d87efajmcpstatic int amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp);
547d87efajmcpstatic int amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp);
557d87efajmcpstatic int amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
567d87efajmcp    cred_t *credp, int *rvalp);
57ac48dfeVikram Hegdestatic int amd_iommu_quiesce(dev_info_t *dip);
587d87efajmcp
597d87efajmcpstatic struct cb_ops amd_iommu_cb_ops = {
607d87efajmcp	amd_iommu_open,		/* cb_open */
617d87efajmcp	amd_iommu_close,	/* cb_close */
627d87efajmcp	nodev,			/* cb_strategy */
637d87efajmcp	nodev,			/* cb_print */
647d87efajmcp	nodev,			/* cb_dump */
657d87efajmcp	nodev,			/* cb_read */
667d87efajmcp	nodev,			/* cb_write */
677d87efajmcp	amd_iommu_ioctl,	/* cb_ioctl */
687d87efajmcp	nodev,			/* cb_devmap */
697d87efajmcp	nodev,			/* cb_mmap */
707d87efajmcp	nodev,			/* cb_segmap */
717d87efajmcp	nochpoll,		/* cb_chpoll */
727d87efajmcp	ddi_prop_op,		/* cb_prop_op */
737d87efajmcp	NULL,			/* cb_str */
747d87efajmcp	D_NEW | D_MP,		/* cb_flag */
757d87efajmcp	CB_REV,			/* cb_rev */
767d87efajmcp	nodev,			/* cb_aread */
777d87efajmcp	nodev			/* cb_awrite */
787d87efajmcp};
797d87efajmcp
807d87efajmcpstatic struct dev_ops amd_iommu_dev_ops = {
817d87efajmcp	DEVO_REV,		/* devo_rev */
827d87efajmcp	0,			/* devo_refcnt */
837d87efajmcp	amd_iommu_getinfo,	/* devo_getinfo */
847d87efajmcp	nulldev,		/* devo_identify */
857d87efajmcp	nulldev,		/* devo_probe */
867d87efajmcp	amd_iommu_attach,	/* devo_attach */
877d87efajmcp	amd_iommu_detach,	/* devo_detach */
887d87efajmcp	nodev,			/* devo_reset */
897d87efajmcp	&amd_iommu_cb_ops,	/* devo_cb_ops */
907d87efajmcp	NULL,			/* devo_bus_ops */
91ac48dfeVikram Hegde	nulldev,		/* devo_power */
92ac48dfeVikram Hegde	amd_iommu_quiesce,	/* devo_quiesce */
937d87efajmcp};
947d87efajmcp
957d87efajmcpstatic struct modldrv modldrv = {
967d87efajmcp	&mod_driverops,
977d87efajmcp	"AMD IOMMU 0.1",
987d87efajmcp	&amd_iommu_dev_ops
997d87efajmcp};
1007d87efajmcp
1017d87efajmcpstatic struct modlinkage modlinkage = {
1027d87efajmcp	MODREV_1,
1037d87efajmcp	(void *)&modldrv,
1047d87efajmcp	NULL
1057d87efajmcp};
1067d87efajmcp
1077d87efajmcpamd_iommu_debug_t amd_iommu_debug;
1087d87efajmcpkmutex_t amd_iommu_global_lock;
1097d87efajmcpconst char *amd_iommu_modname = "amd_iommu";
1107d87efajmcpamd_iommu_alias_t **amd_iommu_alias;
1117d87efajmcpamd_iommu_page_table_hash_t amd_iommu_page_table_hash;
1127d87efajmcpstatic void *amd_iommu_statep;
1137d87efajmcpint amd_iommu_64bit_bug;
1147d87efajmcpint amd_iommu_unity_map;
1157d87efajmcpint amd_iommu_no_RW_perms;
1167d87efajmcpint amd_iommu_no_unmap;
1177d87efajmcpint amd_iommu_pageva_inval_all;
1187d87efajmcpint amd_iommu_disable;		/* disable IOMMU */
1197d87efajmcpchar *amd_iommu_disable_list;	/* list of drivers bypassing IOMMU */
1207d87efajmcp
1217d87efajmcpint
1227d87efajmcp_init(void)
1237d87efajmcp{
1247d87efajmcp	int error = ENOTSUP;
1257d87efajmcp
1267d87efajmcp#if defined(__amd64) && !defined(__xpv)
1277d87efajmcp
1286732dbbVikram Hegde	if (get_hwenv() != HW_NATIVE)
1296732dbbVikram Hegde		return (ENOTSUP);
1306732dbbVikram Hegde
1317d87efajmcp	error = ddi_soft_state_init(&amd_iommu_statep,
1327d87efajmcp	    sizeof (struct amd_iommu_state), 1);
1337d87efajmcp	if (error) {
1347d87efajmcp		cmn_err(CE_WARN, "%s: _init: failed to init soft state.",
1357d87efajmcp		    amd_iommu_modname);
1367d87efajmcp		return (error);
1377d87efajmcp	}
1387d87efajmcp
1397d87efajmcp	if (amd_iommu_acpi_init() != DDI_SUCCESS) {
1407d87efajmcp		if (amd_iommu_debug) {
1417d87efajmcp			cmn_err(CE_WARN, "%s: _init: ACPI init failed.",
1427d87efajmcp			    amd_iommu_modname);
1437d87efajmcp		}
1447d87efajmcp		ddi_soft_state_fini(&amd_iommu_statep);
1457d87efajmcp		return (ENOTSUP);
1467d87efajmcp	}
1477d87efajmcp
1487d87efajmcp	amd_iommu_read_boot_props();
1497d87efajmcp
1507d87efajmcp	if (amd_iommu_page_table_hash_init(&amd_iommu_page_table_hash)
1517d87efajmcp	    != DDI_SUCCESS) {
1527d87efajmcp		cmn_err(CE_WARN, "%s: _init: Page table hash init failed.",
1537d87efajmcp		    amd_iommu_modname);
1547d87efajmcp		if (amd_iommu_disable_list) {
1557d87efajmcp			kmem_free(amd_iommu_disable_list,
1567d87efajmcp			    strlen(amd_iommu_disable_list) + 1);
1577d87efajmcp			amd_iommu_disable_list = NULL;
1587d87efajmcp		}
1597d87efajmcp		amd_iommu_acpi_fini();
1607d87efajmcp		ddi_soft_state_fini(&amd_iommu_statep);
1617d87efajmcp		amd_iommu_statep = NULL;
1627d87efajmcp		return (EFAULT);
1637d87efajmcp	}
1647d87efajmcp
1657d87efajmcp	error = mod_install(&modlinkage);
1667d87efajmcp	if (error) {
1677d87efajmcp		cmn_err(CE_WARN, "%s: _init: mod_install failed.",
1687d87efajmcp		    amd_iommu_modname);
1697d87efajmcp		amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
1707d87efajmcp		if (amd_iommu_disable_list) {
1717d87efajmcp			kmem_free(amd_iommu_disable_list,
1727d87efajmcp			    strlen(amd_iommu_disable_list) + 1);
1737d87efajmcp			amd_iommu_disable_list = NULL;
1747d87efajmcp		}
1757d87efajmcp		amd_iommu_acpi_fini();
1767d87efajmcp		ddi_soft_state_fini(&amd_iommu_statep);
1777d87efajmcp		amd_iommu_statep = NULL;
1787d87efajmcp		return (error);
1797d87efajmcp	}
1807d87efajmcp	error = 0;
1817d87efajmcp#endif
1827d87efajmcp
1837d87efajmcp	return (error);
1847d87efajmcp}
1857d87efajmcp
1867d87efajmcpint
1877d87efajmcp_info(struct modinfo *modinfop)
1887d87efajmcp{
1897d87efajmcp	return (mod_info(&modlinkage, modinfop));
1907d87efajmcp}
1917d87efajmcp
1927d87efajmcpint
1937d87efajmcp_fini(void)
1947d87efajmcp{
1957d87efajmcp	int error;
1967d87efajmcp
1977d87efajmcp	error = mod_remove(&modlinkage);
1987d87efajmcp	if (error)
1997d87efajmcp		return (error);
2007d87efajmcp
2017d87efajmcp	amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
2027d87efajmcp	if (amd_iommu_disable_list) {
2037d87efajmcp		kmem_free(amd_iommu_disable_list,
2047d87efajmcp		    strlen(amd_iommu_disable_list) + 1);
2057d87efajmcp		amd_iommu_disable_list = NULL;
2067d87efajmcp	}
2077d87efajmcp	amd_iommu_acpi_fini();
2087d87efajmcp	ddi_soft_state_fini(&amd_iommu_statep);
2097d87efajmcp	amd_iommu_statep = NULL;
2107d87efajmcp
2117d87efajmcp	return (0);
2127d87efajmcp}
2137d87efajmcp
2147d87efajmcp/*ARGSUSED*/
2157d87efajmcpstatic int
2167d87efajmcpamd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2177d87efajmcp{
2187d87efajmcp	struct amd_iommu_state *statep;
2197d87efajmcp
2207d87efajmcp	ASSERT(result);
2217d87efajmcp
2227d87efajmcp	*result = NULL;
2237d87efajmcp
2247d87efajmcp	switch (cmd) {
2257d87efajmcp	case DDI_INFO_DEVT2DEVINFO:
2267d87efajmcp		statep = ddi_get_soft_state(amd_iommu_statep,
2277d87efajmcp		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg)));
2287d87efajmcp		if (statep) {
2297d87efajmcp			*result = statep->aioms_devi;
2307d87efajmcp			return (DDI_SUCCESS);
2317d87efajmcp		}
2327d87efajmcp		break;
2337d87efajmcp	case DDI_INFO_DEVT2INSTANCE:
2347d87efajmcp		*result = (void *)(uintptr_t)
2357d87efajmcp		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg));
2367d87efajmcp		return (DDI_SUCCESS);
2377d87efajmcp	}
2387d87efajmcp
2397d87efajmcp	return (DDI_FAILURE);
2407d87efajmcp}
2417d87efajmcp
2427d87efajmcpstatic int
2437d87efajmcpamd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2447d87efajmcp{
2457d87efajmcp	int instance = ddi_get_instance(dip);
2467d87efajmcp	const char *driver = ddi_driver_name(dip);
2477d87efajmcp	struct amd_iommu_state *statep;
2487d87efajmcp
2497d87efajmcp	ASSERT(instance >= 0);
2507d87efajmcp	ASSERT(driver);
2517d87efajmcp
2527d87efajmcp	switch (cmd) {
2537d87efajmcp	case DDI_ATTACH:
2547d87efajmcp		if (ddi_soft_state_zalloc(amd_iommu_statep, instance)
2557d87efajmcp		    != DDI_SUCCESS) {
2567d87efajmcp			cmn_err(CE_WARN, "Unable to allocate soft state for "
2577d87efajmcp			    "%s%d", driver, instance);
2587d87efajmcp			return (DDI_FAILURE);
2597d87efajmcp		}
2607d87efajmcp
2617d87efajmcp		statep = ddi_get_soft_state(amd_iommu_statep, instance);
2627d87efajmcp		if (statep == NULL) {
2637d87efajmcp			cmn_err(CE_WARN, "Unable to get soft state for "
2647d87efajmcp			    "%s%d", driver, instance);
2657d87efajmcp			ddi_soft_state_free(amd_iommu_statep, instance);
2667d87efajmcp			return (DDI_FAILURE);
2677d87efajmcp		}
2687d87efajmcp
2697d87efajmcp		if (ddi_create_minor_node(dip, AMD_IOMMU_MINOR_NAME, S_IFCHR,
2707d87efajmcp		    AMD_IOMMU_INST2MINOR(instance), AMD_IOMMU_NODETYPE,
2717d87efajmcp		    0) != DDI_SUCCESS) {
2727d87efajmcp			cmn_err(CE_WARN, "Unable to create minor node for "
2737d87efajmcp			    "%s%d", driver, instance);
2747d87efajmcp			ddi_remove_minor_node(dip, NULL);
2757d87efajmcp			ddi_soft_state_free(amd_iommu_statep, instance);
2767d87efajmcp			return (DDI_FAILURE);
2777d87efajmcp		}
2787d87efajmcp
2797d87efajmcp		statep->aioms_devi = dip;
2807d87efajmcp		statep->aioms_instance = instance;
2817d87efajmcp		statep->aioms_iommu_start = NULL;
2827d87efajmcp		statep->aioms_iommu_end = NULL;
2837d87efajmcp
2847d87efajmcp		amd_iommu_lookup_conf_props(dip);
2857d87efajmcp
2867d87efajmcp		if (amd_iommu_disable_list) {
2877d87efajmcp			cmn_err(CE_NOTE, "AMD IOMMU disabled for the following"
2887d87efajmcp			    " drivers:\n%s", amd_iommu_disable_list);
2897d87efajmcp		}
2907d87efajmcp
2917d87efajmcp		if (amd_iommu_disable) {
2927d87efajmcp			cmn_err(CE_NOTE, "AMD IOMMU disabled by user");
2937d87efajmcp		} else if (amd_iommu_setup(dip, statep) != DDI_SUCCESS) {
2947d87efajmcp			cmn_err(CE_WARN, "Unable to initialize AMD IOMMU "
2957d87efajmcp			    "%s%d", driver, instance);
2967d87efajmcp			ddi_remove_minor_node(dip, NULL);
2977d87efajmcp			ddi_soft_state_free(amd_iommu_statep, instance);
2987d87efajmcp			return (DDI_FAILURE);
2997d87efajmcp		}
3007d87efajmcp
3017d87efajmcp		ddi_report_dev(dip);
3027d87efajmcp
3037d87efajmcp		return (DDI_SUCCESS);
3047d87efajmcp
3057d87efajmcp	case DDI_RESUME:
3067d87efajmcp		return (DDI_SUCCESS);
3077d87efajmcp	default:
3087d87efajmcp		return (DDI_FAILURE);
3097d87efajmcp	}
3107d87efajmcp}
3117d87efajmcp
3127d87efajmcpstatic int
3137d87efajmcpamd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3147d87efajmcp{
3157d87efajmcp	int instance = ddi_get_instance(dip);
3167d87efajmcp	const char *driver = ddi_driver_name(dip);
3177d87efajmcp	struct amd_iommu_state *statep;
3187d87efajmcp
3197d87efajmcp	ASSERT(instance >= 0);
3207d87efajmcp	ASSERT(driver);
3217d87efajmcp
3227d87efajmcp	switch (cmd) {
3237d87efajmcp	case DDI_DETACH:
3247d87efajmcp		statep = ddi_get_soft_state(amd_iommu_statep, instance);
3257d87efajmcp		if (statep == NULL) {
3267d87efajmcp			cmn_err(CE_WARN, "%s%d: Cannot get soft state",
3277d87efajmcp			    driver, instance);
3287d87efajmcp			return (DDI_FAILURE);
3297d87efajmcp		}
3307d87efajmcp		return (DDI_FAILURE);
3317d87efajmcp	case DDI_SUSPEND:
3327d87efajmcp		return (DDI_SUCCESS);
3337d87efajmcp	default:
3347d87efajmcp		return (DDI_FAILURE);
3357d87efajmcp	}
3367d87efajmcp}
3377d87efajmcp
3387d87efajmcp/*ARGSUSED*/
3397d87efajmcpstatic int
3407d87efajmcpamd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp)
3417d87efajmcp{
3427d87efajmcp	int instance = AMD_IOMMU_MINOR2INST(getminor(*devp));
3437d87efajmcp	struct amd_iommu_state *statep;
3447d87efajmcp	const char *f = "amd_iommu_open";
3457d87efajmcp
3467d87efajmcp	if (instance < 0) {
3477d87efajmcp		cmn_err(CE_WARN, "%s: invalid instance %d",
3487d87efajmcp		    f, instance);
3497d87efajmcp		return (ENXIO);
3507d87efajmcp	}
3517d87efajmcp
3527d87efajmcp	if (!(flag & (FREAD|FWRITE))) {
3537d87efajmcp		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
3547d87efajmcp		return (EINVAL);
3557d87efajmcp	}
3567d87efajmcp
3577d87efajmcp	if (otyp != OTYP_CHR) {
3587d87efajmcp		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
3597d87efajmcp		return (EINVAL);
3607d87efajmcp	}
3617d87efajmcp
3627d87efajmcp	statep = ddi_get_soft_state(amd_iommu_statep, instance);
3637d87efajmcp	if (statep == NULL) {
3647d87efajmcp		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
3657d87efajmcp		    f, instance);
3667d87efajmcp		return (ENXIO);
3677d87efajmcp	}
3687d87efajmcp
3697d87efajmcp	ASSERT(statep->aioms_instance == instance);
3707d87efajmcp
3717d87efajmcp	return (0);
3727d87efajmcp}
3737d87efajmcp
3747d87efajmcp/*ARGSUSED*/
3757d87efajmcpstatic int
3767d87efajmcpamd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp)
3777d87efajmcp{
3787d87efajmcp	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
3797d87efajmcp	struct amd_iommu_state *statep;
3807d87efajmcp	const char *f = "amd_iommu_close";
3817d87efajmcp
3827d87efajmcp	if (instance < 0) {
3837d87efajmcp		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
3847d87efajmcp		return (ENXIO);
3857d87efajmcp	}
3867d87efajmcp
3877d87efajmcp	if (!(flag & (FREAD|FWRITE))) {
3887d87efajmcp		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
3897d87efajmcp		return (EINVAL);
3907d87efajmcp	}
3917d87efajmcp
3927d87efajmcp	if (otyp != OTYP_CHR) {
3937d87efajmcp		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
3947d87efajmcp		return (EINVAL);
3957d87efajmcp	}
3967d87efajmcp
3977d87efajmcp	statep = ddi_get_soft_state(amd_iommu_statep, instance);
3987d87efajmcp	if (statep == NULL) {
3997d87efajmcp		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
4007d87efajmcp		    f, instance);
4017d87efajmcp		return (ENXIO);
4027d87efajmcp	}
4037d87efajmcp
4047d87efajmcp	ASSERT(statep->aioms_instance == instance);
4057d87efajmcp	return (0);
4067d87efajmcp
4077d87efajmcp}
4087d87efajmcp
4097d87efajmcp/*ARGSUSED*/
4107d87efajmcpstatic int
4117d87efajmcpamd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
4127d87efajmcp    int *rvalp)
4137d87efajmcp{
4147d87efajmcp	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
4157d87efajmcp	struct amd_iommu_state *statep;
4167d87efajmcp	const char *f = "amd_iommu_ioctl";
4177d87efajmcp
4187d87efajmcp	ASSERT(*rvalp);
4197d87efajmcp
4207d87efajmcp	if (instance < 0) {
4217d87efajmcp		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
4227d87efajmcp		return (ENXIO);
4237d87efajmcp	}
4247d87efajmcp
4257d87efajmcp
4267d87efajmcp	if (!(mode & (FREAD|FWRITE))) {
4277d87efajmcp		cmn_err(CE_WARN, "%s: invalid mode %d", f, mode);
4287d87efajmcp		return (EINVAL);
4297d87efajmcp	}
4307d87efajmcp
4317d87efajmcp	if (mode & FKIOCTL) {
4327d87efajmcp		cmn_err(CE_WARN, "%s: FKIOCTL unsupported mode %d", f, mode);
4337d87efajmcp		return (EINVAL);
4347d87efajmcp	}
4357d87efajmcp
4367d87efajmcp	statep = ddi_get_soft_state(amd_iommu_statep, instance);
4377d87efajmcp	if (statep == NULL) {
4387d87efajmcp		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
4397d87efajmcp		    f, instance);
4407d87efajmcp		return (ENXIO);
4417d87efajmcp	}
4427d87efajmcp
4437d87efajmcp	ASSERT(statep->aioms_instance == instance);
4447d87efajmcp
4457d87efajmcp	return (ENOTTY);
4467d87efajmcp}
447ac48dfeVikram Hegde
448ac48dfeVikram Hegdestatic int
449ac48dfeVikram Hegdeamd_iommu_quiesce(dev_info_t *dip)
450ac48dfeVikram Hegde{
451ac48dfeVikram Hegde	int instance = ddi_get_instance(dip);
452ac48dfeVikram Hegde	struct amd_iommu_state *statep;
453ac48dfeVikram Hegde	const char *f = "amd_iommu_quiesce";
454ac48dfeVikram Hegde
455ac48dfeVikram Hegde	statep = ddi_get_soft_state(amd_iommu_statep, instance);
456ac48dfeVikram Hegde	if (statep == NULL) {
457ac48dfeVikram Hegde		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
458ac48dfeVikram Hegde		    f, instance);
459ac48dfeVikram Hegde		return (DDI_FAILURE);
460ac48dfeVikram Hegde	}
461ac48dfeVikram Hegde
462ac48dfeVikram Hegde	if (amd_iommu_teardown(dip, statep, AMD_IOMMU_QUIESCE) != DDI_SUCCESS) {
463ac48dfeVikram Hegde		cmn_err(CE_WARN, "%s: Unable to quiesce AMD IOMMU "
464ac48dfeVikram Hegde		    "%s%d", f, ddi_driver_name(dip), instance);
465ac48dfeVikram Hegde		return (DDI_FAILURE);
466ac48dfeVikram Hegde	}
467ac48dfeVikram Hegde
468ac48dfeVikram Hegde	return (DDI_SUCCESS);
469ac48dfeVikram Hegde}
470