xref: /illumos-gate/usr/src/uts/i86pc/io/amd_iommu/amd_iommu.c (revision 86ef0a63e1cfa5dc98606efef379365acca98063)
16732dbb3SVikram Hegde /*
26732dbb3SVikram Hegde  * CDDL HEADER START
36732dbb3SVikram Hegde  *
46732dbb3SVikram Hegde  * The contents of this file are subject to the terms of the
56732dbb3SVikram Hegde  * Common Development and Distribution License (the "License").
66732dbb3SVikram Hegde  * You may not use this file except in compliance with the License.
76732dbb3SVikram Hegde  *
86732dbb3SVikram Hegde  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96732dbb3SVikram Hegde  * or http://www.opensolaris.org/os/licensing.
106732dbb3SVikram Hegde  * See the License for the specific language governing permissions
116732dbb3SVikram Hegde  * and limitations under the License.
126732dbb3SVikram Hegde  *
136732dbb3SVikram Hegde  * When distributing Covered Code, include this CDDL HEADER in each
146732dbb3SVikram Hegde  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156732dbb3SVikram Hegde  * If applicable, add the following below this CDDL HEADER, with the
166732dbb3SVikram Hegde  * fields enclosed by brackets "[]" replaced with your own identifying
176732dbb3SVikram Hegde  * information: Portions Copyright [yyyy] [name of copyright owner]
186732dbb3SVikram Hegde  *
196732dbb3SVikram Hegde  * CDDL HEADER END
206732dbb3SVikram Hegde  */
216732dbb3SVikram Hegde 
226732dbb3SVikram Hegde /*
236732dbb3SVikram Hegde  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
246732dbb3SVikram Hegde  * Use is subject to license terms.
256732dbb3SVikram Hegde  */
266732dbb3SVikram Hegde 
276732dbb3SVikram Hegde #include <sys/types.h>
286732dbb3SVikram Hegde #include <sys/file.h>
296732dbb3SVikram Hegde #include <sys/errno.h>
306732dbb3SVikram Hegde #include <sys/open.h>
316732dbb3SVikram Hegde #include <sys/stat.h>
326732dbb3SVikram Hegde #include <sys/cred.h>
336732dbb3SVikram Hegde #include <sys/modctl.h>
346732dbb3SVikram Hegde #include <sys/conf.h>
356732dbb3SVikram Hegde #include <sys/devops.h>
366732dbb3SVikram Hegde #include <sys/ddi.h>
376732dbb3SVikram Hegde #include <sys/x86_archext.h>
386732dbb3SVikram Hegde 
396732dbb3SVikram Hegde #include <sys/amd_iommu.h>
406732dbb3SVikram Hegde #include "amd_iommu_impl.h"
416732dbb3SVikram Hegde #include "amd_iommu_acpi.h"
426732dbb3SVikram Hegde 
436732dbb3SVikram Hegde 
446732dbb3SVikram Hegde #define	AMD_IOMMU_MINOR2INST(x)	(x)
456732dbb3SVikram Hegde #define	AMD_IOMMU_INST2MINOR(x)	(x)
466732dbb3SVikram Hegde #define	AMD_IOMMU_NODETYPE	"ddi_iommu"
476732dbb3SVikram Hegde #define	AMD_IOMMU_MINOR_NAME	"amd-iommu"
486732dbb3SVikram Hegde 
496732dbb3SVikram Hegde static int amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
506732dbb3SVikram Hegde     void **result);
516732dbb3SVikram Hegde static int amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
526732dbb3SVikram Hegde static int amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
536732dbb3SVikram Hegde static int amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp);
546732dbb3SVikram Hegde static int amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp);
556732dbb3SVikram Hegde static int amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
566732dbb3SVikram Hegde     cred_t *credp, int *rvalp);
57ac48dfe8SVikram Hegde static int amd_iommu_quiesce(dev_info_t *dip);
586732dbb3SVikram Hegde 
596732dbb3SVikram Hegde static struct cb_ops amd_iommu_cb_ops = {
606732dbb3SVikram Hegde 	amd_iommu_open,		/* cb_open */
616732dbb3SVikram Hegde 	amd_iommu_close,	/* cb_close */
626732dbb3SVikram Hegde 	nodev,			/* cb_strategy */
636732dbb3SVikram Hegde 	nodev,			/* cb_print */
646732dbb3SVikram Hegde 	nodev,			/* cb_dump */
656732dbb3SVikram Hegde 	nodev,			/* cb_read */
666732dbb3SVikram Hegde 	nodev,			/* cb_write */
676732dbb3SVikram Hegde 	amd_iommu_ioctl,	/* cb_ioctl */
686732dbb3SVikram Hegde 	nodev,			/* cb_devmap */
696732dbb3SVikram Hegde 	nodev,			/* cb_mmap */
706732dbb3SVikram Hegde 	nodev,			/* cb_segmap */
716732dbb3SVikram Hegde 	nochpoll,		/* cb_chpoll */
726732dbb3SVikram Hegde 	ddi_prop_op,		/* cb_prop_op */
736732dbb3SVikram Hegde 	NULL,			/* cb_str */
746732dbb3SVikram Hegde 	D_NEW | D_MP,		/* cb_flag */
756732dbb3SVikram Hegde 	CB_REV,			/* cb_rev */
766732dbb3SVikram Hegde 	nodev,			/* cb_aread */
776732dbb3SVikram Hegde 	nodev			/* cb_awrite */
786732dbb3SVikram Hegde };
796732dbb3SVikram Hegde 
806732dbb3SVikram Hegde static struct dev_ops amd_iommu_dev_ops = {
816732dbb3SVikram Hegde 	DEVO_REV,		/* devo_rev */
826732dbb3SVikram Hegde 	0,			/* devo_refcnt */
836732dbb3SVikram Hegde 	amd_iommu_getinfo,	/* devo_getinfo */
846732dbb3SVikram Hegde 	nulldev,		/* devo_identify */
856732dbb3SVikram Hegde 	nulldev,		/* devo_probe */
866732dbb3SVikram Hegde 	amd_iommu_attach,	/* devo_attach */
876732dbb3SVikram Hegde 	amd_iommu_detach,	/* devo_detach */
886732dbb3SVikram Hegde 	nodev,			/* devo_reset */
896732dbb3SVikram Hegde 	&amd_iommu_cb_ops,	/* devo_cb_ops */
906732dbb3SVikram Hegde 	NULL,			/* devo_bus_ops */
91ac48dfe8SVikram Hegde 	nulldev,		/* devo_power */
92ac48dfe8SVikram Hegde 	amd_iommu_quiesce,	/* devo_quiesce */
936732dbb3SVikram Hegde };
946732dbb3SVikram Hegde 
956732dbb3SVikram Hegde static struct modldrv modldrv = {
966732dbb3SVikram Hegde 	&mod_driverops,
976732dbb3SVikram Hegde 	"AMD IOMMU 0.1",
986732dbb3SVikram Hegde 	&amd_iommu_dev_ops
996732dbb3SVikram Hegde };
1006732dbb3SVikram Hegde 
1016732dbb3SVikram Hegde static struct modlinkage modlinkage = {
1026732dbb3SVikram Hegde 	MODREV_1,
1036732dbb3SVikram Hegde 	(void *)&modldrv,
1046732dbb3SVikram Hegde 	NULL
1056732dbb3SVikram Hegde };
1066732dbb3SVikram Hegde 
1076732dbb3SVikram Hegde amd_iommu_debug_t amd_iommu_debug;
1086732dbb3SVikram Hegde kmutex_t amd_iommu_global_lock;
1096732dbb3SVikram Hegde const char *amd_iommu_modname = "amd_iommu";
1106732dbb3SVikram Hegde amd_iommu_alias_t **amd_iommu_alias;
1116732dbb3SVikram Hegde amd_iommu_page_table_hash_t amd_iommu_page_table_hash;
1126732dbb3SVikram Hegde static void *amd_iommu_statep;
1136732dbb3SVikram Hegde int amd_iommu_64bit_bug;
1146732dbb3SVikram Hegde int amd_iommu_unity_map;
1156732dbb3SVikram Hegde int amd_iommu_no_RW_perms;
1166732dbb3SVikram Hegde int amd_iommu_no_unmap;
1176732dbb3SVikram Hegde int amd_iommu_pageva_inval_all;
1186732dbb3SVikram Hegde int amd_iommu_disable;		/* disable IOMMU */
1196732dbb3SVikram Hegde char *amd_iommu_disable_list;	/* list of drivers bypassing IOMMU */
1206732dbb3SVikram Hegde 
1216732dbb3SVikram Hegde int
_init(void)1226732dbb3SVikram Hegde _init(void)
1236732dbb3SVikram Hegde {
1246732dbb3SVikram Hegde 	int error = ENOTSUP;
1256732dbb3SVikram Hegde 
126*86ef0a63SRichard Lowe #if !defined(__xpv)
1276732dbb3SVikram Hegde 
1286732dbb3SVikram Hegde 	if (get_hwenv() != HW_NATIVE)
1296732dbb3SVikram Hegde 		return (ENOTSUP);
1306732dbb3SVikram Hegde 
1316732dbb3SVikram Hegde 	error = ddi_soft_state_init(&amd_iommu_statep,
1326732dbb3SVikram Hegde 	    sizeof (struct amd_iommu_state), 1);
1336732dbb3SVikram Hegde 	if (error) {
1346732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: _init: failed to init soft state.",
1356732dbb3SVikram Hegde 		    amd_iommu_modname);
1366732dbb3SVikram Hegde 		return (error);
1376732dbb3SVikram Hegde 	}
1386732dbb3SVikram Hegde 
1396732dbb3SVikram Hegde 	if (amd_iommu_acpi_init() != DDI_SUCCESS) {
1406732dbb3SVikram Hegde 		if (amd_iommu_debug) {
1416732dbb3SVikram Hegde 			cmn_err(CE_WARN, "%s: _init: ACPI init failed.",
1426732dbb3SVikram Hegde 			    amd_iommu_modname);
1436732dbb3SVikram Hegde 		}
1446732dbb3SVikram Hegde 		ddi_soft_state_fini(&amd_iommu_statep);
1456732dbb3SVikram Hegde 		return (ENOTSUP);
1466732dbb3SVikram Hegde 	}
1476732dbb3SVikram Hegde 
1486732dbb3SVikram Hegde 	amd_iommu_read_boot_props();
1496732dbb3SVikram Hegde 
1506732dbb3SVikram Hegde 	if (amd_iommu_page_table_hash_init(&amd_iommu_page_table_hash)
1516732dbb3SVikram Hegde 	    != DDI_SUCCESS) {
1526732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: _init: Page table hash init failed.",
1536732dbb3SVikram Hegde 		    amd_iommu_modname);
1546732dbb3SVikram Hegde 		if (amd_iommu_disable_list) {
1556732dbb3SVikram Hegde 			kmem_free(amd_iommu_disable_list,
1566732dbb3SVikram Hegde 			    strlen(amd_iommu_disable_list) + 1);
1576732dbb3SVikram Hegde 			amd_iommu_disable_list = NULL;
1586732dbb3SVikram Hegde 		}
1596732dbb3SVikram Hegde 		amd_iommu_acpi_fini();
1606732dbb3SVikram Hegde 		ddi_soft_state_fini(&amd_iommu_statep);
1616732dbb3SVikram Hegde 		amd_iommu_statep = NULL;
1626732dbb3SVikram Hegde 		return (EFAULT);
1636732dbb3SVikram Hegde 	}
1646732dbb3SVikram Hegde 
1656732dbb3SVikram Hegde 	error = mod_install(&modlinkage);
1666732dbb3SVikram Hegde 	if (error) {
1676732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: _init: mod_install failed.",
1686732dbb3SVikram Hegde 		    amd_iommu_modname);
1696732dbb3SVikram Hegde 		amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
1706732dbb3SVikram Hegde 		if (amd_iommu_disable_list) {
1716732dbb3SVikram Hegde 			kmem_free(amd_iommu_disable_list,
1726732dbb3SVikram Hegde 			    strlen(amd_iommu_disable_list) + 1);
1736732dbb3SVikram Hegde 			amd_iommu_disable_list = NULL;
1746732dbb3SVikram Hegde 		}
1756732dbb3SVikram Hegde 		amd_iommu_acpi_fini();
1766732dbb3SVikram Hegde 		ddi_soft_state_fini(&amd_iommu_statep);
1776732dbb3SVikram Hegde 		amd_iommu_statep = NULL;
1786732dbb3SVikram Hegde 		return (error);
1796732dbb3SVikram Hegde 	}
1806732dbb3SVikram Hegde 	error = 0;
1816732dbb3SVikram Hegde #endif
1826732dbb3SVikram Hegde 
1836732dbb3SVikram Hegde 	return (error);
1846732dbb3SVikram Hegde }
1856732dbb3SVikram Hegde 
1866732dbb3SVikram Hegde int
_info(struct modinfo * modinfop)1876732dbb3SVikram Hegde _info(struct modinfo *modinfop)
1886732dbb3SVikram Hegde {
1896732dbb3SVikram Hegde 	return (mod_info(&modlinkage, modinfop));
1906732dbb3SVikram Hegde }
1916732dbb3SVikram Hegde 
1926732dbb3SVikram Hegde int
_fini(void)1936732dbb3SVikram Hegde _fini(void)
1946732dbb3SVikram Hegde {
1956732dbb3SVikram Hegde 	int error;
1966732dbb3SVikram Hegde 
1976732dbb3SVikram Hegde 	error = mod_remove(&modlinkage);
1986732dbb3SVikram Hegde 	if (error)
1996732dbb3SVikram Hegde 		return (error);
2006732dbb3SVikram Hegde 
2016732dbb3SVikram Hegde 	amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
2026732dbb3SVikram Hegde 	if (amd_iommu_disable_list) {
2036732dbb3SVikram Hegde 		kmem_free(amd_iommu_disable_list,
2046732dbb3SVikram Hegde 		    strlen(amd_iommu_disable_list) + 1);
2056732dbb3SVikram Hegde 		amd_iommu_disable_list = NULL;
2066732dbb3SVikram Hegde 	}
2076732dbb3SVikram Hegde 	amd_iommu_acpi_fini();
2086732dbb3SVikram Hegde 	ddi_soft_state_fini(&amd_iommu_statep);
2096732dbb3SVikram Hegde 	amd_iommu_statep = NULL;
2106732dbb3SVikram Hegde 
2116732dbb3SVikram Hegde 	return (0);
2126732dbb3SVikram Hegde }
2136732dbb3SVikram Hegde 
2146732dbb3SVikram Hegde /*ARGSUSED*/
2156732dbb3SVikram Hegde static int
amd_iommu_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2166732dbb3SVikram Hegde amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2176732dbb3SVikram Hegde {
2186732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
2196732dbb3SVikram Hegde 
2206732dbb3SVikram Hegde 	ASSERT(result);
2216732dbb3SVikram Hegde 
2226732dbb3SVikram Hegde 	*result = NULL;
2236732dbb3SVikram Hegde 
2246732dbb3SVikram Hegde 	switch (cmd) {
2256732dbb3SVikram Hegde 	case DDI_INFO_DEVT2DEVINFO:
2266732dbb3SVikram Hegde 		statep = ddi_get_soft_state(amd_iommu_statep,
2276732dbb3SVikram Hegde 		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg)));
2286732dbb3SVikram Hegde 		if (statep) {
2296732dbb3SVikram Hegde 			*result = statep->aioms_devi;
2306732dbb3SVikram Hegde 			return (DDI_SUCCESS);
2316732dbb3SVikram Hegde 		}
2326732dbb3SVikram Hegde 		break;
2336732dbb3SVikram Hegde 	case DDI_INFO_DEVT2INSTANCE:
2346732dbb3SVikram Hegde 		*result = (void *)(uintptr_t)
2356732dbb3SVikram Hegde 		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg));
2366732dbb3SVikram Hegde 		return (DDI_SUCCESS);
2376732dbb3SVikram Hegde 	}
2386732dbb3SVikram Hegde 
2396732dbb3SVikram Hegde 	return (DDI_FAILURE);
2406732dbb3SVikram Hegde }
2416732dbb3SVikram Hegde 
2426732dbb3SVikram Hegde static int
amd_iommu_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2436732dbb3SVikram Hegde amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2446732dbb3SVikram Hegde {
2456732dbb3SVikram Hegde 	int instance = ddi_get_instance(dip);
2466732dbb3SVikram Hegde 	const char *driver = ddi_driver_name(dip);
2476732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
2486732dbb3SVikram Hegde 
2496732dbb3SVikram Hegde 	ASSERT(instance >= 0);
2506732dbb3SVikram Hegde 	ASSERT(driver);
2516732dbb3SVikram Hegde 
2526732dbb3SVikram Hegde 	switch (cmd) {
2536732dbb3SVikram Hegde 	case DDI_ATTACH:
2546732dbb3SVikram Hegde 		if (ddi_soft_state_zalloc(amd_iommu_statep, instance)
2556732dbb3SVikram Hegde 		    != DDI_SUCCESS) {
2566732dbb3SVikram Hegde 			cmn_err(CE_WARN, "Unable to allocate soft state for "
2576732dbb3SVikram Hegde 			    "%s%d", driver, instance);
2586732dbb3SVikram Hegde 			return (DDI_FAILURE);
2596732dbb3SVikram Hegde 		}
2606732dbb3SVikram Hegde 
2616732dbb3SVikram Hegde 		statep = ddi_get_soft_state(amd_iommu_statep, instance);
2626732dbb3SVikram Hegde 		if (statep == NULL) {
2636732dbb3SVikram Hegde 			cmn_err(CE_WARN, "Unable to get soft state for "
2646732dbb3SVikram Hegde 			    "%s%d", driver, instance);
2656732dbb3SVikram Hegde 			ddi_soft_state_free(amd_iommu_statep, instance);
2666732dbb3SVikram Hegde 			return (DDI_FAILURE);
2676732dbb3SVikram Hegde 		}
2686732dbb3SVikram Hegde 
2696732dbb3SVikram Hegde 		if (ddi_create_minor_node(dip, AMD_IOMMU_MINOR_NAME, S_IFCHR,
2706732dbb3SVikram Hegde 		    AMD_IOMMU_INST2MINOR(instance), AMD_IOMMU_NODETYPE,
2716732dbb3SVikram Hegde 		    0) != DDI_SUCCESS) {
2726732dbb3SVikram Hegde 			cmn_err(CE_WARN, "Unable to create minor node for "
2736732dbb3SVikram Hegde 			    "%s%d", driver, instance);
2746732dbb3SVikram Hegde 			ddi_remove_minor_node(dip, NULL);
2756732dbb3SVikram Hegde 			ddi_soft_state_free(amd_iommu_statep, instance);
2766732dbb3SVikram Hegde 			return (DDI_FAILURE);
2776732dbb3SVikram Hegde 		}
2786732dbb3SVikram Hegde 
2796732dbb3SVikram Hegde 		statep->aioms_devi = dip;
2806732dbb3SVikram Hegde 		statep->aioms_instance = instance;
2816732dbb3SVikram Hegde 		statep->aioms_iommu_start = NULL;
2826732dbb3SVikram Hegde 		statep->aioms_iommu_end = NULL;
2836732dbb3SVikram Hegde 
2846732dbb3SVikram Hegde 		amd_iommu_lookup_conf_props(dip);
2856732dbb3SVikram Hegde 
2866732dbb3SVikram Hegde 		if (amd_iommu_disable_list) {
2876732dbb3SVikram Hegde 			cmn_err(CE_NOTE, "AMD IOMMU disabled for the following"
2886732dbb3SVikram Hegde 			    " drivers:\n%s", amd_iommu_disable_list);
2896732dbb3SVikram Hegde 		}
2906732dbb3SVikram Hegde 
2916732dbb3SVikram Hegde 		if (amd_iommu_disable) {
2926732dbb3SVikram Hegde 			cmn_err(CE_NOTE, "AMD IOMMU disabled by user");
2936732dbb3SVikram Hegde 		} else if (amd_iommu_setup(dip, statep) != DDI_SUCCESS) {
2946732dbb3SVikram Hegde 			cmn_err(CE_WARN, "Unable to initialize AMD IOMMU "
2956732dbb3SVikram Hegde 			    "%s%d", driver, instance);
2966732dbb3SVikram Hegde 			ddi_remove_minor_node(dip, NULL);
2976732dbb3SVikram Hegde 			ddi_soft_state_free(amd_iommu_statep, instance);
2986732dbb3SVikram Hegde 			return (DDI_FAILURE);
2996732dbb3SVikram Hegde 		}
3006732dbb3SVikram Hegde 
3016732dbb3SVikram Hegde 		ddi_report_dev(dip);
3026732dbb3SVikram Hegde 
3036732dbb3SVikram Hegde 		return (DDI_SUCCESS);
3046732dbb3SVikram Hegde 
3056732dbb3SVikram Hegde 	case DDI_RESUME:
3066732dbb3SVikram Hegde 		return (DDI_SUCCESS);
3076732dbb3SVikram Hegde 	default:
3086732dbb3SVikram Hegde 		return (DDI_FAILURE);
3096732dbb3SVikram Hegde 	}
3106732dbb3SVikram Hegde }
3116732dbb3SVikram Hegde 
3126732dbb3SVikram Hegde static int
amd_iommu_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3136732dbb3SVikram Hegde amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3146732dbb3SVikram Hegde {
3156732dbb3SVikram Hegde 	int instance = ddi_get_instance(dip);
3166732dbb3SVikram Hegde 	const char *driver = ddi_driver_name(dip);
3176732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
3186732dbb3SVikram Hegde 
3196732dbb3SVikram Hegde 	ASSERT(instance >= 0);
3206732dbb3SVikram Hegde 	ASSERT(driver);
3216732dbb3SVikram Hegde 
3226732dbb3SVikram Hegde 	switch (cmd) {
3236732dbb3SVikram Hegde 	case DDI_DETACH:
3246732dbb3SVikram Hegde 		statep = ddi_get_soft_state(amd_iommu_statep, instance);
3256732dbb3SVikram Hegde 		if (statep == NULL) {
3266732dbb3SVikram Hegde 			cmn_err(CE_WARN, "%s%d: Cannot get soft state",
3276732dbb3SVikram Hegde 			    driver, instance);
3286732dbb3SVikram Hegde 			return (DDI_FAILURE);
3296732dbb3SVikram Hegde 		}
3306732dbb3SVikram Hegde 		return (DDI_FAILURE);
3316732dbb3SVikram Hegde 	case DDI_SUSPEND:
3326732dbb3SVikram Hegde 		return (DDI_SUCCESS);
3336732dbb3SVikram Hegde 	default:
3346732dbb3SVikram Hegde 		return (DDI_FAILURE);
3356732dbb3SVikram Hegde 	}
3366732dbb3SVikram Hegde }
3376732dbb3SVikram Hegde 
3386732dbb3SVikram Hegde /*ARGSUSED*/
3396732dbb3SVikram Hegde static int
amd_iommu_open(dev_t * devp,int flag,int otyp,cred_t * credp)3406732dbb3SVikram Hegde amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp)
3416732dbb3SVikram Hegde {
3426732dbb3SVikram Hegde 	int instance = AMD_IOMMU_MINOR2INST(getminor(*devp));
3436732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
3446732dbb3SVikram Hegde 	const char *f = "amd_iommu_open";
3456732dbb3SVikram Hegde 
3466732dbb3SVikram Hegde 	if (instance < 0) {
3476732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid instance %d",
3486732dbb3SVikram Hegde 		    f, instance);
3496732dbb3SVikram Hegde 		return (ENXIO);
3506732dbb3SVikram Hegde 	}
3516732dbb3SVikram Hegde 
3526732dbb3SVikram Hegde 	if (!(flag & (FREAD|FWRITE))) {
3536732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
3546732dbb3SVikram Hegde 		return (EINVAL);
3556732dbb3SVikram Hegde 	}
3566732dbb3SVikram Hegde 
3576732dbb3SVikram Hegde 	if (otyp != OTYP_CHR) {
3586732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
3596732dbb3SVikram Hegde 		return (EINVAL);
3606732dbb3SVikram Hegde 	}
3616732dbb3SVikram Hegde 
3626732dbb3SVikram Hegde 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
3636732dbb3SVikram Hegde 	if (statep == NULL) {
3646732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
3656732dbb3SVikram Hegde 		    f, instance);
3666732dbb3SVikram Hegde 		return (ENXIO);
3676732dbb3SVikram Hegde 	}
3686732dbb3SVikram Hegde 
3696732dbb3SVikram Hegde 	ASSERT(statep->aioms_instance == instance);
3706732dbb3SVikram Hegde 
3716732dbb3SVikram Hegde 	return (0);
3726732dbb3SVikram Hegde }
3736732dbb3SVikram Hegde 
3746732dbb3SVikram Hegde /*ARGSUSED*/
3756732dbb3SVikram Hegde static int
amd_iommu_close(dev_t dev,int flag,int otyp,cred_t * credp)3766732dbb3SVikram Hegde amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp)
3776732dbb3SVikram Hegde {
3786732dbb3SVikram Hegde 	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
3796732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
3806732dbb3SVikram Hegde 	const char *f = "amd_iommu_close";
3816732dbb3SVikram Hegde 
3826732dbb3SVikram Hegde 	if (instance < 0) {
3836732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
3846732dbb3SVikram Hegde 		return (ENXIO);
3856732dbb3SVikram Hegde 	}
3866732dbb3SVikram Hegde 
3876732dbb3SVikram Hegde 	if (!(flag & (FREAD|FWRITE))) {
3886732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
3896732dbb3SVikram Hegde 		return (EINVAL);
3906732dbb3SVikram Hegde 	}
3916732dbb3SVikram Hegde 
3926732dbb3SVikram Hegde 	if (otyp != OTYP_CHR) {
3936732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
3946732dbb3SVikram Hegde 		return (EINVAL);
3956732dbb3SVikram Hegde 	}
3966732dbb3SVikram Hegde 
3976732dbb3SVikram Hegde 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
3986732dbb3SVikram Hegde 	if (statep == NULL) {
3996732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
4006732dbb3SVikram Hegde 		    f, instance);
4016732dbb3SVikram Hegde 		return (ENXIO);
4026732dbb3SVikram Hegde 	}
4036732dbb3SVikram Hegde 
4046732dbb3SVikram Hegde 	ASSERT(statep->aioms_instance == instance);
4056732dbb3SVikram Hegde 	return (0);
4066732dbb3SVikram Hegde 
4076732dbb3SVikram Hegde }
4086732dbb3SVikram Hegde 
4096732dbb3SVikram Hegde /*ARGSUSED*/
4106732dbb3SVikram Hegde static int
amd_iommu_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)4116732dbb3SVikram Hegde amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
4126732dbb3SVikram Hegde     int *rvalp)
4136732dbb3SVikram Hegde {
4146732dbb3SVikram Hegde 	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
4156732dbb3SVikram Hegde 	struct amd_iommu_state *statep;
4166732dbb3SVikram Hegde 	const char *f = "amd_iommu_ioctl";
4176732dbb3SVikram Hegde 
4186732dbb3SVikram Hegde 	ASSERT(*rvalp);
4196732dbb3SVikram Hegde 
4206732dbb3SVikram Hegde 	if (instance < 0) {
4216732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
4226732dbb3SVikram Hegde 		return (ENXIO);
4236732dbb3SVikram Hegde 	}
4246732dbb3SVikram Hegde 
4256732dbb3SVikram Hegde 
4266732dbb3SVikram Hegde 	if (!(mode & (FREAD|FWRITE))) {
4276732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: invalid mode %d", f, mode);
4286732dbb3SVikram Hegde 		return (EINVAL);
4296732dbb3SVikram Hegde 	}
4306732dbb3SVikram Hegde 
4316732dbb3SVikram Hegde 	if (mode & FKIOCTL) {
4326732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: FKIOCTL unsupported mode %d", f, mode);
4336732dbb3SVikram Hegde 		return (EINVAL);
4346732dbb3SVikram Hegde 	}
4356732dbb3SVikram Hegde 
4366732dbb3SVikram Hegde 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
4376732dbb3SVikram Hegde 	if (statep == NULL) {
4386732dbb3SVikram Hegde 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
4396732dbb3SVikram Hegde 		    f, instance);
4406732dbb3SVikram Hegde 		return (ENXIO);
4416732dbb3SVikram Hegde 	}
4426732dbb3SVikram Hegde 
4436732dbb3SVikram Hegde 	ASSERT(statep->aioms_instance == instance);
4446732dbb3SVikram Hegde 
4456732dbb3SVikram Hegde 	return (ENOTTY);
4466732dbb3SVikram Hegde }
447ac48dfe8SVikram Hegde 
448ac48dfe8SVikram Hegde static int
amd_iommu_quiesce(dev_info_t * dip)449ac48dfe8SVikram Hegde amd_iommu_quiesce(dev_info_t *dip)
450ac48dfe8SVikram Hegde {
451ac48dfe8SVikram Hegde 	int instance = ddi_get_instance(dip);
452ac48dfe8SVikram Hegde 	struct amd_iommu_state *statep;
453ac48dfe8SVikram Hegde 	const char *f = "amd_iommu_quiesce";
454ac48dfe8SVikram Hegde 
455ac48dfe8SVikram Hegde 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
456ac48dfe8SVikram Hegde 	if (statep == NULL) {
457ac48dfe8SVikram Hegde 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
458ac48dfe8SVikram Hegde 		    f, instance);
459ac48dfe8SVikram Hegde 		return (DDI_FAILURE);
460ac48dfe8SVikram Hegde 	}
461ac48dfe8SVikram Hegde 
462ac48dfe8SVikram Hegde 	if (amd_iommu_teardown(dip, statep, AMD_IOMMU_QUIESCE) != DDI_SUCCESS) {
463ac48dfe8SVikram Hegde 		cmn_err(CE_WARN, "%s: Unable to quiesce AMD IOMMU "
464ac48dfe8SVikram Hegde 		    "%s%d", f, ddi_driver_name(dip), instance);
465ac48dfe8SVikram Hegde 		return (DDI_FAILURE);
466ac48dfe8SVikram Hegde 	}
467ac48dfe8SVikram Hegde 
468ac48dfe8SVikram Hegde 	return (DDI_SUCCESS);
469ac48dfe8SVikram Hegde }
470