7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * CDDL HEADER START
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * The contents of this file are subject to the terms of the
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Common Development and Distribution License (the "License").
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * You may not use this file except in compliance with the License.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * or http://www.opensolaris.org/os/licensing.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * See the License for the specific language governing permissions
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * and limitations under the License.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * When distributing Covered Code, include this CDDL HEADER in each
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * If applicable, add the following below this CDDL HEADER, with the
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * fields enclosed by brackets "[]" replaced with your own identifying
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * information: Portions Copyright [yyyy] [name of copyright owner]
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * CDDL HEADER END
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Use is subject to license terms.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/types.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/file.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/errno.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/open.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/stat.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/cred.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/modctl.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/conf.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/devops.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/ddi.h>
6732dbb379bf754b70168b01ba56793737f9f3e7Vikram Hegde#include <sys/x86_archext.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/amd_iommu.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include "amd_iommu_impl.h"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include "amd_iommu_acpi.h"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#define AMD_IOMMU_MINOR2INST(x) (x)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#define AMD_IOMMU_INST2MINOR(x) (x)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#define AMD_IOMMU_NODETYPE "ddi_iommu"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#define AMD_IOMMU_MINOR_NAME "amd-iommu"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp void **result);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cred_t *credp, int *rvalp);
ac48dfe87039078897ed719af26744eca776508cVikram Hegdestatic int amd_iommu_quiesce(dev_info_t *dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic struct cb_ops amd_iommu_cb_ops = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_open, /* cb_open */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_close, /* cb_close */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_strategy */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_print */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_dump */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_read */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_write */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_ioctl, /* cb_ioctl */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_devmap */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_mmap */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_segmap */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nochpoll, /* cb_chpoll */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_prop_op, /* cb_prop_op */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp NULL, /* cb_str */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp D_NEW | D_MP, /* cb_flag */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp CB_REV, /* cb_rev */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* cb_aread */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev /* cb_awrite */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic struct dev_ops amd_iommu_dev_ops = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DEVO_REV, /* devo_rev */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0, /* devo_refcnt */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_getinfo, /* devo_getinfo */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nulldev, /* devo_identify */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nulldev, /* devo_probe */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_attach, /* devo_attach */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_detach, /* devo_detach */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp nodev, /* devo_reset */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &amd_iommu_cb_ops, /* devo_cb_ops */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp NULL, /* devo_bus_ops */
ac48dfe87039078897ed719af26744eca776508cVikram Hegde nulldev, /* devo_power */
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_quiesce, /* devo_quiesce */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic struct modldrv modldrv = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &mod_driverops,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "AMD IOMMU 0.1",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &amd_iommu_dev_ops
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic struct modlinkage modlinkage = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp MODREV_1,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void *)&modldrv,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp NULL
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_debug_t amd_iommu_debug;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpkmutex_t amd_iommu_global_lock;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpconst char *amd_iommu_modname = "amd_iommu";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_alias_t **amd_iommu_alias;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_page_table_hash_t amd_iommu_page_table_hash;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void *amd_iommu_statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_64bit_bug;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_unity_map;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_no_RW_perms;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_no_unmap;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_pageva_inval_all;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint amd_iommu_disable; /* disable IOMMU */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpchar *amd_iommu_disable_list; /* list of drivers bypassing IOMMU */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp_init(void)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = ENOTSUP;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#if defined(__amd64) && !defined(__xpv)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
6732dbb379bf754b70168b01ba56793737f9f3e7Vikram Hegde if (get_hwenv() != HW_NATIVE)
6732dbb379bf754b70168b01ba56793737f9f3e7Vikram Hegde return (ENOTSUP);
6732dbb379bf754b70168b01ba56793737f9f3e7Vikram Hegde
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = ddi_soft_state_init(&amd_iommu_statep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp sizeof (struct amd_iommu_state), 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (error) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: _init: failed to init soft state.",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_modname);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_acpi_init() != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: _init: ACPI init failed.",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_modname);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_fini(&amd_iommu_statep);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENOTSUP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_read_boot_props();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_page_table_hash_init(&amd_iommu_page_table_hash)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: _init: Page table hash init failed.",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_modname);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable_list) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(amd_iommu_disable_list,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp strlen(amd_iommu_disable_list) + 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable_list = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_fini();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_fini(&amd_iommu_statep);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_statep = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EFAULT);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = mod_install(&modlinkage);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (error) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: _init: mod_install failed.",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_modname);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable_list) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(amd_iommu_disable_list,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp strlen(amd_iommu_disable_list) + 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable_list = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_fini();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_fini(&amd_iommu_statep);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_statep = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#endif
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp_info(struct modinfo *modinfop)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (mod_info(&modlinkage, modinfop));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp_fini(void)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = mod_remove(&modlinkage);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (error)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_page_table_hash_fini(&amd_iommu_page_table_hash);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable_list) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(amd_iommu_disable_list,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp strlen(amd_iommu_disable_list) + 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable_list = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_fini();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_fini(&amd_iommu_statep);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_statep = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(result);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *result = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp switch (cmd) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_INFO_DEVT2DEVINFO:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_MINOR2INST(getminor((dev_t)arg)));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *result = statep->aioms_devi;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp break;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_INFO_DEVT2INSTANCE:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *result = (void *)(uintptr_t)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_MINOR2INST(getminor((dev_t)arg));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(instance >= 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(driver);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp switch (cmd) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_ATTACH:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_soft_state_zalloc(amd_iommu_statep, instance)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "Unable to allocate soft state for "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%s%d", driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "Unable to get soft state for "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%s%d", driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_free(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_create_minor_node(dip, AMD_IOMMU_MINOR_NAME, S_IFCHR,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_INST2MINOR(instance), AMD_IOMMU_NODETYPE,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "Unable to create minor node for "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%s%d", driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_remove_minor_node(dip, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_free(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_devi = dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_instance = instance;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_iommu_start = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_iommu_end = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_lookup_conf_props(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable_list) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "AMD IOMMU disabled for the following"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp " drivers:\n%s", amd_iommu_disable_list);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "AMD IOMMU disabled by user");
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else if (amd_iommu_setup(dip, statep) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "Unable to initialize AMD IOMMU "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%s%d", driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_remove_minor_node(dip, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_soft_state_free(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_report_dev(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_RESUME:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp default:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(instance >= 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(driver);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp switch (cmd) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_DETACH:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s%d: Cannot get soft state",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp case DDI_SUSPEND:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp default:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_open(dev_t *devp, int flag, int otyp, cred_t *credp)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = AMD_IOMMU_MINOR2INST(getminor(*devp));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_open";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (instance < 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid instance %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!(flag & (FREAD|FWRITE))) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (otyp != OTYP_CHR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(statep->aioms_instance == instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_close(dev_t dev, int flag, int otyp, cred_t *credp)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_close";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (instance < 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!(flag & (FREAD|FWRITE))) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid flags %d", f, flag);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (otyp != OTYP_CHR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid otyp %d", f, otyp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(statep->aioms_instance == instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int *rvalp)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = AMD_IOMMU_MINOR2INST(getminor(dev));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct amd_iommu_state *statep;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_ioctl";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(*rvalp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (instance < 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid instance %d", f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!(mode & (FREAD|FWRITE))) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: invalid mode %d", f, mode);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (mode & FKIOCTL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: FKIOCTL unsupported mode %d", f, mode);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (EINVAL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep = ddi_get_soft_state(amd_iommu_statep, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENXIO);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(statep->aioms_instance == instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (ENOTTY);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegdestatic int
ac48dfe87039078897ed719af26744eca776508cVikram Hegdeamd_iommu_quiesce(dev_info_t *dip)
ac48dfe87039078897ed719af26744eca776508cVikram Hegde{
ac48dfe87039078897ed719af26744eca776508cVikram Hegde int instance = ddi_get_instance(dip);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde struct amd_iommu_state *statep;
ac48dfe87039078897ed719af26744eca776508cVikram Hegde const char *f = "amd_iommu_quiesce";
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde statep = ddi_get_soft_state(amd_iommu_statep, instance);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (statep == NULL) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde cmn_err(CE_WARN, "%s: cannot get soft state: instance %d",
ac48dfe87039078897ed719af26744eca776508cVikram Hegde f, instance);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde return (DDI_FAILURE);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde }
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (amd_iommu_teardown(dip, statep, AMD_IOMMU_QUIESCE) != DDI_SUCCESS) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde cmn_err(CE_WARN, "%s: Unable to quiesce AMD IOMMU "
ac48dfe87039078897ed719af26744eca776508cVikram Hegde "%s%d", f, ddi_driver_name(dip), instance);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde return (DDI_FAILURE);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde }
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde return (DDI_SUCCESS);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde}