17613SVikram.Hegde@Sun.COM /* 27613SVikram.Hegde@Sun.COM * CDDL HEADER START 37613SVikram.Hegde@Sun.COM * 47613SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the 57613SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License"). 67613SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License. 77613SVikram.Hegde@Sun.COM * 87613SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97613SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing. 107613SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions 117613SVikram.Hegde@Sun.COM * and limitations under the License. 127613SVikram.Hegde@Sun.COM * 137613SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147613SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157613SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167613SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177613SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187613SVikram.Hegde@Sun.COM * 197613SVikram.Hegde@Sun.COM * CDDL HEADER END 207613SVikram.Hegde@Sun.COM */ 217613SVikram.Hegde@Sun.COM /* 227613SVikram.Hegde@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237613SVikram.Hegde@Sun.COM * Use is subject to license terms. 247613SVikram.Hegde@Sun.COM */ 257613SVikram.Hegde@Sun.COM 267613SVikram.Hegde@Sun.COM #pragma ident "@(#)iommulib.c 1.6 08/09/07 SMI" 277613SVikram.Hegde@Sun.COM 287613SVikram.Hegde@Sun.COM #include <sys/sunddi.h> 297613SVikram.Hegde@Sun.COM #include <sys/sunndi.h> 307613SVikram.Hegde@Sun.COM #include <sys/errno.h> 317613SVikram.Hegde@Sun.COM #include <sys/modctl.h> 327613SVikram.Hegde@Sun.COM #include <sys/iommulib.h> 337613SVikram.Hegde@Sun.COM 347613SVikram.Hegde@Sun.COM /* ******** Type definitions private to this file ********************** */ 357613SVikram.Hegde@Sun.COM 367613SVikram.Hegde@Sun.COM /* 1 per IOMMU unit. There may be more than one per dip */ 377613SVikram.Hegde@Sun.COM typedef struct iommulib_unit { 387613SVikram.Hegde@Sun.COM kmutex_t ilu_lock; 397613SVikram.Hegde@Sun.COM uint64_t ilu_ref; 407613SVikram.Hegde@Sun.COM uint32_t ilu_unitid; 417613SVikram.Hegde@Sun.COM dev_info_t *ilu_dip; 427613SVikram.Hegde@Sun.COM iommulib_ops_t *ilu_ops; 437613SVikram.Hegde@Sun.COM void* ilu_data; 447613SVikram.Hegde@Sun.COM struct iommulib_unit *ilu_next; 457613SVikram.Hegde@Sun.COM struct iommulib_unit *ilu_prev; 467613SVikram.Hegde@Sun.COM } iommulib_unit_t; 477613SVikram.Hegde@Sun.COM 487613SVikram.Hegde@Sun.COM typedef struct iommulib_cache { 497613SVikram.Hegde@Sun.COM dev_info_t *cache_rdip; 507613SVikram.Hegde@Sun.COM iommulib_unit_t *cache_unit; 517613SVikram.Hegde@Sun.COM struct iommulib_cache *cache_next; 527613SVikram.Hegde@Sun.COM struct iommulib_cache *cache_prev; 537613SVikram.Hegde@Sun.COM } iommulib_cache_t; 547613SVikram.Hegde@Sun.COM 557613SVikram.Hegde@Sun.COM typedef struct iommulib_nex { 567613SVikram.Hegde@Sun.COM dev_info_t *nex_dip; 577613SVikram.Hegde@Sun.COM iommulib_nexops_t nex_ops; 587613SVikram.Hegde@Sun.COM struct iommulib_nex *nex_next; 597613SVikram.Hegde@Sun.COM struct iommulib_nex *nex_prev; 607613SVikram.Hegde@Sun.COM } iommulib_nex_t; 617613SVikram.Hegde@Sun.COM 627613SVikram.Hegde@Sun.COM /* ********* Function prototypes ********************* */ 637613SVikram.Hegde@Sun.COM static int lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp); 647613SVikram.Hegde@Sun.COM static void insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp); 657613SVikram.Hegde@Sun.COM 667613SVikram.Hegde@Sun.COM 677613SVikram.Hegde@Sun.COM /* ********* Globals ************************ */ 687613SVikram.Hegde@Sun.COM 697613SVikram.Hegde@Sun.COM /* IOMMU side: Following data protected by lock */ 707613SVikram.Hegde@Sun.COM static kmutex_t iommulib_lock; 717613SVikram.Hegde@Sun.COM static iommulib_unit_t *iommulib_list; 727613SVikram.Hegde@Sun.COM static uint64_t iommulib_unit_ids = 0; 737613SVikram.Hegde@Sun.COM static uint64_t iommulib_num_units = 0; 747613SVikram.Hegde@Sun.COM 757613SVikram.Hegde@Sun.COM /* rootnex side data */ 767613SVikram.Hegde@Sun.COM 777613SVikram.Hegde@Sun.COM static kmutex_t iommulib_nexus_lock; 787613SVikram.Hegde@Sun.COM static iommulib_nex_t *iommulib_nexus_list; 797613SVikram.Hegde@Sun.COM 807613SVikram.Hegde@Sun.COM #define IOMMULIB_CACHE_SIZE 256 817613SVikram.Hegde@Sun.COM static kmutex_t iommulib_cache_lock; 827613SVikram.Hegde@Sun.COM static iommulib_cache_t **iommulib_cache; 837613SVikram.Hegde@Sun.COM 847613SVikram.Hegde@Sun.COM /* tunable via /etc/system */ 857613SVikram.Hegde@Sun.COM static uint_t iommulib_cache_size = IOMMULIB_CACHE_SIZE; 867613SVikram.Hegde@Sun.COM 877613SVikram.Hegde@Sun.COM /* can be set atomically without lock */ 887613SVikram.Hegde@Sun.COM static volatile uint32_t iommulib_fini; 897613SVikram.Hegde@Sun.COM 907613SVikram.Hegde@Sun.COM /* debug flag */ 917613SVikram.Hegde@Sun.COM static int iommulib_debug; 927613SVikram.Hegde@Sun.COM 937613SVikram.Hegde@Sun.COM /* 947613SVikram.Hegde@Sun.COM * Module linkage information for the kernel. 957613SVikram.Hegde@Sun.COM */ 967613SVikram.Hegde@Sun.COM static struct modlmisc modlmisc = { 977613SVikram.Hegde@Sun.COM &mod_miscops, "IOMMU library module" 987613SVikram.Hegde@Sun.COM }; 997613SVikram.Hegde@Sun.COM 1007613SVikram.Hegde@Sun.COM static struct modlinkage modlinkage = { 1017613SVikram.Hegde@Sun.COM MODREV_1, (void *)&modlmisc, NULL 1027613SVikram.Hegde@Sun.COM }; 1037613SVikram.Hegde@Sun.COM 1047613SVikram.Hegde@Sun.COM int 1057613SVikram.Hegde@Sun.COM _init(void) 1067613SVikram.Hegde@Sun.COM { 1077613SVikram.Hegde@Sun.COM /* 1087613SVikram.Hegde@Sun.COM * static mutexes automagically initialized 1097613SVikram.Hegde@Sun.COM * by being allocated in zeroed memory 1107613SVikram.Hegde@Sun.COM */ 1117613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_cache_lock); 1127613SVikram.Hegde@Sun.COM iommulib_cache = kmem_zalloc( 1137613SVikram.Hegde@Sun.COM sizeof (iommulib_cache_t *) * iommulib_cache_size, KM_SLEEP); 1147613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_cache_lock); 1157613SVikram.Hegde@Sun.COM 1167613SVikram.Hegde@Sun.COM return (mod_install(&modlinkage)); 1177613SVikram.Hegde@Sun.COM } 1187613SVikram.Hegde@Sun.COM 1197613SVikram.Hegde@Sun.COM int 1207613SVikram.Hegde@Sun.COM _fini(void) 1217613SVikram.Hegde@Sun.COM { 1227613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 1237613SVikram.Hegde@Sun.COM if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 1247613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 1257613SVikram.Hegde@Sun.COM return (EBUSY); 1267613SVikram.Hegde@Sun.COM } 1277613SVikram.Hegde@Sun.COM iommulib_fini = 1; 1287613SVikram.Hegde@Sun.COM 1297613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_cache_lock); 1307613SVikram.Hegde@Sun.COM kmem_free(iommulib_cache, 1317613SVikram.Hegde@Sun.COM sizeof (iommulib_cache_t *) * iommulib_cache_size); 1327613SVikram.Hegde@Sun.COM iommulib_cache = NULL; 1337613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_cache_lock); 1347613SVikram.Hegde@Sun.COM 1357613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 1367613SVikram.Hegde@Sun.COM return (mod_remove(&modlinkage)); 1377613SVikram.Hegde@Sun.COM } 1387613SVikram.Hegde@Sun.COM 1397613SVikram.Hegde@Sun.COM int 1407613SVikram.Hegde@Sun.COM _info(struct modinfo *modinfop) 1417613SVikram.Hegde@Sun.COM { 1427613SVikram.Hegde@Sun.COM return (mod_info(&modlinkage, modinfop)); 1437613SVikram.Hegde@Sun.COM } 1447613SVikram.Hegde@Sun.COM 1457613SVikram.Hegde@Sun.COM /* 1467613SVikram.Hegde@Sun.COM * Routines with iommulib_iommu_* are invoked from the 1477613SVikram.Hegde@Sun.COM * IOMMU driver. 1487613SVikram.Hegde@Sun.COM * Routines with iommulib_nex* are invoked from the 1497613SVikram.Hegde@Sun.COM * nexus driver (typically rootnex) 1507613SVikram.Hegde@Sun.COM */ 1517613SVikram.Hegde@Sun.COM 1527613SVikram.Hegde@Sun.COM int 1537613SVikram.Hegde@Sun.COM iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 1547613SVikram.Hegde@Sun.COM iommulib_nexhandle_t *handle) 1557613SVikram.Hegde@Sun.COM { 1567613SVikram.Hegde@Sun.COM iommulib_nex_t *nexp; 1577613SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip); 1587613SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip); 1597613SVikram.Hegde@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 1607613SVikram.Hegde@Sun.COM const char *f = "iommulib_nexus_register"; 1617613SVikram.Hegde@Sun.COM 1627613SVikram.Hegde@Sun.COM ASSERT(nexops); 1637613SVikram.Hegde@Sun.COM ASSERT(handle); 1647613SVikram.Hegde@Sun.COM 1657613SVikram.Hegde@Sun.COM *handle = NULL; 1667613SVikram.Hegde@Sun.COM 1677613SVikram.Hegde@Sun.COM /* 1687613SVikram.Hegde@Sun.COM * Root node is never busy held 1697613SVikram.Hegde@Sun.COM */ 1707613SVikram.Hegde@Sun.COM if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 1717613SVikram.Hegde@Sun.COM !DEVI_BUSY_OWNED(pdip))) { 1727613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 1737613SVikram.Hegde@Sun.COM "or busy held for nexops vector (%p). Failing registration", 1747613SVikram.Hegde@Sun.COM f, (void *)nexops); 1757613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 1767613SVikram.Hegde@Sun.COM } 1777613SVikram.Hegde@Sun.COM 1787613SVikram.Hegde@Sun.COM if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 1797613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 1807613SVikram.Hegde@Sun.COM "in nexops vector (%p). Failing NEXUS registration", 1817613SVikram.Hegde@Sun.COM f, driver, instance, (void *)nexops); 1827613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 1837613SVikram.Hegde@Sun.COM } 1847613SVikram.Hegde@Sun.COM 1857613SVikram.Hegde@Sun.COM ASSERT(nexops->nops_data == NULL); 1867613SVikram.Hegde@Sun.COM 1877613SVikram.Hegde@Sun.COM if (nexops->nops_id == NULL) { 1887613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 1897613SVikram.Hegde@Sun.COM "Failing registration for nexops vector: %p", 1907613SVikram.Hegde@Sun.COM f, driver, instance, (void *)nexops); 1917613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 1927613SVikram.Hegde@Sun.COM } 1937613SVikram.Hegde@Sun.COM 1947613SVikram.Hegde@Sun.COM if (nexops->nops_dma_allochdl == NULL) { 1957613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 1967613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 1977613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 1987613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 1997613SVikram.Hegde@Sun.COM } 2007613SVikram.Hegde@Sun.COM 2017613SVikram.Hegde@Sun.COM if (nexops->nops_dma_freehdl == NULL) { 2027613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 2037613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2047613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2057613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2067613SVikram.Hegde@Sun.COM } 2077613SVikram.Hegde@Sun.COM 2087613SVikram.Hegde@Sun.COM if (nexops->nops_dma_bindhdl == NULL) { 2097613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 2107613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2117613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2127613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2137613SVikram.Hegde@Sun.COM } 2147613SVikram.Hegde@Sun.COM 2157613SVikram.Hegde@Sun.COM if (nexops->nops_dma_sync == NULL) { 2167613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 2177613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2187613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2197613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2207613SVikram.Hegde@Sun.COM } 2217613SVikram.Hegde@Sun.COM 2227613SVikram.Hegde@Sun.COM 2237613SVikram.Hegde@Sun.COM if (nexops->nops_dma_reset_cookies == NULL) { 2247613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. " 2257613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2267613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2277613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2287613SVikram.Hegde@Sun.COM } 2297613SVikram.Hegde@Sun.COM 2307613SVikram.Hegde@Sun.COM if (nexops->nops_dma_get_cookies == NULL) { 2317613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 2327613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2337613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2347613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2357613SVikram.Hegde@Sun.COM } 2367613SVikram.Hegde@Sun.COM 2377613SVikram.Hegde@Sun.COM if (nexops->nops_dma_win == NULL) { 2387613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 2397613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2407613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2417613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2427613SVikram.Hegde@Sun.COM } 2437613SVikram.Hegde@Sun.COM 2447613SVikram.Hegde@Sun.COM /* Check for legacy ops */ 2457613SVikram.Hegde@Sun.COM if (nexops->nops_dma_map == NULL) { 2467613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_map op. " 2477613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2487613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2497613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2507613SVikram.Hegde@Sun.COM } 2517613SVikram.Hegde@Sun.COM 2527613SVikram.Hegde@Sun.COM if (nexops->nops_dma_mctl == NULL) { 2537613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_mctl op. " 2547613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 2557613SVikram.Hegde@Sun.COM driver, instance, (void *)nexops); 2567613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2577613SVikram.Hegde@Sun.COM } 2587613SVikram.Hegde@Sun.COM 2597613SVikram.Hegde@Sun.COM nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 2607613SVikram.Hegde@Sun.COM 2617613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 2627613SVikram.Hegde@Sun.COM if (iommulib_fini == 1) { 2637613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 2647613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 2657613SVikram.Hegde@Sun.COM "Failing NEXUS register.", f); 2667613SVikram.Hegde@Sun.COM kmem_free(nexp, sizeof (iommulib_nex_t)); 2677613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 2687613SVikram.Hegde@Sun.COM } 2697613SVikram.Hegde@Sun.COM 2707613SVikram.Hegde@Sun.COM /* 2717613SVikram.Hegde@Sun.COM * fini/register race conditions have been handled. Now create the 2727613SVikram.Hegde@Sun.COM * nexus struct 2737613SVikram.Hegde@Sun.COM */ 2747613SVikram.Hegde@Sun.COM ndi_hold_devi(dip); 2757613SVikram.Hegde@Sun.COM nexp->nex_dip = dip; 2767613SVikram.Hegde@Sun.COM nexp->nex_ops = *nexops; 2777613SVikram.Hegde@Sun.COM 2787613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_nexus_lock); 2797613SVikram.Hegde@Sun.COM nexp->nex_next = iommulib_nexus_list; 2807613SVikram.Hegde@Sun.COM iommulib_nexus_list = nexp; 2817613SVikram.Hegde@Sun.COM nexp->nex_prev = NULL; 2827613SVikram.Hegde@Sun.COM 2837613SVikram.Hegde@Sun.COM if (nexp->nex_next != NULL) 2847613SVikram.Hegde@Sun.COM nexp->nex_next->nex_prev = nexp; 2857613SVikram.Hegde@Sun.COM 2867613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_nexus_lock); 2877613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 2887613SVikram.Hegde@Sun.COM 2897613SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 2907613SVikram.Hegde@Sun.COM "nexops=%p", f, driver, instance, ddi_node_name(dip), 2917613SVikram.Hegde@Sun.COM (void *)nexops); 2927613SVikram.Hegde@Sun.COM 2937613SVikram.Hegde@Sun.COM *handle = nexp; 2947613SVikram.Hegde@Sun.COM 2957613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 2967613SVikram.Hegde@Sun.COM } 2977613SVikram.Hegde@Sun.COM 2987613SVikram.Hegde@Sun.COM int 2997613SVikram.Hegde@Sun.COM iommulib_nexus_unregister(iommulib_nexhandle_t handle) 3007613SVikram.Hegde@Sun.COM { 3017613SVikram.Hegde@Sun.COM dev_info_t *dip; 3027613SVikram.Hegde@Sun.COM int instance; 3037613SVikram.Hegde@Sun.COM const char *driver; 3047613SVikram.Hegde@Sun.COM iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 3057613SVikram.Hegde@Sun.COM const char *f = "iommulib_nexus_unregister"; 3067613SVikram.Hegde@Sun.COM 3077613SVikram.Hegde@Sun.COM ASSERT(nexp); 3087613SVikram.Hegde@Sun.COM 3097613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_nexus_lock); 3107613SVikram.Hegde@Sun.COM 3117613SVikram.Hegde@Sun.COM dip = nexp->nex_dip; 3127613SVikram.Hegde@Sun.COM driver = ddi_driver_name(dip); 3137613SVikram.Hegde@Sun.COM instance = ddi_get_instance(dip); 3147613SVikram.Hegde@Sun.COM 3157613SVikram.Hegde@Sun.COM /* A future enhancement would be to add ref-counts */ 3167613SVikram.Hegde@Sun.COM 3177613SVikram.Hegde@Sun.COM if (nexp->nex_prev == NULL) { 3187613SVikram.Hegde@Sun.COM iommulib_nexus_list = nexp->nex_next; 3197613SVikram.Hegde@Sun.COM } else { 3207613SVikram.Hegde@Sun.COM nexp->nex_prev->nex_next = nexp->nex_next; 3217613SVikram.Hegde@Sun.COM } 3227613SVikram.Hegde@Sun.COM 3237613SVikram.Hegde@Sun.COM if (nexp->nex_next != NULL) 3247613SVikram.Hegde@Sun.COM nexp->nex_next->nex_prev = nexp->nex_prev; 3257613SVikram.Hegde@Sun.COM 3267613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_nexus_lock); 3277613SVikram.Hegde@Sun.COM 3287613SVikram.Hegde@Sun.COM kmem_free(nexp, sizeof (iommulib_nex_t)); 3297613SVikram.Hegde@Sun.COM 3307613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NEXUS (%s) handle successfully " 3317613SVikram.Hegde@Sun.COM "unregistered from IOMMULIB", f, driver, instance, 3327613SVikram.Hegde@Sun.COM ddi_node_name(dip)); 3337613SVikram.Hegde@Sun.COM 3347613SVikram.Hegde@Sun.COM ndi_rele_devi(dip); 3357613SVikram.Hegde@Sun.COM 3367613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 3377613SVikram.Hegde@Sun.COM } 3387613SVikram.Hegde@Sun.COM 3397613SVikram.Hegde@Sun.COM static iommulib_nexops_t * 3407613SVikram.Hegde@Sun.COM lookup_nexops(dev_info_t *dip) 3417613SVikram.Hegde@Sun.COM { 3427613SVikram.Hegde@Sun.COM iommulib_nex_t *nexp; 3437613SVikram.Hegde@Sun.COM 3447613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_nexus_lock); 3457613SVikram.Hegde@Sun.COM nexp = iommulib_nexus_list; 3467613SVikram.Hegde@Sun.COM while (nexp) { 3477613SVikram.Hegde@Sun.COM if (nexp->nex_dip == dip) 3487613SVikram.Hegde@Sun.COM break; 3497613SVikram.Hegde@Sun.COM nexp = nexp->nex_next; 3507613SVikram.Hegde@Sun.COM } 3517613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_nexus_lock); 3527613SVikram.Hegde@Sun.COM 3537613SVikram.Hegde@Sun.COM return (nexp ? &nexp->nex_ops : NULL); 3547613SVikram.Hegde@Sun.COM } 3557613SVikram.Hegde@Sun.COM 3567613SVikram.Hegde@Sun.COM int 3577613SVikram.Hegde@Sun.COM iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 3587613SVikram.Hegde@Sun.COM iommulib_handle_t *handle) 3597613SVikram.Hegde@Sun.COM { 3607613SVikram.Hegde@Sun.COM const char *vendor; 3617613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 3627613SVikram.Hegde@Sun.COM int instance = ddi_get_instance(dip); 3637613SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(dip); 3647613SVikram.Hegde@Sun.COM dev_info_t *pdip = ddi_get_parent(dip); 3657613SVikram.Hegde@Sun.COM const char *f = "iommulib_register"; 3667613SVikram.Hegde@Sun.COM 3677613SVikram.Hegde@Sun.COM ASSERT(ops); 3687613SVikram.Hegde@Sun.COM ASSERT(handle); 3697613SVikram.Hegde@Sun.COM 3707613SVikram.Hegde@Sun.COM if (i_ddi_node_state(dip) < DS_PROBED || !DEVI_BUSY_OWNED(pdip)) { 3717613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: devinfo node not in DS_PROBED or " 3727613SVikram.Hegde@Sun.COM "busy held for ops vector (%p). Failing registration", 3737613SVikram.Hegde@Sun.COM f, (void *)ops); 3747613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 3757613SVikram.Hegde@Sun.COM } 3767613SVikram.Hegde@Sun.COM 3777613SVikram.Hegde@Sun.COM 3787613SVikram.Hegde@Sun.COM if (ops->ilops_vers != IOMMU_OPS_VERSION) { 3797613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 3807613SVikram.Hegde@Sun.COM "in ops vector (%p). Failing registration", f, driver, 3817613SVikram.Hegde@Sun.COM instance, (void *)ops); 3827613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 3837613SVikram.Hegde@Sun.COM } 3847613SVikram.Hegde@Sun.COM 3857613SVikram.Hegde@Sun.COM switch (ops->ilops_vendor) { 3867613SVikram.Hegde@Sun.COM case AMD_IOMMU: 3877613SVikram.Hegde@Sun.COM vendor = "AMD"; 3887613SVikram.Hegde@Sun.COM break; 3897613SVikram.Hegde@Sun.COM case INTEL_IOMMU: 3907613SVikram.Hegde@Sun.COM vendor = "Intel"; 3917613SVikram.Hegde@Sun.COM break; 3927613SVikram.Hegde@Sun.COM case INVALID_VENDOR: 3937613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 3947613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 3957613SVikram.Hegde@Sun.COM driver, instance, ops->ilops_vendor, (void *)ops); 3967613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 3977613SVikram.Hegde@Sun.COM default: 3987613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 3997613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4007613SVikram.Hegde@Sun.COM driver, instance, ops->ilops_vendor, (void *)ops); 4017613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4027613SVikram.Hegde@Sun.COM } 4037613SVikram.Hegde@Sun.COM 4047613SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: Detected IOMMU registration from vendor %s", 4057613SVikram.Hegde@Sun.COM f, driver, instance, vendor); 4067613SVikram.Hegde@Sun.COM 4077613SVikram.Hegde@Sun.COM if (ops->ilops_data == NULL) { 4087613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 4097613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4107613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4117613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4127613SVikram.Hegde@Sun.COM } 4137613SVikram.Hegde@Sun.COM 4147613SVikram.Hegde@Sun.COM if (ops->ilops_id == NULL) { 4157613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 4167613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4177613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4187613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4197613SVikram.Hegde@Sun.COM } 4207613SVikram.Hegde@Sun.COM 4217613SVikram.Hegde@Sun.COM if (ops->ilops_probe == NULL) { 4227613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL probe op. " 4237613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4247613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4257613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4267613SVikram.Hegde@Sun.COM } 4277613SVikram.Hegde@Sun.COM 4287613SVikram.Hegde@Sun.COM if (ops->ilops_dma_allochdl == NULL) { 4297613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. " 4307613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4317613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4327613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4337613SVikram.Hegde@Sun.COM } 4347613SVikram.Hegde@Sun.COM 4357613SVikram.Hegde@Sun.COM if (ops->ilops_dma_freehdl == NULL) { 4367613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. " 4377613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4387613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4397613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4407613SVikram.Hegde@Sun.COM } 4417613SVikram.Hegde@Sun.COM 4427613SVikram.Hegde@Sun.COM if (ops->ilops_dma_bindhdl == NULL) { 4437613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. " 4447613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4457613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4467613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4477613SVikram.Hegde@Sun.COM } 4487613SVikram.Hegde@Sun.COM 4497613SVikram.Hegde@Sun.COM if (ops->ilops_dma_sync == NULL) { 4507613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 4517613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4527613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4537613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4547613SVikram.Hegde@Sun.COM } 4557613SVikram.Hegde@Sun.COM 4567613SVikram.Hegde@Sun.COM if (ops->ilops_dma_win == NULL) { 4577613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 4587613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4597613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4607613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4617613SVikram.Hegde@Sun.COM } 4627613SVikram.Hegde@Sun.COM 4637613SVikram.Hegde@Sun.COM /* Check for legacy ops */ 4647613SVikram.Hegde@Sun.COM if (ops->ilops_dma_map == NULL) { 4657613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_map op. " 4667613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4677613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4687613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4697613SVikram.Hegde@Sun.COM } 4707613SVikram.Hegde@Sun.COM 4717613SVikram.Hegde@Sun.COM if (ops->ilops_dma_mctl == NULL) { 4727613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_mctl op. " 4737613SVikram.Hegde@Sun.COM "Failing registration for ops vector: %p", f, 4747613SVikram.Hegde@Sun.COM driver, instance, (void *)ops); 4757613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4767613SVikram.Hegde@Sun.COM } 4777613SVikram.Hegde@Sun.COM 4787613SVikram.Hegde@Sun.COM unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 4797613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 4807613SVikram.Hegde@Sun.COM if (iommulib_fini == 1) { 4817613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 4827613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 4837613SVikram.Hegde@Sun.COM f); 4847613SVikram.Hegde@Sun.COM kmem_free(unitp, sizeof (iommulib_unit_t)); 4857613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 4867613SVikram.Hegde@Sun.COM } 4877613SVikram.Hegde@Sun.COM 4887613SVikram.Hegde@Sun.COM /* 4897613SVikram.Hegde@Sun.COM * fini/register race conditions have been handled. Now create the 4907613SVikram.Hegde@Sun.COM * IOMMU unit 4917613SVikram.Hegde@Sun.COM */ 4927613SVikram.Hegde@Sun.COM mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 4937613SVikram.Hegde@Sun.COM 4947613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 4957613SVikram.Hegde@Sun.COM unitp->ilu_unitid = ++iommulib_unit_ids; 4967613SVikram.Hegde@Sun.COM unitp->ilu_ref = 0; 4977613SVikram.Hegde@Sun.COM ndi_hold_devi(dip); 4987613SVikram.Hegde@Sun.COM unitp->ilu_dip = dip; 4997613SVikram.Hegde@Sun.COM unitp->ilu_ops = ops; 5007613SVikram.Hegde@Sun.COM unitp->ilu_data = ops->ilops_data; 5017613SVikram.Hegde@Sun.COM 5027613SVikram.Hegde@Sun.COM unitp->ilu_next = iommulib_list; 5037613SVikram.Hegde@Sun.COM unitp->ilu_prev = NULL; 5047613SVikram.Hegde@Sun.COM iommulib_list->ilu_prev = unitp; 5057613SVikram.Hegde@Sun.COM iommulib_list = unitp; 5067613SVikram.Hegde@Sun.COM 5077613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 5087613SVikram.Hegde@Sun.COM 5097613SVikram.Hegde@Sun.COM iommulib_num_units++; 5107613SVikram.Hegde@Sun.COM 5117613SVikram.Hegde@Sun.COM *handle = unitp; 5127613SVikram.Hegde@Sun.COM 5137613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 5147613SVikram.Hegde@Sun.COM 5157613SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: Succesfully registered IOMMU unit " 5167613SVikram.Hegde@Sun.COM "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 5177613SVikram.Hegde@Sun.COM f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 5187613SVikram.Hegde@Sun.COM unitp->ilu_unitid); 5197613SVikram.Hegde@Sun.COM 5207613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 5217613SVikram.Hegde@Sun.COM } 5227613SVikram.Hegde@Sun.COM 5237613SVikram.Hegde@Sun.COM int 5247613SVikram.Hegde@Sun.COM iommulib_iommu_unregister(iommulib_handle_t handle) 5257613SVikram.Hegde@Sun.COM { 5267613SVikram.Hegde@Sun.COM uint32_t unitid; 5277613SVikram.Hegde@Sun.COM dev_info_t *dip; 5287613SVikram.Hegde@Sun.COM int instance; 5297613SVikram.Hegde@Sun.COM const char *driver; 5307613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 5317613SVikram.Hegde@Sun.COM const char *f = "iommulib_unregister"; 5327613SVikram.Hegde@Sun.COM 5337613SVikram.Hegde@Sun.COM ASSERT(unitp); 5347613SVikram.Hegde@Sun.COM 5357613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 5367613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 5377613SVikram.Hegde@Sun.COM 5387613SVikram.Hegde@Sun.COM unitid = unitp->ilu_unitid; 5397613SVikram.Hegde@Sun.COM dip = unitp->ilu_dip; 5407613SVikram.Hegde@Sun.COM driver = ddi_driver_name(dip); 5417613SVikram.Hegde@Sun.COM instance = ddi_get_instance(dip); 5427613SVikram.Hegde@Sun.COM 5437613SVikram.Hegde@Sun.COM if (unitp->ilu_ref != 0) { 5447613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 5457613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 5467613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 5477613SVikram.Hegde@Sun.COM "unregister IOMMULIB unitid %u", 5487613SVikram.Hegde@Sun.COM f, driver, instance, unitid); 5497613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 5507613SVikram.Hegde@Sun.COM } 5517613SVikram.Hegde@Sun.COM unitp->ilu_unitid = 0; 5527613SVikram.Hegde@Sun.COM ASSERT(unitp->ilu_ref == 0); 5537613SVikram.Hegde@Sun.COM 5547613SVikram.Hegde@Sun.COM if (unitp->ilu_prev == NULL) { 5557613SVikram.Hegde@Sun.COM iommulib_list = unitp->ilu_next; 5567613SVikram.Hegde@Sun.COM unitp->ilu_next->ilu_prev = NULL; 5577613SVikram.Hegde@Sun.COM } else { 5587613SVikram.Hegde@Sun.COM unitp->ilu_prev->ilu_next = unitp->ilu_next; 5597613SVikram.Hegde@Sun.COM unitp->ilu_next->ilu_prev = unitp->ilu_prev; 5607613SVikram.Hegde@Sun.COM } 5617613SVikram.Hegde@Sun.COM 5627613SVikram.Hegde@Sun.COM iommulib_num_units--; 5637613SVikram.Hegde@Sun.COM 5647613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 5657613SVikram.Hegde@Sun.COM 5667613SVikram.Hegde@Sun.COM mutex_destroy(&unitp->ilu_lock); 5677613SVikram.Hegde@Sun.COM kmem_free(unitp, sizeof (iommulib_unit_t)); 5687613SVikram.Hegde@Sun.COM 5697613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 5707613SVikram.Hegde@Sun.COM 5717613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 5727613SVikram.Hegde@Sun.COM "unregistered", f, driver, instance, unitid); 5737613SVikram.Hegde@Sun.COM 5747613SVikram.Hegde@Sun.COM ndi_rele_devi(dip); 5757613SVikram.Hegde@Sun.COM 5767613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 5777613SVikram.Hegde@Sun.COM } 5787613SVikram.Hegde@Sun.COM 5797613SVikram.Hegde@Sun.COM int 5807613SVikram.Hegde@Sun.COM iommulib_nex_open(dev_info_t *rdip, uint_t *errorp) 5817613SVikram.Hegde@Sun.COM { 5827613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 5837613SVikram.Hegde@Sun.COM int instance = ddi_get_instance(rdip); 5847613SVikram.Hegde@Sun.COM const char *driver = ddi_driver_name(rdip); 5857613SVikram.Hegde@Sun.COM const char *f = "iommulib_nex_open"; 5867613SVikram.Hegde@Sun.COM 5877613SVikram.Hegde@Sun.COM *errorp = 0; 5887613SVikram.Hegde@Sun.COM DEVI(rdip)->devi_iommulib_handle = NULL; 5897613SVikram.Hegde@Sun.COM 5907613SVikram.Hegde@Sun.COM /* prevent use of IOMMU for AMD IOMMU's DMA */ 5917613SVikram.Hegde@Sun.COM if (strcmp(driver, "amd_iommu") == 0) { 5927613SVikram.Hegde@Sun.COM *errorp = ENOTSUP; 5937613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 5947613SVikram.Hegde@Sun.COM } 5957613SVikram.Hegde@Sun.COM 5967613SVikram.Hegde@Sun.COM if (lookup_cache(rdip, &unitp) == DDI_SUCCESS) { 5977613SVikram.Hegde@Sun.COM DEVI(rdip)->devi_iommulib_handle = 5987613SVikram.Hegde@Sun.COM (iommulib_handle_t)unitp; 5997613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 6007613SVikram.Hegde@Sun.COM } 6017613SVikram.Hegde@Sun.COM 6027613SVikram.Hegde@Sun.COM 6037613SVikram.Hegde@Sun.COM /* 6047613SVikram.Hegde@Sun.COM * Ok this dip is not in the cache. Use the probe entry point 6057613SVikram.Hegde@Sun.COM * to determine in a hardware specific manner whether this 6067613SVikram.Hegde@Sun.COM * dip is controlled by an IOMMU. If yes, insert it into the 6077613SVikram.Hegde@Sun.COM * cache and return the handle corresponding to the IOMMU unit. 6087613SVikram.Hegde@Sun.COM */ 6097613SVikram.Hegde@Sun.COM 6107613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 6117613SVikram.Hegde@Sun.COM for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 6127613SVikram.Hegde@Sun.COM if (unitp->ilu_ops->ilops_probe(rdip) == DDI_SUCCESS) 6137613SVikram.Hegde@Sun.COM break; 6147613SVikram.Hegde@Sun.COM } 6157613SVikram.Hegde@Sun.COM 6167613SVikram.Hegde@Sun.COM if (unitp == NULL) { 6177613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 6187613SVikram.Hegde@Sun.COM if (iommulib_debug) { 619*7717SVikram.Hegde@Sun.COM char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 6207613SVikram.Hegde@Sun.COM cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 6217613SVikram.Hegde@Sun.COM "controlled by an IOMMU: path=%s", f, driver, 6227613SVikram.Hegde@Sun.COM instance, (void *)rdip, ddi_pathname(rdip, buf)); 623*7717SVikram.Hegde@Sun.COM kmem_free(buf, MAXPATHLEN); 6247613SVikram.Hegde@Sun.COM } 6257613SVikram.Hegde@Sun.COM *errorp = ENOTSUP; 6267613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 6277613SVikram.Hegde@Sun.COM } 6287613SVikram.Hegde@Sun.COM 6297613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 6307613SVikram.Hegde@Sun.COM unitp->ilu_ref++; 6317613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 6327613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 6337613SVikram.Hegde@Sun.COM 6347613SVikram.Hegde@Sun.COM insert_cache(rdip, unitp); 6357613SVikram.Hegde@Sun.COM 6367613SVikram.Hegde@Sun.COM DEVI(rdip)->devi_iommulib_handle = unitp; 6377613SVikram.Hegde@Sun.COM 6387613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 6397613SVikram.Hegde@Sun.COM } 6407613SVikram.Hegde@Sun.COM 6417613SVikram.Hegde@Sun.COM void 6427613SVikram.Hegde@Sun.COM iommulib_nex_close(dev_info_t *rdip) 6437613SVikram.Hegde@Sun.COM { 6447613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 6457613SVikram.Hegde@Sun.COM const char *driver; 6467613SVikram.Hegde@Sun.COM int instance; 6477613SVikram.Hegde@Sun.COM uint32_t unitid; 6487613SVikram.Hegde@Sun.COM const char *f = "iommulib_nex_close"; 6497613SVikram.Hegde@Sun.COM 6507613SVikram.Hegde@Sun.COM unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle; 6517613SVikram.Hegde@Sun.COM if (unitp == NULL) 6527613SVikram.Hegde@Sun.COM return; 6537613SVikram.Hegde@Sun.COM 6547613SVikram.Hegde@Sun.COM DEVI(rdip)->devi_iommulib_handle = NULL; 6557613SVikram.Hegde@Sun.COM 6567613SVikram.Hegde@Sun.COM /* 6577613SVikram.Hegde@Sun.COM * Assume we don't support DR of IOMMUs. The mapping of 6587613SVikram.Hegde@Sun.COM * dips to IOMMU units should not change. Let the mapping 6597613SVikram.Hegde@Sun.COM * persist in the cache. 6607613SVikram.Hegde@Sun.COM */ 6617613SVikram.Hegde@Sun.COM 6627613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 6637613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 6647613SVikram.Hegde@Sun.COM unitid = unitp->ilu_unitid; 6657613SVikram.Hegde@Sun.COM driver = ddi_driver_name(unitp->ilu_dip); 6667613SVikram.Hegde@Sun.COM instance = ddi_get_instance(unitp->ilu_dip); 6677613SVikram.Hegde@Sun.COM unitp->ilu_ref--; 6687613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 6697613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 6707613SVikram.Hegde@Sun.COM 6717613SVikram.Hegde@Sun.COM if (iommulib_debug) { 672*7717SVikram.Hegde@Sun.COM char *buf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 673*7717SVikram.Hegde@Sun.COM (void) ddi_pathname(rdip, buf); 6747613SVikram.Hegde@Sun.COM cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 6757613SVikram.Hegde@Sun.COM "unitid=%u rdip path = %s", f, driver, instance, 6767613SVikram.Hegde@Sun.COM (void *)rdip, unitid, buf); 677*7717SVikram.Hegde@Sun.COM kmem_free(buf, MAXPATHLEN); 6787613SVikram.Hegde@Sun.COM } 6797613SVikram.Hegde@Sun.COM } 6807613SVikram.Hegde@Sun.COM 6817613SVikram.Hegde@Sun.COM int 6827613SVikram.Hegde@Sun.COM iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 6837613SVikram.Hegde@Sun.COM ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 6847613SVikram.Hegde@Sun.COM caddr_t arg, ddi_dma_handle_t *dma_handlep) 6857613SVikram.Hegde@Sun.COM { 6867613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 6877613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 6887613SVikram.Hegde@Sun.COM 6897613SVikram.Hegde@Sun.COM ASSERT(unitp); 6907613SVikram.Hegde@Sun.COM 6917613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 6927613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 6937613SVikram.Hegde@Sun.COM attr, waitfp, arg, dma_handlep)); 6947613SVikram.Hegde@Sun.COM } 6957613SVikram.Hegde@Sun.COM 6967613SVikram.Hegde@Sun.COM int 6977613SVikram.Hegde@Sun.COM iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 6987613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle) 6997613SVikram.Hegde@Sun.COM { 7007613SVikram.Hegde@Sun.COM int error; 7017613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7027613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7037613SVikram.Hegde@Sun.COM 7047613SVikram.Hegde@Sun.COM ASSERT(unitp); 7057613SVikram.Hegde@Sun.COM 7067613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7077613SVikram.Hegde@Sun.COM error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 7087613SVikram.Hegde@Sun.COM rdip, dma_handle); 7097613SVikram.Hegde@Sun.COM 7107613SVikram.Hegde@Sun.COM iommulib_nex_close(rdip); 7117613SVikram.Hegde@Sun.COM 7127613SVikram.Hegde@Sun.COM return (error); 7137613SVikram.Hegde@Sun.COM } 7147613SVikram.Hegde@Sun.COM 7157613SVikram.Hegde@Sun.COM int 7167613SVikram.Hegde@Sun.COM iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 7177613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 7187613SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookiep, uint_t *ccountp) 7197613SVikram.Hegde@Sun.COM { 7207613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7217613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7227613SVikram.Hegde@Sun.COM 7237613SVikram.Hegde@Sun.COM ASSERT(unitp); 7247613SVikram.Hegde@Sun.COM 7257613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7267613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 7277613SVikram.Hegde@Sun.COM dmareq, cookiep, ccountp)); 7287613SVikram.Hegde@Sun.COM } 7297613SVikram.Hegde@Sun.COM 7307613SVikram.Hegde@Sun.COM int 7317613SVikram.Hegde@Sun.COM iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 7327613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle) 7337613SVikram.Hegde@Sun.COM { 7347613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7357613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7367613SVikram.Hegde@Sun.COM 7377613SVikram.Hegde@Sun.COM ASSERT(unitp); 7387613SVikram.Hegde@Sun.COM 7397613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7407613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 7417613SVikram.Hegde@Sun.COM dma_handle)); 7427613SVikram.Hegde@Sun.COM } 7437613SVikram.Hegde@Sun.COM 7447613SVikram.Hegde@Sun.COM int 7457613SVikram.Hegde@Sun.COM iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 7467613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle, off_t off, size_t len, 7477613SVikram.Hegde@Sun.COM uint_t cache_flags) 7487613SVikram.Hegde@Sun.COM { 7497613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7507613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7517613SVikram.Hegde@Sun.COM 7527613SVikram.Hegde@Sun.COM ASSERT(unitp); 7537613SVikram.Hegde@Sun.COM 7547613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7557613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 7567613SVikram.Hegde@Sun.COM off, len, cache_flags)); 7577613SVikram.Hegde@Sun.COM } 7587613SVikram.Hegde@Sun.COM 7597613SVikram.Hegde@Sun.COM int 7607613SVikram.Hegde@Sun.COM iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 7617613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 7627613SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookiep, uint_t *ccountp) 7637613SVikram.Hegde@Sun.COM { 7647613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7657613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7667613SVikram.Hegde@Sun.COM 7677613SVikram.Hegde@Sun.COM ASSERT(unitp); 7687613SVikram.Hegde@Sun.COM 7697613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7707613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 7717613SVikram.Hegde@Sun.COM win, offp, lenp, cookiep, ccountp)); 7727613SVikram.Hegde@Sun.COM } 7737613SVikram.Hegde@Sun.COM 7747613SVikram.Hegde@Sun.COM /* Obsolete DMA routines */ 7757613SVikram.Hegde@Sun.COM 7767613SVikram.Hegde@Sun.COM int 7777613SVikram.Hegde@Sun.COM iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip, 7787613SVikram.Hegde@Sun.COM struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle) 7797613SVikram.Hegde@Sun.COM { 7807613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7817613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = handle; 7827613SVikram.Hegde@Sun.COM 7837613SVikram.Hegde@Sun.COM ASSERT(unitp); 7847613SVikram.Hegde@Sun.COM 7857613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 7867613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_map(handle, dip, rdip, dmareq, 7877613SVikram.Hegde@Sun.COM dma_handle)); 7887613SVikram.Hegde@Sun.COM } 7897613SVikram.Hegde@Sun.COM 7907613SVikram.Hegde@Sun.COM int 7917613SVikram.Hegde@Sun.COM iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip, 7927613SVikram.Hegde@Sun.COM ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request, 7937613SVikram.Hegde@Sun.COM off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags) 7947613SVikram.Hegde@Sun.COM { 7957613SVikram.Hegde@Sun.COM iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 7967613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 7977613SVikram.Hegde@Sun.COM 7987613SVikram.Hegde@Sun.COM ASSERT(unitp); 7997613SVikram.Hegde@Sun.COM 8007613SVikram.Hegde@Sun.COM /* No need to grab lock - the handle is reference counted */ 8017613SVikram.Hegde@Sun.COM return (unitp->ilu_ops->ilops_dma_mctl(handle, dip, rdip, dma_handle, 8027613SVikram.Hegde@Sun.COM request, offp, lenp, objpp, cache_flags)); 8037613SVikram.Hegde@Sun.COM } 8047613SVikram.Hegde@Sun.COM 8057613SVikram.Hegde@Sun.COM /* Utility routines invoked by IOMMU drivers */ 8067613SVikram.Hegde@Sun.COM int 8077613SVikram.Hegde@Sun.COM iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 8087613SVikram.Hegde@Sun.COM ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 8097613SVikram.Hegde@Sun.COM ddi_dma_handle_t *handlep) 8107613SVikram.Hegde@Sun.COM { 8117613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8127613SVikram.Hegde@Sun.COM if (nexops == NULL) 8137613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8147613SVikram.Hegde@Sun.COM return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 8157613SVikram.Hegde@Sun.COM handlep)); 8167613SVikram.Hegde@Sun.COM } 8177613SVikram.Hegde@Sun.COM 8187613SVikram.Hegde@Sun.COM int 8197613SVikram.Hegde@Sun.COM iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 8207613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle) 8217613SVikram.Hegde@Sun.COM { 8227613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8237613SVikram.Hegde@Sun.COM if (nexops == NULL) 8247613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8257613SVikram.Hegde@Sun.COM return (nexops->nops_dma_freehdl(dip, rdip, handle)); 8267613SVikram.Hegde@Sun.COM } 8277613SVikram.Hegde@Sun.COM 8287613SVikram.Hegde@Sun.COM int 8297613SVikram.Hegde@Sun.COM iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 8307613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 8317613SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookiep, uint_t *ccountp) 8327613SVikram.Hegde@Sun.COM { 8337613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8347613SVikram.Hegde@Sun.COM if (nexops == NULL) 8357613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8367613SVikram.Hegde@Sun.COM return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 8377613SVikram.Hegde@Sun.COM cookiep, ccountp)); 8387613SVikram.Hegde@Sun.COM } 8397613SVikram.Hegde@Sun.COM 8407613SVikram.Hegde@Sun.COM int 8417613SVikram.Hegde@Sun.COM iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 8427613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle) 8437613SVikram.Hegde@Sun.COM { 8447613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8457613SVikram.Hegde@Sun.COM if (nexops == NULL) 8467613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8477613SVikram.Hegde@Sun.COM return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 8487613SVikram.Hegde@Sun.COM } 8497613SVikram.Hegde@Sun.COM 8507613SVikram.Hegde@Sun.COM void 8517613SVikram.Hegde@Sun.COM iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 8527613SVikram.Hegde@Sun.COM { 8537613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8547613SVikram.Hegde@Sun.COM nexops->nops_dma_reset_cookies(dip, handle); 8557613SVikram.Hegde@Sun.COM } 8567613SVikram.Hegde@Sun.COM 8577613SVikram.Hegde@Sun.COM int 8587613SVikram.Hegde@Sun.COM iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 8597613SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookiep, uint_t *ccountp) 8607613SVikram.Hegde@Sun.COM { 8617613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8627613SVikram.Hegde@Sun.COM if (nexops == NULL) 8637613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8647613SVikram.Hegde@Sun.COM return (nexops->nops_dma_get_cookies(dip, handle, cookiep, ccountp)); 8657613SVikram.Hegde@Sun.COM } 8667613SVikram.Hegde@Sun.COM 8677613SVikram.Hegde@Sun.COM int 8687613SVikram.Hegde@Sun.COM iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 8697613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 8707613SVikram.Hegde@Sun.COM { 8717613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8727613SVikram.Hegde@Sun.COM if (nexops == NULL) 8737613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8747613SVikram.Hegde@Sun.COM return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 8757613SVikram.Hegde@Sun.COM cache_flags)); 8767613SVikram.Hegde@Sun.COM } 8777613SVikram.Hegde@Sun.COM 8787613SVikram.Hegde@Sun.COM int 8797613SVikram.Hegde@Sun.COM iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 8807613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 8817613SVikram.Hegde@Sun.COM ddi_dma_cookie_t *cookiep, uint_t *ccountp) 8827613SVikram.Hegde@Sun.COM { 8837613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8847613SVikram.Hegde@Sun.COM if (nexops == NULL) 8857613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8867613SVikram.Hegde@Sun.COM return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 8877613SVikram.Hegde@Sun.COM cookiep, ccountp)); 8887613SVikram.Hegde@Sun.COM } 8897613SVikram.Hegde@Sun.COM 8907613SVikram.Hegde@Sun.COM int 8917613SVikram.Hegde@Sun.COM iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip, 8927613SVikram.Hegde@Sun.COM struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep) 8937613SVikram.Hegde@Sun.COM { 8947613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 8957613SVikram.Hegde@Sun.COM if (nexops == NULL) 8967613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 8977613SVikram.Hegde@Sun.COM return (nexops->nops_dma_map(dip, rdip, dmareq, handlep)); 8987613SVikram.Hegde@Sun.COM } 8997613SVikram.Hegde@Sun.COM 9007613SVikram.Hegde@Sun.COM int 9017613SVikram.Hegde@Sun.COM iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 9027613SVikram.Hegde@Sun.COM ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp, 9037613SVikram.Hegde@Sun.COM size_t *lenp, caddr_t *objpp, uint_t cache_flags) 9047613SVikram.Hegde@Sun.COM { 9057613SVikram.Hegde@Sun.COM iommulib_nexops_t *nexops = lookup_nexops(dip); 9067613SVikram.Hegde@Sun.COM if (nexops == NULL) 9077613SVikram.Hegde@Sun.COM return (DDI_FAILURE); 9087613SVikram.Hegde@Sun.COM return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp, 9097613SVikram.Hegde@Sun.COM objpp, cache_flags)); 9107613SVikram.Hegde@Sun.COM } 9117613SVikram.Hegde@Sun.COM 9127613SVikram.Hegde@Sun.COM int 9137613SVikram.Hegde@Sun.COM iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 9147613SVikram.Hegde@Sun.COM { 9157613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 9167613SVikram.Hegde@Sun.COM uint64_t unitid; 9177613SVikram.Hegde@Sun.COM 9187613SVikram.Hegde@Sun.COM unitp = (iommulib_unit_t *)handle; 9197613SVikram.Hegde@Sun.COM 9207613SVikram.Hegde@Sun.COM ASSERT(unitp); 9217613SVikram.Hegde@Sun.COM ASSERT(unitidp); 9227613SVikram.Hegde@Sun.COM 9237613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 9247613SVikram.Hegde@Sun.COM unitid = unitp->ilu_unitid; 9257613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 9267613SVikram.Hegde@Sun.COM 9277613SVikram.Hegde@Sun.COM ASSERT(unitid > 0); 9287613SVikram.Hegde@Sun.COM *unitidp = (uint64_t)unitid; 9297613SVikram.Hegde@Sun.COM 9307613SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 9317613SVikram.Hegde@Sun.COM } 9327613SVikram.Hegde@Sun.COM 9337613SVikram.Hegde@Sun.COM dev_info_t * 9347613SVikram.Hegde@Sun.COM iommulib_iommu_getdip(iommulib_handle_t handle) 9357613SVikram.Hegde@Sun.COM { 9367613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 9377613SVikram.Hegde@Sun.COM dev_info_t *dip; 9387613SVikram.Hegde@Sun.COM 9397613SVikram.Hegde@Sun.COM unitp = (iommulib_unit_t *)handle; 9407613SVikram.Hegde@Sun.COM 9417613SVikram.Hegde@Sun.COM ASSERT(unitp); 9427613SVikram.Hegde@Sun.COM 9437613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 9447613SVikram.Hegde@Sun.COM dip = unitp->ilu_dip; 9457613SVikram.Hegde@Sun.COM ASSERT(dip); 9467613SVikram.Hegde@Sun.COM ndi_hold_devi(dip); 9477613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 9487613SVikram.Hegde@Sun.COM 9497613SVikram.Hegde@Sun.COM return (dip); 9507613SVikram.Hegde@Sun.COM } 9517613SVikram.Hegde@Sun.COM 9527613SVikram.Hegde@Sun.COM iommulib_ops_t * 9537613SVikram.Hegde@Sun.COM iommulib_iommu_getops(iommulib_handle_t handle) 9547613SVikram.Hegde@Sun.COM { 9557613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 9567613SVikram.Hegde@Sun.COM iommulib_ops_t *ops; 9577613SVikram.Hegde@Sun.COM 9587613SVikram.Hegde@Sun.COM unitp = (iommulib_unit_t *)handle; 9597613SVikram.Hegde@Sun.COM 9607613SVikram.Hegde@Sun.COM ASSERT(unitp); 9617613SVikram.Hegde@Sun.COM 9627613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 9637613SVikram.Hegde@Sun.COM ops = unitp->ilu_ops; 9647613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 9657613SVikram.Hegde@Sun.COM 9667613SVikram.Hegde@Sun.COM ASSERT(ops); 9677613SVikram.Hegde@Sun.COM 9687613SVikram.Hegde@Sun.COM return (ops); 9697613SVikram.Hegde@Sun.COM } 9707613SVikram.Hegde@Sun.COM 9717613SVikram.Hegde@Sun.COM void * 9727613SVikram.Hegde@Sun.COM iommulib_iommu_getdata(iommulib_handle_t handle) 9737613SVikram.Hegde@Sun.COM { 9747613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 9757613SVikram.Hegde@Sun.COM void *data; 9767613SVikram.Hegde@Sun.COM 9777613SVikram.Hegde@Sun.COM unitp = (iommulib_unit_t *)handle; 9787613SVikram.Hegde@Sun.COM 9797613SVikram.Hegde@Sun.COM ASSERT(unitp); 9807613SVikram.Hegde@Sun.COM 9817613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 9827613SVikram.Hegde@Sun.COM data = unitp->ilu_data; 9837613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 9847613SVikram.Hegde@Sun.COM 9857613SVikram.Hegde@Sun.COM ASSERT(data); 9867613SVikram.Hegde@Sun.COM 9877613SVikram.Hegde@Sun.COM return (data); 9887613SVikram.Hegde@Sun.COM } 9897613SVikram.Hegde@Sun.COM 9907613SVikram.Hegde@Sun.COM /* 9917613SVikram.Hegde@Sun.COM * Internal routines 9927613SVikram.Hegde@Sun.COM */ 9937613SVikram.Hegde@Sun.COM 9947613SVikram.Hegde@Sun.COM static uint32_t 9957613SVikram.Hegde@Sun.COM hashfn(uint64_t ptr) 9967613SVikram.Hegde@Sun.COM { 9977613SVikram.Hegde@Sun.COM return (ptr % iommulib_cache_size); 9987613SVikram.Hegde@Sun.COM } 9997613SVikram.Hegde@Sun.COM 10007613SVikram.Hegde@Sun.COM static int 10017613SVikram.Hegde@Sun.COM lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp) 10027613SVikram.Hegde@Sun.COM { 10037613SVikram.Hegde@Sun.COM uint64_t idx; 10047613SVikram.Hegde@Sun.COM iommulib_cache_t *cachep; 10057613SVikram.Hegde@Sun.COM iommulib_unit_t *unitp; 10067613SVikram.Hegde@Sun.COM int retval = DDI_FAILURE; 10077613SVikram.Hegde@Sun.COM 10087613SVikram.Hegde@Sun.COM *unitpp = NULL; 10097613SVikram.Hegde@Sun.COM 10107613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 10117613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_cache_lock); 10127613SVikram.Hegde@Sun.COM 10137613SVikram.Hegde@Sun.COM ASSERT(iommulib_cache); 10147613SVikram.Hegde@Sun.COM 10157613SVikram.Hegde@Sun.COM idx = hashfn((uint64_t)(uintptr_t)rdip); 10167613SVikram.Hegde@Sun.COM 10177613SVikram.Hegde@Sun.COM ASSERT(idx < iommulib_cache_size); 10187613SVikram.Hegde@Sun.COM 10197613SVikram.Hegde@Sun.COM for (cachep = iommulib_cache[idx]; cachep; 10207613SVikram.Hegde@Sun.COM cachep = cachep->cache_next) { 10217613SVikram.Hegde@Sun.COM if (cachep->cache_rdip == rdip) 10227613SVikram.Hegde@Sun.COM break; 10237613SVikram.Hegde@Sun.COM } 10247613SVikram.Hegde@Sun.COM 10257613SVikram.Hegde@Sun.COM if (cachep != NULL) { 10267613SVikram.Hegde@Sun.COM unitp = cachep->cache_unit; 10277613SVikram.Hegde@Sun.COM mutex_enter(&unitp->ilu_lock); 10287613SVikram.Hegde@Sun.COM unitp->ilu_ref++; 10297613SVikram.Hegde@Sun.COM mutex_exit(&unitp->ilu_lock); 10307613SVikram.Hegde@Sun.COM *unitpp = unitp; 10317613SVikram.Hegde@Sun.COM retval = DDI_SUCCESS; 10327613SVikram.Hegde@Sun.COM } 10337613SVikram.Hegde@Sun.COM 10347613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_cache_lock); 10357613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 10367613SVikram.Hegde@Sun.COM return (retval); 10377613SVikram.Hegde@Sun.COM } 10387613SVikram.Hegde@Sun.COM 10397613SVikram.Hegde@Sun.COM static void 10407613SVikram.Hegde@Sun.COM insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp) 10417613SVikram.Hegde@Sun.COM { 10427613SVikram.Hegde@Sun.COM uint32_t idx; 10437613SVikram.Hegde@Sun.COM iommulib_cache_t *cachep; 10447613SVikram.Hegde@Sun.COM 10457613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_lock); 10467613SVikram.Hegde@Sun.COM mutex_enter(&iommulib_cache_lock); 10477613SVikram.Hegde@Sun.COM 10487613SVikram.Hegde@Sun.COM ASSERT(iommulib_cache); 10497613SVikram.Hegde@Sun.COM 10507613SVikram.Hegde@Sun.COM idx = hashfn((uint64_t)(uintptr_t)rdip); 10517613SVikram.Hegde@Sun.COM 10527613SVikram.Hegde@Sun.COM ASSERT(idx < iommulib_cache_size); 10537613SVikram.Hegde@Sun.COM 10547613SVikram.Hegde@Sun.COM for (cachep = iommulib_cache[idx]; cachep; 10557613SVikram.Hegde@Sun.COM cachep = cachep->cache_next) { 10567613SVikram.Hegde@Sun.COM if (cachep->cache_rdip == rdip) 10577613SVikram.Hegde@Sun.COM break; 10587613SVikram.Hegde@Sun.COM } 10597613SVikram.Hegde@Sun.COM 10607613SVikram.Hegde@Sun.COM if (cachep == NULL) { 10617613SVikram.Hegde@Sun.COM cachep = kmem_zalloc(sizeof (iommulib_cache_t), KM_SLEEP); 10627613SVikram.Hegde@Sun.COM cachep->cache_rdip = rdip; 10637613SVikram.Hegde@Sun.COM cachep->cache_unit = unitp; /* ref-count set by caller */ 10647613SVikram.Hegde@Sun.COM cachep->cache_prev = NULL; 10657613SVikram.Hegde@Sun.COM cachep->cache_next = iommulib_cache[idx]; 10667613SVikram.Hegde@Sun.COM if (cachep->cache_next) 10677613SVikram.Hegde@Sun.COM cachep->cache_next->cache_prev = cachep; 10687613SVikram.Hegde@Sun.COM iommulib_cache[idx] = cachep; 10697613SVikram.Hegde@Sun.COM } 10707613SVikram.Hegde@Sun.COM 10717613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_cache_lock); 10727613SVikram.Hegde@Sun.COM mutex_exit(&iommulib_lock); 10737613SVikram.Hegde@Sun.COM } 1074