120906b23SVikram Hegde /* 220906b23SVikram Hegde * CDDL HEADER START 320906b23SVikram Hegde * 420906b23SVikram Hegde * The contents of this file are subject to the terms of the 520906b23SVikram Hegde * Common Development and Distribution License (the "License"). 620906b23SVikram Hegde * You may not use this file except in compliance with the License. 720906b23SVikram Hegde * 820906b23SVikram Hegde * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 920906b23SVikram Hegde * or http://www.opensolaris.org/os/licensing. 1020906b23SVikram Hegde * See the License for the specific language governing permissions 1120906b23SVikram Hegde * and limitations under the License. 1220906b23SVikram Hegde * 1320906b23SVikram Hegde * When distributing Covered Code, include this CDDL HEADER in each 1420906b23SVikram Hegde * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1520906b23SVikram Hegde * If applicable, add the following below this CDDL HEADER, with the 1620906b23SVikram Hegde * fields enclosed by brackets "[]" replaced with your own identifying 1720906b23SVikram Hegde * information: Portions Copyright [yyyy] [name of copyright owner] 1820906b23SVikram Hegde * 1920906b23SVikram Hegde * CDDL HEADER END 2020906b23SVikram Hegde */ 2120906b23SVikram Hegde /* 2250200e77SFrank Van Der Linden * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23*cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 2420906b23SVikram Hegde */ 2520906b23SVikram Hegde 2620906b23SVikram Hegde #pragma ident "@(#)iommulib.c 1.6 08/09/07 SMI" 2720906b23SVikram Hegde 2820906b23SVikram Hegde #include <sys/sunddi.h> 2920906b23SVikram Hegde #include <sys/sunndi.h> 3020906b23SVikram Hegde #include <sys/errno.h> 3120906b23SVikram Hegde #include <sys/modctl.h> 3220906b23SVikram Hegde #include <sys/iommulib.h> 3320906b23SVikram Hegde 3420906b23SVikram Hegde /* ******** Type definitions private to this file ********************** */ 3520906b23SVikram Hegde 3620906b23SVikram Hegde /* 1 per IOMMU unit. There may be more than one per dip */ 3720906b23SVikram Hegde typedef struct iommulib_unit { 3820906b23SVikram Hegde kmutex_t ilu_lock; 3920906b23SVikram Hegde uint64_t ilu_ref; 4020906b23SVikram Hegde uint32_t ilu_unitid; 4120906b23SVikram Hegde dev_info_t *ilu_dip; 4220906b23SVikram Hegde iommulib_ops_t *ilu_ops; 4320906b23SVikram Hegde void* ilu_data; 4420906b23SVikram Hegde struct iommulib_unit *ilu_next; 4520906b23SVikram Hegde struct iommulib_unit *ilu_prev; 4650200e77SFrank Van Der Linden iommulib_nexhandle_t ilu_nex; 4720906b23SVikram Hegde } iommulib_unit_t; 4820906b23SVikram Hegde 4920906b23SVikram Hegde typedef struct iommulib_nex { 5020906b23SVikram Hegde dev_info_t *nex_dip; 5120906b23SVikram Hegde iommulib_nexops_t nex_ops; 5220906b23SVikram Hegde struct iommulib_nex *nex_next; 5320906b23SVikram Hegde struct iommulib_nex *nex_prev; 5450200e77SFrank Van Der Linden uint_t nex_ref; 5520906b23SVikram Hegde } iommulib_nex_t; 5620906b23SVikram Hegde 5720906b23SVikram Hegde /* ********* Globals ************************ */ 5820906b23SVikram Hegde 5965cf7c95SVikram Hegde /* For IOMMU drivers */ 6065cf7c95SVikram Hegde smbios_hdl_t *iommulib_smbios; 6165cf7c95SVikram Hegde 6220906b23SVikram Hegde /* IOMMU side: Following data protected by lock */ 6320906b23SVikram Hegde static kmutex_t iommulib_lock; 6420906b23SVikram Hegde static iommulib_unit_t *iommulib_list; 6520906b23SVikram Hegde static uint64_t iommulib_unit_ids = 0; 6620906b23SVikram Hegde static uint64_t iommulib_num_units = 0; 6720906b23SVikram Hegde 6820906b23SVikram Hegde /* rootnex side data */ 6920906b23SVikram Hegde 7020906b23SVikram Hegde static kmutex_t iommulib_nexus_lock; 7120906b23SVikram Hegde static iommulib_nex_t *iommulib_nexus_list; 7220906b23SVikram Hegde 7320906b23SVikram Hegde /* can be set atomically without lock */ 7420906b23SVikram Hegde static volatile uint32_t iommulib_fini; 7520906b23SVikram Hegde 7620906b23SVikram Hegde /* debug flag */ 7720906b23SVikram Hegde static int iommulib_debug; 7820906b23SVikram Hegde 7920906b23SVikram Hegde /* 8020906b23SVikram Hegde * Module linkage information for the kernel. 8120906b23SVikram Hegde */ 8220906b23SVikram Hegde static struct modlmisc modlmisc = { 8320906b23SVikram Hegde &mod_miscops, "IOMMU library module" 8420906b23SVikram Hegde }; 8520906b23SVikram Hegde 8620906b23SVikram Hegde static struct modlinkage modlinkage = { 8720906b23SVikram Hegde MODREV_1, (void *)&modlmisc, NULL 8820906b23SVikram Hegde }; 8920906b23SVikram Hegde 9020906b23SVikram Hegde int 9120906b23SVikram Hegde _init(void) 9220906b23SVikram Hegde { 9320906b23SVikram Hegde return (mod_install(&modlinkage)); 9420906b23SVikram Hegde } 9520906b23SVikram Hegde 9620906b23SVikram Hegde int 9720906b23SVikram Hegde _fini(void) 9820906b23SVikram Hegde { 9920906b23SVikram Hegde mutex_enter(&iommulib_lock); 10020906b23SVikram Hegde if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 10120906b23SVikram Hegde mutex_exit(&iommulib_lock); 10220906b23SVikram Hegde return (EBUSY); 10320906b23SVikram Hegde } 10420906b23SVikram Hegde iommulib_fini = 1; 10520906b23SVikram Hegde 10620906b23SVikram Hegde mutex_exit(&iommulib_lock); 10720906b23SVikram Hegde return (mod_remove(&modlinkage)); 10820906b23SVikram Hegde } 10920906b23SVikram Hegde 11020906b23SVikram Hegde int 11120906b23SVikram Hegde _info(struct modinfo *modinfop) 11220906b23SVikram Hegde { 11320906b23SVikram Hegde return (mod_info(&modlinkage, modinfop)); 11420906b23SVikram Hegde } 11520906b23SVikram Hegde 11620906b23SVikram Hegde /* 11720906b23SVikram Hegde * Routines with iommulib_iommu_* are invoked from the 11820906b23SVikram Hegde * IOMMU driver. 11920906b23SVikram Hegde * Routines with iommulib_nex* are invoked from the 12020906b23SVikram Hegde * nexus driver (typically rootnex) 12120906b23SVikram Hegde */ 12220906b23SVikram Hegde 12320906b23SVikram Hegde int 12420906b23SVikram Hegde iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 12520906b23SVikram Hegde iommulib_nexhandle_t *handle) 12620906b23SVikram Hegde { 12720906b23SVikram Hegde iommulib_nex_t *nexp; 12820906b23SVikram Hegde int instance = ddi_get_instance(dip); 12920906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 13020906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 13120906b23SVikram Hegde const char *f = "iommulib_nexus_register"; 13220906b23SVikram Hegde 13320906b23SVikram Hegde ASSERT(nexops); 13420906b23SVikram Hegde ASSERT(handle); 13520906b23SVikram Hegde 13620906b23SVikram Hegde *handle = NULL; 13720906b23SVikram Hegde 13820906b23SVikram Hegde /* 13920906b23SVikram Hegde * Root node is never busy held 14020906b23SVikram Hegde */ 14120906b23SVikram Hegde if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 14220906b23SVikram Hegde !DEVI_BUSY_OWNED(pdip))) { 14320906b23SVikram Hegde cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 14420906b23SVikram Hegde "or busy held for nexops vector (%p). Failing registration", 14520906b23SVikram Hegde f, (void *)nexops); 14620906b23SVikram Hegde return (DDI_FAILURE); 14720906b23SVikram Hegde } 14820906b23SVikram Hegde 14920906b23SVikram Hegde if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 15020906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 15120906b23SVikram Hegde "in nexops vector (%p). Failing NEXUS registration", 15220906b23SVikram Hegde f, driver, instance, (void *)nexops); 15320906b23SVikram Hegde return (DDI_FAILURE); 15420906b23SVikram Hegde } 15520906b23SVikram Hegde 15620906b23SVikram Hegde ASSERT(nexops->nops_data == NULL); 15720906b23SVikram Hegde 15820906b23SVikram Hegde if (nexops->nops_id == NULL) { 15920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 16020906b23SVikram Hegde "Failing registration for nexops vector: %p", 16120906b23SVikram Hegde f, driver, instance, (void *)nexops); 16220906b23SVikram Hegde return (DDI_FAILURE); 16320906b23SVikram Hegde } 16420906b23SVikram Hegde 16520906b23SVikram Hegde if (nexops->nops_dma_allochdl == NULL) { 16620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 16720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 16820906b23SVikram Hegde driver, instance, (void *)nexops); 16920906b23SVikram Hegde return (DDI_FAILURE); 17020906b23SVikram Hegde } 17120906b23SVikram Hegde 17220906b23SVikram Hegde if (nexops->nops_dma_freehdl == NULL) { 17320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 17420906b23SVikram Hegde "Failing registration for ops vector: %p", f, 17520906b23SVikram Hegde driver, instance, (void *)nexops); 17620906b23SVikram Hegde return (DDI_FAILURE); 17720906b23SVikram Hegde } 17820906b23SVikram Hegde 17920906b23SVikram Hegde if (nexops->nops_dma_bindhdl == NULL) { 18020906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 18120906b23SVikram Hegde "Failing registration for ops vector: %p", f, 18220906b23SVikram Hegde driver, instance, (void *)nexops); 18320906b23SVikram Hegde return (DDI_FAILURE); 18420906b23SVikram Hegde } 18520906b23SVikram Hegde 18620906b23SVikram Hegde if (nexops->nops_dma_sync == NULL) { 18720906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 18820906b23SVikram Hegde "Failing registration for ops vector: %p", f, 18920906b23SVikram Hegde driver, instance, (void *)nexops); 19020906b23SVikram Hegde return (DDI_FAILURE); 19120906b23SVikram Hegde } 19220906b23SVikram Hegde 19320906b23SVikram Hegde if (nexops->nops_dma_reset_cookies == NULL) { 19420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. " 19520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 19620906b23SVikram Hegde driver, instance, (void *)nexops); 19720906b23SVikram Hegde return (DDI_FAILURE); 19820906b23SVikram Hegde } 19920906b23SVikram Hegde 20020906b23SVikram Hegde if (nexops->nops_dma_get_cookies == NULL) { 20120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 20220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 20320906b23SVikram Hegde driver, instance, (void *)nexops); 20420906b23SVikram Hegde return (DDI_FAILURE); 20520906b23SVikram Hegde } 20620906b23SVikram Hegde 20794f1124eSVikram Hegde if (nexops->nops_dma_set_cookies == NULL) { 20894f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_set_cookies op. " 20994f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 21094f1124eSVikram Hegde driver, instance, (void *)nexops); 21194f1124eSVikram Hegde return (DDI_FAILURE); 21294f1124eSVikram Hegde } 21394f1124eSVikram Hegde 21494f1124eSVikram Hegde if (nexops->nops_dma_clear_cookies == NULL) { 21594f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_clear_cookies op. " 21694f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 21794f1124eSVikram Hegde driver, instance, (void *)nexops); 21894f1124eSVikram Hegde return (DDI_FAILURE); 21994f1124eSVikram Hegde } 22094f1124eSVikram Hegde 22194f1124eSVikram Hegde if (nexops->nops_dma_get_sleep_flags == NULL) { 22294f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_sleep_flags op. " 22394f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 22494f1124eSVikram Hegde driver, instance, (void *)nexops); 22594f1124eSVikram Hegde return (DDI_FAILURE); 22694f1124eSVikram Hegde } 22794f1124eSVikram Hegde 22820906b23SVikram Hegde if (nexops->nops_dma_win == NULL) { 22920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 23020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 23120906b23SVikram Hegde driver, instance, (void *)nexops); 23220906b23SVikram Hegde return (DDI_FAILURE); 23320906b23SVikram Hegde } 23420906b23SVikram Hegde 23550200e77SFrank Van Der Linden if (nexops->nops_dmahdl_setprivate == NULL) { 23650200e77SFrank Van Der Linden cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_setprivate op. " 23750200e77SFrank Van Der Linden "Failing registration for ops vector: %p", f, 23850200e77SFrank Van Der Linden driver, instance, (void *)nexops); 23950200e77SFrank Van Der Linden return (DDI_FAILURE); 24050200e77SFrank Van Der Linden } 24150200e77SFrank Van Der Linden 24250200e77SFrank Van Der Linden if (nexops->nops_dmahdl_getprivate == NULL) { 24350200e77SFrank Van Der Linden cmn_err(CE_WARN, "%s: %s%d: NULL nops_dmahdl_getprivate op. " 24450200e77SFrank Van Der Linden "Failing registration for ops vector: %p", f, 24550200e77SFrank Van Der Linden driver, instance, (void *)nexops); 24650200e77SFrank Van Der Linden return (DDI_FAILURE); 24750200e77SFrank Van Der Linden } 24850200e77SFrank Van Der Linden 24920906b23SVikram Hegde nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 25020906b23SVikram Hegde 25120906b23SVikram Hegde mutex_enter(&iommulib_lock); 25220906b23SVikram Hegde if (iommulib_fini == 1) { 25320906b23SVikram Hegde mutex_exit(&iommulib_lock); 25420906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 25520906b23SVikram Hegde "Failing NEXUS register.", f); 25620906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 25720906b23SVikram Hegde return (DDI_FAILURE); 25820906b23SVikram Hegde } 25920906b23SVikram Hegde 26020906b23SVikram Hegde /* 26120906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 26220906b23SVikram Hegde * nexus struct 26320906b23SVikram Hegde */ 26420906b23SVikram Hegde ndi_hold_devi(dip); 26520906b23SVikram Hegde nexp->nex_dip = dip; 26620906b23SVikram Hegde nexp->nex_ops = *nexops; 26720906b23SVikram Hegde 26820906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 26920906b23SVikram Hegde nexp->nex_next = iommulib_nexus_list; 27020906b23SVikram Hegde iommulib_nexus_list = nexp; 27120906b23SVikram Hegde nexp->nex_prev = NULL; 27220906b23SVikram Hegde 27320906b23SVikram Hegde if (nexp->nex_next != NULL) 27420906b23SVikram Hegde nexp->nex_next->nex_prev = nexp; 27520906b23SVikram Hegde 27650200e77SFrank Van Der Linden nexp->nex_ref = 0; 27750200e77SFrank Van Der Linden 27850200e77SFrank Van Der Linden /* 27950200e77SFrank Van Der Linden * The nexus device won't be controlled by an IOMMU. 28050200e77SFrank Van Der Linden */ 28150200e77SFrank Van Der Linden DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 28250200e77SFrank Van Der Linden 28350200e77SFrank Van Der Linden DEVI(dip)->devi_iommulib_nex_handle = nexp; 28450200e77SFrank Van Der Linden 28520906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 28620906b23SVikram Hegde mutex_exit(&iommulib_lock); 28720906b23SVikram Hegde 28820906b23SVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 28920906b23SVikram Hegde "nexops=%p", f, driver, instance, ddi_node_name(dip), 29020906b23SVikram Hegde (void *)nexops); 29120906b23SVikram Hegde 29220906b23SVikram Hegde *handle = nexp; 29320906b23SVikram Hegde 29420906b23SVikram Hegde return (DDI_SUCCESS); 29520906b23SVikram Hegde } 29620906b23SVikram Hegde 29720906b23SVikram Hegde int 29820906b23SVikram Hegde iommulib_nexus_unregister(iommulib_nexhandle_t handle) 29920906b23SVikram Hegde { 30020906b23SVikram Hegde dev_info_t *dip; 30120906b23SVikram Hegde int instance; 30220906b23SVikram Hegde const char *driver; 30320906b23SVikram Hegde iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 30420906b23SVikram Hegde const char *f = "iommulib_nexus_unregister"; 30520906b23SVikram Hegde 30620906b23SVikram Hegde ASSERT(nexp); 30720906b23SVikram Hegde 30850200e77SFrank Van Der Linden if (nexp->nex_ref != 0) 30950200e77SFrank Van Der Linden return (DDI_FAILURE); 31050200e77SFrank Van Der Linden 31120906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 31220906b23SVikram Hegde 31320906b23SVikram Hegde dip = nexp->nex_dip; 31420906b23SVikram Hegde driver = ddi_driver_name(dip); 31520906b23SVikram Hegde instance = ddi_get_instance(dip); 31620906b23SVikram Hegde 31720906b23SVikram Hegde /* A future enhancement would be to add ref-counts */ 31820906b23SVikram Hegde 31920906b23SVikram Hegde if (nexp->nex_prev == NULL) { 32020906b23SVikram Hegde iommulib_nexus_list = nexp->nex_next; 32120906b23SVikram Hegde } else { 32220906b23SVikram Hegde nexp->nex_prev->nex_next = nexp->nex_next; 32320906b23SVikram Hegde } 32420906b23SVikram Hegde 32520906b23SVikram Hegde if (nexp->nex_next != NULL) 32620906b23SVikram Hegde nexp->nex_next->nex_prev = nexp->nex_prev; 32720906b23SVikram Hegde 32820906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 32920906b23SVikram Hegde 33020906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 33120906b23SVikram Hegde 33294f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: NEXUS (%s) handle successfully " 33320906b23SVikram Hegde "unregistered from IOMMULIB", f, driver, instance, 33420906b23SVikram Hegde ddi_node_name(dip)); 33520906b23SVikram Hegde 33620906b23SVikram Hegde ndi_rele_devi(dip); 33720906b23SVikram Hegde 33820906b23SVikram Hegde return (DDI_SUCCESS); 33920906b23SVikram Hegde } 34020906b23SVikram Hegde 34120906b23SVikram Hegde int 34220906b23SVikram Hegde iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 34320906b23SVikram Hegde iommulib_handle_t *handle) 34420906b23SVikram Hegde { 34520906b23SVikram Hegde const char *vendor; 34620906b23SVikram Hegde iommulib_unit_t *unitp; 34720906b23SVikram Hegde int instance = ddi_get_instance(dip); 34820906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 34920906b23SVikram Hegde const char *f = "iommulib_register"; 35020906b23SVikram Hegde 35120906b23SVikram Hegde ASSERT(ops); 35220906b23SVikram Hegde ASSERT(handle); 35320906b23SVikram Hegde 35420906b23SVikram Hegde if (ops->ilops_vers != IOMMU_OPS_VERSION) { 35520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 35620906b23SVikram Hegde "in ops vector (%p). Failing registration", f, driver, 35720906b23SVikram Hegde instance, (void *)ops); 35820906b23SVikram Hegde return (DDI_FAILURE); 35920906b23SVikram Hegde } 36020906b23SVikram Hegde 36120906b23SVikram Hegde switch (ops->ilops_vendor) { 36220906b23SVikram Hegde case AMD_IOMMU: 36320906b23SVikram Hegde vendor = "AMD"; 36420906b23SVikram Hegde break; 36520906b23SVikram Hegde case INTEL_IOMMU: 36620906b23SVikram Hegde vendor = "Intel"; 36720906b23SVikram Hegde break; 36820906b23SVikram Hegde case INVALID_VENDOR: 36920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 37020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 37120906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 37220906b23SVikram Hegde return (DDI_FAILURE); 37320906b23SVikram Hegde default: 37420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 37520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 37620906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 37720906b23SVikram Hegde return (DDI_FAILURE); 37820906b23SVikram Hegde } 37920906b23SVikram Hegde 38094f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Detected IOMMU registration from vendor" 38194f1124eSVikram Hegde " %s", f, driver, instance, vendor); 38220906b23SVikram Hegde 38320906b23SVikram Hegde if (ops->ilops_data == NULL) { 38420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 38520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 38620906b23SVikram Hegde driver, instance, (void *)ops); 38720906b23SVikram Hegde return (DDI_FAILURE); 38820906b23SVikram Hegde } 38920906b23SVikram Hegde 39020906b23SVikram Hegde if (ops->ilops_id == NULL) { 39120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 39220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 39320906b23SVikram Hegde driver, instance, (void *)ops); 39420906b23SVikram Hegde return (DDI_FAILURE); 39520906b23SVikram Hegde } 39620906b23SVikram Hegde 39720906b23SVikram Hegde if (ops->ilops_probe == NULL) { 39820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL probe op. " 39920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 40020906b23SVikram Hegde driver, instance, (void *)ops); 40120906b23SVikram Hegde return (DDI_FAILURE); 40220906b23SVikram Hegde } 40320906b23SVikram Hegde 40420906b23SVikram Hegde if (ops->ilops_dma_allochdl == NULL) { 40520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. " 40620906b23SVikram Hegde "Failing registration for ops vector: %p", f, 40720906b23SVikram Hegde driver, instance, (void *)ops); 40820906b23SVikram Hegde return (DDI_FAILURE); 40920906b23SVikram Hegde } 41020906b23SVikram Hegde 41120906b23SVikram Hegde if (ops->ilops_dma_freehdl == NULL) { 41220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. " 41320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 41420906b23SVikram Hegde driver, instance, (void *)ops); 41520906b23SVikram Hegde return (DDI_FAILURE); 41620906b23SVikram Hegde } 41720906b23SVikram Hegde 41820906b23SVikram Hegde if (ops->ilops_dma_bindhdl == NULL) { 41920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. " 42020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 42120906b23SVikram Hegde driver, instance, (void *)ops); 42220906b23SVikram Hegde return (DDI_FAILURE); 42320906b23SVikram Hegde } 42420906b23SVikram Hegde 42520906b23SVikram Hegde if (ops->ilops_dma_sync == NULL) { 42620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 42720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 42820906b23SVikram Hegde driver, instance, (void *)ops); 42920906b23SVikram Hegde return (DDI_FAILURE); 43020906b23SVikram Hegde } 43120906b23SVikram Hegde 43220906b23SVikram Hegde if (ops->ilops_dma_win == NULL) { 43320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 43420906b23SVikram Hegde "Failing registration for ops vector: %p", f, 43520906b23SVikram Hegde driver, instance, (void *)ops); 43620906b23SVikram Hegde return (DDI_FAILURE); 43720906b23SVikram Hegde } 43820906b23SVikram Hegde 43920906b23SVikram Hegde unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 44020906b23SVikram Hegde mutex_enter(&iommulib_lock); 44120906b23SVikram Hegde if (iommulib_fini == 1) { 44220906b23SVikram Hegde mutex_exit(&iommulib_lock); 44320906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 44420906b23SVikram Hegde f); 44520906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 44620906b23SVikram Hegde return (DDI_FAILURE); 44720906b23SVikram Hegde } 44820906b23SVikram Hegde 44920906b23SVikram Hegde /* 45020906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 45120906b23SVikram Hegde * IOMMU unit 45220906b23SVikram Hegde */ 45320906b23SVikram Hegde mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 45420906b23SVikram Hegde 45520906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 45620906b23SVikram Hegde unitp->ilu_unitid = ++iommulib_unit_ids; 45720906b23SVikram Hegde unitp->ilu_ref = 0; 45820906b23SVikram Hegde ndi_hold_devi(dip); 45920906b23SVikram Hegde unitp->ilu_dip = dip; 46020906b23SVikram Hegde unitp->ilu_ops = ops; 46120906b23SVikram Hegde unitp->ilu_data = ops->ilops_data; 46220906b23SVikram Hegde 46320906b23SVikram Hegde unitp->ilu_next = iommulib_list; 46420906b23SVikram Hegde iommulib_list = unitp; 46594f1124eSVikram Hegde unitp->ilu_prev = NULL; 46694f1124eSVikram Hegde if (unitp->ilu_next) 46794f1124eSVikram Hegde unitp->ilu_next->ilu_prev = unitp; 46820906b23SVikram Hegde 46950200e77SFrank Van Der Linden /* 47050200e77SFrank Van Der Linden * The IOMMU device itself is not controlled by an IOMMU. 47150200e77SFrank Van Der Linden */ 47250200e77SFrank Van Der Linden DEVI(dip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 47350200e77SFrank Van Der Linden 47420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 47520906b23SVikram Hegde 47620906b23SVikram Hegde iommulib_num_units++; 47720906b23SVikram Hegde 47820906b23SVikram Hegde *handle = unitp; 47920906b23SVikram Hegde 48020906b23SVikram Hegde mutex_exit(&iommulib_lock); 48120906b23SVikram Hegde 48294f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered IOMMU unit " 48320906b23SVikram Hegde "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 48420906b23SVikram Hegde f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 48520906b23SVikram Hegde unitp->ilu_unitid); 48620906b23SVikram Hegde 48720906b23SVikram Hegde return (DDI_SUCCESS); 48820906b23SVikram Hegde } 48920906b23SVikram Hegde 49020906b23SVikram Hegde int 49120906b23SVikram Hegde iommulib_iommu_unregister(iommulib_handle_t handle) 49220906b23SVikram Hegde { 49320906b23SVikram Hegde uint32_t unitid; 49420906b23SVikram Hegde dev_info_t *dip; 49520906b23SVikram Hegde int instance; 49620906b23SVikram Hegde const char *driver; 49720906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 49820906b23SVikram Hegde const char *f = "iommulib_unregister"; 49920906b23SVikram Hegde 50020906b23SVikram Hegde ASSERT(unitp); 50120906b23SVikram Hegde 50220906b23SVikram Hegde mutex_enter(&iommulib_lock); 50320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 50420906b23SVikram Hegde 50520906b23SVikram Hegde unitid = unitp->ilu_unitid; 50620906b23SVikram Hegde dip = unitp->ilu_dip; 50720906b23SVikram Hegde driver = ddi_driver_name(dip); 50820906b23SVikram Hegde instance = ddi_get_instance(dip); 50920906b23SVikram Hegde 51020906b23SVikram Hegde if (unitp->ilu_ref != 0) { 51120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 51220906b23SVikram Hegde mutex_exit(&iommulib_lock); 51320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 51420906b23SVikram Hegde "unregister IOMMULIB unitid %u", 51520906b23SVikram Hegde f, driver, instance, unitid); 51620906b23SVikram Hegde return (DDI_FAILURE); 51720906b23SVikram Hegde } 51820906b23SVikram Hegde unitp->ilu_unitid = 0; 51920906b23SVikram Hegde ASSERT(unitp->ilu_ref == 0); 52020906b23SVikram Hegde 52120906b23SVikram Hegde if (unitp->ilu_prev == NULL) { 52220906b23SVikram Hegde iommulib_list = unitp->ilu_next; 52320906b23SVikram Hegde unitp->ilu_next->ilu_prev = NULL; 52420906b23SVikram Hegde } else { 52520906b23SVikram Hegde unitp->ilu_prev->ilu_next = unitp->ilu_next; 52620906b23SVikram Hegde unitp->ilu_next->ilu_prev = unitp->ilu_prev; 52720906b23SVikram Hegde } 52820906b23SVikram Hegde 52920906b23SVikram Hegde iommulib_num_units--; 53020906b23SVikram Hegde 53120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 53220906b23SVikram Hegde 53320906b23SVikram Hegde mutex_destroy(&unitp->ilu_lock); 53420906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 53520906b23SVikram Hegde 53620906b23SVikram Hegde mutex_exit(&iommulib_lock); 53720906b23SVikram Hegde 53820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 53920906b23SVikram Hegde "unregistered", f, driver, instance, unitid); 54020906b23SVikram Hegde 54120906b23SVikram Hegde ndi_rele_devi(dip); 54220906b23SVikram Hegde 54320906b23SVikram Hegde return (DDI_SUCCESS); 54420906b23SVikram Hegde } 54520906b23SVikram Hegde 54620906b23SVikram Hegde int 54750200e77SFrank Van Der Linden iommulib_nex_open(dev_info_t *dip, dev_info_t *rdip) 54820906b23SVikram Hegde { 54920906b23SVikram Hegde iommulib_unit_t *unitp; 55020906b23SVikram Hegde int instance = ddi_get_instance(rdip); 55120906b23SVikram Hegde const char *driver = ddi_driver_name(rdip); 55220906b23SVikram Hegde const char *f = "iommulib_nex_open"; 55320906b23SVikram Hegde 55450200e77SFrank Van Der Linden ASSERT(DEVI(dip)->devi_iommulib_nex_handle != NULL); 55594f1124eSVikram Hegde ASSERT(DEVI(rdip)->devi_iommulib_handle == NULL); 55620906b23SVikram Hegde 55720906b23SVikram Hegde /* prevent use of IOMMU for AMD IOMMU's DMA */ 55820906b23SVikram Hegde if (strcmp(driver, "amd_iommu") == 0) { 55950200e77SFrank Van Der Linden DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 56050200e77SFrank Van Der Linden return (DDI_ENOTSUP); 56120906b23SVikram Hegde } 56220906b23SVikram Hegde 56320906b23SVikram Hegde /* 56494f1124eSVikram Hegde * Use the probe entry point to determine in a hardware specific 56594f1124eSVikram Hegde * manner whether this dip is controlled by an IOMMU. If yes, 56694f1124eSVikram Hegde * return the handle corresponding to the IOMMU unit. 56720906b23SVikram Hegde */ 56820906b23SVikram Hegde 56920906b23SVikram Hegde mutex_enter(&iommulib_lock); 57020906b23SVikram Hegde for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 57194f1124eSVikram Hegde if (unitp->ilu_ops->ilops_probe(unitp, rdip) == DDI_SUCCESS) 57220906b23SVikram Hegde break; 57320906b23SVikram Hegde } 57420906b23SVikram Hegde 57520906b23SVikram Hegde if (unitp == NULL) { 57620906b23SVikram Hegde mutex_exit(&iommulib_lock); 57720906b23SVikram Hegde if (iommulib_debug) { 578d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 57920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 58020906b23SVikram Hegde "controlled by an IOMMU: path=%s", f, driver, 58120906b23SVikram Hegde instance, (void *)rdip, ddi_pathname(rdip, buf)); 582d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 58320906b23SVikram Hegde } 58450200e77SFrank Van Der Linden DEVI(rdip)->devi_iommulib_handle = IOMMU_HANDLE_UNUSED; 58550200e77SFrank Van Der Linden return (DDI_ENOTSUP); 58620906b23SVikram Hegde } 58720906b23SVikram Hegde 58820906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 58950200e77SFrank Van Der Linden unitp->ilu_nex = DEVI(dip)->devi_iommulib_nex_handle; 59020906b23SVikram Hegde unitp->ilu_ref++; 59150200e77SFrank Van Der Linden DEVI(rdip)->devi_iommulib_handle = unitp; 59220906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 59320906b23SVikram Hegde mutex_exit(&iommulib_lock); 59420906b23SVikram Hegde 59550200e77SFrank Van Der Linden atomic_inc_uint(&DEVI(dip)->devi_iommulib_nex_handle->nex_ref); 59620906b23SVikram Hegde 59720906b23SVikram Hegde return (DDI_SUCCESS); 59820906b23SVikram Hegde } 59920906b23SVikram Hegde 60020906b23SVikram Hegde void 60120906b23SVikram Hegde iommulib_nex_close(dev_info_t *rdip) 60220906b23SVikram Hegde { 60320906b23SVikram Hegde iommulib_unit_t *unitp; 60420906b23SVikram Hegde const char *driver; 60520906b23SVikram Hegde int instance; 60620906b23SVikram Hegde uint32_t unitid; 60750200e77SFrank Van Der Linden iommulib_nex_t *nexp; 60820906b23SVikram Hegde const char *f = "iommulib_nex_close"; 60920906b23SVikram Hegde 61050200e77SFrank Van Der Linden ASSERT(IOMMU_USED(rdip)); 61120906b23SVikram Hegde 61250200e77SFrank Van Der Linden unitp = DEVI(rdip)->devi_iommulib_handle; 61320906b23SVikram Hegde 61420906b23SVikram Hegde mutex_enter(&iommulib_lock); 61520906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 61650200e77SFrank Van Der Linden 61750200e77SFrank Van Der Linden nexp = (iommulib_nex_t *)unitp->ilu_nex; 61850200e77SFrank Van Der Linden DEVI(rdip)->devi_iommulib_handle = NULL; 61950200e77SFrank Van Der Linden 62020906b23SVikram Hegde unitid = unitp->ilu_unitid; 62120906b23SVikram Hegde driver = ddi_driver_name(unitp->ilu_dip); 62220906b23SVikram Hegde instance = ddi_get_instance(unitp->ilu_dip); 62350200e77SFrank Van Der Linden 62420906b23SVikram Hegde unitp->ilu_ref--; 62520906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 62620906b23SVikram Hegde mutex_exit(&iommulib_lock); 62720906b23SVikram Hegde 62850200e77SFrank Van Der Linden atomic_dec_uint(&nexp->nex_ref); 62950200e77SFrank Van Der Linden 63020906b23SVikram Hegde if (iommulib_debug) { 631d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 632d8fc7d07SVikram Hegde (void) ddi_pathname(rdip, buf); 63320906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 63420906b23SVikram Hegde "unitid=%u rdip path = %s", f, driver, instance, 63520906b23SVikram Hegde (void *)rdip, unitid, buf); 636d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 63720906b23SVikram Hegde } 63820906b23SVikram Hegde } 63920906b23SVikram Hegde 64020906b23SVikram Hegde int 64120906b23SVikram Hegde iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 64220906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 64320906b23SVikram Hegde caddr_t arg, ddi_dma_handle_t *dma_handlep) 64420906b23SVikram Hegde { 64520906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 64620906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 64720906b23SVikram Hegde 64820906b23SVikram Hegde ASSERT(unitp); 64920906b23SVikram Hegde 65020906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 65120906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 65220906b23SVikram Hegde attr, waitfp, arg, dma_handlep)); 65320906b23SVikram Hegde } 65420906b23SVikram Hegde 65520906b23SVikram Hegde int 65620906b23SVikram Hegde iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 65720906b23SVikram Hegde ddi_dma_handle_t dma_handle) 65820906b23SVikram Hegde { 65920906b23SVikram Hegde int error; 66020906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 66120906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 66220906b23SVikram Hegde 66320906b23SVikram Hegde ASSERT(unitp); 66420906b23SVikram Hegde 66520906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 66620906b23SVikram Hegde error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 66720906b23SVikram Hegde rdip, dma_handle); 66820906b23SVikram Hegde 66920906b23SVikram Hegde return (error); 67020906b23SVikram Hegde } 67120906b23SVikram Hegde 67220906b23SVikram Hegde int 67320906b23SVikram Hegde iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 67420906b23SVikram Hegde ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 67520906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 67620906b23SVikram Hegde { 67720906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 67820906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 67920906b23SVikram Hegde 68020906b23SVikram Hegde ASSERT(unitp); 68120906b23SVikram Hegde 68220906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 68320906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 68420906b23SVikram Hegde dmareq, cookiep, ccountp)); 68520906b23SVikram Hegde } 68620906b23SVikram Hegde 68720906b23SVikram Hegde int 68820906b23SVikram Hegde iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 68920906b23SVikram Hegde ddi_dma_handle_t dma_handle) 69020906b23SVikram Hegde { 69120906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 69220906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 69320906b23SVikram Hegde 69420906b23SVikram Hegde ASSERT(unitp); 69520906b23SVikram Hegde 69620906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 69720906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 69820906b23SVikram Hegde dma_handle)); 69920906b23SVikram Hegde } 70020906b23SVikram Hegde 70120906b23SVikram Hegde int 70220906b23SVikram Hegde iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 70320906b23SVikram Hegde ddi_dma_handle_t dma_handle, off_t off, size_t len, 70420906b23SVikram Hegde uint_t cache_flags) 70520906b23SVikram Hegde { 70620906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 70720906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 70820906b23SVikram Hegde 70920906b23SVikram Hegde ASSERT(unitp); 71020906b23SVikram Hegde 71120906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 71220906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 71320906b23SVikram Hegde off, len, cache_flags)); 71420906b23SVikram Hegde } 71520906b23SVikram Hegde 71620906b23SVikram Hegde int 71720906b23SVikram Hegde iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 71820906b23SVikram Hegde ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 71920906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 72020906b23SVikram Hegde { 72120906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 72220906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 72320906b23SVikram Hegde 72420906b23SVikram Hegde ASSERT(unitp); 72520906b23SVikram Hegde 72620906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 72720906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 72820906b23SVikram Hegde win, offp, lenp, cookiep, ccountp)); 72920906b23SVikram Hegde } 73020906b23SVikram Hegde 73150200e77SFrank Van Der Linden int 73250200e77SFrank Van Der Linden iommulib_nexdma_mapobject(dev_info_t *dip, dev_info_t *rdip, 73350200e77SFrank Van Der Linden ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 73450200e77SFrank Van Der Linden ddi_dma_obj_t *dmao) 73550200e77SFrank Van Der Linden { 73650200e77SFrank Van Der Linden iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 73750200e77SFrank Van Der Linden iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 73850200e77SFrank Van Der Linden 73950200e77SFrank Van Der Linden return (unitp->ilu_ops->ilops_dma_mapobject(handle, dip, rdip, 74050200e77SFrank Van Der Linden dma_handle, dmareq, dmao)); 74150200e77SFrank Van Der Linden } 74250200e77SFrank Van Der Linden 74350200e77SFrank Van Der Linden int 74450200e77SFrank Van Der Linden iommulib_nexdma_unmapobject(dev_info_t *dip, dev_info_t *rdip, 74550200e77SFrank Van Der Linden ddi_dma_handle_t dma_handle, ddi_dma_obj_t *dmao) 74650200e77SFrank Van Der Linden { 74750200e77SFrank Van Der Linden iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 74850200e77SFrank Van Der Linden iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 74950200e77SFrank Van Der Linden 75050200e77SFrank Van Der Linden return (unitp->ilu_ops->ilops_dma_unmapobject(handle, dip, rdip, 75150200e77SFrank Van Der Linden dma_handle, dmao)); 75250200e77SFrank Van Der Linden } 75350200e77SFrank Van Der Linden 75420906b23SVikram Hegde /* Utility routines invoked by IOMMU drivers */ 75520906b23SVikram Hegde int 75620906b23SVikram Hegde iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 75720906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 75820906b23SVikram Hegde ddi_dma_handle_t *handlep) 75920906b23SVikram Hegde { 76050200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 76150200e77SFrank Van Der Linden 76250200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 76320906b23SVikram Hegde return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 76420906b23SVikram Hegde handlep)); 76520906b23SVikram Hegde } 76620906b23SVikram Hegde 76720906b23SVikram Hegde int 76820906b23SVikram Hegde iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 76920906b23SVikram Hegde ddi_dma_handle_t handle) 77020906b23SVikram Hegde { 77150200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 77250200e77SFrank Van Der Linden 77350200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 77450200e77SFrank Van Der Linden ASSERT(nexops); 77520906b23SVikram Hegde return (nexops->nops_dma_freehdl(dip, rdip, handle)); 77620906b23SVikram Hegde } 77720906b23SVikram Hegde 77820906b23SVikram Hegde int 77920906b23SVikram Hegde iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 78020906b23SVikram Hegde ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 78120906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 78220906b23SVikram Hegde { 78350200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 78450200e77SFrank Van Der Linden 78550200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 78620906b23SVikram Hegde return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 78720906b23SVikram Hegde cookiep, ccountp)); 78820906b23SVikram Hegde } 78920906b23SVikram Hegde 79020906b23SVikram Hegde int 79120906b23SVikram Hegde iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 79220906b23SVikram Hegde ddi_dma_handle_t handle) 79320906b23SVikram Hegde { 79450200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 79550200e77SFrank Van Der Linden 79650200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 79720906b23SVikram Hegde return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 79820906b23SVikram Hegde } 79920906b23SVikram Hegde 80020906b23SVikram Hegde void 80120906b23SVikram Hegde iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 80220906b23SVikram Hegde { 80350200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 80450200e77SFrank Van Der Linden 80550200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 80620906b23SVikram Hegde nexops->nops_dma_reset_cookies(dip, handle); 80720906b23SVikram Hegde } 80820906b23SVikram Hegde 80920906b23SVikram Hegde int 81020906b23SVikram Hegde iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 81194f1124eSVikram Hegde ddi_dma_cookie_t **cookiepp, uint_t *ccountp) 81220906b23SVikram Hegde { 81350200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 81450200e77SFrank Van Der Linden 81550200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 81694f1124eSVikram Hegde return (nexops->nops_dma_get_cookies(dip, handle, cookiepp, ccountp)); 81794f1124eSVikram Hegde } 81894f1124eSVikram Hegde 81994f1124eSVikram Hegde int 82094f1124eSVikram Hegde iommulib_iommu_dma_set_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 82194f1124eSVikram Hegde ddi_dma_cookie_t *cookiep, uint_t ccount) 82294f1124eSVikram Hegde { 82350200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 82450200e77SFrank Van Der Linden 82550200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 82694f1124eSVikram Hegde return (nexops->nops_dma_set_cookies(dip, handle, cookiep, ccount)); 82794f1124eSVikram Hegde } 82894f1124eSVikram Hegde 82994f1124eSVikram Hegde int 83094f1124eSVikram Hegde iommulib_iommu_dma_clear_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 83194f1124eSVikram Hegde { 83250200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 83350200e77SFrank Van Der Linden 83450200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 83594f1124eSVikram Hegde return (nexops->nops_dma_clear_cookies(dip, handle)); 83694f1124eSVikram Hegde } 83794f1124eSVikram Hegde 83894f1124eSVikram Hegde int 83994f1124eSVikram Hegde iommulib_iommu_dma_get_sleep_flags(dev_info_t *dip, ddi_dma_handle_t handle) 84094f1124eSVikram Hegde { 84150200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 84250200e77SFrank Van Der Linden 84350200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 84494f1124eSVikram Hegde return (nexops->nops_dma_get_sleep_flags(handle)); 84520906b23SVikram Hegde } 84620906b23SVikram Hegde 84720906b23SVikram Hegde int 84820906b23SVikram Hegde iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 84920906b23SVikram Hegde ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 85020906b23SVikram Hegde { 85150200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 85250200e77SFrank Van Der Linden 85350200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 85420906b23SVikram Hegde return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 85520906b23SVikram Hegde cache_flags)); 85620906b23SVikram Hegde } 85720906b23SVikram Hegde 85820906b23SVikram Hegde int 85920906b23SVikram Hegde iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 86020906b23SVikram Hegde ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 86120906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 86220906b23SVikram Hegde { 86350200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 86450200e77SFrank Van Der Linden 86550200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 86620906b23SVikram Hegde return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 86720906b23SVikram Hegde cookiep, ccountp)); 86820906b23SVikram Hegde } 86920906b23SVikram Hegde 87020906b23SVikram Hegde int 87150200e77SFrank Van Der Linden iommulib_iommu_dmahdl_setprivate(dev_info_t *dip, dev_info_t *rdip, 87250200e77SFrank Van Der Linden ddi_dma_handle_t handle, void *priv) 87350200e77SFrank Van Der Linden { 87450200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 87550200e77SFrank Van Der Linden 87650200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 87750200e77SFrank Van Der Linden return (nexops->nops_dmahdl_setprivate(dip, rdip, handle, priv)); 87850200e77SFrank Van Der Linden } 87950200e77SFrank Van Der Linden 88050200e77SFrank Van Der Linden void * 88150200e77SFrank Van Der Linden iommulib_iommu_dmahdl_getprivate(dev_info_t *dip, dev_info_t *rdip, 88250200e77SFrank Van Der Linden ddi_dma_handle_t handle) 88350200e77SFrank Van Der Linden { 88450200e77SFrank Van Der Linden iommulib_nexops_t *nexops; 88550200e77SFrank Van Der Linden 88650200e77SFrank Van Der Linden nexops = &DEVI(dip)->devi_iommulib_nex_handle->nex_ops; 88750200e77SFrank Van Der Linden return (nexops->nops_dmahdl_getprivate(dip, rdip, handle)); 88850200e77SFrank Van Der Linden } 88950200e77SFrank Van Der Linden 89050200e77SFrank Van Der Linden int 89120906b23SVikram Hegde iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 89220906b23SVikram Hegde { 89320906b23SVikram Hegde iommulib_unit_t *unitp; 89420906b23SVikram Hegde uint64_t unitid; 89520906b23SVikram Hegde 89620906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 89720906b23SVikram Hegde 89820906b23SVikram Hegde ASSERT(unitp); 89920906b23SVikram Hegde ASSERT(unitidp); 90020906b23SVikram Hegde 90120906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 90220906b23SVikram Hegde unitid = unitp->ilu_unitid; 90320906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 90420906b23SVikram Hegde 90520906b23SVikram Hegde ASSERT(unitid > 0); 90620906b23SVikram Hegde *unitidp = (uint64_t)unitid; 90720906b23SVikram Hegde 90820906b23SVikram Hegde return (DDI_SUCCESS); 90920906b23SVikram Hegde } 91020906b23SVikram Hegde 91120906b23SVikram Hegde dev_info_t * 91220906b23SVikram Hegde iommulib_iommu_getdip(iommulib_handle_t handle) 91320906b23SVikram Hegde { 91420906b23SVikram Hegde iommulib_unit_t *unitp; 91520906b23SVikram Hegde dev_info_t *dip; 91620906b23SVikram Hegde 91720906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 91820906b23SVikram Hegde 91920906b23SVikram Hegde ASSERT(unitp); 92020906b23SVikram Hegde 92120906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 92220906b23SVikram Hegde dip = unitp->ilu_dip; 92320906b23SVikram Hegde ASSERT(dip); 92420906b23SVikram Hegde ndi_hold_devi(dip); 92520906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 92620906b23SVikram Hegde 92720906b23SVikram Hegde return (dip); 92820906b23SVikram Hegde } 92920906b23SVikram Hegde 93020906b23SVikram Hegde iommulib_ops_t * 93120906b23SVikram Hegde iommulib_iommu_getops(iommulib_handle_t handle) 93220906b23SVikram Hegde { 93320906b23SVikram Hegde iommulib_unit_t *unitp; 93420906b23SVikram Hegde iommulib_ops_t *ops; 93520906b23SVikram Hegde 93620906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 93720906b23SVikram Hegde 93820906b23SVikram Hegde ASSERT(unitp); 93920906b23SVikram Hegde 94020906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 94120906b23SVikram Hegde ops = unitp->ilu_ops; 94220906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 94320906b23SVikram Hegde 94420906b23SVikram Hegde ASSERT(ops); 94520906b23SVikram Hegde 94620906b23SVikram Hegde return (ops); 94720906b23SVikram Hegde } 94820906b23SVikram Hegde 94920906b23SVikram Hegde void * 95020906b23SVikram Hegde iommulib_iommu_getdata(iommulib_handle_t handle) 95120906b23SVikram Hegde { 95220906b23SVikram Hegde iommulib_unit_t *unitp; 95320906b23SVikram Hegde void *data; 95420906b23SVikram Hegde 95520906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 95620906b23SVikram Hegde 95720906b23SVikram Hegde ASSERT(unitp); 95820906b23SVikram Hegde 95920906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 96020906b23SVikram Hegde data = unitp->ilu_data; 96120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 96220906b23SVikram Hegde 96320906b23SVikram Hegde ASSERT(data); 96420906b23SVikram Hegde 96520906b23SVikram Hegde return (data); 96620906b23SVikram Hegde } 967