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_cache { 4920906b23SVikram Hegde dev_info_t *cache_rdip; 5020906b23SVikram Hegde iommulib_unit_t *cache_unit; 5120906b23SVikram Hegde struct iommulib_cache *cache_next; 5220906b23SVikram Hegde struct iommulib_cache *cache_prev; 5320906b23SVikram Hegde } iommulib_cache_t; 5420906b23SVikram Hegde 5520906b23SVikram Hegde typedef struct iommulib_nex { 5620906b23SVikram Hegde dev_info_t *nex_dip; 5720906b23SVikram Hegde iommulib_nexops_t nex_ops; 5820906b23SVikram Hegde struct iommulib_nex *nex_next; 5920906b23SVikram Hegde struct iommulib_nex *nex_prev; 6020906b23SVikram Hegde } iommulib_nex_t; 6120906b23SVikram Hegde 6220906b23SVikram Hegde /* ********* Function prototypes ********************* */ 6320906b23SVikram Hegde static int lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp); 6420906b23SVikram Hegde static void insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp); 6520906b23SVikram Hegde 6620906b23SVikram Hegde 6720906b23SVikram Hegde /* ********* Globals ************************ */ 6820906b23SVikram Hegde 6920906b23SVikram Hegde /* IOMMU side: Following data protected by lock */ 7020906b23SVikram Hegde static kmutex_t iommulib_lock; 7120906b23SVikram Hegde static iommulib_unit_t *iommulib_list; 7220906b23SVikram Hegde static uint64_t iommulib_unit_ids = 0; 7320906b23SVikram Hegde static uint64_t iommulib_num_units = 0; 7420906b23SVikram Hegde 7520906b23SVikram Hegde /* rootnex side data */ 7620906b23SVikram Hegde 7720906b23SVikram Hegde static kmutex_t iommulib_nexus_lock; 7820906b23SVikram Hegde static iommulib_nex_t *iommulib_nexus_list; 7920906b23SVikram Hegde 8020906b23SVikram Hegde #define IOMMULIB_CACHE_SIZE 256 8120906b23SVikram Hegde static kmutex_t iommulib_cache_lock; 8220906b23SVikram Hegde static iommulib_cache_t **iommulib_cache; 8320906b23SVikram Hegde 8420906b23SVikram Hegde /* tunable via /etc/system */ 8520906b23SVikram Hegde static uint_t iommulib_cache_size = IOMMULIB_CACHE_SIZE; 8620906b23SVikram Hegde 8720906b23SVikram Hegde /* can be set atomically without lock */ 8820906b23SVikram Hegde static volatile uint32_t iommulib_fini; 8920906b23SVikram Hegde 9020906b23SVikram Hegde /* debug flag */ 9120906b23SVikram Hegde static int iommulib_debug; 9220906b23SVikram Hegde 9320906b23SVikram Hegde /* 9420906b23SVikram Hegde * Module linkage information for the kernel. 9520906b23SVikram Hegde */ 9620906b23SVikram Hegde static struct modlmisc modlmisc = { 9720906b23SVikram Hegde &mod_miscops, "IOMMU library module" 9820906b23SVikram Hegde }; 9920906b23SVikram Hegde 10020906b23SVikram Hegde static struct modlinkage modlinkage = { 10120906b23SVikram Hegde MODREV_1, (void *)&modlmisc, NULL 10220906b23SVikram Hegde }; 10320906b23SVikram Hegde 10420906b23SVikram Hegde int 10520906b23SVikram Hegde _init(void) 10620906b23SVikram Hegde { 10720906b23SVikram Hegde /* 10820906b23SVikram Hegde * static mutexes automagically initialized 10920906b23SVikram Hegde * by being allocated in zeroed memory 11020906b23SVikram Hegde */ 11120906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 11220906b23SVikram Hegde iommulib_cache = kmem_zalloc( 11320906b23SVikram Hegde sizeof (iommulib_cache_t *) * iommulib_cache_size, KM_SLEEP); 11420906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 11520906b23SVikram Hegde 11620906b23SVikram Hegde return (mod_install(&modlinkage)); 11720906b23SVikram Hegde } 11820906b23SVikram Hegde 11920906b23SVikram Hegde int 12020906b23SVikram Hegde _fini(void) 12120906b23SVikram Hegde { 12220906b23SVikram Hegde mutex_enter(&iommulib_lock); 12320906b23SVikram Hegde if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 12420906b23SVikram Hegde mutex_exit(&iommulib_lock); 12520906b23SVikram Hegde return (EBUSY); 12620906b23SVikram Hegde } 12720906b23SVikram Hegde iommulib_fini = 1; 12820906b23SVikram Hegde 12920906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 13020906b23SVikram Hegde kmem_free(iommulib_cache, 13120906b23SVikram Hegde sizeof (iommulib_cache_t *) * iommulib_cache_size); 13220906b23SVikram Hegde iommulib_cache = NULL; 13320906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 13420906b23SVikram Hegde 13520906b23SVikram Hegde mutex_exit(&iommulib_lock); 13620906b23SVikram Hegde return (mod_remove(&modlinkage)); 13720906b23SVikram Hegde } 13820906b23SVikram Hegde 13920906b23SVikram Hegde int 14020906b23SVikram Hegde _info(struct modinfo *modinfop) 14120906b23SVikram Hegde { 14220906b23SVikram Hegde return (mod_info(&modlinkage, modinfop)); 14320906b23SVikram Hegde } 14420906b23SVikram Hegde 14520906b23SVikram Hegde /* 14620906b23SVikram Hegde * Routines with iommulib_iommu_* are invoked from the 14720906b23SVikram Hegde * IOMMU driver. 14820906b23SVikram Hegde * Routines with iommulib_nex* are invoked from the 14920906b23SVikram Hegde * nexus driver (typically rootnex) 15020906b23SVikram Hegde */ 15120906b23SVikram Hegde 15220906b23SVikram Hegde int 15320906b23SVikram Hegde iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 15420906b23SVikram Hegde iommulib_nexhandle_t *handle) 15520906b23SVikram Hegde { 15620906b23SVikram Hegde iommulib_nex_t *nexp; 15720906b23SVikram Hegde int instance = ddi_get_instance(dip); 15820906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 15920906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 16020906b23SVikram Hegde const char *f = "iommulib_nexus_register"; 16120906b23SVikram Hegde 16220906b23SVikram Hegde ASSERT(nexops); 16320906b23SVikram Hegde ASSERT(handle); 16420906b23SVikram Hegde 16520906b23SVikram Hegde *handle = NULL; 16620906b23SVikram Hegde 16720906b23SVikram Hegde /* 16820906b23SVikram Hegde * Root node is never busy held 16920906b23SVikram Hegde */ 17020906b23SVikram Hegde if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 17120906b23SVikram Hegde !DEVI_BUSY_OWNED(pdip))) { 17220906b23SVikram Hegde cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 17320906b23SVikram Hegde "or busy held for nexops vector (%p). Failing registration", 17420906b23SVikram Hegde f, (void *)nexops); 17520906b23SVikram Hegde return (DDI_FAILURE); 17620906b23SVikram Hegde } 17720906b23SVikram Hegde 17820906b23SVikram Hegde if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 17920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 18020906b23SVikram Hegde "in nexops vector (%p). Failing NEXUS registration", 18120906b23SVikram Hegde f, driver, instance, (void *)nexops); 18220906b23SVikram Hegde return (DDI_FAILURE); 18320906b23SVikram Hegde } 18420906b23SVikram Hegde 18520906b23SVikram Hegde ASSERT(nexops->nops_data == NULL); 18620906b23SVikram Hegde 18720906b23SVikram Hegde if (nexops->nops_id == NULL) { 18820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 18920906b23SVikram Hegde "Failing registration for nexops vector: %p", 19020906b23SVikram Hegde f, driver, instance, (void *)nexops); 19120906b23SVikram Hegde return (DDI_FAILURE); 19220906b23SVikram Hegde } 19320906b23SVikram Hegde 19420906b23SVikram Hegde if (nexops->nops_dma_allochdl == NULL) { 19520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 19620906b23SVikram Hegde "Failing registration for ops vector: %p", f, 19720906b23SVikram Hegde driver, instance, (void *)nexops); 19820906b23SVikram Hegde return (DDI_FAILURE); 19920906b23SVikram Hegde } 20020906b23SVikram Hegde 20120906b23SVikram Hegde if (nexops->nops_dma_freehdl == NULL) { 20220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 20320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 20420906b23SVikram Hegde driver, instance, (void *)nexops); 20520906b23SVikram Hegde return (DDI_FAILURE); 20620906b23SVikram Hegde } 20720906b23SVikram Hegde 20820906b23SVikram Hegde if (nexops->nops_dma_bindhdl == NULL) { 20920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 21020906b23SVikram Hegde "Failing registration for ops vector: %p", f, 21120906b23SVikram Hegde driver, instance, (void *)nexops); 21220906b23SVikram Hegde return (DDI_FAILURE); 21320906b23SVikram Hegde } 21420906b23SVikram Hegde 21520906b23SVikram Hegde if (nexops->nops_dma_sync == NULL) { 21620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 21720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 21820906b23SVikram Hegde driver, instance, (void *)nexops); 21920906b23SVikram Hegde return (DDI_FAILURE); 22020906b23SVikram Hegde } 22120906b23SVikram Hegde 22220906b23SVikram Hegde 22320906b23SVikram Hegde if (nexops->nops_dma_reset_cookies == NULL) { 22420906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies 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 if (nexops->nops_dma_get_cookies == NULL) { 23120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 23220906b23SVikram Hegde "Failing registration for ops vector: %p", f, 23320906b23SVikram Hegde driver, instance, (void *)nexops); 23420906b23SVikram Hegde return (DDI_FAILURE); 23520906b23SVikram Hegde } 23620906b23SVikram Hegde 23720906b23SVikram Hegde if (nexops->nops_dma_win == NULL) { 23820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 23920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 24020906b23SVikram Hegde driver, instance, (void *)nexops); 24120906b23SVikram Hegde return (DDI_FAILURE); 24220906b23SVikram Hegde } 24320906b23SVikram Hegde 24420906b23SVikram Hegde /* Check for legacy ops */ 24520906b23SVikram Hegde if (nexops->nops_dma_map == NULL) { 24620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_map op. " 24720906b23SVikram Hegde "Failing registration for ops vector: %p", f, 24820906b23SVikram Hegde driver, instance, (void *)nexops); 24920906b23SVikram Hegde return (DDI_FAILURE); 25020906b23SVikram Hegde } 25120906b23SVikram Hegde 25220906b23SVikram Hegde if (nexops->nops_dma_mctl == NULL) { 25320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_mctl op. " 25420906b23SVikram Hegde "Failing registration for ops vector: %p", f, 25520906b23SVikram Hegde driver, instance, (void *)nexops); 25620906b23SVikram Hegde return (DDI_FAILURE); 25720906b23SVikram Hegde } 25820906b23SVikram Hegde 25920906b23SVikram Hegde nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 26020906b23SVikram Hegde 26120906b23SVikram Hegde mutex_enter(&iommulib_lock); 26220906b23SVikram Hegde if (iommulib_fini == 1) { 26320906b23SVikram Hegde mutex_exit(&iommulib_lock); 26420906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 26520906b23SVikram Hegde "Failing NEXUS register.", f); 26620906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 26720906b23SVikram Hegde return (DDI_FAILURE); 26820906b23SVikram Hegde } 26920906b23SVikram Hegde 27020906b23SVikram Hegde /* 27120906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 27220906b23SVikram Hegde * nexus struct 27320906b23SVikram Hegde */ 27420906b23SVikram Hegde ndi_hold_devi(dip); 27520906b23SVikram Hegde nexp->nex_dip = dip; 27620906b23SVikram Hegde nexp->nex_ops = *nexops; 27720906b23SVikram Hegde 27820906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 27920906b23SVikram Hegde nexp->nex_next = iommulib_nexus_list; 28020906b23SVikram Hegde iommulib_nexus_list = nexp; 28120906b23SVikram Hegde nexp->nex_prev = NULL; 28220906b23SVikram Hegde 28320906b23SVikram Hegde if (nexp->nex_next != NULL) 28420906b23SVikram Hegde nexp->nex_next->nex_prev = nexp; 28520906b23SVikram Hegde 28620906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 28720906b23SVikram Hegde mutex_exit(&iommulib_lock); 28820906b23SVikram Hegde 28920906b23SVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 29020906b23SVikram Hegde "nexops=%p", f, driver, instance, ddi_node_name(dip), 29120906b23SVikram Hegde (void *)nexops); 29220906b23SVikram Hegde 29320906b23SVikram Hegde *handle = nexp; 29420906b23SVikram Hegde 29520906b23SVikram Hegde return (DDI_SUCCESS); 29620906b23SVikram Hegde } 29720906b23SVikram Hegde 29820906b23SVikram Hegde int 29920906b23SVikram Hegde iommulib_nexus_unregister(iommulib_nexhandle_t handle) 30020906b23SVikram Hegde { 30120906b23SVikram Hegde dev_info_t *dip; 30220906b23SVikram Hegde int instance; 30320906b23SVikram Hegde const char *driver; 30420906b23SVikram Hegde iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 30520906b23SVikram Hegde const char *f = "iommulib_nexus_unregister"; 30620906b23SVikram Hegde 30720906b23SVikram Hegde ASSERT(nexp); 30820906b23SVikram Hegde 30920906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 31020906b23SVikram Hegde 31120906b23SVikram Hegde dip = nexp->nex_dip; 31220906b23SVikram Hegde driver = ddi_driver_name(dip); 31320906b23SVikram Hegde instance = ddi_get_instance(dip); 31420906b23SVikram Hegde 31520906b23SVikram Hegde /* A future enhancement would be to add ref-counts */ 31620906b23SVikram Hegde 31720906b23SVikram Hegde if (nexp->nex_prev == NULL) { 31820906b23SVikram Hegde iommulib_nexus_list = nexp->nex_next; 31920906b23SVikram Hegde } else { 32020906b23SVikram Hegde nexp->nex_prev->nex_next = nexp->nex_next; 32120906b23SVikram Hegde } 32220906b23SVikram Hegde 32320906b23SVikram Hegde if (nexp->nex_next != NULL) 32420906b23SVikram Hegde nexp->nex_next->nex_prev = nexp->nex_prev; 32520906b23SVikram Hegde 32620906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 32720906b23SVikram Hegde 32820906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 32920906b23SVikram Hegde 33020906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NEXUS (%s) handle successfully " 33120906b23SVikram Hegde "unregistered from IOMMULIB", f, driver, instance, 33220906b23SVikram Hegde ddi_node_name(dip)); 33320906b23SVikram Hegde 33420906b23SVikram Hegde ndi_rele_devi(dip); 33520906b23SVikram Hegde 33620906b23SVikram Hegde return (DDI_SUCCESS); 33720906b23SVikram Hegde } 33820906b23SVikram Hegde 33920906b23SVikram Hegde static iommulib_nexops_t * 34020906b23SVikram Hegde lookup_nexops(dev_info_t *dip) 34120906b23SVikram Hegde { 34220906b23SVikram Hegde iommulib_nex_t *nexp; 34320906b23SVikram Hegde 34420906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 34520906b23SVikram Hegde nexp = iommulib_nexus_list; 34620906b23SVikram Hegde while (nexp) { 34720906b23SVikram Hegde if (nexp->nex_dip == dip) 34820906b23SVikram Hegde break; 34920906b23SVikram Hegde nexp = nexp->nex_next; 35020906b23SVikram Hegde } 35120906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 35220906b23SVikram Hegde 35320906b23SVikram Hegde return (nexp ? &nexp->nex_ops : NULL); 35420906b23SVikram Hegde } 35520906b23SVikram Hegde 35620906b23SVikram Hegde int 35720906b23SVikram Hegde iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 35820906b23SVikram Hegde iommulib_handle_t *handle) 35920906b23SVikram Hegde { 36020906b23SVikram Hegde const char *vendor; 36120906b23SVikram Hegde iommulib_unit_t *unitp; 36220906b23SVikram Hegde int instance = ddi_get_instance(dip); 36320906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 36420906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 36520906b23SVikram Hegde const char *f = "iommulib_register"; 36620906b23SVikram Hegde 36720906b23SVikram Hegde ASSERT(ops); 36820906b23SVikram Hegde ASSERT(handle); 36920906b23SVikram Hegde 37020906b23SVikram Hegde if (i_ddi_node_state(dip) < DS_PROBED || !DEVI_BUSY_OWNED(pdip)) { 37120906b23SVikram Hegde cmn_err(CE_WARN, "%s: devinfo node not in DS_PROBED or " 37220906b23SVikram Hegde "busy held for ops vector (%p). Failing registration", 37320906b23SVikram Hegde f, (void *)ops); 37420906b23SVikram Hegde return (DDI_FAILURE); 37520906b23SVikram Hegde } 37620906b23SVikram Hegde 37720906b23SVikram Hegde 37820906b23SVikram Hegde if (ops->ilops_vers != IOMMU_OPS_VERSION) { 37920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 38020906b23SVikram Hegde "in ops vector (%p). Failing registration", f, driver, 38120906b23SVikram Hegde instance, (void *)ops); 38220906b23SVikram Hegde return (DDI_FAILURE); 38320906b23SVikram Hegde } 38420906b23SVikram Hegde 38520906b23SVikram Hegde switch (ops->ilops_vendor) { 38620906b23SVikram Hegde case AMD_IOMMU: 38720906b23SVikram Hegde vendor = "AMD"; 38820906b23SVikram Hegde break; 38920906b23SVikram Hegde case INTEL_IOMMU: 39020906b23SVikram Hegde vendor = "Intel"; 39120906b23SVikram Hegde break; 39220906b23SVikram Hegde case INVALID_VENDOR: 39320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 39420906b23SVikram Hegde "Failing registration for ops vector: %p", f, 39520906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 39620906b23SVikram Hegde return (DDI_FAILURE); 39720906b23SVikram Hegde default: 39820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 39920906b23SVikram Hegde "Failing registration for ops vector: %p", f, 40020906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 40120906b23SVikram Hegde return (DDI_FAILURE); 40220906b23SVikram Hegde } 40320906b23SVikram Hegde 40420906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: Detected IOMMU registration from vendor %s", 40520906b23SVikram Hegde f, driver, instance, vendor); 40620906b23SVikram Hegde 40720906b23SVikram Hegde if (ops->ilops_data == NULL) { 40820906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 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_id == NULL) { 41520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 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_probe == NULL) { 42220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL probe 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_allochdl == NULL) { 42920906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl 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_freehdl == NULL) { 43620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl 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_bindhdl == NULL) { 44320906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl 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 if (ops->ilops_dma_sync == NULL) { 45020906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 45120906b23SVikram Hegde "Failing registration for ops vector: %p", f, 45220906b23SVikram Hegde driver, instance, (void *)ops); 45320906b23SVikram Hegde return (DDI_FAILURE); 45420906b23SVikram Hegde } 45520906b23SVikram Hegde 45620906b23SVikram Hegde if (ops->ilops_dma_win == NULL) { 45720906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 45820906b23SVikram Hegde "Failing registration for ops vector: %p", f, 45920906b23SVikram Hegde driver, instance, (void *)ops); 46020906b23SVikram Hegde return (DDI_FAILURE); 46120906b23SVikram Hegde } 46220906b23SVikram Hegde 46320906b23SVikram Hegde /* Check for legacy ops */ 46420906b23SVikram Hegde if (ops->ilops_dma_map == NULL) { 46520906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_map op. " 46620906b23SVikram Hegde "Failing registration for ops vector: %p", f, 46720906b23SVikram Hegde driver, instance, (void *)ops); 46820906b23SVikram Hegde return (DDI_FAILURE); 46920906b23SVikram Hegde } 47020906b23SVikram Hegde 47120906b23SVikram Hegde if (ops->ilops_dma_mctl == NULL) { 47220906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_mctl op. " 47320906b23SVikram Hegde "Failing registration for ops vector: %p", f, 47420906b23SVikram Hegde driver, instance, (void *)ops); 47520906b23SVikram Hegde return (DDI_FAILURE); 47620906b23SVikram Hegde } 47720906b23SVikram Hegde 47820906b23SVikram Hegde unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 47920906b23SVikram Hegde mutex_enter(&iommulib_lock); 48020906b23SVikram Hegde if (iommulib_fini == 1) { 48120906b23SVikram Hegde mutex_exit(&iommulib_lock); 48220906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 48320906b23SVikram Hegde f); 48420906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 48520906b23SVikram Hegde return (DDI_FAILURE); 48620906b23SVikram Hegde } 48720906b23SVikram Hegde 48820906b23SVikram Hegde /* 48920906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 49020906b23SVikram Hegde * IOMMU unit 49120906b23SVikram Hegde */ 49220906b23SVikram Hegde mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 49320906b23SVikram Hegde 49420906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 49520906b23SVikram Hegde unitp->ilu_unitid = ++iommulib_unit_ids; 49620906b23SVikram Hegde unitp->ilu_ref = 0; 49720906b23SVikram Hegde ndi_hold_devi(dip); 49820906b23SVikram Hegde unitp->ilu_dip = dip; 49920906b23SVikram Hegde unitp->ilu_ops = ops; 50020906b23SVikram Hegde unitp->ilu_data = ops->ilops_data; 50120906b23SVikram Hegde 50220906b23SVikram Hegde unitp->ilu_next = iommulib_list; 50320906b23SVikram Hegde unitp->ilu_prev = NULL; 50420906b23SVikram Hegde iommulib_list->ilu_prev = unitp; 50520906b23SVikram Hegde iommulib_list = unitp; 50620906b23SVikram Hegde 50720906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 50820906b23SVikram Hegde 50920906b23SVikram Hegde iommulib_num_units++; 51020906b23SVikram Hegde 51120906b23SVikram Hegde *handle = unitp; 51220906b23SVikram Hegde 51320906b23SVikram Hegde mutex_exit(&iommulib_lock); 51420906b23SVikram Hegde 51520906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: Succesfully registered IOMMU unit " 51620906b23SVikram Hegde "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 51720906b23SVikram Hegde f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 51820906b23SVikram Hegde unitp->ilu_unitid); 51920906b23SVikram Hegde 52020906b23SVikram Hegde return (DDI_SUCCESS); 52120906b23SVikram Hegde } 52220906b23SVikram Hegde 52320906b23SVikram Hegde int 52420906b23SVikram Hegde iommulib_iommu_unregister(iommulib_handle_t handle) 52520906b23SVikram Hegde { 52620906b23SVikram Hegde uint32_t unitid; 52720906b23SVikram Hegde dev_info_t *dip; 52820906b23SVikram Hegde int instance; 52920906b23SVikram Hegde const char *driver; 53020906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 53120906b23SVikram Hegde const char *f = "iommulib_unregister"; 53220906b23SVikram Hegde 53320906b23SVikram Hegde ASSERT(unitp); 53420906b23SVikram Hegde 53520906b23SVikram Hegde mutex_enter(&iommulib_lock); 53620906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 53720906b23SVikram Hegde 53820906b23SVikram Hegde unitid = unitp->ilu_unitid; 53920906b23SVikram Hegde dip = unitp->ilu_dip; 54020906b23SVikram Hegde driver = ddi_driver_name(dip); 54120906b23SVikram Hegde instance = ddi_get_instance(dip); 54220906b23SVikram Hegde 54320906b23SVikram Hegde if (unitp->ilu_ref != 0) { 54420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 54520906b23SVikram Hegde mutex_exit(&iommulib_lock); 54620906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 54720906b23SVikram Hegde "unregister IOMMULIB unitid %u", 54820906b23SVikram Hegde f, driver, instance, unitid); 54920906b23SVikram Hegde return (DDI_FAILURE); 55020906b23SVikram Hegde } 55120906b23SVikram Hegde unitp->ilu_unitid = 0; 55220906b23SVikram Hegde ASSERT(unitp->ilu_ref == 0); 55320906b23SVikram Hegde 55420906b23SVikram Hegde if (unitp->ilu_prev == NULL) { 55520906b23SVikram Hegde iommulib_list = unitp->ilu_next; 55620906b23SVikram Hegde unitp->ilu_next->ilu_prev = NULL; 55720906b23SVikram Hegde } else { 55820906b23SVikram Hegde unitp->ilu_prev->ilu_next = unitp->ilu_next; 55920906b23SVikram Hegde unitp->ilu_next->ilu_prev = unitp->ilu_prev; 56020906b23SVikram Hegde } 56120906b23SVikram Hegde 56220906b23SVikram Hegde iommulib_num_units--; 56320906b23SVikram Hegde 56420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 56520906b23SVikram Hegde 56620906b23SVikram Hegde mutex_destroy(&unitp->ilu_lock); 56720906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 56820906b23SVikram Hegde 56920906b23SVikram Hegde mutex_exit(&iommulib_lock); 57020906b23SVikram Hegde 57120906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 57220906b23SVikram Hegde "unregistered", f, driver, instance, unitid); 57320906b23SVikram Hegde 57420906b23SVikram Hegde ndi_rele_devi(dip); 57520906b23SVikram Hegde 57620906b23SVikram Hegde return (DDI_SUCCESS); 57720906b23SVikram Hegde } 57820906b23SVikram Hegde 57920906b23SVikram Hegde int 58020906b23SVikram Hegde iommulib_nex_open(dev_info_t *rdip, uint_t *errorp) 58120906b23SVikram Hegde { 58220906b23SVikram Hegde iommulib_unit_t *unitp; 58320906b23SVikram Hegde int instance = ddi_get_instance(rdip); 58420906b23SVikram Hegde const char *driver = ddi_driver_name(rdip); 58520906b23SVikram Hegde const char *f = "iommulib_nex_open"; 58620906b23SVikram Hegde 58720906b23SVikram Hegde *errorp = 0; 58820906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = NULL; 58920906b23SVikram Hegde 59020906b23SVikram Hegde /* prevent use of IOMMU for AMD IOMMU's DMA */ 59120906b23SVikram Hegde if (strcmp(driver, "amd_iommu") == 0) { 59220906b23SVikram Hegde *errorp = ENOTSUP; 59320906b23SVikram Hegde return (DDI_FAILURE); 59420906b23SVikram Hegde } 59520906b23SVikram Hegde 59620906b23SVikram Hegde if (lookup_cache(rdip, &unitp) == DDI_SUCCESS) { 59720906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = 59820906b23SVikram Hegde (iommulib_handle_t)unitp; 59920906b23SVikram Hegde return (DDI_SUCCESS); 60020906b23SVikram Hegde } 60120906b23SVikram Hegde 60220906b23SVikram Hegde 60320906b23SVikram Hegde /* 60420906b23SVikram Hegde * Ok this dip is not in the cache. Use the probe entry point 60520906b23SVikram Hegde * to determine in a hardware specific manner whether this 60620906b23SVikram Hegde * dip is controlled by an IOMMU. If yes, insert it into the 60720906b23SVikram Hegde * cache and return the handle corresponding to the IOMMU unit. 60820906b23SVikram Hegde */ 60920906b23SVikram Hegde 61020906b23SVikram Hegde mutex_enter(&iommulib_lock); 61120906b23SVikram Hegde for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 61220906b23SVikram Hegde if (unitp->ilu_ops->ilops_probe(rdip) == DDI_SUCCESS) 61320906b23SVikram Hegde break; 61420906b23SVikram Hegde } 61520906b23SVikram Hegde 61620906b23SVikram Hegde if (unitp == NULL) { 61720906b23SVikram Hegde mutex_exit(&iommulib_lock); 61820906b23SVikram Hegde if (iommulib_debug) { 619*d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 62020906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 62120906b23SVikram Hegde "controlled by an IOMMU: path=%s", f, driver, 62220906b23SVikram Hegde instance, (void *)rdip, ddi_pathname(rdip, buf)); 623*d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 62420906b23SVikram Hegde } 62520906b23SVikram Hegde *errorp = ENOTSUP; 62620906b23SVikram Hegde return (DDI_FAILURE); 62720906b23SVikram Hegde } 62820906b23SVikram Hegde 62920906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 63020906b23SVikram Hegde unitp->ilu_ref++; 63120906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 63220906b23SVikram Hegde mutex_exit(&iommulib_lock); 63320906b23SVikram Hegde 63420906b23SVikram Hegde insert_cache(rdip, unitp); 63520906b23SVikram Hegde 63620906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = unitp; 63720906b23SVikram Hegde 63820906b23SVikram Hegde return (DDI_SUCCESS); 63920906b23SVikram Hegde } 64020906b23SVikram Hegde 64120906b23SVikram Hegde void 64220906b23SVikram Hegde iommulib_nex_close(dev_info_t *rdip) 64320906b23SVikram Hegde { 64420906b23SVikram Hegde iommulib_unit_t *unitp; 64520906b23SVikram Hegde const char *driver; 64620906b23SVikram Hegde int instance; 64720906b23SVikram Hegde uint32_t unitid; 64820906b23SVikram Hegde const char *f = "iommulib_nex_close"; 64920906b23SVikram Hegde 65020906b23SVikram Hegde unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle; 65120906b23SVikram Hegde if (unitp == NULL) 65220906b23SVikram Hegde return; 65320906b23SVikram Hegde 65420906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = NULL; 65520906b23SVikram Hegde 65620906b23SVikram Hegde /* 65720906b23SVikram Hegde * Assume we don't support DR of IOMMUs. The mapping of 65820906b23SVikram Hegde * dips to IOMMU units should not change. Let the mapping 65920906b23SVikram Hegde * persist in the cache. 66020906b23SVikram Hegde */ 66120906b23SVikram Hegde 66220906b23SVikram Hegde mutex_enter(&iommulib_lock); 66320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 66420906b23SVikram Hegde unitid = unitp->ilu_unitid; 66520906b23SVikram Hegde driver = ddi_driver_name(unitp->ilu_dip); 66620906b23SVikram Hegde instance = ddi_get_instance(unitp->ilu_dip); 66720906b23SVikram Hegde unitp->ilu_ref--; 66820906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 66920906b23SVikram Hegde mutex_exit(&iommulib_lock); 67020906b23SVikram Hegde 67120906b23SVikram Hegde if (iommulib_debug) { 672*d8fc7d07SVikram Hegde char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 673*d8fc7d07SVikram Hegde (void) ddi_pathname(rdip, buf); 67420906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 67520906b23SVikram Hegde "unitid=%u rdip path = %s", f, driver, instance, 67620906b23SVikram Hegde (void *)rdip, unitid, buf); 677*d8fc7d07SVikram Hegde kmem_free(buf, MAXPATHLEN); 67820906b23SVikram Hegde } 67920906b23SVikram Hegde } 68020906b23SVikram Hegde 68120906b23SVikram Hegde int 68220906b23SVikram Hegde iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 68320906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 68420906b23SVikram Hegde caddr_t arg, ddi_dma_handle_t *dma_handlep) 68520906b23SVikram Hegde { 68620906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 68720906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 68820906b23SVikram Hegde 68920906b23SVikram Hegde ASSERT(unitp); 69020906b23SVikram Hegde 69120906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 69220906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 69320906b23SVikram Hegde attr, waitfp, arg, dma_handlep)); 69420906b23SVikram Hegde } 69520906b23SVikram Hegde 69620906b23SVikram Hegde int 69720906b23SVikram Hegde iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 69820906b23SVikram Hegde ddi_dma_handle_t dma_handle) 69920906b23SVikram Hegde { 70020906b23SVikram Hegde int error; 70120906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 70220906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 70320906b23SVikram Hegde 70420906b23SVikram Hegde ASSERT(unitp); 70520906b23SVikram Hegde 70620906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 70720906b23SVikram Hegde error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 70820906b23SVikram Hegde rdip, dma_handle); 70920906b23SVikram Hegde 71020906b23SVikram Hegde iommulib_nex_close(rdip); 71120906b23SVikram Hegde 71220906b23SVikram Hegde return (error); 71320906b23SVikram Hegde } 71420906b23SVikram Hegde 71520906b23SVikram Hegde int 71620906b23SVikram Hegde iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 71720906b23SVikram Hegde ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 71820906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 71920906b23SVikram Hegde { 72020906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 72120906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 72220906b23SVikram Hegde 72320906b23SVikram Hegde ASSERT(unitp); 72420906b23SVikram Hegde 72520906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 72620906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 72720906b23SVikram Hegde dmareq, cookiep, ccountp)); 72820906b23SVikram Hegde } 72920906b23SVikram Hegde 73020906b23SVikram Hegde int 73120906b23SVikram Hegde iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 73220906b23SVikram Hegde ddi_dma_handle_t dma_handle) 73320906b23SVikram Hegde { 73420906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 73520906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 73620906b23SVikram Hegde 73720906b23SVikram Hegde ASSERT(unitp); 73820906b23SVikram Hegde 73920906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 74020906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 74120906b23SVikram Hegde dma_handle)); 74220906b23SVikram Hegde } 74320906b23SVikram Hegde 74420906b23SVikram Hegde int 74520906b23SVikram Hegde iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 74620906b23SVikram Hegde ddi_dma_handle_t dma_handle, off_t off, size_t len, 74720906b23SVikram Hegde uint_t cache_flags) 74820906b23SVikram Hegde { 74920906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 75020906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 75120906b23SVikram Hegde 75220906b23SVikram Hegde ASSERT(unitp); 75320906b23SVikram Hegde 75420906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 75520906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 75620906b23SVikram Hegde off, len, cache_flags)); 75720906b23SVikram Hegde } 75820906b23SVikram Hegde 75920906b23SVikram Hegde int 76020906b23SVikram Hegde iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 76120906b23SVikram Hegde ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 76220906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 76320906b23SVikram Hegde { 76420906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 76520906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 76620906b23SVikram Hegde 76720906b23SVikram Hegde ASSERT(unitp); 76820906b23SVikram Hegde 76920906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 77020906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 77120906b23SVikram Hegde win, offp, lenp, cookiep, ccountp)); 77220906b23SVikram Hegde } 77320906b23SVikram Hegde 77420906b23SVikram Hegde /* Obsolete DMA routines */ 77520906b23SVikram Hegde 77620906b23SVikram Hegde int 77720906b23SVikram Hegde iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip, 77820906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle) 77920906b23SVikram Hegde { 78020906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 78120906b23SVikram Hegde iommulib_unit_t *unitp = handle; 78220906b23SVikram Hegde 78320906b23SVikram Hegde ASSERT(unitp); 78420906b23SVikram Hegde 78520906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 78620906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_map(handle, dip, rdip, dmareq, 78720906b23SVikram Hegde dma_handle)); 78820906b23SVikram Hegde } 78920906b23SVikram Hegde 79020906b23SVikram Hegde int 79120906b23SVikram Hegde iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip, 79220906b23SVikram Hegde ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request, 79320906b23SVikram Hegde off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags) 79420906b23SVikram Hegde { 79520906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 79620906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 79720906b23SVikram Hegde 79820906b23SVikram Hegde ASSERT(unitp); 79920906b23SVikram Hegde 80020906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 80120906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_mctl(handle, dip, rdip, dma_handle, 80220906b23SVikram Hegde request, offp, lenp, objpp, cache_flags)); 80320906b23SVikram Hegde } 80420906b23SVikram Hegde 80520906b23SVikram Hegde /* Utility routines invoked by IOMMU drivers */ 80620906b23SVikram Hegde int 80720906b23SVikram Hegde iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 80820906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 80920906b23SVikram Hegde ddi_dma_handle_t *handlep) 81020906b23SVikram Hegde { 81120906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 81220906b23SVikram Hegde if (nexops == NULL) 81320906b23SVikram Hegde return (DDI_FAILURE); 81420906b23SVikram Hegde return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 81520906b23SVikram Hegde handlep)); 81620906b23SVikram Hegde } 81720906b23SVikram Hegde 81820906b23SVikram Hegde int 81920906b23SVikram Hegde iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 82020906b23SVikram Hegde ddi_dma_handle_t handle) 82120906b23SVikram Hegde { 82220906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 82320906b23SVikram Hegde if (nexops == NULL) 82420906b23SVikram Hegde return (DDI_FAILURE); 82520906b23SVikram Hegde return (nexops->nops_dma_freehdl(dip, rdip, handle)); 82620906b23SVikram Hegde } 82720906b23SVikram Hegde 82820906b23SVikram Hegde int 82920906b23SVikram Hegde iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 83020906b23SVikram Hegde ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 83120906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 83220906b23SVikram Hegde { 83320906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 83420906b23SVikram Hegde if (nexops == NULL) 83520906b23SVikram Hegde return (DDI_FAILURE); 83620906b23SVikram Hegde return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 83720906b23SVikram Hegde cookiep, ccountp)); 83820906b23SVikram Hegde } 83920906b23SVikram Hegde 84020906b23SVikram Hegde int 84120906b23SVikram Hegde iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 84220906b23SVikram Hegde ddi_dma_handle_t handle) 84320906b23SVikram Hegde { 84420906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 84520906b23SVikram Hegde if (nexops == NULL) 84620906b23SVikram Hegde return (DDI_FAILURE); 84720906b23SVikram Hegde return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 84820906b23SVikram Hegde } 84920906b23SVikram Hegde 85020906b23SVikram Hegde void 85120906b23SVikram Hegde iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 85220906b23SVikram Hegde { 85320906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 85420906b23SVikram Hegde nexops->nops_dma_reset_cookies(dip, handle); 85520906b23SVikram Hegde } 85620906b23SVikram Hegde 85720906b23SVikram Hegde int 85820906b23SVikram Hegde iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 85920906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 86020906b23SVikram Hegde { 86120906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 86220906b23SVikram Hegde if (nexops == NULL) 86320906b23SVikram Hegde return (DDI_FAILURE); 86420906b23SVikram Hegde return (nexops->nops_dma_get_cookies(dip, handle, cookiep, ccountp)); 86520906b23SVikram Hegde } 86620906b23SVikram Hegde 86720906b23SVikram Hegde int 86820906b23SVikram Hegde iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 86920906b23SVikram Hegde ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 87020906b23SVikram Hegde { 87120906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 87220906b23SVikram Hegde if (nexops == NULL) 87320906b23SVikram Hegde return (DDI_FAILURE); 87420906b23SVikram Hegde return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 87520906b23SVikram Hegde cache_flags)); 87620906b23SVikram Hegde } 87720906b23SVikram Hegde 87820906b23SVikram Hegde int 87920906b23SVikram Hegde iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 88020906b23SVikram Hegde ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 88120906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 88220906b23SVikram Hegde { 88320906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 88420906b23SVikram Hegde if (nexops == NULL) 88520906b23SVikram Hegde return (DDI_FAILURE); 88620906b23SVikram Hegde return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 88720906b23SVikram Hegde cookiep, ccountp)); 88820906b23SVikram Hegde } 88920906b23SVikram Hegde 89020906b23SVikram Hegde int 89120906b23SVikram Hegde iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip, 89220906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep) 89320906b23SVikram Hegde { 89420906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 89520906b23SVikram Hegde if (nexops == NULL) 89620906b23SVikram Hegde return (DDI_FAILURE); 89720906b23SVikram Hegde return (nexops->nops_dma_map(dip, rdip, dmareq, handlep)); 89820906b23SVikram Hegde } 89920906b23SVikram Hegde 90020906b23SVikram Hegde int 90120906b23SVikram Hegde iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 90220906b23SVikram Hegde ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp, 90320906b23SVikram Hegde size_t *lenp, caddr_t *objpp, uint_t cache_flags) 90420906b23SVikram Hegde { 90520906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 90620906b23SVikram Hegde if (nexops == NULL) 90720906b23SVikram Hegde return (DDI_FAILURE); 90820906b23SVikram Hegde return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp, 90920906b23SVikram Hegde objpp, cache_flags)); 91020906b23SVikram Hegde } 91120906b23SVikram Hegde 91220906b23SVikram Hegde int 91320906b23SVikram Hegde iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 91420906b23SVikram Hegde { 91520906b23SVikram Hegde iommulib_unit_t *unitp; 91620906b23SVikram Hegde uint64_t unitid; 91720906b23SVikram Hegde 91820906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 91920906b23SVikram Hegde 92020906b23SVikram Hegde ASSERT(unitp); 92120906b23SVikram Hegde ASSERT(unitidp); 92220906b23SVikram Hegde 92320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 92420906b23SVikram Hegde unitid = unitp->ilu_unitid; 92520906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 92620906b23SVikram Hegde 92720906b23SVikram Hegde ASSERT(unitid > 0); 92820906b23SVikram Hegde *unitidp = (uint64_t)unitid; 92920906b23SVikram Hegde 93020906b23SVikram Hegde return (DDI_SUCCESS); 93120906b23SVikram Hegde } 93220906b23SVikram Hegde 93320906b23SVikram Hegde dev_info_t * 93420906b23SVikram Hegde iommulib_iommu_getdip(iommulib_handle_t handle) 93520906b23SVikram Hegde { 93620906b23SVikram Hegde iommulib_unit_t *unitp; 93720906b23SVikram Hegde dev_info_t *dip; 93820906b23SVikram Hegde 93920906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 94020906b23SVikram Hegde 94120906b23SVikram Hegde ASSERT(unitp); 94220906b23SVikram Hegde 94320906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 94420906b23SVikram Hegde dip = unitp->ilu_dip; 94520906b23SVikram Hegde ASSERT(dip); 94620906b23SVikram Hegde ndi_hold_devi(dip); 94720906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 94820906b23SVikram Hegde 94920906b23SVikram Hegde return (dip); 95020906b23SVikram Hegde } 95120906b23SVikram Hegde 95220906b23SVikram Hegde iommulib_ops_t * 95320906b23SVikram Hegde iommulib_iommu_getops(iommulib_handle_t handle) 95420906b23SVikram Hegde { 95520906b23SVikram Hegde iommulib_unit_t *unitp; 95620906b23SVikram Hegde iommulib_ops_t *ops; 95720906b23SVikram Hegde 95820906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 95920906b23SVikram Hegde 96020906b23SVikram Hegde ASSERT(unitp); 96120906b23SVikram Hegde 96220906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 96320906b23SVikram Hegde ops = unitp->ilu_ops; 96420906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 96520906b23SVikram Hegde 96620906b23SVikram Hegde ASSERT(ops); 96720906b23SVikram Hegde 96820906b23SVikram Hegde return (ops); 96920906b23SVikram Hegde } 97020906b23SVikram Hegde 97120906b23SVikram Hegde void * 97220906b23SVikram Hegde iommulib_iommu_getdata(iommulib_handle_t handle) 97320906b23SVikram Hegde { 97420906b23SVikram Hegde iommulib_unit_t *unitp; 97520906b23SVikram Hegde void *data; 97620906b23SVikram Hegde 97720906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 97820906b23SVikram Hegde 97920906b23SVikram Hegde ASSERT(unitp); 98020906b23SVikram Hegde 98120906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 98220906b23SVikram Hegde data = unitp->ilu_data; 98320906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 98420906b23SVikram Hegde 98520906b23SVikram Hegde ASSERT(data); 98620906b23SVikram Hegde 98720906b23SVikram Hegde return (data); 98820906b23SVikram Hegde } 98920906b23SVikram Hegde 99020906b23SVikram Hegde /* 99120906b23SVikram Hegde * Internal routines 99220906b23SVikram Hegde */ 99320906b23SVikram Hegde 99420906b23SVikram Hegde static uint32_t 99520906b23SVikram Hegde hashfn(uint64_t ptr) 99620906b23SVikram Hegde { 99720906b23SVikram Hegde return (ptr % iommulib_cache_size); 99820906b23SVikram Hegde } 99920906b23SVikram Hegde 100020906b23SVikram Hegde static int 100120906b23SVikram Hegde lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp) 100220906b23SVikram Hegde { 100320906b23SVikram Hegde uint64_t idx; 100420906b23SVikram Hegde iommulib_cache_t *cachep; 100520906b23SVikram Hegde iommulib_unit_t *unitp; 100620906b23SVikram Hegde int retval = DDI_FAILURE; 100720906b23SVikram Hegde 100820906b23SVikram Hegde *unitpp = NULL; 100920906b23SVikram Hegde 101020906b23SVikram Hegde mutex_enter(&iommulib_lock); 101120906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 101220906b23SVikram Hegde 101320906b23SVikram Hegde ASSERT(iommulib_cache); 101420906b23SVikram Hegde 101520906b23SVikram Hegde idx = hashfn((uint64_t)(uintptr_t)rdip); 101620906b23SVikram Hegde 101720906b23SVikram Hegde ASSERT(idx < iommulib_cache_size); 101820906b23SVikram Hegde 101920906b23SVikram Hegde for (cachep = iommulib_cache[idx]; cachep; 102020906b23SVikram Hegde cachep = cachep->cache_next) { 102120906b23SVikram Hegde if (cachep->cache_rdip == rdip) 102220906b23SVikram Hegde break; 102320906b23SVikram Hegde } 102420906b23SVikram Hegde 102520906b23SVikram Hegde if (cachep != NULL) { 102620906b23SVikram Hegde unitp = cachep->cache_unit; 102720906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 102820906b23SVikram Hegde unitp->ilu_ref++; 102920906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 103020906b23SVikram Hegde *unitpp = unitp; 103120906b23SVikram Hegde retval = DDI_SUCCESS; 103220906b23SVikram Hegde } 103320906b23SVikram Hegde 103420906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 103520906b23SVikram Hegde mutex_exit(&iommulib_lock); 103620906b23SVikram Hegde return (retval); 103720906b23SVikram Hegde } 103820906b23SVikram Hegde 103920906b23SVikram Hegde static void 104020906b23SVikram Hegde insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp) 104120906b23SVikram Hegde { 104220906b23SVikram Hegde uint32_t idx; 104320906b23SVikram Hegde iommulib_cache_t *cachep; 104420906b23SVikram Hegde 104520906b23SVikram Hegde mutex_enter(&iommulib_lock); 104620906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 104720906b23SVikram Hegde 104820906b23SVikram Hegde ASSERT(iommulib_cache); 104920906b23SVikram Hegde 105020906b23SVikram Hegde idx = hashfn((uint64_t)(uintptr_t)rdip); 105120906b23SVikram Hegde 105220906b23SVikram Hegde ASSERT(idx < iommulib_cache_size); 105320906b23SVikram Hegde 105420906b23SVikram Hegde for (cachep = iommulib_cache[idx]; cachep; 105520906b23SVikram Hegde cachep = cachep->cache_next) { 105620906b23SVikram Hegde if (cachep->cache_rdip == rdip) 105720906b23SVikram Hegde break; 105820906b23SVikram Hegde } 105920906b23SVikram Hegde 106020906b23SVikram Hegde if (cachep == NULL) { 106120906b23SVikram Hegde cachep = kmem_zalloc(sizeof (iommulib_cache_t), KM_SLEEP); 106220906b23SVikram Hegde cachep->cache_rdip = rdip; 106320906b23SVikram Hegde cachep->cache_unit = unitp; /* ref-count set by caller */ 106420906b23SVikram Hegde cachep->cache_prev = NULL; 106520906b23SVikram Hegde cachep->cache_next = iommulib_cache[idx]; 106620906b23SVikram Hegde if (cachep->cache_next) 106720906b23SVikram Hegde cachep->cache_next->cache_prev = cachep; 106820906b23SVikram Hegde iommulib_cache[idx] = cachep; 106920906b23SVikram Hegde } 107020906b23SVikram Hegde 107120906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 107220906b23SVikram Hegde mutex_exit(&iommulib_lock); 107320906b23SVikram Hegde } 1074