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