xref: /onnv-gate/usr/src/uts/i86pc/io/amd_iommu/amd_iommu.c (revision 10567:f8c0a7fe6191)
110535SVikram.Hegde@Sun.COM /*
210535SVikram.Hegde@Sun.COM  * CDDL HEADER START
310535SVikram.Hegde@Sun.COM  *
410535SVikram.Hegde@Sun.COM  * The contents of this file are subject to the terms of the
510535SVikram.Hegde@Sun.COM  * Common Development and Distribution License (the "License").
610535SVikram.Hegde@Sun.COM  * You may not use this file except in compliance with the License.
710535SVikram.Hegde@Sun.COM  *
810535SVikram.Hegde@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910535SVikram.Hegde@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010535SVikram.Hegde@Sun.COM  * See the License for the specific language governing permissions
1110535SVikram.Hegde@Sun.COM  * and limitations under the License.
1210535SVikram.Hegde@Sun.COM  *
1310535SVikram.Hegde@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410535SVikram.Hegde@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510535SVikram.Hegde@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610535SVikram.Hegde@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710535SVikram.Hegde@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810535SVikram.Hegde@Sun.COM  *
1910535SVikram.Hegde@Sun.COM  * CDDL HEADER END
2010535SVikram.Hegde@Sun.COM  */
2110535SVikram.Hegde@Sun.COM 
2210535SVikram.Hegde@Sun.COM /*
2310535SVikram.Hegde@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2410535SVikram.Hegde@Sun.COM  * Use is subject to license terms.
2510535SVikram.Hegde@Sun.COM  */
2610535SVikram.Hegde@Sun.COM 
2710535SVikram.Hegde@Sun.COM #include <sys/types.h>
2810535SVikram.Hegde@Sun.COM #include <sys/file.h>
2910535SVikram.Hegde@Sun.COM #include <sys/errno.h>
3010535SVikram.Hegde@Sun.COM #include <sys/open.h>
3110535SVikram.Hegde@Sun.COM #include <sys/stat.h>
3210535SVikram.Hegde@Sun.COM #include <sys/cred.h>
3310535SVikram.Hegde@Sun.COM #include <sys/modctl.h>
3410535SVikram.Hegde@Sun.COM #include <sys/conf.h>
3510535SVikram.Hegde@Sun.COM #include <sys/devops.h>
3610535SVikram.Hegde@Sun.COM #include <sys/ddi.h>
3710535SVikram.Hegde@Sun.COM #include <sys/x86_archext.h>
3810535SVikram.Hegde@Sun.COM 
3910535SVikram.Hegde@Sun.COM #include <sys/amd_iommu.h>
4010535SVikram.Hegde@Sun.COM #include "amd_iommu_impl.h"
4110535SVikram.Hegde@Sun.COM #include "amd_iommu_acpi.h"
4210535SVikram.Hegde@Sun.COM 
4310535SVikram.Hegde@Sun.COM 
4410535SVikram.Hegde@Sun.COM #define	AMD_IOMMU_MINOR2INST(x)	(x)
4510535SVikram.Hegde@Sun.COM #define	AMD_IOMMU_INST2MINOR(x)	(x)
4610535SVikram.Hegde@Sun.COM #define	AMD_IOMMU_NODETYPE	"ddi_iommu"
4710535SVikram.Hegde@Sun.COM #define	AMD_IOMMU_MINOR_NAME	"amd-iommu"
4810535SVikram.Hegde@Sun.COM 
4910535SVikram.Hegde@Sun.COM static int amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
5010535SVikram.Hegde@Sun.COM     void **result);
5110535SVikram.Hegde@Sun.COM static int amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
5210535SVikram.Hegde@Sun.COM static int amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
5310535SVikram.Hegde@Sun.COM static int amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp);
5410535SVikram.Hegde@Sun.COM static int amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp);
5510535SVikram.Hegde@Sun.COM static int amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5610535SVikram.Hegde@Sun.COM     cred_t *credp, int *rvalp);
57*10536SVikram.Hegde@Sun.COM static int amd_iommu_quiesce(dev_info_t *dip);
5810535SVikram.Hegde@Sun.COM 
5910535SVikram.Hegde@Sun.COM static struct cb_ops amd_iommu_cb_ops = {
6010535SVikram.Hegde@Sun.COM 	amd_iommu_open,		/* cb_open */
6110535SVikram.Hegde@Sun.COM 	amd_iommu_close,	/* cb_close */
6210535SVikram.Hegde@Sun.COM 	nodev,			/* cb_strategy */
6310535SVikram.Hegde@Sun.COM 	nodev,			/* cb_print */
6410535SVikram.Hegde@Sun.COM 	nodev,			/* cb_dump */
6510535SVikram.Hegde@Sun.COM 	nodev,			/* cb_read */
6610535SVikram.Hegde@Sun.COM 	nodev,			/* cb_write */
6710535SVikram.Hegde@Sun.COM 	amd_iommu_ioctl,	/* cb_ioctl */
6810535SVikram.Hegde@Sun.COM 	nodev,			/* cb_devmap */
6910535SVikram.Hegde@Sun.COM 	nodev,			/* cb_mmap */
7010535SVikram.Hegde@Sun.COM 	nodev,			/* cb_segmap */
7110535SVikram.Hegde@Sun.COM 	nochpoll,		/* cb_chpoll */
7210535SVikram.Hegde@Sun.COM 	ddi_prop_op,		/* cb_prop_op */
7310535SVikram.Hegde@Sun.COM 	NULL,			/* cb_str */
7410535SVikram.Hegde@Sun.COM 	D_NEW | D_MP,		/* cb_flag */
7510535SVikram.Hegde@Sun.COM 	CB_REV,			/* cb_rev */
7610535SVikram.Hegde@Sun.COM 	nodev,			/* cb_aread */
7710535SVikram.Hegde@Sun.COM 	nodev			/* cb_awrite */
7810535SVikram.Hegde@Sun.COM };
7910535SVikram.Hegde@Sun.COM 
8010535SVikram.Hegde@Sun.COM static struct dev_ops amd_iommu_dev_ops = {
8110535SVikram.Hegde@Sun.COM 	DEVO_REV,		/* devo_rev */
8210535SVikram.Hegde@Sun.COM 	0,			/* devo_refcnt */
8310535SVikram.Hegde@Sun.COM 	amd_iommu_getinfo,	/* devo_getinfo */
8410535SVikram.Hegde@Sun.COM 	nulldev,		/* devo_identify */
8510535SVikram.Hegde@Sun.COM 	nulldev,		/* devo_probe */
8610535SVikram.Hegde@Sun.COM 	amd_iommu_attach,	/* devo_attach */
8710535SVikram.Hegde@Sun.COM 	amd_iommu_detach,	/* devo_detach */
8810535SVikram.Hegde@Sun.COM 	nodev,			/* devo_reset */
8910535SVikram.Hegde@Sun.COM 	&amd_iommu_cb_ops,	/* devo_cb_ops */
9010535SVikram.Hegde@Sun.COM 	NULL,			/* devo_bus_ops */
91*10536SVikram.Hegde@Sun.COM 	nulldev,		/* devo_power */
92*10536SVikram.Hegde@Sun.COM 	amd_iommu_quiesce,	/* devo_quiesce */
9310535SVikram.Hegde@Sun.COM };
9410535SVikram.Hegde@Sun.COM 
9510535SVikram.Hegde@Sun.COM static struct modldrv modldrv = {
9610535SVikram.Hegde@Sun.COM 	&mod_driverops,
9710535SVikram.Hegde@Sun.COM 	"AMD IOMMU 0.1",
9810535SVikram.Hegde@Sun.COM 	&amd_iommu_dev_ops
9910535SVikram.Hegde@Sun.COM };
10010535SVikram.Hegde@Sun.COM 
10110535SVikram.Hegde@Sun.COM static struct modlinkage modlinkage = {
10210535SVikram.Hegde@Sun.COM 	MODREV_1,
10310535SVikram.Hegde@Sun.COM 	(void *)&modldrv,
10410535SVikram.Hegde@Sun.COM 	NULL
10510535SVikram.Hegde@Sun.COM };
10610535SVikram.Hegde@Sun.COM 
10710535SVikram.Hegde@Sun.COM amd_iommu_debug_t amd_iommu_debug;
10810535SVikram.Hegde@Sun.COM kmutex_t amd_iommu_global_lock;
10910535SVikram.Hegde@Sun.COM const char *amd_iommu_modname = "amd_iommu";
11010535SVikram.Hegde@Sun.COM amd_iommu_alias_t **amd_iommu_alias;
11110535SVikram.Hegde@Sun.COM amd_iommu_page_table_hash_t amd_iommu_page_table_hash;
11210535SVikram.Hegde@Sun.COM static void *amd_iommu_statep;
11310535SVikram.Hegde@Sun.COM int amd_iommu_64bit_bug;
11410535SVikram.Hegde@Sun.COM int amd_iommu_unity_map;
11510535SVikram.Hegde@Sun.COM int amd_iommu_no_RW_perms;
11610535SVikram.Hegde@Sun.COM int amd_iommu_no_unmap;
11710535SVikram.Hegde@Sun.COM int amd_iommu_pageva_inval_all;
11810535SVikram.Hegde@Sun.COM int amd_iommu_disable;		/* disable IOMMU */
11910535SVikram.Hegde@Sun.COM char *amd_iommu_disable_list;	/* list of drivers bypassing IOMMU */
12010535SVikram.Hegde@Sun.COM 
12110535SVikram.Hegde@Sun.COM int
_init(void)12210535SVikram.Hegde@Sun.COM _init(void)
12310535SVikram.Hegde@Sun.COM {
12410535SVikram.Hegde@Sun.COM 	int error = ENOTSUP;
12510535SVikram.Hegde@Sun.COM 
12610535SVikram.Hegde@Sun.COM #if defined(__amd64) && !defined(__xpv)
12710535SVikram.Hegde@Sun.COM 
12810535SVikram.Hegde@Sun.COM 	if (get_hwenv() != HW_NATIVE)
12910535SVikram.Hegde@Sun.COM 		return (ENOTSUP);
13010535SVikram.Hegde@Sun.COM 
13110535SVikram.Hegde@Sun.COM 	error = ddi_soft_state_init(&amd_iommu_statep,
13210535SVikram.Hegde@Sun.COM 	    sizeof (struct amd_iommu_state), 1);
13310535SVikram.Hegde@Sun.COM 	if (error) {
13410535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: _init: failed to init soft state.",
13510535SVikram.Hegde@Sun.COM 		    amd_iommu_modname);
13610535SVikram.Hegde@Sun.COM 		return (error);
13710535SVikram.Hegde@Sun.COM 	}
13810535SVikram.Hegde@Sun.COM 
13910535SVikram.Hegde@Sun.COM 	if (amd_iommu_acpi_init() != DDI_SUCCESS) {
14010535SVikram.Hegde@Sun.COM 		if (amd_iommu_debug) {
14110535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "%s: _init: ACPI init failed.",
14210535SVikram.Hegde@Sun.COM 			    amd_iommu_modname);
14310535SVikram.Hegde@Sun.COM 		}
14410535SVikram.Hegde@Sun.COM 		ddi_soft_state_fini(&amd_iommu_statep);
14510535SVikram.Hegde@Sun.COM 		return (ENOTSUP);
14610535SVikram.Hegde@Sun.COM 	}
14710535SVikram.Hegde@Sun.COM 
14810535SVikram.Hegde@Sun.COM 	amd_iommu_read_boot_props();
14910535SVikram.Hegde@Sun.COM 
15010535SVikram.Hegde@Sun.COM 	if (amd_iommu_page_table_hash_init(&amd_iommu_page_table_hash)
15110535SVikram.Hegde@Sun.COM 	    != DDI_SUCCESS) {
15210535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: _init: Page table hash init failed.",
15310535SVikram.Hegde@Sun.COM 		    amd_iommu_modname);
15410535SVikram.Hegde@Sun.COM 		if (amd_iommu_disable_list) {
15510535SVikram.Hegde@Sun.COM 			kmem_free(amd_iommu_disable_list,
15610535SVikram.Hegde@Sun.COM 			    strlen(amd_iommu_disable_list) + 1);
15710535SVikram.Hegde@Sun.COM 			amd_iommu_disable_list = NULL;
15810535SVikram.Hegde@Sun.COM 		}
15910535SVikram.Hegde@Sun.COM 		amd_iommu_acpi_fini();
16010535SVikram.Hegde@Sun.COM 		ddi_soft_state_fini(&amd_iommu_statep);
16110535SVikram.Hegde@Sun.COM 		amd_iommu_statep = NULL;
16210535SVikram.Hegde@Sun.COM 		return (EFAULT);
16310535SVikram.Hegde@Sun.COM 	}
16410535SVikram.Hegde@Sun.COM 
16510535SVikram.Hegde@Sun.COM 	error = mod_install(&modlinkage);
16610535SVikram.Hegde@Sun.COM 	if (error) {
16710535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: _init: mod_install failed.",
16810535SVikram.Hegde@Sun.COM 		    amd_iommu_modname);
16910535SVikram.Hegde@Sun.COM 		amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
17010535SVikram.Hegde@Sun.COM 		if (amd_iommu_disable_list) {
17110535SVikram.Hegde@Sun.COM 			kmem_free(amd_iommu_disable_list,
17210535SVikram.Hegde@Sun.COM 			    strlen(amd_iommu_disable_list) + 1);
17310535SVikram.Hegde@Sun.COM 			amd_iommu_disable_list = NULL;
17410535SVikram.Hegde@Sun.COM 		}
17510535SVikram.Hegde@Sun.COM 		amd_iommu_acpi_fini();
17610535SVikram.Hegde@Sun.COM 		ddi_soft_state_fini(&amd_iommu_statep);
17710535SVikram.Hegde@Sun.COM 		amd_iommu_statep = NULL;
17810535SVikram.Hegde@Sun.COM 		return (error);
17910535SVikram.Hegde@Sun.COM 	}
18010535SVikram.Hegde@Sun.COM 	error = 0;
18110535SVikram.Hegde@Sun.COM #endif
18210535SVikram.Hegde@Sun.COM 
18310535SVikram.Hegde@Sun.COM 	return (error);
18410535SVikram.Hegde@Sun.COM }
18510535SVikram.Hegde@Sun.COM 
18610535SVikram.Hegde@Sun.COM int
_info(struct modinfo * modinfop)18710535SVikram.Hegde@Sun.COM _info(struct modinfo *modinfop)
18810535SVikram.Hegde@Sun.COM {
18910535SVikram.Hegde@Sun.COM 	return (mod_info(&modlinkage, modinfop));
19010535SVikram.Hegde@Sun.COM }
19110535SVikram.Hegde@Sun.COM 
19210535SVikram.Hegde@Sun.COM int
_fini(void)19310535SVikram.Hegde@Sun.COM _fini(void)
19410535SVikram.Hegde@Sun.COM {
19510535SVikram.Hegde@Sun.COM 	int error;
19610535SVikram.Hegde@Sun.COM 
19710535SVikram.Hegde@Sun.COM 	error = mod_remove(&modlinkage);
19810535SVikram.Hegde@Sun.COM 	if (error)
19910535SVikram.Hegde@Sun.COM 		return (error);
20010535SVikram.Hegde@Sun.COM 
20110535SVikram.Hegde@Sun.COM 	amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
20210535SVikram.Hegde@Sun.COM 	if (amd_iommu_disable_list) {
20310535SVikram.Hegde@Sun.COM 		kmem_free(amd_iommu_disable_list,
20410535SVikram.Hegde@Sun.COM 		    strlen(amd_iommu_disable_list) + 1);
20510535SVikram.Hegde@Sun.COM 		amd_iommu_disable_list = NULL;
20610535SVikram.Hegde@Sun.COM 	}
20710535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_fini();
20810535SVikram.Hegde@Sun.COM 	ddi_soft_state_fini(&amd_iommu_statep);
20910535SVikram.Hegde@Sun.COM 	amd_iommu_statep = NULL;
21010535SVikram.Hegde@Sun.COM 
21110535SVikram.Hegde@Sun.COM 	return (0);
21210535SVikram.Hegde@Sun.COM }
21310535SVikram.Hegde@Sun.COM 
21410535SVikram.Hegde@Sun.COM /*ARGSUSED*/
21510535SVikram.Hegde@Sun.COM static int
amd_iommu_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)21610535SVikram.Hegde@Sun.COM amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
21710535SVikram.Hegde@Sun.COM {
21810535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
21910535SVikram.Hegde@Sun.COM 
22010535SVikram.Hegde@Sun.COM 	ASSERT(result);
22110535SVikram.Hegde@Sun.COM 
22210535SVikram.Hegde@Sun.COM 	*result = NULL;
22310535SVikram.Hegde@Sun.COM 
22410535SVikram.Hegde@Sun.COM 	switch (cmd) {
22510535SVikram.Hegde@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
22610535SVikram.Hegde@Sun.COM 		statep = ddi_get_soft_state(amd_iommu_statep,
22710535SVikram.Hegde@Sun.COM 		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg)));
22810535SVikram.Hegde@Sun.COM 		if (statep) {
22910535SVikram.Hegde@Sun.COM 			*result = statep->aioms_devi;
23010535SVikram.Hegde@Sun.COM 			return (DDI_SUCCESS);
23110535SVikram.Hegde@Sun.COM 		}
23210535SVikram.Hegde@Sun.COM 		break;
23310535SVikram.Hegde@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
23410535SVikram.Hegde@Sun.COM 		*result = (void *)(uintptr_t)
23510535SVikram.Hegde@Sun.COM 		    AMD_IOMMU_MINOR2INST(getminor((dev_t)arg));
23610535SVikram.Hegde@Sun.COM 		return (DDI_SUCCESS);
23710535SVikram.Hegde@Sun.COM 	}
23810535SVikram.Hegde@Sun.COM 
23910535SVikram.Hegde@Sun.COM 	return (DDI_FAILURE);
24010535SVikram.Hegde@Sun.COM }
24110535SVikram.Hegde@Sun.COM 
24210535SVikram.Hegde@Sun.COM static int
amd_iommu_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)24310535SVikram.Hegde@Sun.COM amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
24410535SVikram.Hegde@Sun.COM {
24510535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(dip);
24610535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(dip);
24710535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
24810535SVikram.Hegde@Sun.COM 
24910535SVikram.Hegde@Sun.COM 	ASSERT(instance >= 0);
25010535SVikram.Hegde@Sun.COM 	ASSERT(driver);
25110535SVikram.Hegde@Sun.COM 
25210535SVikram.Hegde@Sun.COM 	switch (cmd) {
25310535SVikram.Hegde@Sun.COM 	case DDI_ATTACH:
25410535SVikram.Hegde@Sun.COM 		if (ddi_soft_state_zalloc(amd_iommu_statep, instance)
25510535SVikram.Hegde@Sun.COM 		    != DDI_SUCCESS) {
25610535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "Unable to allocate soft state for "
25710535SVikram.Hegde@Sun.COM 			    "%s%d", driver, instance);
25810535SVikram.Hegde@Sun.COM 			return (DDI_FAILURE);
25910535SVikram.Hegde@Sun.COM 		}
26010535SVikram.Hegde@Sun.COM 
26110535SVikram.Hegde@Sun.COM 		statep = ddi_get_soft_state(amd_iommu_statep, instance);
26210535SVikram.Hegde@Sun.COM 		if (statep == NULL) {
26310535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "Unable to get soft state for "
26410535SVikram.Hegde@Sun.COM 			    "%s%d", driver, instance);
26510535SVikram.Hegde@Sun.COM 			ddi_soft_state_free(amd_iommu_statep, instance);
26610535SVikram.Hegde@Sun.COM 			return (DDI_FAILURE);
26710535SVikram.Hegde@Sun.COM 		}
26810535SVikram.Hegde@Sun.COM 
26910535SVikram.Hegde@Sun.COM 		if (ddi_create_minor_node(dip, AMD_IOMMU_MINOR_NAME, S_IFCHR,
27010535SVikram.Hegde@Sun.COM 		    AMD_IOMMU_INST2MINOR(instance), AMD_IOMMU_NODETYPE,
27110535SVikram.Hegde@Sun.COM 		    0) != DDI_SUCCESS) {
27210535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "Unable to create minor node for "
27310535SVikram.Hegde@Sun.COM 			    "%s%d", driver, instance);
27410535SVikram.Hegde@Sun.COM 			ddi_remove_minor_node(dip, NULL);
27510535SVikram.Hegde@Sun.COM 			ddi_soft_state_free(amd_iommu_statep, instance);
27610535SVikram.Hegde@Sun.COM 			return (DDI_FAILURE);
27710535SVikram.Hegde@Sun.COM 		}
27810535SVikram.Hegde@Sun.COM 
27910535SVikram.Hegde@Sun.COM 		statep->aioms_devi = dip;
28010535SVikram.Hegde@Sun.COM 		statep->aioms_instance = instance;
28110535SVikram.Hegde@Sun.COM 		statep->aioms_iommu_start = NULL;
28210535SVikram.Hegde@Sun.COM 		statep->aioms_iommu_end = NULL;
28310535SVikram.Hegde@Sun.COM 
28410535SVikram.Hegde@Sun.COM 		amd_iommu_lookup_conf_props(dip);
28510535SVikram.Hegde@Sun.COM 
28610535SVikram.Hegde@Sun.COM 		if (amd_iommu_disable_list) {
28710535SVikram.Hegde@Sun.COM 			cmn_err(CE_NOTE, "AMD IOMMU disabled for the following"
28810535SVikram.Hegde@Sun.COM 			    " drivers:\n%s", amd_iommu_disable_list);
28910535SVikram.Hegde@Sun.COM 		}
29010535SVikram.Hegde@Sun.COM 
29110535SVikram.Hegde@Sun.COM 		if (amd_iommu_disable) {
29210535SVikram.Hegde@Sun.COM 			cmn_err(CE_NOTE, "AMD IOMMU disabled by user");
29310535SVikram.Hegde@Sun.COM 		} else if (amd_iommu_setup(dip, statep) != DDI_SUCCESS) {
29410535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "Unable to initialize AMD IOMMU "
29510535SVikram.Hegde@Sun.COM 			    "%s%d", driver, instance);
29610535SVikram.Hegde@Sun.COM 			ddi_remove_minor_node(dip, NULL);
29710535SVikram.Hegde@Sun.COM 			ddi_soft_state_free(amd_iommu_statep, instance);
29810535SVikram.Hegde@Sun.COM 			return (DDI_FAILURE);
29910535SVikram.Hegde@Sun.COM 		}
30010535SVikram.Hegde@Sun.COM 
30110535SVikram.Hegde@Sun.COM 		ddi_report_dev(dip);
30210535SVikram.Hegde@Sun.COM 
30310535SVikram.Hegde@Sun.COM 		return (DDI_SUCCESS);
30410535SVikram.Hegde@Sun.COM 
30510535SVikram.Hegde@Sun.COM 	case DDI_RESUME:
30610535SVikram.Hegde@Sun.COM 		return (DDI_SUCCESS);
30710535SVikram.Hegde@Sun.COM 	default:
30810535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
30910535SVikram.Hegde@Sun.COM 	}
31010535SVikram.Hegde@Sun.COM }
31110535SVikram.Hegde@Sun.COM 
31210535SVikram.Hegde@Sun.COM static int
amd_iommu_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)31310535SVikram.Hegde@Sun.COM amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
31410535SVikram.Hegde@Sun.COM {
31510535SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(dip);
31610535SVikram.Hegde@Sun.COM 	const char *driver = ddi_driver_name(dip);
31710535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
31810535SVikram.Hegde@Sun.COM 
31910535SVikram.Hegde@Sun.COM 	ASSERT(instance >= 0);
32010535SVikram.Hegde@Sun.COM 	ASSERT(driver);
32110535SVikram.Hegde@Sun.COM 
32210535SVikram.Hegde@Sun.COM 	switch (cmd) {
32310535SVikram.Hegde@Sun.COM 	case DDI_DETACH:
32410535SVikram.Hegde@Sun.COM 		statep = ddi_get_soft_state(amd_iommu_statep, instance);
32510535SVikram.Hegde@Sun.COM 		if (statep == NULL) {
32610535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "%s%d: Cannot get soft state",
32710535SVikram.Hegde@Sun.COM 			    driver, instance);
32810535SVikram.Hegde@Sun.COM 			return (DDI_FAILURE);
32910535SVikram.Hegde@Sun.COM 		}
33010535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
33110535SVikram.Hegde@Sun.COM 	case DDI_SUSPEND:
33210535SVikram.Hegde@Sun.COM 		return (DDI_SUCCESS);
33310535SVikram.Hegde@Sun.COM 	default:
33410535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
33510535SVikram.Hegde@Sun.COM 	}
33610535SVikram.Hegde@Sun.COM }
33710535SVikram.Hegde@Sun.COM 
33810535SVikram.Hegde@Sun.COM /*ARGSUSED*/
33910535SVikram.Hegde@Sun.COM static int
amd_iommu_open(dev_t * devp,int flag,int otyp,cred_t * credp)34010535SVikram.Hegde@Sun.COM amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp)
34110535SVikram.Hegde@Sun.COM {
34210535SVikram.Hegde@Sun.COM 	int instance = AMD_IOMMU_MINOR2INST(getminor(*devp));
34310535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
34410535SVikram.Hegde@Sun.COM 	const char *f = "amd_iommu_open";
34510535SVikram.Hegde@Sun.COM 
34610535SVikram.Hegde@Sun.COM 	if (instance < 0) {
34710535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid instance %d",
34810535SVikram.Hegde@Sun.COM 		    f, instance);
34910535SVikram.Hegde@Sun.COM 		return (ENXIO);
35010535SVikram.Hegde@Sun.COM 	}
35110535SVikram.Hegde@Sun.COM 
35210535SVikram.Hegde@Sun.COM 	if (!(flag & (FREAD|FWRITE))) {
35310535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
35410535SVikram.Hegde@Sun.COM 		return (EINVAL);
35510535SVikram.Hegde@Sun.COM 	}
35610535SVikram.Hegde@Sun.COM 
35710535SVikram.Hegde@Sun.COM 	if (otyp != OTYP_CHR) {
35810535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
35910535SVikram.Hegde@Sun.COM 		return (EINVAL);
36010535SVikram.Hegde@Sun.COM 	}
36110535SVikram.Hegde@Sun.COM 
36210535SVikram.Hegde@Sun.COM 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
36310535SVikram.Hegde@Sun.COM 	if (statep == NULL) {
36410535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
36510535SVikram.Hegde@Sun.COM 		    f, instance);
36610535SVikram.Hegde@Sun.COM 		return (ENXIO);
36710535SVikram.Hegde@Sun.COM 	}
36810535SVikram.Hegde@Sun.COM 
36910535SVikram.Hegde@Sun.COM 	ASSERT(statep->aioms_instance == instance);
37010535SVikram.Hegde@Sun.COM 
37110535SVikram.Hegde@Sun.COM 	return (0);
37210535SVikram.Hegde@Sun.COM }
37310535SVikram.Hegde@Sun.COM 
37410535SVikram.Hegde@Sun.COM /*ARGSUSED*/
37510535SVikram.Hegde@Sun.COM static int
amd_iommu_close(dev_t dev,int flag,int otyp,cred_t * credp)37610535SVikram.Hegde@Sun.COM amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp)
37710535SVikram.Hegde@Sun.COM {
37810535SVikram.Hegde@Sun.COM 	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
37910535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
38010535SVikram.Hegde@Sun.COM 	const char *f = "amd_iommu_close";
38110535SVikram.Hegde@Sun.COM 
38210535SVikram.Hegde@Sun.COM 	if (instance < 0) {
38310535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
38410535SVikram.Hegde@Sun.COM 		return (ENXIO);
38510535SVikram.Hegde@Sun.COM 	}
38610535SVikram.Hegde@Sun.COM 
38710535SVikram.Hegde@Sun.COM 	if (!(flag & (FREAD|FWRITE))) {
38810535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
38910535SVikram.Hegde@Sun.COM 		return (EINVAL);
39010535SVikram.Hegde@Sun.COM 	}
39110535SVikram.Hegde@Sun.COM 
39210535SVikram.Hegde@Sun.COM 	if (otyp != OTYP_CHR) {
39310535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
39410535SVikram.Hegde@Sun.COM 		return (EINVAL);
39510535SVikram.Hegde@Sun.COM 	}
39610535SVikram.Hegde@Sun.COM 
39710535SVikram.Hegde@Sun.COM 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
39810535SVikram.Hegde@Sun.COM 	if (statep == NULL) {
39910535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
40010535SVikram.Hegde@Sun.COM 		    f, instance);
40110535SVikram.Hegde@Sun.COM 		return (ENXIO);
40210535SVikram.Hegde@Sun.COM 	}
40310535SVikram.Hegde@Sun.COM 
40410535SVikram.Hegde@Sun.COM 	ASSERT(statep->aioms_instance == instance);
40510535SVikram.Hegde@Sun.COM 	return (0);
40610535SVikram.Hegde@Sun.COM 
40710535SVikram.Hegde@Sun.COM }
40810535SVikram.Hegde@Sun.COM 
40910535SVikram.Hegde@Sun.COM /*ARGSUSED*/
41010535SVikram.Hegde@Sun.COM static int
amd_iommu_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)41110535SVikram.Hegde@Sun.COM amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
41210535SVikram.Hegde@Sun.COM     int *rvalp)
41310535SVikram.Hegde@Sun.COM {
41410535SVikram.Hegde@Sun.COM 	int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
41510535SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
41610535SVikram.Hegde@Sun.COM 	const char *f = "amd_iommu_ioctl";
41710535SVikram.Hegde@Sun.COM 
41810535SVikram.Hegde@Sun.COM 	ASSERT(*rvalp);
41910535SVikram.Hegde@Sun.COM 
42010535SVikram.Hegde@Sun.COM 	if (instance < 0) {
42110535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
42210535SVikram.Hegde@Sun.COM 		return (ENXIO);
42310535SVikram.Hegde@Sun.COM 	}
42410535SVikram.Hegde@Sun.COM 
42510535SVikram.Hegde@Sun.COM 
42610535SVikram.Hegde@Sun.COM 	if (!(mode & (FREAD|FWRITE))) {
42710535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: invalid mode %d", f, mode);
42810535SVikram.Hegde@Sun.COM 		return (EINVAL);
42910535SVikram.Hegde@Sun.COM 	}
43010535SVikram.Hegde@Sun.COM 
43110535SVikram.Hegde@Sun.COM 	if (mode & FKIOCTL) {
43210535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: FKIOCTL unsupported mode %d", f, mode);
43310535SVikram.Hegde@Sun.COM 		return (EINVAL);
43410535SVikram.Hegde@Sun.COM 	}
43510535SVikram.Hegde@Sun.COM 
43610535SVikram.Hegde@Sun.COM 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
43710535SVikram.Hegde@Sun.COM 	if (statep == NULL) {
43810535SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
43910535SVikram.Hegde@Sun.COM 		    f, instance);
44010535SVikram.Hegde@Sun.COM 		return (ENXIO);
44110535SVikram.Hegde@Sun.COM 	}
44210535SVikram.Hegde@Sun.COM 
44310535SVikram.Hegde@Sun.COM 	ASSERT(statep->aioms_instance == instance);
44410535SVikram.Hegde@Sun.COM 
44510535SVikram.Hegde@Sun.COM 	return (ENOTTY);
44610535SVikram.Hegde@Sun.COM }
447*10536SVikram.Hegde@Sun.COM 
448*10536SVikram.Hegde@Sun.COM static int
amd_iommu_quiesce(dev_info_t * dip)449*10536SVikram.Hegde@Sun.COM amd_iommu_quiesce(dev_info_t *dip)
450*10536SVikram.Hegde@Sun.COM {
451*10536SVikram.Hegde@Sun.COM 	int instance = ddi_get_instance(dip);
452*10536SVikram.Hegde@Sun.COM 	struct amd_iommu_state *statep;
453*10536SVikram.Hegde@Sun.COM 	const char *f = "amd_iommu_quiesce";
454*10536SVikram.Hegde@Sun.COM 
455*10536SVikram.Hegde@Sun.COM 	statep = ddi_get_soft_state(amd_iommu_statep, instance);
456*10536SVikram.Hegde@Sun.COM 	if (statep == NULL) {
457*10536SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
458*10536SVikram.Hegde@Sun.COM 		    f, instance);
459*10536SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
460*10536SVikram.Hegde@Sun.COM 	}
461*10536SVikram.Hegde@Sun.COM 
462*10536SVikram.Hegde@Sun.COM 	if (amd_iommu_teardown(dip, statep, AMD_IOMMU_QUIESCE) != DDI_SUCCESS) {
463*10536SVikram.Hegde@Sun.COM 		cmn_err(CE_WARN, "%s: Unable to quiesce AMD IOMMU "
464*10536SVikram.Hegde@Sun.COM 		    "%s%d", f, ddi_driver_name(dip), instance);
465*10536SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
466*10536SVikram.Hegde@Sun.COM 	}
467*10536SVikram.Hegde@Sun.COM 
468*10536SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
469*10536SVikram.Hegde@Sun.COM }
470