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/*
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/sunddi.h>
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam#include <sys/sunndi.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/iommulib.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/amd_iommu.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/pci_cap.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/bootconf.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include <sys/ddidmareq.h>
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include "amd_iommu_impl.h"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include "amd_iommu_acpi.h"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp#include "amd_iommu_page_tables.h"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ac48dfe87039078897ed719af26744eca776508cVikram Hegdestatic int amd_iommu_fini(amd_iommu_t *iommu, int type);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void amd_iommu_teardown_interrupts(amd_iommu_t *iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void amd_iommu_stop(amd_iommu_t *iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_allochdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_freehdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t *ccountp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_unbindhdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp size_t len, uint_t cache_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int amd_iommu_win(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t *ccountp);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int amd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int amd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int unmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpextern void *device_arena_alloc(size_t size, int vm_flag);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpextern void device_arena_free(void * vaddr, size_t size);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpddi_dma_attr_t amd_iommu_dma_attr = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DMA_ATTR_V0,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0U, /* dma_attr_addr_lo */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0xffffffffffffffffULL, /* dma_attr_addr_hi */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0xffffffffU, /* dma_attr_count_max */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (uint64_t)4096, /* dma_attr_align */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 1, /* dma_attr_burstsizes */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 64, /* dma_attr_minxfer */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0xffffffffU, /* dma_attr_maxxfer */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0xffffffffU, /* dma_attr_seg */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 1, /* dma_attr_sgllen, variable */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 64, /* dma_attr_granular */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp 0 /* dma_attr_flags */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpddi_device_acc_attr_t amd_iommu_devacc = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_DEVICE_ATTR_V0,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_NEVERSWAP_ACC,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_STRICTORDER_ACC
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstruct iommulib_ops amd_iommulib_ops = {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp IOMMU_OPS_VERSION,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "AMD IOMMU Vers. 1",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp NULL,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_probe,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_allochdl,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_freehdl,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_bindhdl,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_unbindhdl,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_sync,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_win,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden amd_iommu_mapobject,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden amd_iommu_unmapobject,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic kmutex_t amd_iommu_pgtable_lock;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_register(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommulib_ops_t *iommulib_ops;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommulib_handle_t handle;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_register";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommulib_ops = kmem_zalloc(sizeof (iommulib_ops_t), KM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *iommulib_ops = amd_iommulib_ops;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommulib_ops->ilops_data = (void *)iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iommulib_ops = iommulib_ops;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_register(dip, iommulib_ops, &handle)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Register with iommulib "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "failed idx=%d", f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(iommulib_ops, sizeof (iommulib_ops_t));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iommulib_handle = handle;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_unregister(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_iommulib_handle == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* we never registered */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_unregister(iommu->aiomt_iommulib_handle)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(iommu->aiomt_iommulib_ops, sizeof (iommulib_ops_t));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iommulib_ops = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iommulib_handle = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_setup_passthru(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp gfx_entry_t *gfxp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup passthru mapping for "special" devices
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_set_passthru(iommu, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (gfxp = gfx_devinfo_list; gfxp; gfxp = gfxp->g_next) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp gfxp->g_ref++;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dip = gfxp->g_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (dip) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_set_passthru(iommu, dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp gfxp->g_ref--;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_start(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_ivhd_t *hinfop;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_start";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hinfop = amd_iommu_lookup_all_ivhd();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Disable HT tunnel translation.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * XXX use ACPI
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_HT_TUN_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (hinfop) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "amd_iommu: using ACPI for CTRL registers");
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_ISOC, hinfop->ach_Isoc);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_RESPASSPW, hinfop->ach_ResPassPW);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_PASSPW, hinfop->ach_PassPW);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_INVTO, 5);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * The Device table entry bit 0 (V) controls whether the device
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * table entry is valid for address translation and Device table
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * entry bit 128 (IV) controls whether interrupt remapping is valid.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * By setting both to zero we are essentially doing pass-thru. Since
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * this table is zeroed on allocation, essentially we will have
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * pass-thru when IOMMU is enabled.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Finally enable the IOMMU ... */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_ENABLE, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Successfully started AMD IOMMU", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "AMD IOMMU (%d,%d) enabled",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_stop(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_stop";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTINT_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMWAITINT_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLOG_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Disable translation on HT tunnel traffic
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_HT_TUN_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMYU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Successfully stopped AMD IOMMU", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_setup_tables_and_buffers(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t dma_bufsz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp caddr_t addr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t p2sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int i;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint64_t *dentry;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int err;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_setup_tables_and_buffers";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * We will put the Device Table, Command Buffer and
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Event Log in contiguous memory. Allocate the maximum
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * size allowed for such structures
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Device Table: 256b * 64K = 32B * 64K
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Command Buffer: 128b * 32K = 16B * 32K
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Event Log: 128b * 32K = 16B * 32K
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_devtbl_sz = (1<<AMD_IOMMU_DEVTBL_SZ) * AMD_IOMMU_DEVENT_SZ;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_cmdbuf_sz = (1<<AMD_IOMMU_CMDBUF_SZ) * AMD_IOMMU_CMD_SZ;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_eventlog_sz =
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (1<<AMD_IOMMU_EVENTLOG_SZ) * AMD_IOMMU_EVENT_SZ;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_bufsz = iommu->aiomt_devtbl_sz + iommu->aiomt_cmdbuf_sz
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp + iommu->aiomt_eventlog_sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Alloc a DMA handle.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_dma_alloc_handle(dip, &amd_iommu_dma_attr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_DMA_SLEEP, NULL, &iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot alloc DMA handle for "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "AMD IOMMU tables and buffers", f, driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Alloc memory for tables and buffers
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * XXX remove cast to size_t
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_dma_mem_alloc(iommu->aiomt_dmahdl, dma_bufsz,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &amd_iommu_devacc, DDI_DMA_CONSISTENT|IOMEM_DATA_UNCACHED,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_DMA_SLEEP, NULL, (caddr_t *)&iommu->aiomt_dma_bufva,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (size_t *)&iommu->aiomt_dma_mem_realsz, &iommu->aiomt_dma_mem_hdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot alloc memory for DMA "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "to AMD IOMMU tables and buffers", f, driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_bufva = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_realsz = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_free_handle(&iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dmahdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * The VA must be 4K aligned and >= table size
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(((uintptr_t)iommu->aiomt_dma_bufva &
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_TABLE_ALIGN) == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(iommu->aiomt_dma_mem_realsz >= dma_bufsz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Now bind the handle
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_dma_addr_bind_handle(iommu->aiomt_dmahdl, NULL,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_bufva, iommu->aiomt_dma_mem_realsz,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp NULL, &iommu->aiomt_buf_dma_cookie, &iommu->aiomt_buf_dma_ncookie);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_DMA_MAPPED) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot bind memory for DMA "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "to AMD IOMMU tables and buffers. bufrealsz=%p",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void *)(uintptr_t)iommu->aiomt_dma_mem_realsz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_size = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_type = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_ncookie = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_hdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_bufva = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_realsz = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_free_handle(&iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dmahdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * We assume the DMA engine on the IOMMU is capable of handling the
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * whole table buffer in a single cookie. If not and multiple cookies
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * are needed we fail.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_buf_dma_ncookie != 1) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot handle multiple "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "cookies for DMA to AMD IOMMU tables and buffers. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "#cookies=%u", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_ncookie);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_dma_unbind_handle(iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_size = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_type = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_ncookie = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_hdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_bufva = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_realsz = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_free_handle(&iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dmahdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * The address in the cookie must be 4K aligned and >= table size
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT((iommu->aiomt_buf_dma_cookie.dmac_cookie_addr
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp & AMD_IOMMU_TABLE_ALIGN) == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp <= iommu->aiomt_dma_mem_realsz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(iommu->aiomt_buf_dma_cookie.dmac_size >= dma_bufsz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup the device table pointers in the iommu struct as
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * well as the IOMMU device table register
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_devtbl = iommu->aiomt_dma_bufva;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp bzero(iommu->aiomt_devtbl, iommu->aiomt_devtbl_sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Set V=1 and TV = 0, so any inadvertant pass-thrus cause
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * page faults. Also set SE bit so we aren't swamped with
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * page fault messages
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i <= AMD_IOMMU_MAX_DEVICEID; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*LINTED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dentry = (uint64_t *)&iommu->aiomt_devtbl
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp [i * AMD_IOMMU_DEVTBL_ENTRY_SZ];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(dentry, AMD_IOMMU_DEVTBL_V, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SE, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp addr = (caddr_t)(uintptr_t)iommu->aiomt_buf_dma_cookie.dmac_cookie_addr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_DEVTABBASE, ((uint64_t)(uintptr_t)addr) >> 12);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp sz = (iommu->aiomt_devtbl_sz >> 12) - 1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(sz <= ((1 << 9) - 1));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_DEVTABSIZE, sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup the command buffer pointers
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_cmdbuf = iommu->aiomt_devtbl +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_devtbl_sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp bzero(iommu->aiomt_cmdbuf, iommu->aiomt_cmdbuf_sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp addr += iommu->aiomt_devtbl_sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMBASE, ((uint64_t)(uintptr_t)addr) >> 12);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2sz = AMD_IOMMU_CMDBUF_SZ;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(p2sz >= AMD_IOMMU_CMDBUF_MINSZ &&
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2sz <= AMD_IOMMU_CMDBUF_MAXSZ);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMLEN, p2sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*LINTED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_cmd_tail = (uint32_t *)iommu->aiomt_cmdbuf;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDHEADPTR, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_tail_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDTAILPTR, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup the event log pointers
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_eventlog = iommu->aiomt_cmdbuf +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_eventlog_sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp bzero(iommu->aiomt_eventlog, iommu->aiomt_eventlog_sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp addr += iommu->aiomt_cmdbuf_sz;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTBASE, ((uint64_t)(uintptr_t)addr) >> 12);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2sz = AMD_IOMMU_EVENTLOG_SZ;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(p2sz >= AMD_IOMMU_EVENTLOG_MINSZ &&
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2sz <= AMD_IOMMU_EVENTLOG_MAXSZ);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLEN, sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*LINTED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_event_head = (uint32_t *)iommu->aiomt_eventlog;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTHEADPTR, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_tail_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTTAILPTR, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* dma sync so device sees this init */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp SYNC_FORDEV(iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_TABLES) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: successfully setup AMD IOMMU "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "tables, idx=%d", f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void
ac48dfe87039078897ed719af26744eca776508cVikram Hegdeamd_iommu_teardown_tables_and_buffers(amd_iommu_t *iommu, int type)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_teardown_tables_and_buffers";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_eventlog = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTBASE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLEN, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_EVENTHEADPTR, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_eventlog_head_va),
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_EVENTTAILPTR, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_cmdbuf = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMBASE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMLEN, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_CMDHEADPTR, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_cmdbuf_head_va),
ac48dfe87039078897ed719af26744eca776508cVikram Hegde AMD_IOMMU_CMDTAILPTR, 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_devtbl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_DEVTABBASE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_devtbl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_DEVTABSIZE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (iommu->aiomt_dmahdl == NULL || type == AMD_IOMMU_QUIESCE)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Unbind the handle */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_dma_unbind_handle(iommu->aiomt_dmahdl) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: failed to unbind handle: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%p for IOMMU idx=%d", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void *)iommu->aiomt_dmahdl, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_laddress = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_size = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_cookie.dmac_type = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_buf_dma_ncookie = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Free the table memory allocated for DMA */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_mem_free(&iommu->aiomt_dma_mem_hdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_hdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_bufva = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dma_mem_realsz = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Free the DMA handle */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_free_handle(&iommu->aiomt_dmahdl);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dmahdl = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_enable_interrupts(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_RUN) == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_LOG_RUN) == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Must be set prior to enabling command buffer */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Must be set prior to enabling event logging */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_ENABLE, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* No interrupts for completion wait - too heavy weight. use polling */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_COMWAITINT_ENABLE, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLOG_ENABLE, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_ctrl_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTINT_ENABLE, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_setup_exclusion(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_ivmd_t *minfop;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp minfop = amd_iommu_lookup_all_ivmd();
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (minfop && minfop->acm_ExclRange == 1) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "Programming exclusion range");
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_ADDR,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp minfop->acm_ivmd_phys_start >> 12);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_ALLOW, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_EXEN, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_LIM, (minfop->acm_ivmd_phys_start +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp minfop->acm_ivmd_phys_len) >> 12);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "Skipping exclusion range");
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_ADDR, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_ALLOW, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_base_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_EXEN, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_excl_lim_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_LIM, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_teardown_exclusion(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) amd_iommu_setup_exclusion(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic uint_t
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_intr_handler(caddr_t arg1, caddr_t arg2)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*LINTED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu = (amd_iommu_t *)arg1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_intr_handler";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(arg1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(arg2 == NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d. In INTR handler",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_LOG_INT) == 1) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: IOMMU unit idx=%d "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Event Log Interrupt", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISPLAY);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp WAIT_SEC(1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_LOG_INT, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_INTR_CLAIMED);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (AMD_IOMMU_REG_GET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_OVERFLOW_INT) == 1) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "!%s: %s%d: IOMMU unit idx=%d "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Event Overflow Interrupt", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) amd_iommu_read_log(iommu, AMD_IOMMU_LOG_DISCARD);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_LOG_INT, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64(REGADDR64(iommu->aiomt_reg_status_va),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENT_OVERFLOW_INT, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_INTR_CLAIMED);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_INTR_UNCLAIMED);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_setup_interrupts(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int intrcap0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int intrcapN;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int type;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int err;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int req;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int avail;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int p2req;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int actual;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int i;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int j;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_setup_interrupts";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_intr_get_supported_types(dip, &type) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: ddi_intr_get_supported_types "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "failed: idx=%d", f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Interrupt types supported = 0x%x", f, driver, instance,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx, type);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * for now we only support MSI
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if ((type & DDI_INTR_TYPE_MSI) == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "MSI interrupts not supported. Failing init.",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. MSI supported",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_MSI, &req);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_get_nintrs failed err = %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, err);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "MSI number of interrupts requested: %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, req);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (req == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "interrupts requested. Failing init", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_intr_get_navail(dip, DDI_INTR_TYPE_MSI, &avail);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_get_navail failed err = %d", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, iommu->aiomt_idx, err);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "MSI number of interrupts available: %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, avail);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (avail == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: 0 MSI "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "interrupts available. Failing init", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (avail < req) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: MSI "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "interrupts: requested (%d) > available (%d). "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Failing init", f, driver, instance, iommu->aiomt_idx,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp req, avail);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Allocate memory for DDI interrupt handles */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable_sz = req * sizeof (ddi_intr_handle_t);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable = kmem_zalloc(iommu->aiomt_intr_htable_sz,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp KM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_state = AMD_IOMMU_INTR_TABLE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Convert req to a power of two as required by ddi_intr_alloc */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2req = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp while (1<<p2req <= req)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2req++;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp p2req--;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp req = 1<<p2req;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "MSI power of 2 number of interrupts: %d,%d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, p2req, req);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp err = ddi_intr_alloc(iommu->aiomt_dip, iommu->aiomt_intr_htable,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_INTR_TYPE_MSI, 0, req, &actual, DDI_INTR_ALLOC_STRICT);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (err != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_alloc failed: err = %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, err);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_actual_intrs = actual;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_state = AMD_IOMMU_INTR_ALLOCED;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "number of interrupts actually allocated %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, actual);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_actual_intrs < req) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_alloc failed: actual (%d) < req (%d)",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_actual_intrs, req);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_intr_add_handler(iommu->aiomt_intr_htable[i],
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_intr_handler, (void *)iommu, NULL)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_add_handler failed: intr = %d, err = %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, i, err);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (j = 0; j < i; j++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_remove_handler(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable[j]);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_state = AMD_IOMMU_INTR_HANDLER;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp intrcap0 = intrcapN = -1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_intr_get_cap(iommu->aiomt_intr_htable[0], &intrcap0)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS ||
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_intr_get_cap(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable[iommu->aiomt_actual_intrs - 1], &intrcapN)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS || intrcap0 != intrcapN) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_get_cap failed or inconsistent cap among "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "interrupts: intrcap0 (%d) < intrcapN (%d)",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx, intrcap0, intrcapN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_cap = intrcap0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (intrcap0 & DDI_INTR_FLAG_BLOCK) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Need to call block enable */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Need to call block enable",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_intr_block_enable(iommu->aiomt_intr_htable,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_actual_intrs) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_block enable failed ", f, driver,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_block_disable(iommu->aiomt_intr_htable,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_actual_intrs);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Need to call individual enable",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_intr_enable(iommu->aiomt_intr_htable[i])
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "ddi_intr_enable failed: intr = %d", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, iommu->aiomt_idx, i);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (j = 0; j < i; j++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_disable(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable[j]);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_teardown_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_state = AMD_IOMMU_INTR_ENABLED;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_INTR) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: AMD IOMMU idx=%d: "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Interrupts successfully %s enabled. # of interrupts = %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, iommu->aiomt_idx,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (intrcap0 & DDI_INTR_FLAG_BLOCK) ? "(block)" :
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "(individually)", iommu->aiomt_actual_intrs);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic void
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_teardown_interrupts(amd_iommu_t *iommu)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int i;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ENABLED) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_intr_cap & DDI_INTR_FLAG_BLOCK) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_block_disable(iommu->aiomt_intr_htable,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_actual_intrs);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_disable(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable[i]);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_HANDLER) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_remove_handler(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable[i]);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_ALLOCED) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < iommu->aiomt_actual_intrs; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_intr_free(iommu->aiomt_intr_htable[i]);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_intr_state & AMD_IOMMU_INTR_TABLE) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(iommu->aiomt_intr_htable,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable_sz);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_htable_sz = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_intr_state = AMD_IOMMU_INTR_INVALID;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic amd_iommu_t *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_init(dev_info_t *dip, ddi_acc_handle_t handle, int idx,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint16_t cap_base)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t caphdr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t low_addr32;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t hi_addr32;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t range;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t misc;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint64_t pgoffset;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_global_t *global;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_acpi_ivhd_t *hinfop;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam int bus, device, func;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_init";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp low_addr32 = PCI_CAP_GET32(handle, 0, cap_base,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CAP_ADDR_LOW_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!(low_addr32 & AMD_IOMMU_REG_ADDR_LOCKED)) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: capability registers not locked. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "Unable to use IOMMU unit idx=%d - skipping ...", f, driver,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu = kmem_zalloc(sizeof (amd_iommu_t), KM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_init(&iommu->aiomt_mutex, NULL, MUTEX_DRIVER, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_enter(&iommu->aiomt_mutex);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_init(&iommu->aiomt_cmdlock, NULL, MUTEX_DRIVER, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_init(&iommu->aiomt_eventlock, NULL, MUTEX_DRIVER, NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_dip = dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_idx = idx;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (acpica_get_bdf(iommu->aiomt_dip, &bus, &device, &func)
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam != DDI_SUCCESS) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam cmn_err(CE_WARN, "%s: %s%d: Failed to get BDF"
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam "Unable to use IOMMU unit idx=%d - skipping ...",
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam f, driver, instance, idx);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (NULL);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam iommu->aiomt_bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) |
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam (uint8_t)func;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Since everything in the capability block is locked and RO at this
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * point, copy everything into the IOMMU struct
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* Get cap header */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp caphdr = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_HDR_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_cap_hdr = caphdr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_npcache = AMD_IOMMU_REG_GET32(&caphdr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CAP_NPCACHE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_httun = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_HTTUN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam global = amd_iommu_lookup_acpi_global();
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam hinfop = amd_iommu_lookup_any_ivhd(iommu);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (hinfop)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iotlb = hinfop->ach_IotlbSup;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp else
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_iotlb =
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_IOTLB);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_captype = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_capid = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Get address of IOMMU control registers
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hi_addr32 = PCI_CAP_GET32(handle, 0, cap_base,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CAP_ADDR_HI_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_low_addr32 = low_addr32;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_hi_addr32 = hi_addr32;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp low_addr32 &= ~AMD_IOMMU_REG_ADDR_LOCKED;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (hinfop) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_pa = hinfop->ach_IOMMU_reg_base;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(hinfop->ach_IOMMU_pci_seg == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_pa = ((uint64_t)hi_addr32 << 32 | low_addr32);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Get cap range reg
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp range = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_RANGE_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_range = range;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_rng_valid = AMD_IOMMU_REG_GET32(&range,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_RNG_VALID);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_rng_valid) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_rng_bus = AMD_IOMMU_REG_GET32(&range,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_RNG_BUS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_first_devfn = AMD_IOMMU_REG_GET32(&range,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_FIRST_DEVFN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_last_devfn = AMD_IOMMU_REG_GET32(&range,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_LAST_DEVFN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_rng_bus = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_first_devfn = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_last_devfn = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (hinfop)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_ht_unitid = hinfop->ach_IOMMU_UnitID;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp else
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_ht_unitid = AMD_IOMMU_REG_GET32(&range,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_HT_UNITID);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Get cap misc reg
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp misc = PCI_CAP_GET32(handle, 0, cap_base, AMD_IOMMU_CAP_MISC_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_misc = misc;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (global) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_htatsresv = global->acg_HtAtsResv;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_vasize = global->acg_VAsize;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_pasize = global->acg_PAsize;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_htatsresv = AMD_IOMMU_REG_GET32(&misc,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_HT_ATSRSV);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_vasize = AMD_IOMMU_REG_GET32(&misc,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_VA_SIZE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_pasize = AMD_IOMMU_REG_GET32(&misc,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_PA_SIZE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (hinfop) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_msinum = hinfop->ach_IOMMU_MSInum;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_msinum =
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_GET32(&misc, AMD_IOMMU_MSINUM);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Set up mapping between control registers PA and VA
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp pgoffset = iommu->aiomt_reg_pa & MMU_PAGEOFFSET;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(pgoffset == 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_pages = mmu_btopr(AMD_IOMMU_REG_SIZE + pgoffset);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_size = mmu_ptob(iommu->aiomt_reg_pages);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_va = (uintptr_t)device_arena_alloc(
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ptob(iommu->aiomt_reg_pages), VM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_va == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Failed to alloc VA for IOMMU "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "control regs. Skipping IOMMU idx=%d", f, driver,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hat_devload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_size,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mmu_btop(iommu->aiomt_reg_pa), PROT_READ | PROT_WRITE
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp | HAT_STRICTORDER, HAT_LOAD_LOCK);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_va = iommu->aiomt_va + pgoffset;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup the various control register's VA
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_devtbl_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_DEVTBL_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_cmdbuf_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_eventlog_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLOG_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_ctrl_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CTRL_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_excl_base_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_BASE_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_excl_lim_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EXCL_LIM_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_cmdbuf_head_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_HEAD_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_cmdbuf_tail_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CMDBUF_TAIL_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_eventlog_head_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLOG_HEAD_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_eventlog_tail_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_EVENTLOG_TAIL_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_status_va = iommu->aiomt_reg_va +
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_STATUS_REG_OFF;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Setup the DEVICE table, CMD buffer, and LOG buffer in
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * memory and setup DMA access to this memory location
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_setup_tables_and_buffers(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_setup_exclusion(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_enable_interrupts(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_setup_interrupts(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * need to setup domain table before gfx bypass
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_init_page_tables(iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Set pass-thru for special devices like IOAPIC and HPET
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Also, gfx devices don't use DDI for DMA. No need to register
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * before setting up gfx passthru
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_setup_passthru(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam /* Initialize device table entries based on ACPI settings */
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (amd_iommu_acpi_init_devtbl(iommu) != DDI_SUCCESS) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam cmn_err(CE_WARN, "%s: %s%d: Can't initialize device table",
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam f, driver, instance);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam mutex_exit(&iommu->aiomt_mutex);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (NULL);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_start(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* xxx register/start race */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_register(iommu) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde (void) amd_iommu_fini(iommu, AMD_IOMMU_TEARDOWN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: IOMMU idx=%d inited.", f, driver,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (iommu);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
ac48dfe87039078897ed719af26744eca776508cVikram Hegdeamd_iommu_fini(amd_iommu_t *iommu, int type)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int idx = iommu->aiomt_idx;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip = iommu->aiomt_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_fini";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (type == AMD_IOMMU_TEARDOWN) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde mutex_enter(&iommu->aiomt_mutex);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (amd_iommu_unregister(iommu) != DDI_SUCCESS) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit failed. "
ac48dfe87039078897ed719af26744eca776508cVikram Hegde "idx = %d", f, driver, instance, idx);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde return (DDI_FAILURE);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_stop(iommu);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (type == AMD_IOMMU_TEARDOWN) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_fini_page_tables(iommu);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_teardown_interrupts(iommu);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_teardown_exclusion(iommu);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde }
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_teardown_tables_and_buffers(iommu, type);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (type == AMD_IOMMU_QUIESCE)
ac48dfe87039078897ed719af26744eca776508cVikram Hegde return (DDI_SUCCESS);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu->aiomt_va != NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hat_unload(kas.a_hat, (void *)(uintptr_t)iommu->aiomt_va,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_size, HAT_UNLOAD_UNLOCK);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp device_arena_free((void *)(uintptr_t)iommu->aiomt_va,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ptob(iommu->aiomt_reg_pages));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_va = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu->aiomt_reg_va = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_destroy(&iommu->aiomt_eventlock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_destroy(&iommu->aiomt_cmdlock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&iommu->aiomt_mutex);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_destroy(&iommu->aiomt_mutex);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(iommu, sizeof (amd_iommu_t));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: Fini of IOMMU unit complete. idx = %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_setup(dev_info_t *dip, amd_iommu_state_t *statep)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_acc_handle_t handle;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint8_t base_class;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint8_t sub_class;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint8_t prog_class;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int idx;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t id;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint16_t cap_base;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t caphdr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint8_t cap_type;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint8_t cap_id;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_setup";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(instance >= 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(driver);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* First setup PCI access to config space */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: PCI config setup failed: %s%d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * The AMD IOMMU is part of an independent PCI function. There may be
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * more than one IOMMU in that PCI function
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp prog_class = pci_config_get8(handle, PCI_CONF_PROGCLASS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (base_class != PCI_CLASS_PERIPH || sub_class != PCI_PERIPH_IOMMU ||
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp prog_class != AMD_IOMMU_PCI_PROG_IF) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: invalid PCI class(0x%x)/"
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "subclass(0x%x)/programming interface(0x%x)", f, driver,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp instance, base_class, sub_class, prog_class);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp pci_config_teardown(&handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Find and initialize all IOMMU units in this function
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (idx = 0; ; idx++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (pci_cap_probe(handle, idx, &id, &cap_base) != DDI_SUCCESS)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp break;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* check if cap ID is secure device cap id */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (id != PCI_CAP_ID_SECURE_DEV) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde cmn_err(CE_NOTE,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%s: %s%d: skipping IOMMU: idx(0x%x) "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "cap ID (0x%x) != secure dev capid (0x%x)",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, idx, id,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp PCI_CAP_ID_SECURE_DEV);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp continue;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /* check if cap type is IOMMU cap type */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp caphdr = PCI_CAP_GET32(handle, 0, cap_base,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_CAP_HDR_OFF);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cap_type = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_TYPE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cap_id = AMD_IOMMU_REG_GET32(&caphdr, AMD_IOMMU_CAP_ID);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (cap_type != AMD_IOMMU_CAP) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "cap type (0x%x) != AMD IOMMU CAP (0x%x)", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, idx, cap_type, AMD_IOMMU_CAP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp continue;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(cap_id == PCI_CAP_ID_SECURE_DEV);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(cap_id == id);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp iommu = amd_iommu_init(dip, handle, idx, cap_base);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommu == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: skipping IOMMU: idx(0x%x) "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "failed to init IOMMU", f,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp driver, instance, idx);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp continue;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (statep->aioms_iommu_start == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_iommu_start = iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_iommu_end->aiomt_next = iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_iommu_end = iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_nunits++;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp pci_config_teardown(&handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: state=%p: setup %d IOMMU units",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, (void *)statep, statep->aioms_nunits);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpint
ac48dfe87039078897ed719af26744eca776508cVikram Hegdeamd_iommu_teardown(dev_info_t *dip, amd_iommu_state_t *statep, int type)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(dip);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde amd_iommu_t *iommu, *next_iommu;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int teardown;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = DDI_SUCCESS;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_teardown";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp teardown = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (iommu = statep->aioms_iommu_start; iommu;
ac48dfe87039078897ed719af26744eca776508cVikram Hegde iommu = next_iommu) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(statep->aioms_nunits > 0);
ac48dfe87039078897ed719af26744eca776508cVikram Hegde next_iommu = iommu->aiomt_next;
ac48dfe87039078897ed719af26744eca776508cVikram Hegde if (amd_iommu_fini(iommu, type) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp continue;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp statep->aioms_nunits--;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp teardown++;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s%d: state=%p: toredown %d units. "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "%d units left", f, driver, instance, (void *)statep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp teardown, statep->aioms_nunits);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliamdev_info_t *
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliamamd_iommu_pci_dip(dev_info_t *rdip, const char *path)
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam{
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam dev_info_t *pdip;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam const char *driver = ddi_driver_name(rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam int instance = ddi_get_instance(rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam const char *f = "amd_iommu_pci_dip";
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam /* Hold rdip so it and its parents don't go away */
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam ndi_hold_devi(rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (ddi_is_pci_dip(rdip))
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam pdip = rdip;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam while (pdip = ddi_get_parent(pdip)) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (ddi_is_pci_dip(pdip)) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam ndi_hold_devi(pdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam ndi_rele_devi(rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (pdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam cmn_err(
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam#ifdef DEBUG
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam CE_PANIC,
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam#else
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam CE_WARN,
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam#endif /* DEBUG */
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam "%s: %s%d dip = %p has no PCI parent, path = %s",
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam f, driver, instance, (void *)rdip, path);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam ndi_rele_devi(rdip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (NULL);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam}
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/* Interface with IOMMULIB */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_probe(iommulib_handle_t handle, dev_info_t *rdip)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *s;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam int bus, device, func, bdf;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam amd_iommu_acpi_ivhd_t *hinfop;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam dev_info_t *pci_dip;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam const char *f = "amd_iommu_probe";
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam int instance = ddi_get_instance(iommu->aiomt_dip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam const char *idriver = ddi_driver_name(iommu->aiomt_dip);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam char *path, *pathp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_disable_list) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s = strstr(amd_iommu_disable_list, driver);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (s == NULL)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_SUCCESS);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (s == amd_iommu_disable_list || *(s - 1) == ':') {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s += strlen(driver);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (*s == '\0' || *s == ':') {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_set_passthru(iommu, rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if ((pathp = ddi_pathname(rdip, path)) == NULL)
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam pathp = "<unknown>";
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam pci_dip = amd_iommu_pci_dip(rdip, path);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (pci_dip == NULL) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get PCI dip "
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam "for rdip=%p, path = %s",
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam f, idriver, instance, iommu->aiomt_idx, (void *)rdip,
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam pathp);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam kmem_free(path, MAXPATHLEN);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (DDI_FAILURE);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (acpica_get_bdf(pci_dip, &bus, &device, &func) != DDI_SUCCESS) {
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam cmn_err(CE_WARN, "%s: %s%d: idx = %d, failed to get BDF "
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam "for rdip=%p, path = %s",
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam f, idriver, instance, iommu->aiomt_idx, (void *)rdip,
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam pathp);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam kmem_free(path, MAXPATHLEN);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (DDI_FAILURE);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam }
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam kmem_free(path, MAXPATHLEN);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam /*
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam * See whether device is described by IVRS as being managed
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam * by this IOMMU
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam */
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam bdf = ((uint8_t)bus << 8) | ((uint8_t)device << 3) | (uint8_t)func;
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam hinfop = amd_iommu_lookup_ivhd(bdf);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam if (hinfop && hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf)
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (DDI_SUCCESS);
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam
ba758cf1b2fe06a606303351c36a766f2f9f6665Jerry Gilliam return (DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_allochdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *dma_handlep)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (iommulib_iommu_dma_allochdl(dip, rdip, attr, waitfp,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp arg, dma_handlep));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_freehdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (iommulib_iommu_dma_freehdl(dip, rdip, dma_handle));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip, ddi_dma_attr_t *attrp,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookie_array, uint_t ccount,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int km_flags)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(iommu->aiomt_dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(iommu->aiomt_dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int idx = iommu->aiomt_idx;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int i;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint64_t start_va;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *path;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "map_current_window";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp path = kmem_alloc(MAXPATHLEN, km_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (path == NULL) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (DDI_DMA_NORESOURCES);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_pathname(rdip, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_enter(&amd_iommu_pgtable_lock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug == AMD_IOMMU_DEBUG_PAGE_TABLES) {
ac48dfe87039078897ed719af26744eca776508cVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: idx=%d Attempting to get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "from handle for device %s",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, idx, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp start_va = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < ccount; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if ((error = amd_iommu_map_pa2va(iommu, rdip, attrp, dmareq,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_cookie_addr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_size,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_VMEM_MAP, &start_va, km_flags)) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp break;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_cookie_addr = (uintptr_t)start_va;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_type = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (i != ccount) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot map cookie# %d "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %s", f, driver, instance, idx, i, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) unmap_current_window(iommu, rdip, cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount, i, 1);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_PAGE_TABLES) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: return SUCCESS", f);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_DMA_MAPPED;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpout:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&amd_iommu_pgtable_lock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(path, MAXPATHLEN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpunmap_current_window(amd_iommu_t *iommu, dev_info_t *rdip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array, uint_t ccount, int ncookies, int locked)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(iommu->aiomt_dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(iommu->aiomt_dip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int idx = iommu->aiomt_idx;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int i;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *path;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int pathfree;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "unmap_current_window";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!locked)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_enter(&amd_iommu_pgtable_lock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp path = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (path) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_pathname(rdip, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp pathfree = 1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp path = "<path-mem-alloc-failed>";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp pathfree = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ncookies == -1)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ncookies = ccount;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp for (i = 0; i < ncookies; i++) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_unmap_va(iommu, rdip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_cookie_addr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array[i].dmac_size,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_VMEM_MAP) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp break;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_cmd(iommu, AMD_IOMMU_CMD_COMPL_WAIT, NULL, 0, 0)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: AMD IOMMU completion wait failed for: %s",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (i != ncookies) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: idx=%d Cannot unmap cookie# %d "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %s", f, driver, instance, idx, i, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_SUCCESS;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpout:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (pathfree)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(path, MAXPATHLEN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (!locked)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp mutex_exit(&amd_iommu_pgtable_lock);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_bindhdl(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct ddi_dma_req *dmareq, ddi_dma_cookie_t *cookiep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t *ccountp)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int dma_error = DDI_DMA_NOMAPPING;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *path;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_impl_t *hp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_attr_t *attrp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int km_flags;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_bindhdl";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_error = iommulib_iommu_dma_bindhdl(dip, rdip, dma_handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dmareq, cookiep, ccountp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (dma_error != DDI_DMA_MAPPED && dma_error != DDI_DMA_PARTIAL_MAP)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (dma_error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp path = kmem_alloc(MAXPATHLEN, km_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (path) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) ddi_pathname(rdip, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_error = DDI_DMA_NORESOURCES;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto unbind;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s got cookie (%p), #cookies: %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, path,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void *)cookiep->dmac_cookie_addr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *ccountp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if ((error = iommulib_iommu_dma_get_cookies(dip, dma_handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &cookie_array, &ccount)) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %s", f, driver, instance, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_error = error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto unbind;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hp = (ddi_dma_impl_t *)dma_handle;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp attrp = &hp->dmai_attr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = map_current_window(iommu, rdip, attrp, dmareq,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array, ccount, km_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (error != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_error = error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto unbind;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if ((error = iommulib_iommu_dma_set_cookies(dip, dma_handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array, ccount)) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %s", f, driver, instance, path);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dma_error = error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto unbind;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *cookiep = cookie_array[0];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (amd_iommu_debug & AMD_IOMMU_DEBUG_BIND) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_NOTE, "%s: %s remapped cookie (%p), #cookies: %d",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, path,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void *)(uintptr_t)cookiep->dmac_cookie_addr,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *ccountp);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(path, MAXPATHLEN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(dma_error == DDI_DMA_MAPPED || dma_error == DDI_DMA_PARTIAL_MAP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (dma_error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpunbind:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(path, MAXPATHLEN);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (dma_error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_unbindhdl(iommulib_handle_t handle,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t dma_handle)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_unbindhdl";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_unbindhdl(dip, rdip, dma_handle)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: failed to unbindhdl for dip=%p",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: failed to unmap current window "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for dip=%p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_SUCCESS;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpout:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (cookie_array)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_sync(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle, off_t off,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp size_t len, uint_t cache_flags)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_sync";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ASSERT(cookie_array == NULL);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: Cannot get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: Cannot clear cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = iommulib_iommu_dma_sync(dip, rdip, dma_handle, off,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp len, cache_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: Cannot set cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp } else {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpout:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (cookie_array)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp/*ARGSUSED*/
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpstatic int
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_win(iommulib_handle_t handle, dev_info_t *dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp dev_info_t *rdip, ddi_dma_handle_t dma_handle, uint_t win,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp off_t *offp, size_t *lenp, ddi_dma_cookie_t *cookiep,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t *ccountp)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_t *iommu = iommulib_iommu_getdata(handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_cookie_t *cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint_t ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int km_flags;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_impl_t *hp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_dma_attr_t *attrp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp struct ddi_dma_req sdmareq = {0};
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp int instance = ddi_get_instance(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *driver = ddi_driver_name(rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp const char *f = "amd_iommu_win";
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp km_flags = iommulib_iommu_dma_get_sleep_flags(dip, dma_handle);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_clear_cookies(dip, dma_handle) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot clear cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_win(dip, rdip, dma_handle, win,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp offp, lenp, cookiep, ccountp) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: failed switch windows for dip=%p",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) unmap_current_window(iommu, rdip, cookie_array, ccount, -1, 0);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (cookie_array) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array = NULL;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount = 0;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_get_cookies(dip, dma_handle, &cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot get cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp hp = (ddi_dma_impl_t *)dma_handle;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp attrp = &hp->dmai_attr;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp sdmareq.dmar_flags = DDI_DMA_RDWR;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = map_current_window(iommu, rdip, attrp, &sdmareq,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cookie_array, ccount, km_flags);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (iommulib_iommu_dma_set_cookies(dip, dma_handle, cookie_array,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ccount) != DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp cmn_err(CE_WARN, "%s: %s%d: Cannot set cookies "
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp "for device %p", f, driver, instance, (void *)rdip);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp error = DDI_FAILURE;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp goto out;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *cookiep = cookie_array[0];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpout:
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (cookie_array)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp kmem_free(cookie_array, sizeof (ddi_dma_cookie_t) * ccount);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (error);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenamd_iommu_mapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden struct ddi_dma_req *dmareq, ddi_dma_obj_t *dmao)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_ENOTSUP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden/*ARGSUSED*/
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenstatic int
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Lindenamd_iommu_unmapobject(iommulib_handle_t handle, dev_info_t *dip,
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden dev_info_t *rdip, ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao)
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden{
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden return (DDI_ENOTSUP);
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden}
50200e773f0242e336d032a7b43485e1bcfc9bfeFrank Van Der Linden
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpuint64_t
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_reg_get64_workaround(uint64_t *regp, uint32_t bits)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp split_t s;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t *ptr32 = (uint32_t *)regp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint64_t *s64p = &(s.u64);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s.u32[0] = ptr32[0];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s.u32[1] = ptr32[1];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (AMD_IOMMU_REG_GET64_IMPL(s64p, bits));
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpuint64_t
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_reg_set64_workaround(uint64_t *regp, uint32_t bits, uint64_t value)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp split_t s;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint32_t *ptr32 = (uint32_t *)regp;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp uint64_t *s64p = &(s.u64);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s.u32[0] = ptr32[0];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp s.u32[1] = ptr32[1];
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp AMD_IOMMU_REG_SET64_IMPL(s64p, bits, value);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp *regp = s.u64;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp return (s.u64);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpvoid
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_read_boot_props(void)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *propval;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * if "amd-iommu = no/false" boot property is set,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * ignore AMD iommu
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_PROP_DONTPASS, "amd-iommu", &propval) == DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (strcmp(propval, "no") == 0 ||
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp strcmp(propval, "false") == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable = 1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_prop_free(propval);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp /*
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp * Copy the list of drivers for which IOMMU is disabled by user.
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp */
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_PROP_DONTPASS, "amd-iommu-disable-list", &propval)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp == DDI_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable_list = kmem_alloc(strlen(propval) + 1,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp KM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) strcpy(amd_iommu_disable_list, propval);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_prop_free(propval);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpvoid
7d87efa8fdfb9453670f2832df666fdae8291a84jmcpamd_iommu_lookup_conf_props(dev_info_t *dip)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp{
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp char *disable;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu", &disable)
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp == DDI_PROP_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (strcmp(disable, "no") == 0) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable = 1;
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_prop_free(disable);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp DDI_PROP_DONTPASS|DDI_PROP_NOTPROM, "amd-iommu-disable-list",
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp &disable) == DDI_PROP_SUCCESS) {
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp amd_iommu_disable_list = kmem_alloc(strlen(disable) + 1,
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp KM_SLEEP);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp (void) strcpy(amd_iommu_disable_list, disable);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp ddi_prop_free(disable);
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp }
7d87efa8fdfb9453670f2832df666fdae8291a84jmcp}