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 /* 2220906b23SVikram Hegde * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2320906b23SVikram Hegde * Use is subject to license terms. 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; 4620906b23SVikram Hegde } iommulib_unit_t; 4720906b23SVikram Hegde 4820906b23SVikram Hegde typedef struct iommulib_nex { 4920906b23SVikram Hegde dev_info_t *nex_dip; 5020906b23SVikram Hegde iommulib_nexops_t nex_ops; 5120906b23SVikram Hegde struct iommulib_nex *nex_next; 5220906b23SVikram Hegde struct iommulib_nex *nex_prev; 5320906b23SVikram Hegde } iommulib_nex_t; 5420906b23SVikram Hegde 5520906b23SVikram Hegde /* ********* Globals ************************ */ 5620906b23SVikram Hegde 5720906b23SVikram Hegde /* IOMMU side: Following data protected by lock */ 5820906b23SVikram Hegde static kmutex_t iommulib_lock; 5920906b23SVikram Hegde static iommulib_unit_t *iommulib_list; 6020906b23SVikram Hegde static uint64_t iommulib_unit_ids = 0; 6120906b23SVikram Hegde static uint64_t iommulib_num_units = 0; 6220906b23SVikram Hegde 6320906b23SVikram Hegde /* rootnex side data */ 6420906b23SVikram Hegde 6520906b23SVikram Hegde static kmutex_t iommulib_nexus_lock; 6620906b23SVikram Hegde static iommulib_nex_t *iommulib_nexus_list; 6720906b23SVikram Hegde 6820906b23SVikram Hegde /* can be set atomically without lock */ 6920906b23SVikram Hegde static volatile uint32_t iommulib_fini; 7020906b23SVikram Hegde 7120906b23SVikram Hegde /* debug flag */ 7220906b23SVikram Hegde static int iommulib_debug; 7320906b23SVikram Hegde 7420906b23SVikram Hegde /* 7520906b23SVikram Hegde * Module linkage information for the kernel. 7620906b23SVikram Hegde */ 7720906b23SVikram Hegde static struct modlmisc modlmisc = { 7820906b23SVikram Hegde &mod_miscops, "IOMMU library module" 7920906b23SVikram Hegde }; 8020906b23SVikram Hegde 8120906b23SVikram Hegde static struct modlinkage modlinkage = { 8220906b23SVikram Hegde MODREV_1, (void *)&modlmisc, NULL 8320906b23SVikram Hegde }; 8420906b23SVikram Hegde 8520906b23SVikram Hegde int 8620906b23SVikram Hegde _init(void) 8720906b23SVikram Hegde { 8820906b23SVikram Hegde return (mod_install(&modlinkage)); 8920906b23SVikram Hegde } 9020906b23SVikram Hegde 9120906b23SVikram Hegde int 9220906b23SVikram Hegde _fini(void) 9320906b23SVikram Hegde { 9420906b23SVikram Hegde mutex_enter(&iommulib_lock); 9520906b23SVikram Hegde if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 9620906b23SVikram Hegde mutex_exit(&iommulib_lock); 9720906b23SVikram Hegde return (EBUSY); 9820906b23SVikram Hegde } 9920906b23SVikram Hegde iommulib_fini = 1; 10020906b23SVikram Hegde 10120906b23SVikram Hegde mutex_exit(&iommulib_lock); 10220906b23SVikram Hegde return (mod_remove(&modlinkage)); 10320906b23SVikram Hegde } 10420906b23SVikram Hegde 10520906b23SVikram Hegde int 10620906b23SVikram Hegde _info(struct modinfo *modinfop) 10720906b23SVikram Hegde { 10820906b23SVikram Hegde return (mod_info(&modlinkage, modinfop)); 10920906b23SVikram Hegde } 11020906b23SVikram Hegde 11120906b23SVikram Hegde /* 11220906b23SVikram Hegde * Routines with iommulib_iommu_* are invoked from the 11320906b23SVikram Hegde * IOMMU driver. 11420906b23SVikram Hegde * Routines with iommulib_nex* are invoked from the 11520906b23SVikram Hegde * nexus driver (typically rootnex) 11620906b23SVikram Hegde */ 11720906b23SVikram Hegde 11820906b23SVikram Hegde int 11920906b23SVikram Hegde iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 12020906b23SVikram Hegde iommulib_nexhandle_t *handle) 12120906b23SVikram Hegde { 12220906b23SVikram Hegde iommulib_nex_t *nexp; 12320906b23SVikram Hegde int instance = ddi_get_instance(dip); 12420906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 12520906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 12620906b23SVikram Hegde const char *f = "iommulib_nexus_register"; 12720906b23SVikram Hegde 12820906b23SVikram Hegde ASSERT(nexops); 12920906b23SVikram Hegde ASSERT(handle); 13020906b23SVikram Hegde 13120906b23SVikram Hegde *handle = NULL; 13220906b23SVikram Hegde 13320906b23SVikram Hegde /* 13420906b23SVikram Hegde * Root node is never busy held 13520906b23SVikram Hegde */ 13620906b23SVikram Hegde if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 13720906b23SVikram Hegde !DEVI_BUSY_OWNED(pdip))) { 13820906b23SVikram Hegde cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 13920906b23SVikram Hegde "or busy held for nexops vector (%p). Failing registration", 14020906b23SVikram Hegde f, (void *)nexops); 14120906b23SVikram Hegde return (DDI_FAILURE); 14220906b23SVikram Hegde } 14320906b23SVikram Hegde 14420906b23SVikram Hegde if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 14520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 14620906b23SVikram Hegde "in nexops vector (%p). Failing NEXUS registration", 14720906b23SVikram Hegde f, driver, instance, (void *)nexops); 14820906b23SVikram Hegde return (DDI_FAILURE); 14920906b23SVikram Hegde } 15020906b23SVikram Hegde 15120906b23SVikram Hegde ASSERT(nexops->nops_data == NULL); 15220906b23SVikram Hegde 15320906b23SVikram Hegde if (nexops->nops_id == NULL) { 15420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 15520906b23SVikram Hegde "Failing registration for nexops vector: %p", 15620906b23SVikram Hegde f, driver, instance, (void *)nexops); 15720906b23SVikram Hegde return (DDI_FAILURE); 15820906b23SVikram Hegde } 15920906b23SVikram Hegde 16020906b23SVikram Hegde if (nexops->nops_dma_allochdl == NULL) { 16120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 16220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 16320906b23SVikram Hegde driver, instance, (void *)nexops); 16420906b23SVikram Hegde return (DDI_FAILURE); 16520906b23SVikram Hegde } 16620906b23SVikram Hegde 16720906b23SVikram Hegde if (nexops->nops_dma_freehdl == NULL) { 16820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 16920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 17020906b23SVikram Hegde driver, instance, (void *)nexops); 17120906b23SVikram Hegde return (DDI_FAILURE); 17220906b23SVikram Hegde } 17320906b23SVikram Hegde 17420906b23SVikram Hegde if (nexops->nops_dma_bindhdl == NULL) { 17520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 17620906b23SVikram Hegde "Failing registration for ops vector: %p", f, 17720906b23SVikram Hegde driver, instance, (void *)nexops); 17820906b23SVikram Hegde return (DDI_FAILURE); 17920906b23SVikram Hegde } 18020906b23SVikram Hegde 18120906b23SVikram Hegde if (nexops->nops_dma_sync == NULL) { 18220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 18320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 18420906b23SVikram Hegde driver, instance, (void *)nexops); 18520906b23SVikram Hegde return (DDI_FAILURE); 18620906b23SVikram Hegde } 18720906b23SVikram Hegde 18820906b23SVikram Hegde if (nexops->nops_dma_reset_cookies == NULL) { 18920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. " 19020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 19120906b23SVikram Hegde driver, instance, (void *)nexops); 19220906b23SVikram Hegde return (DDI_FAILURE); 19320906b23SVikram Hegde } 19420906b23SVikram Hegde 19520906b23SVikram Hegde if (nexops->nops_dma_get_cookies == NULL) { 19620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 19720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 19820906b23SVikram Hegde driver, instance, (void *)nexops); 19920906b23SVikram Hegde return (DDI_FAILURE); 20020906b23SVikram Hegde } 20120906b23SVikram Hegde 202*94f1124eSVikram Hegde if (nexops->nops_dma_set_cookies == NULL) { 203*94f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_set_cookies op. " 204*94f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 205*94f1124eSVikram Hegde driver, instance, (void *)nexops); 206*94f1124eSVikram Hegde return (DDI_FAILURE); 207*94f1124eSVikram Hegde } 208*94f1124eSVikram Hegde 209*94f1124eSVikram Hegde if (nexops->nops_dma_clear_cookies == NULL) { 210*94f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_clear_cookies op. " 211*94f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 212*94f1124eSVikram Hegde driver, instance, (void *)nexops); 213*94f1124eSVikram Hegde return (DDI_FAILURE); 214*94f1124eSVikram Hegde } 215*94f1124eSVikram Hegde 216*94f1124eSVikram Hegde if (nexops->nops_dma_get_sleep_flags == NULL) { 217*94f1124eSVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_sleep_flags op. " 218*94f1124eSVikram Hegde "Failing registration for ops vector: %p", f, 219*94f1124eSVikram Hegde driver, instance, (void *)nexops); 220*94f1124eSVikram Hegde return (DDI_FAILURE); 221*94f1124eSVikram Hegde } 222*94f1124eSVikram Hegde 22320906b23SVikram Hegde if (nexops->nops_dma_win == NULL) { 22420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 22520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 22620906b23SVikram Hegde driver, instance, (void *)nexops); 22720906b23SVikram Hegde return (DDI_FAILURE); 22820906b23SVikram Hegde } 22920906b23SVikram Hegde 23020906b23SVikram Hegde /* Check for legacy ops */ 23120906b23SVikram Hegde if (nexops->nops_dma_map == NULL) { 23220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_map op. " 23320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 23420906b23SVikram Hegde driver, instance, (void *)nexops); 23520906b23SVikram Hegde return (DDI_FAILURE); 23620906b23SVikram Hegde } 23720906b23SVikram Hegde 23820906b23SVikram Hegde if (nexops->nops_dma_mctl == NULL) { 23920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_mctl op. " 24020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 24120906b23SVikram Hegde driver, instance, (void *)nexops); 24220906b23SVikram Hegde return (DDI_FAILURE); 24320906b23SVikram Hegde } 24420906b23SVikram Hegde 24520906b23SVikram Hegde nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 24620906b23SVikram Hegde 24720906b23SVikram Hegde mutex_enter(&iommulib_lock); 24820906b23SVikram Hegde if (iommulib_fini == 1) { 24920906b23SVikram Hegde mutex_exit(&iommulib_lock); 25020906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 25120906b23SVikram Hegde "Failing NEXUS register.", f); 25220906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 25320906b23SVikram Hegde return (DDI_FAILURE); 25420906b23SVikram Hegde } 25520906b23SVikram Hegde 25620906b23SVikram Hegde /* 25720906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 25820906b23SVikram Hegde * nexus struct 25920906b23SVikram Hegde */ 26020906b23SVikram Hegde ndi_hold_devi(dip); 26120906b23SVikram Hegde nexp->nex_dip = dip; 26220906b23SVikram Hegde nexp->nex_ops = *nexops; 26320906b23SVikram Hegde 26420906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 26520906b23SVikram Hegde nexp->nex_next = iommulib_nexus_list; 26620906b23SVikram Hegde iommulib_nexus_list = nexp; 26720906b23SVikram Hegde nexp->nex_prev = NULL; 26820906b23SVikram Hegde 26920906b23SVikram Hegde if (nexp->nex_next != NULL) 27020906b23SVikram Hegde nexp->nex_next->nex_prev = nexp; 27120906b23SVikram Hegde 27220906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 27320906b23SVikram Hegde mutex_exit(&iommulib_lock); 27420906b23SVikram Hegde 27520906b23SVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 27620906b23SVikram Hegde "nexops=%p", f, driver, instance, ddi_node_name(dip), 27720906b23SVikram Hegde (void *)nexops); 27820906b23SVikram Hegde 27920906b23SVikram Hegde *handle = nexp; 28020906b23SVikram Hegde 28120906b23SVikram Hegde return (DDI_SUCCESS); 28220906b23SVikram Hegde } 28320906b23SVikram Hegde 28420906b23SVikram Hegde int 28520906b23SVikram Hegde iommulib_nexus_unregister(iommulib_nexhandle_t handle) 28620906b23SVikram Hegde { 28720906b23SVikram Hegde dev_info_t *dip; 28820906b23SVikram Hegde int instance; 28920906b23SVikram Hegde const char *driver; 29020906b23SVikram Hegde iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 29120906b23SVikram Hegde const char *f = "iommulib_nexus_unregister"; 29220906b23SVikram Hegde 29320906b23SVikram Hegde ASSERT(nexp); 29420906b23SVikram Hegde 29520906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 29620906b23SVikram Hegde 29720906b23SVikram Hegde dip = nexp->nex_dip; 29820906b23SVikram Hegde driver = ddi_driver_name(dip); 29920906b23SVikram Hegde instance = ddi_get_instance(dip); 30020906b23SVikram Hegde 30120906b23SVikram Hegde /* A future enhancement would be to add ref-counts */ 30220906b23SVikram Hegde 30320906b23SVikram Hegde if (nexp->nex_prev == NULL) { 30420906b23SVikram Hegde iommulib_nexus_list = nexp->nex_next; 30520906b23SVikram Hegde } else { 30620906b23SVikram Hegde nexp->nex_prev->nex_next = nexp->nex_next; 30720906b23SVikram Hegde } 30820906b23SVikram Hegde 30920906b23SVikram Hegde if (nexp->nex_next != NULL) 31020906b23SVikram Hegde nexp->nex_next->nex_prev = nexp->nex_prev; 31120906b23SVikram Hegde 31220906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 31320906b23SVikram Hegde 31420906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 31520906b23SVikram Hegde 316*94f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: NEXUS (%s) handle successfully " 31720906b23SVikram Hegde "unregistered from IOMMULIB", f, driver, instance, 31820906b23SVikram Hegde ddi_node_name(dip)); 31920906b23SVikram Hegde 32020906b23SVikram Hegde ndi_rele_devi(dip); 32120906b23SVikram Hegde 32220906b23SVikram Hegde return (DDI_SUCCESS); 32320906b23SVikram Hegde } 32420906b23SVikram Hegde 32520906b23SVikram Hegde static iommulib_nexops_t * 32620906b23SVikram Hegde lookup_nexops(dev_info_t *dip) 32720906b23SVikram Hegde { 32820906b23SVikram Hegde iommulib_nex_t *nexp; 32920906b23SVikram Hegde 33020906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 33120906b23SVikram Hegde nexp = iommulib_nexus_list; 33220906b23SVikram Hegde while (nexp) { 33320906b23SVikram Hegde if (nexp->nex_dip == dip) 33420906b23SVikram Hegde break; 33520906b23SVikram Hegde nexp = nexp->nex_next; 33620906b23SVikram Hegde } 33720906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 33820906b23SVikram Hegde 33920906b23SVikram Hegde return (nexp ? &nexp->nex_ops : NULL); 34020906b23SVikram Hegde } 34120906b23SVikram Hegde 34220906b23SVikram Hegde int 34320906b23SVikram Hegde iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 34420906b23SVikram Hegde iommulib_handle_t *handle) 34520906b23SVikram Hegde { 34620906b23SVikram Hegde const char *vendor; 34720906b23SVikram Hegde iommulib_unit_t *unitp; 34820906b23SVikram Hegde int instance = ddi_get_instance(dip); 34920906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 35020906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 35120906b23SVikram Hegde const char *f = "iommulib_register"; 35220906b23SVikram Hegde 35320906b23SVikram Hegde ASSERT(ops); 35420906b23SVikram Hegde ASSERT(handle); 35520906b23SVikram Hegde 35620906b23SVikram Hegde if (i_ddi_node_state(dip) < DS_PROBED || !DEVI_BUSY_OWNED(pdip)) { 35720906b23SVikram Hegde cmn_err(CE_WARN, "%s: devinfo node not in DS_PROBED or " 35820906b23SVikram Hegde "busy held for ops vector (%p). Failing registration", 35920906b23SVikram Hegde f, (void *)ops); 36020906b23SVikram Hegde return (DDI_FAILURE); 36120906b23SVikram Hegde } 36220906b23SVikram Hegde 36320906b23SVikram Hegde 36420906b23SVikram Hegde if (ops->ilops_vers != IOMMU_OPS_VERSION) { 36520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 36620906b23SVikram Hegde "in ops vector (%p). Failing registration", f, driver, 36720906b23SVikram Hegde instance, (void *)ops); 36820906b23SVikram Hegde return (DDI_FAILURE); 36920906b23SVikram Hegde } 37020906b23SVikram Hegde 37120906b23SVikram Hegde switch (ops->ilops_vendor) { 37220906b23SVikram Hegde case AMD_IOMMU: 37320906b23SVikram Hegde vendor = "AMD"; 37420906b23SVikram Hegde break; 37520906b23SVikram Hegde case INTEL_IOMMU: 37620906b23SVikram Hegde vendor = "Intel"; 37720906b23SVikram Hegde break; 37820906b23SVikram Hegde case INVALID_VENDOR: 37920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 38020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 38120906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 38220906b23SVikram Hegde return (DDI_FAILURE); 38320906b23SVikram Hegde default: 38420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 38520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 38620906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 38720906b23SVikram Hegde return (DDI_FAILURE); 38820906b23SVikram Hegde } 38920906b23SVikram Hegde 390*94f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Detected IOMMU registration from vendor" 391*94f1124eSVikram Hegde " %s", f, driver, instance, vendor); 39220906b23SVikram Hegde 39320906b23SVikram Hegde if (ops->ilops_data == NULL) { 39420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 39520906b23SVikram Hegde "Failing registration for ops vector: %p", f, 39620906b23SVikram Hegde driver, instance, (void *)ops); 39720906b23SVikram Hegde return (DDI_FAILURE); 39820906b23SVikram Hegde } 39920906b23SVikram Hegde 40020906b23SVikram Hegde if (ops->ilops_id == NULL) { 40120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 40220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 40320906b23SVikram Hegde driver, instance, (void *)ops); 40420906b23SVikram Hegde return (DDI_FAILURE); 40520906b23SVikram Hegde } 40620906b23SVikram Hegde 40720906b23SVikram Hegde if (ops->ilops_probe == NULL) { 40820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL probe op. " 40920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 41020906b23SVikram Hegde driver, instance, (void *)ops); 41120906b23SVikram Hegde return (DDI_FAILURE); 41220906b23SVikram Hegde } 41320906b23SVikram Hegde 41420906b23SVikram Hegde if (ops->ilops_dma_allochdl == NULL) { 41520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. " 41620906b23SVikram Hegde "Failing registration for ops vector: %p", f, 41720906b23SVikram Hegde driver, instance, (void *)ops); 41820906b23SVikram Hegde return (DDI_FAILURE); 41920906b23SVikram Hegde } 42020906b23SVikram Hegde 42120906b23SVikram Hegde if (ops->ilops_dma_freehdl == NULL) { 42220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. " 42320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 42420906b23SVikram Hegde driver, instance, (void *)ops); 42520906b23SVikram Hegde return (DDI_FAILURE); 42620906b23SVikram Hegde } 42720906b23SVikram Hegde 42820906b23SVikram Hegde if (ops->ilops_dma_bindhdl == NULL) { 42920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. " 43020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 43120906b23SVikram Hegde driver, instance, (void *)ops); 43220906b23SVikram Hegde return (DDI_FAILURE); 43320906b23SVikram Hegde } 43420906b23SVikram Hegde 43520906b23SVikram Hegde if (ops->ilops_dma_sync == NULL) { 43620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 43720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 43820906b23SVikram Hegde driver, instance, (void *)ops); 43920906b23SVikram Hegde return (DDI_FAILURE); 44020906b23SVikram Hegde } 44120906b23SVikram Hegde 44220906b23SVikram Hegde if (ops->ilops_dma_win == NULL) { 44320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 44420906b23SVikram Hegde "Failing registration for ops vector: %p", f, 44520906b23SVikram Hegde driver, instance, (void *)ops); 44620906b23SVikram Hegde return (DDI_FAILURE); 44720906b23SVikram Hegde } 44820906b23SVikram Hegde 44920906b23SVikram Hegde /* Check for legacy ops */ 45020906b23SVikram Hegde if (ops->ilops_dma_map == NULL) { 45120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_map op. " 45220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 45320906b23SVikram Hegde driver, instance, (void *)ops); 45420906b23SVikram Hegde return (DDI_FAILURE); 45520906b23SVikram Hegde } 45620906b23SVikram Hegde 45720906b23SVikram Hegde if (ops->ilops_dma_mctl == NULL) { 45820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_mctl op. " 45920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 46020906b23SVikram Hegde driver, instance, (void *)ops); 46120906b23SVikram Hegde return (DDI_FAILURE); 46220906b23SVikram Hegde } 46320906b23SVikram Hegde 46420906b23SVikram Hegde unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 46520906b23SVikram Hegde mutex_enter(&iommulib_lock); 46620906b23SVikram Hegde if (iommulib_fini == 1) { 46720906b23SVikram Hegde mutex_exit(&iommulib_lock); 46820906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 46920906b23SVikram Hegde f); 47020906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 47120906b23SVikram Hegde return (DDI_FAILURE); 47220906b23SVikram Hegde } 47320906b23SVikram Hegde 47420906b23SVikram Hegde /* 47520906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 47620906b23SVikram Hegde * IOMMU unit 47720906b23SVikram Hegde */ 47820906b23SVikram Hegde mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 47920906b23SVikram Hegde 48020906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 48120906b23SVikram Hegde unitp->ilu_unitid = ++iommulib_unit_ids; 48220906b23SVikram Hegde unitp->ilu_ref = 0; 48320906b23SVikram Hegde ndi_hold_devi(dip); 48420906b23SVikram Hegde unitp->ilu_dip = dip; 48520906b23SVikram Hegde unitp->ilu_ops = ops; 48620906b23SVikram Hegde unitp->ilu_data = ops->ilops_data; 48720906b23SVikram Hegde 48820906b23SVikram Hegde unitp->ilu_next = iommulib_list; 48920906b23SVikram Hegde iommulib_list = unitp; 490*94f1124eSVikram Hegde unitp->ilu_prev = NULL; 491*94f1124eSVikram Hegde if (unitp->ilu_next) 492*94f1124eSVikram Hegde unitp->ilu_next->ilu_prev = unitp; 49320906b23SVikram Hegde 49420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 49520906b23SVikram Hegde 49620906b23SVikram Hegde iommulib_num_units++; 49720906b23SVikram Hegde 49820906b23SVikram Hegde *handle = unitp; 49920906b23SVikram Hegde 50020906b23SVikram Hegde mutex_exit(&iommulib_lock); 50120906b23SVikram Hegde 502*94f1124eSVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered IOMMU unit " 50320906b23SVikram Hegde "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 50420906b23SVikram Hegde f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 50520906b23SVikram Hegde unitp->ilu_unitid); 50620906b23SVikram Hegde 50720906b23SVikram Hegde return (DDI_SUCCESS); 50820906b23SVikram Hegde } 50920906b23SVikram Hegde 51020906b23SVikram Hegde int 51120906b23SVikram Hegde iommulib_iommu_unregister(iommulib_handle_t handle) 51220906b23SVikram Hegde { 51320906b23SVikram Hegde uint32_t unitid; 51420906b23SVikram Hegde dev_info_t *dip; 51520906b23SVikram Hegde int instance; 51620906b23SVikram Hegde const char *driver; 51720906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 51820906b23SVikram Hegde const char *f = "iommulib_unregister"; 51920906b23SVikram Hegde 52020906b23SVikram Hegde ASSERT(unitp); 52120906b23SVikram Hegde 52220906b23SVikram Hegde mutex_enter(&iommulib_lock); 52320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 52420906b23SVikram Hegde 52520906b23SVikram Hegde unitid = unitp->ilu_unitid; 52620906b23SVikram Hegde dip = unitp->ilu_dip; 52720906b23SVikram Hegde driver = ddi_driver_name(dip); 52820906b23SVikram Hegde instance = ddi_get_instance(dip); 52920906b23SVikram Hegde 53020906b23SVikram Hegde if (unitp->ilu_ref != 0) { 53120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 53220906b23SVikram Hegde mutex_exit(&iommulib_lock); 53320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 53420906b23SVikram Hegde "unregister IOMMULIB unitid %u", 53520906b23SVikram Hegde f, driver, instance, unitid); 53620906b23SVikram Hegde return (DDI_FAILURE); 53720906b23SVikram Hegde } 53820906b23SVikram Hegde unitp->ilu_unitid = 0; 53920906b23SVikram Hegde ASSERT(unitp->ilu_ref == 0); 54020906b23SVikram Hegde 54120906b23SVikram Hegde if (unitp->ilu_prev == NULL) { 54220906b23SVikram Hegde iommulib_list = unitp->ilu_next; 54320906b23SVikram Hegde unitp->ilu_next->ilu_prev = NULL; 54420906b23SVikram Hegde } else { 54520906b23SVikram Hegde unitp->ilu_prev->ilu_next = unitp->ilu_next; 54620906b23SVikram Hegde unitp->ilu_next->ilu_prev = unitp->ilu_prev; 54720906b23SVikram Hegde } 54820906b23SVikram Hegde 54920906b23SVikram Hegde iommulib_num_units--; 55020906b23SVikram Hegde 55120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 55220906b23SVikram Hegde 55320906b23SVikram Hegde mutex_destroy(&unitp->ilu_lock); 55420906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 55520906b23SVikram Hegde 55620906b23SVikram Hegde mutex_exit(&iommulib_lock); 55720906b23SVikram Hegde 55820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 55920906b23SVikram Hegde "unregistered", f, driver, instance, unitid); 56020906b23SVikram Hegde 56120906b23SVikram Hegde ndi_rele_devi(dip); 56220906b23SVikram Hegde 56320906b23SVikram Hegde return (DDI_SUCCESS); 56420906b23SVikram Hegde } 56520906b23SVikram Hegde 56620906b23SVikram Hegde int 56720906b23SVikram Hegde iommulib_nex_open(dev_info_t *rdip, uint_t *errorp) 56820906b23SVikram Hegde { 56920906b23SVikram Hegde iommulib_unit_t *unitp; 57020906b23SVikram Hegde int instance = ddi_get_instance(rdip); 57120906b23SVikram Hegde const char *driver = ddi_driver_name(rdip); 57220906b23SVikram Hegde const char *f = "iommulib_nex_open"; 57320906b23SVikram Hegde 57420906b23SVikram Hegde *errorp = 0; 575*94f1124eSVikram Hegde 576*94f1124eSVikram Hegde if (IOMMU_USED(rdip)) 577*94f1124eSVikram Hegde return (DDI_SUCCESS); 578*94f1124eSVikram Hegde 579*94f1124eSVikram Hegde ASSERT(DEVI(rdip)->devi_iommulib_handle == NULL); 58020906b23SVikram Hegde 58120906b23SVikram Hegde /* prevent use of IOMMU for AMD IOMMU's DMA */ 58220906b23SVikram Hegde if (strcmp(driver, "amd_iommu") == 0) { 58320906b23SVikram Hegde *errorp = ENOTSUP; 58420906b23SVikram Hegde return (DDI_FAILURE); 58520906b23SVikram Hegde } 58620906b23SVikram Hegde 58720906b23SVikram Hegde /* 588*94f1124eSVikram Hegde * Use the probe entry point to determine in a hardware specific 589*94f1124eSVikram Hegde * manner whether this dip is controlled by an IOMMU. If yes, 590*94f1124eSVikram Hegde * return the handle corresponding to the IOMMU unit. 59120906b23SVikram Hegde */ 59220906b23SVikram Hegde 59320906b23SVikram Hegde mutex_enter(&iommulib_lock); 59420906b23SVikram Hegde for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 595*94f1124eSVikram Hegde if (unitp->ilu_ops->ilops_probe(unitp, rdip) == DDI_SUCCESS) 59620906b23SVikram Hegde break; 59720906b23SVikram Hegde } 59820906b23SVikram Hegde 59920906b23SVikram Hegde if (unitp == NULL) { 60020906b23SVikram Hegde mutex_exit(&iommulib_lock); 60120906b23SVikram Hegde if (iommulib_debug) { 602d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 60320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 60420906b23SVikram Hegde "controlled by an IOMMU: path=%s", f, driver, 60520906b23SVikram Hegde instance, (void *)rdip, ddi_pathname(rdip, buf)); 606d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 60720906b23SVikram Hegde } 60820906b23SVikram Hegde *errorp = ENOTSUP; 60920906b23SVikram Hegde return (DDI_FAILURE); 61020906b23SVikram Hegde } 61120906b23SVikram Hegde 61220906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 61320906b23SVikram Hegde unitp->ilu_ref++; 61420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 61520906b23SVikram Hegde mutex_exit(&iommulib_lock); 61620906b23SVikram Hegde 61720906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = unitp; 61820906b23SVikram Hegde 61920906b23SVikram Hegde return (DDI_SUCCESS); 62020906b23SVikram Hegde } 62120906b23SVikram Hegde 62220906b23SVikram Hegde void 62320906b23SVikram Hegde iommulib_nex_close(dev_info_t *rdip) 62420906b23SVikram Hegde { 62520906b23SVikram Hegde iommulib_unit_t *unitp; 62620906b23SVikram Hegde const char *driver; 62720906b23SVikram Hegde int instance; 62820906b23SVikram Hegde uint32_t unitid; 62920906b23SVikram Hegde const char *f = "iommulib_nex_close"; 63020906b23SVikram Hegde 63120906b23SVikram Hegde unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle; 63220906b23SVikram Hegde if (unitp == NULL) 63320906b23SVikram Hegde return; 63420906b23SVikram Hegde 63520906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = NULL; 63620906b23SVikram Hegde 63720906b23SVikram Hegde mutex_enter(&iommulib_lock); 63820906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 63920906b23SVikram Hegde unitid = unitp->ilu_unitid; 64020906b23SVikram Hegde driver = ddi_driver_name(unitp->ilu_dip); 64120906b23SVikram Hegde instance = ddi_get_instance(unitp->ilu_dip); 64220906b23SVikram Hegde unitp->ilu_ref--; 64320906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 64420906b23SVikram Hegde mutex_exit(&iommulib_lock); 64520906b23SVikram Hegde 64620906b23SVikram Hegde if (iommulib_debug) { 647d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 648d8fc7d07SVikram Hegde (void) ddi_pathname(rdip, buf); 64920906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 65020906b23SVikram Hegde "unitid=%u rdip path = %s", f, driver, instance, 65120906b23SVikram Hegde (void *)rdip, unitid, buf); 652d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 65320906b23SVikram Hegde } 65420906b23SVikram Hegde } 65520906b23SVikram Hegde 65620906b23SVikram Hegde int 65720906b23SVikram Hegde iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 65820906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 65920906b23SVikram Hegde caddr_t arg, ddi_dma_handle_t *dma_handlep) 66020906b23SVikram Hegde { 66120906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 66220906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 66320906b23SVikram Hegde 66420906b23SVikram Hegde ASSERT(unitp); 66520906b23SVikram Hegde 66620906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 66720906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 66820906b23SVikram Hegde attr, waitfp, arg, dma_handlep)); 66920906b23SVikram Hegde } 67020906b23SVikram Hegde 67120906b23SVikram Hegde int 67220906b23SVikram Hegde iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 67320906b23SVikram Hegde ddi_dma_handle_t dma_handle) 67420906b23SVikram Hegde { 67520906b23SVikram Hegde int error; 67620906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 67720906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 67820906b23SVikram Hegde 67920906b23SVikram Hegde ASSERT(unitp); 68020906b23SVikram Hegde 68120906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 68220906b23SVikram Hegde error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 68320906b23SVikram Hegde rdip, dma_handle); 68420906b23SVikram Hegde 68520906b23SVikram Hegde return (error); 68620906b23SVikram Hegde } 68720906b23SVikram Hegde 68820906b23SVikram Hegde int 68920906b23SVikram Hegde iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 69020906b23SVikram Hegde ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 69120906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 69220906b23SVikram Hegde { 69320906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 69420906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 69520906b23SVikram Hegde 69620906b23SVikram Hegde ASSERT(unitp); 69720906b23SVikram Hegde 69820906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 69920906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 70020906b23SVikram Hegde dmareq, cookiep, ccountp)); 70120906b23SVikram Hegde } 70220906b23SVikram Hegde 70320906b23SVikram Hegde int 70420906b23SVikram Hegde iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 70520906b23SVikram Hegde ddi_dma_handle_t dma_handle) 70620906b23SVikram Hegde { 70720906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 70820906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 70920906b23SVikram Hegde 71020906b23SVikram Hegde ASSERT(unitp); 71120906b23SVikram Hegde 71220906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 71320906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 71420906b23SVikram Hegde dma_handle)); 71520906b23SVikram Hegde } 71620906b23SVikram Hegde 71720906b23SVikram Hegde int 71820906b23SVikram Hegde iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 71920906b23SVikram Hegde ddi_dma_handle_t dma_handle, off_t off, size_t len, 72020906b23SVikram Hegde uint_t cache_flags) 72120906b23SVikram Hegde { 72220906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 72320906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 72420906b23SVikram Hegde 72520906b23SVikram Hegde ASSERT(unitp); 72620906b23SVikram Hegde 72720906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 72820906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 72920906b23SVikram Hegde off, len, cache_flags)); 73020906b23SVikram Hegde } 73120906b23SVikram Hegde 73220906b23SVikram Hegde int 73320906b23SVikram Hegde iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 73420906b23SVikram Hegde ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 73520906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 73620906b23SVikram Hegde { 73720906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 73820906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 73920906b23SVikram Hegde 74020906b23SVikram Hegde ASSERT(unitp); 74120906b23SVikram Hegde 74220906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 74320906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 74420906b23SVikram Hegde win, offp, lenp, cookiep, ccountp)); 74520906b23SVikram Hegde } 74620906b23SVikram Hegde 74720906b23SVikram Hegde /* Obsolete DMA routines */ 74820906b23SVikram Hegde 74920906b23SVikram Hegde int 75020906b23SVikram Hegde iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip, 75120906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle) 75220906b23SVikram Hegde { 75320906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 75420906b23SVikram Hegde iommulib_unit_t *unitp = handle; 75520906b23SVikram Hegde 75620906b23SVikram Hegde ASSERT(unitp); 75720906b23SVikram Hegde 75820906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 75920906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_map(handle, dip, rdip, dmareq, 76020906b23SVikram Hegde dma_handle)); 76120906b23SVikram Hegde } 76220906b23SVikram Hegde 76320906b23SVikram Hegde int 76420906b23SVikram Hegde iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip, 76520906b23SVikram Hegde ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request, 76620906b23SVikram Hegde off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags) 76720906b23SVikram Hegde { 76820906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 76920906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 77020906b23SVikram Hegde 77120906b23SVikram Hegde ASSERT(unitp); 77220906b23SVikram Hegde 77320906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 77420906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_mctl(handle, dip, rdip, dma_handle, 77520906b23SVikram Hegde request, offp, lenp, objpp, cache_flags)); 77620906b23SVikram Hegde } 77720906b23SVikram Hegde 77820906b23SVikram Hegde /* Utility routines invoked by IOMMU drivers */ 77920906b23SVikram Hegde int 78020906b23SVikram Hegde iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 78120906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 78220906b23SVikram Hegde ddi_dma_handle_t *handlep) 78320906b23SVikram Hegde { 78420906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 78520906b23SVikram Hegde if (nexops == NULL) 78620906b23SVikram Hegde return (DDI_FAILURE); 78720906b23SVikram Hegde return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 78820906b23SVikram Hegde handlep)); 78920906b23SVikram Hegde } 79020906b23SVikram Hegde 79120906b23SVikram Hegde int 79220906b23SVikram Hegde iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 79320906b23SVikram Hegde ddi_dma_handle_t handle) 79420906b23SVikram Hegde { 79520906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 79620906b23SVikram Hegde if (nexops == NULL) 79720906b23SVikram Hegde return (DDI_FAILURE); 79820906b23SVikram Hegde return (nexops->nops_dma_freehdl(dip, rdip, handle)); 79920906b23SVikram Hegde } 80020906b23SVikram Hegde 80120906b23SVikram Hegde int 80220906b23SVikram Hegde iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 80320906b23SVikram Hegde ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 80420906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 80520906b23SVikram Hegde { 80620906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 80720906b23SVikram Hegde if (nexops == NULL) 80820906b23SVikram Hegde return (DDI_FAILURE); 80920906b23SVikram Hegde return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 81020906b23SVikram Hegde cookiep, ccountp)); 81120906b23SVikram Hegde } 81220906b23SVikram Hegde 81320906b23SVikram Hegde int 81420906b23SVikram Hegde iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 81520906b23SVikram Hegde ddi_dma_handle_t handle) 81620906b23SVikram Hegde { 81720906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 81820906b23SVikram Hegde if (nexops == NULL) 81920906b23SVikram Hegde return (DDI_FAILURE); 82020906b23SVikram Hegde return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 82120906b23SVikram Hegde } 82220906b23SVikram Hegde 82320906b23SVikram Hegde void 82420906b23SVikram Hegde iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 82520906b23SVikram Hegde { 82620906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 82720906b23SVikram Hegde nexops->nops_dma_reset_cookies(dip, handle); 82820906b23SVikram Hegde } 82920906b23SVikram Hegde 83020906b23SVikram Hegde int 83120906b23SVikram Hegde iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 832*94f1124eSVikram Hegde ddi_dma_cookie_t **cookiepp, uint_t *ccountp) 83320906b23SVikram Hegde { 83420906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 83520906b23SVikram Hegde if (nexops == NULL) 83620906b23SVikram Hegde return (DDI_FAILURE); 837*94f1124eSVikram Hegde return (nexops->nops_dma_get_cookies(dip, handle, cookiepp, ccountp)); 838*94f1124eSVikram Hegde } 839*94f1124eSVikram Hegde 840*94f1124eSVikram Hegde int 841*94f1124eSVikram Hegde iommulib_iommu_dma_set_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 842*94f1124eSVikram Hegde ddi_dma_cookie_t *cookiep, uint_t ccount) 843*94f1124eSVikram Hegde { 844*94f1124eSVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 845*94f1124eSVikram Hegde if (nexops == NULL) 846*94f1124eSVikram Hegde return (DDI_FAILURE); 847*94f1124eSVikram Hegde return (nexops->nops_dma_set_cookies(dip, handle, cookiep, ccount)); 848*94f1124eSVikram Hegde } 849*94f1124eSVikram Hegde 850*94f1124eSVikram Hegde int 851*94f1124eSVikram Hegde iommulib_iommu_dma_clear_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 852*94f1124eSVikram Hegde { 853*94f1124eSVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 854*94f1124eSVikram Hegde if (nexops == NULL) 855*94f1124eSVikram Hegde return (DDI_FAILURE); 856*94f1124eSVikram Hegde return (nexops->nops_dma_clear_cookies(dip, handle)); 857*94f1124eSVikram Hegde } 858*94f1124eSVikram Hegde 859*94f1124eSVikram Hegde int 860*94f1124eSVikram Hegde iommulib_iommu_dma_get_sleep_flags(dev_info_t *dip, ddi_dma_handle_t handle) 861*94f1124eSVikram Hegde { 862*94f1124eSVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 863*94f1124eSVikram Hegde if (nexops == NULL) 864*94f1124eSVikram Hegde return (DDI_FAILURE); 865*94f1124eSVikram Hegde return (nexops->nops_dma_get_sleep_flags(handle)); 86620906b23SVikram Hegde } 86720906b23SVikram Hegde 86820906b23SVikram Hegde int 86920906b23SVikram Hegde iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 87020906b23SVikram Hegde ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 87120906b23SVikram Hegde { 87220906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 87320906b23SVikram Hegde if (nexops == NULL) 87420906b23SVikram Hegde return (DDI_FAILURE); 87520906b23SVikram Hegde return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 87620906b23SVikram Hegde cache_flags)); 87720906b23SVikram Hegde } 87820906b23SVikram Hegde 87920906b23SVikram Hegde int 88020906b23SVikram Hegde iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 88120906b23SVikram Hegde ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 88220906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 88320906b23SVikram Hegde { 88420906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 88520906b23SVikram Hegde if (nexops == NULL) 88620906b23SVikram Hegde return (DDI_FAILURE); 88720906b23SVikram Hegde return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 88820906b23SVikram Hegde cookiep, ccountp)); 88920906b23SVikram Hegde } 89020906b23SVikram Hegde 89120906b23SVikram Hegde int 89220906b23SVikram Hegde iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip, 89320906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep) 89420906b23SVikram Hegde { 89520906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 89620906b23SVikram Hegde if (nexops == NULL) 89720906b23SVikram Hegde return (DDI_FAILURE); 89820906b23SVikram Hegde return (nexops->nops_dma_map(dip, rdip, dmareq, handlep)); 89920906b23SVikram Hegde } 90020906b23SVikram Hegde 90120906b23SVikram Hegde int 90220906b23SVikram Hegde iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 90320906b23SVikram Hegde ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp, 90420906b23SVikram Hegde size_t *lenp, caddr_t *objpp, uint_t cache_flags) 90520906b23SVikram Hegde { 90620906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 90720906b23SVikram Hegde if (nexops == NULL) 90820906b23SVikram Hegde return (DDI_FAILURE); 90920906b23SVikram Hegde return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp, 91020906b23SVikram Hegde objpp, cache_flags)); 91120906b23SVikram Hegde } 91220906b23SVikram Hegde 91320906b23SVikram Hegde int 91420906b23SVikram Hegde iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 91520906b23SVikram Hegde { 91620906b23SVikram Hegde iommulib_unit_t *unitp; 91720906b23SVikram Hegde uint64_t unitid; 91820906b23SVikram Hegde 91920906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 92020906b23SVikram Hegde 92120906b23SVikram Hegde ASSERT(unitp); 92220906b23SVikram Hegde ASSERT(unitidp); 92320906b23SVikram Hegde 92420906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 92520906b23SVikram Hegde unitid = unitp->ilu_unitid; 92620906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 92720906b23SVikram Hegde 92820906b23SVikram Hegde ASSERT(unitid > 0); 92920906b23SVikram Hegde *unitidp = (uint64_t)unitid; 93020906b23SVikram Hegde 93120906b23SVikram Hegde return (DDI_SUCCESS); 93220906b23SVikram Hegde } 93320906b23SVikram Hegde 93420906b23SVikram Hegde dev_info_t * 93520906b23SVikram Hegde iommulib_iommu_getdip(iommulib_handle_t handle) 93620906b23SVikram Hegde { 93720906b23SVikram Hegde iommulib_unit_t *unitp; 93820906b23SVikram Hegde dev_info_t *dip; 93920906b23SVikram Hegde 94020906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 94120906b23SVikram Hegde 94220906b23SVikram Hegde ASSERT(unitp); 94320906b23SVikram Hegde 94420906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 94520906b23SVikram Hegde dip = unitp->ilu_dip; 94620906b23SVikram Hegde ASSERT(dip); 94720906b23SVikram Hegde ndi_hold_devi(dip); 94820906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 94920906b23SVikram Hegde 95020906b23SVikram Hegde return (dip); 95120906b23SVikram Hegde } 95220906b23SVikram Hegde 95320906b23SVikram Hegde iommulib_ops_t * 95420906b23SVikram Hegde iommulib_iommu_getops(iommulib_handle_t handle) 95520906b23SVikram Hegde { 95620906b23SVikram Hegde iommulib_unit_t *unitp; 95720906b23SVikram Hegde iommulib_ops_t *ops; 95820906b23SVikram Hegde 95920906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 96020906b23SVikram Hegde 96120906b23SVikram Hegde ASSERT(unitp); 96220906b23SVikram Hegde 96320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 96420906b23SVikram Hegde ops = unitp->ilu_ops; 96520906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 96620906b23SVikram Hegde 96720906b23SVikram Hegde ASSERT(ops); 96820906b23SVikram Hegde 96920906b23SVikram Hegde return (ops); 97020906b23SVikram Hegde } 97120906b23SVikram Hegde 97220906b23SVikram Hegde void * 97320906b23SVikram Hegde iommulib_iommu_getdata(iommulib_handle_t handle) 97420906b23SVikram Hegde { 97520906b23SVikram Hegde iommulib_unit_t *unitp; 97620906b23SVikram Hegde void *data; 97720906b23SVikram Hegde 97820906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 97920906b23SVikram Hegde 98020906b23SVikram Hegde ASSERT(unitp); 98120906b23SVikram Hegde 98220906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 98320906b23SVikram Hegde data = unitp->ilu_data; 98420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 98520906b23SVikram Hegde 98620906b23SVikram Hegde ASSERT(data); 98720906b23SVikram Hegde 98820906b23SVikram Hegde return (data); 98920906b23SVikram Hegde } 990