1*20906b23SVikram Hegde /* 2*20906b23SVikram Hegde * CDDL HEADER START 3*20906b23SVikram Hegde * 4*20906b23SVikram Hegde * The contents of this file are subject to the terms of the 5*20906b23SVikram Hegde * Common Development and Distribution License (the "License"). 6*20906b23SVikram Hegde * You may not use this file except in compliance with the License. 7*20906b23SVikram Hegde * 8*20906b23SVikram Hegde * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*20906b23SVikram Hegde * or http://www.opensolaris.org/os/licensing. 10*20906b23SVikram Hegde * See the License for the specific language governing permissions 11*20906b23SVikram Hegde * and limitations under the License. 12*20906b23SVikram Hegde * 13*20906b23SVikram Hegde * When distributing Covered Code, include this CDDL HEADER in each 14*20906b23SVikram Hegde * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*20906b23SVikram Hegde * If applicable, add the following below this CDDL HEADER, with the 16*20906b23SVikram Hegde * fields enclosed by brackets "[]" replaced with your own identifying 17*20906b23SVikram Hegde * information: Portions Copyright [yyyy] [name of copyright owner] 18*20906b23SVikram Hegde * 19*20906b23SVikram Hegde * CDDL HEADER END 20*20906b23SVikram Hegde */ 21*20906b23SVikram Hegde /* 22*20906b23SVikram Hegde * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*20906b23SVikram Hegde * Use is subject to license terms. 24*20906b23SVikram Hegde */ 25*20906b23SVikram Hegde 26*20906b23SVikram Hegde #pragma ident "@(#)iommulib.c 1.6 08/09/07 SMI" 27*20906b23SVikram Hegde 28*20906b23SVikram Hegde #include <sys/sunddi.h> 29*20906b23SVikram Hegde #include <sys/sunndi.h> 30*20906b23SVikram Hegde #include <sys/errno.h> 31*20906b23SVikram Hegde #include <sys/modctl.h> 32*20906b23SVikram Hegde #include <sys/iommulib.h> 33*20906b23SVikram Hegde 34*20906b23SVikram Hegde /* ******** Type definitions private to this file ********************** */ 35*20906b23SVikram Hegde 36*20906b23SVikram Hegde /* 1 per IOMMU unit. There may be more than one per dip */ 37*20906b23SVikram Hegde typedef struct iommulib_unit { 38*20906b23SVikram Hegde kmutex_t ilu_lock; 39*20906b23SVikram Hegde uint64_t ilu_ref; 40*20906b23SVikram Hegde uint32_t ilu_unitid; 41*20906b23SVikram Hegde dev_info_t *ilu_dip; 42*20906b23SVikram Hegde iommulib_ops_t *ilu_ops; 43*20906b23SVikram Hegde void* ilu_data; 44*20906b23SVikram Hegde struct iommulib_unit *ilu_next; 45*20906b23SVikram Hegde struct iommulib_unit *ilu_prev; 46*20906b23SVikram Hegde } iommulib_unit_t; 47*20906b23SVikram Hegde 48*20906b23SVikram Hegde typedef struct iommulib_cache { 49*20906b23SVikram Hegde dev_info_t *cache_rdip; 50*20906b23SVikram Hegde iommulib_unit_t *cache_unit; 51*20906b23SVikram Hegde struct iommulib_cache *cache_next; 52*20906b23SVikram Hegde struct iommulib_cache *cache_prev; 53*20906b23SVikram Hegde } iommulib_cache_t; 54*20906b23SVikram Hegde 55*20906b23SVikram Hegde typedef struct iommulib_nex { 56*20906b23SVikram Hegde dev_info_t *nex_dip; 57*20906b23SVikram Hegde iommulib_nexops_t nex_ops; 58*20906b23SVikram Hegde struct iommulib_nex *nex_next; 59*20906b23SVikram Hegde struct iommulib_nex *nex_prev; 60*20906b23SVikram Hegde } iommulib_nex_t; 61*20906b23SVikram Hegde 62*20906b23SVikram Hegde /* ********* Function prototypes ********************* */ 63*20906b23SVikram Hegde static int lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp); 64*20906b23SVikram Hegde static void insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp); 65*20906b23SVikram Hegde 66*20906b23SVikram Hegde 67*20906b23SVikram Hegde /* ********* Globals ************************ */ 68*20906b23SVikram Hegde 69*20906b23SVikram Hegde /* IOMMU side: Following data protected by lock */ 70*20906b23SVikram Hegde static kmutex_t iommulib_lock; 71*20906b23SVikram Hegde static iommulib_unit_t *iommulib_list; 72*20906b23SVikram Hegde static uint64_t iommulib_unit_ids = 0; 73*20906b23SVikram Hegde static uint64_t iommulib_num_units = 0; 74*20906b23SVikram Hegde 75*20906b23SVikram Hegde /* rootnex side data */ 76*20906b23SVikram Hegde 77*20906b23SVikram Hegde static kmutex_t iommulib_nexus_lock; 78*20906b23SVikram Hegde static iommulib_nex_t *iommulib_nexus_list; 79*20906b23SVikram Hegde 80*20906b23SVikram Hegde #define IOMMULIB_CACHE_SIZE 256 81*20906b23SVikram Hegde static kmutex_t iommulib_cache_lock; 82*20906b23SVikram Hegde static iommulib_cache_t **iommulib_cache; 83*20906b23SVikram Hegde 84*20906b23SVikram Hegde /* tunable via /etc/system */ 85*20906b23SVikram Hegde static uint_t iommulib_cache_size = IOMMULIB_CACHE_SIZE; 86*20906b23SVikram Hegde 87*20906b23SVikram Hegde /* can be set atomically without lock */ 88*20906b23SVikram Hegde static volatile uint32_t iommulib_fini; 89*20906b23SVikram Hegde 90*20906b23SVikram Hegde /* debug flag */ 91*20906b23SVikram Hegde static int iommulib_debug; 92*20906b23SVikram Hegde 93*20906b23SVikram Hegde /* 94*20906b23SVikram Hegde * Module linkage information for the kernel. 95*20906b23SVikram Hegde */ 96*20906b23SVikram Hegde static struct modlmisc modlmisc = { 97*20906b23SVikram Hegde &mod_miscops, "IOMMU library module" 98*20906b23SVikram Hegde }; 99*20906b23SVikram Hegde 100*20906b23SVikram Hegde static struct modlinkage modlinkage = { 101*20906b23SVikram Hegde MODREV_1, (void *)&modlmisc, NULL 102*20906b23SVikram Hegde }; 103*20906b23SVikram Hegde 104*20906b23SVikram Hegde int 105*20906b23SVikram Hegde _init(void) 106*20906b23SVikram Hegde { 107*20906b23SVikram Hegde /* 108*20906b23SVikram Hegde * static mutexes automagically initialized 109*20906b23SVikram Hegde * by being allocated in zeroed memory 110*20906b23SVikram Hegde */ 111*20906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 112*20906b23SVikram Hegde iommulib_cache = kmem_zalloc( 113*20906b23SVikram Hegde sizeof (iommulib_cache_t *) * iommulib_cache_size, KM_SLEEP); 114*20906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 115*20906b23SVikram Hegde 116*20906b23SVikram Hegde return (mod_install(&modlinkage)); 117*20906b23SVikram Hegde } 118*20906b23SVikram Hegde 119*20906b23SVikram Hegde int 120*20906b23SVikram Hegde _fini(void) 121*20906b23SVikram Hegde { 122*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 123*20906b23SVikram Hegde if (iommulib_list != NULL || iommulib_nexus_list != NULL) { 124*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 125*20906b23SVikram Hegde return (EBUSY); 126*20906b23SVikram Hegde } 127*20906b23SVikram Hegde iommulib_fini = 1; 128*20906b23SVikram Hegde 129*20906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 130*20906b23SVikram Hegde kmem_free(iommulib_cache, 131*20906b23SVikram Hegde sizeof (iommulib_cache_t *) * iommulib_cache_size); 132*20906b23SVikram Hegde iommulib_cache = NULL; 133*20906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 134*20906b23SVikram Hegde 135*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 136*20906b23SVikram Hegde return (mod_remove(&modlinkage)); 137*20906b23SVikram Hegde } 138*20906b23SVikram Hegde 139*20906b23SVikram Hegde int 140*20906b23SVikram Hegde _info(struct modinfo *modinfop) 141*20906b23SVikram Hegde { 142*20906b23SVikram Hegde return (mod_info(&modlinkage, modinfop)); 143*20906b23SVikram Hegde } 144*20906b23SVikram Hegde 145*20906b23SVikram Hegde /* 146*20906b23SVikram Hegde * Routines with iommulib_iommu_* are invoked from the 147*20906b23SVikram Hegde * IOMMU driver. 148*20906b23SVikram Hegde * Routines with iommulib_nex* are invoked from the 149*20906b23SVikram Hegde * nexus driver (typically rootnex) 150*20906b23SVikram Hegde */ 151*20906b23SVikram Hegde 152*20906b23SVikram Hegde int 153*20906b23SVikram Hegde iommulib_nexus_register(dev_info_t *dip, iommulib_nexops_t *nexops, 154*20906b23SVikram Hegde iommulib_nexhandle_t *handle) 155*20906b23SVikram Hegde { 156*20906b23SVikram Hegde iommulib_nex_t *nexp; 157*20906b23SVikram Hegde int instance = ddi_get_instance(dip); 158*20906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 159*20906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 160*20906b23SVikram Hegde const char *f = "iommulib_nexus_register"; 161*20906b23SVikram Hegde 162*20906b23SVikram Hegde ASSERT(nexops); 163*20906b23SVikram Hegde ASSERT(handle); 164*20906b23SVikram Hegde 165*20906b23SVikram Hegde *handle = NULL; 166*20906b23SVikram Hegde 167*20906b23SVikram Hegde /* 168*20906b23SVikram Hegde * Root node is never busy held 169*20906b23SVikram Hegde */ 170*20906b23SVikram Hegde if (dip != ddi_root_node() && (i_ddi_node_state(dip) < DS_PROBED || 171*20906b23SVikram Hegde !DEVI_BUSY_OWNED(pdip))) { 172*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: NEXUS devinfo node not in DS_PROBED " 173*20906b23SVikram Hegde "or busy held for nexops vector (%p). Failing registration", 174*20906b23SVikram Hegde f, (void *)nexops); 175*20906b23SVikram Hegde return (DDI_FAILURE); 176*20906b23SVikram Hegde } 177*20906b23SVikram Hegde 178*20906b23SVikram Hegde if (nexops->nops_vers != IOMMU_NEXOPS_VERSION) { 179*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB nexops version " 180*20906b23SVikram Hegde "in nexops vector (%p). Failing NEXUS registration", 181*20906b23SVikram Hegde f, driver, instance, (void *)nexops); 182*20906b23SVikram Hegde return (DDI_FAILURE); 183*20906b23SVikram Hegde } 184*20906b23SVikram Hegde 185*20906b23SVikram Hegde ASSERT(nexops->nops_data == NULL); 186*20906b23SVikram Hegde 187*20906b23SVikram Hegde if (nexops->nops_id == NULL) { 188*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 189*20906b23SVikram Hegde "Failing registration for nexops vector: %p", 190*20906b23SVikram Hegde f, driver, instance, (void *)nexops); 191*20906b23SVikram Hegde return (DDI_FAILURE); 192*20906b23SVikram Hegde } 193*20906b23SVikram Hegde 194*20906b23SVikram Hegde if (nexops->nops_dma_allochdl == NULL) { 195*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_allochdl op. " 196*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 197*20906b23SVikram Hegde driver, instance, (void *)nexops); 198*20906b23SVikram Hegde return (DDI_FAILURE); 199*20906b23SVikram Hegde } 200*20906b23SVikram Hegde 201*20906b23SVikram Hegde if (nexops->nops_dma_freehdl == NULL) { 202*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_freehdl op. " 203*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 204*20906b23SVikram Hegde driver, instance, (void *)nexops); 205*20906b23SVikram Hegde return (DDI_FAILURE); 206*20906b23SVikram Hegde } 207*20906b23SVikram Hegde 208*20906b23SVikram Hegde if (nexops->nops_dma_bindhdl == NULL) { 209*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_bindhdl op. " 210*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 211*20906b23SVikram Hegde driver, instance, (void *)nexops); 212*20906b23SVikram Hegde return (DDI_FAILURE); 213*20906b23SVikram Hegde } 214*20906b23SVikram Hegde 215*20906b23SVikram Hegde if (nexops->nops_dma_sync == NULL) { 216*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_sync op. " 217*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 218*20906b23SVikram Hegde driver, instance, (void *)nexops); 219*20906b23SVikram Hegde return (DDI_FAILURE); 220*20906b23SVikram Hegde } 221*20906b23SVikram Hegde 222*20906b23SVikram Hegde 223*20906b23SVikram Hegde if (nexops->nops_dma_reset_cookies == NULL) { 224*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_reset_cookies op. " 225*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 226*20906b23SVikram Hegde driver, instance, (void *)nexops); 227*20906b23SVikram Hegde return (DDI_FAILURE); 228*20906b23SVikram Hegde } 229*20906b23SVikram Hegde 230*20906b23SVikram Hegde if (nexops->nops_dma_get_cookies == NULL) { 231*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_get_cookies op. " 232*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 233*20906b23SVikram Hegde driver, instance, (void *)nexops); 234*20906b23SVikram Hegde return (DDI_FAILURE); 235*20906b23SVikram Hegde } 236*20906b23SVikram Hegde 237*20906b23SVikram Hegde if (nexops->nops_dma_win == NULL) { 238*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL nops_dma_win op. " 239*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 240*20906b23SVikram Hegde driver, instance, (void *)nexops); 241*20906b23SVikram Hegde return (DDI_FAILURE); 242*20906b23SVikram Hegde } 243*20906b23SVikram Hegde 244*20906b23SVikram Hegde /* Check for legacy ops */ 245*20906b23SVikram Hegde if (nexops->nops_dma_map == NULL) { 246*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_map op. " 247*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 248*20906b23SVikram Hegde driver, instance, (void *)nexops); 249*20906b23SVikram Hegde return (DDI_FAILURE); 250*20906b23SVikram Hegde } 251*20906b23SVikram Hegde 252*20906b23SVikram Hegde if (nexops->nops_dma_mctl == NULL) { 253*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy nops_dma_mctl op. " 254*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 255*20906b23SVikram Hegde driver, instance, (void *)nexops); 256*20906b23SVikram Hegde return (DDI_FAILURE); 257*20906b23SVikram Hegde } 258*20906b23SVikram Hegde 259*20906b23SVikram Hegde nexp = kmem_zalloc(sizeof (iommulib_nex_t), KM_SLEEP); 260*20906b23SVikram Hegde 261*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 262*20906b23SVikram Hegde if (iommulib_fini == 1) { 263*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 264*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. " 265*20906b23SVikram Hegde "Failing NEXUS register.", f); 266*20906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 267*20906b23SVikram Hegde return (DDI_FAILURE); 268*20906b23SVikram Hegde } 269*20906b23SVikram Hegde 270*20906b23SVikram Hegde /* 271*20906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 272*20906b23SVikram Hegde * nexus struct 273*20906b23SVikram Hegde */ 274*20906b23SVikram Hegde ndi_hold_devi(dip); 275*20906b23SVikram Hegde nexp->nex_dip = dip; 276*20906b23SVikram Hegde nexp->nex_ops = *nexops; 277*20906b23SVikram Hegde 278*20906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 279*20906b23SVikram Hegde nexp->nex_next = iommulib_nexus_list; 280*20906b23SVikram Hegde iommulib_nexus_list = nexp; 281*20906b23SVikram Hegde nexp->nex_prev = NULL; 282*20906b23SVikram Hegde 283*20906b23SVikram Hegde if (nexp->nex_next != NULL) 284*20906b23SVikram Hegde nexp->nex_next->nex_prev = nexp; 285*20906b23SVikram Hegde 286*20906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 287*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 288*20906b23SVikram Hegde 289*20906b23SVikram Hegde cmn_err(CE_NOTE, "!%s: %s%d: Succesfully registered NEXUS %s " 290*20906b23SVikram Hegde "nexops=%p", f, driver, instance, ddi_node_name(dip), 291*20906b23SVikram Hegde (void *)nexops); 292*20906b23SVikram Hegde 293*20906b23SVikram Hegde *handle = nexp; 294*20906b23SVikram Hegde 295*20906b23SVikram Hegde return (DDI_SUCCESS); 296*20906b23SVikram Hegde } 297*20906b23SVikram Hegde 298*20906b23SVikram Hegde int 299*20906b23SVikram Hegde iommulib_nexus_unregister(iommulib_nexhandle_t handle) 300*20906b23SVikram Hegde { 301*20906b23SVikram Hegde dev_info_t *dip; 302*20906b23SVikram Hegde int instance; 303*20906b23SVikram Hegde const char *driver; 304*20906b23SVikram Hegde iommulib_nex_t *nexp = (iommulib_nex_t *)handle; 305*20906b23SVikram Hegde const char *f = "iommulib_nexus_unregister"; 306*20906b23SVikram Hegde 307*20906b23SVikram Hegde ASSERT(nexp); 308*20906b23SVikram Hegde 309*20906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 310*20906b23SVikram Hegde 311*20906b23SVikram Hegde dip = nexp->nex_dip; 312*20906b23SVikram Hegde driver = ddi_driver_name(dip); 313*20906b23SVikram Hegde instance = ddi_get_instance(dip); 314*20906b23SVikram Hegde 315*20906b23SVikram Hegde /* A future enhancement would be to add ref-counts */ 316*20906b23SVikram Hegde 317*20906b23SVikram Hegde if (nexp->nex_prev == NULL) { 318*20906b23SVikram Hegde iommulib_nexus_list = nexp->nex_next; 319*20906b23SVikram Hegde } else { 320*20906b23SVikram Hegde nexp->nex_prev->nex_next = nexp->nex_next; 321*20906b23SVikram Hegde } 322*20906b23SVikram Hegde 323*20906b23SVikram Hegde if (nexp->nex_next != NULL) 324*20906b23SVikram Hegde nexp->nex_next->nex_prev = nexp->nex_prev; 325*20906b23SVikram Hegde 326*20906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 327*20906b23SVikram Hegde 328*20906b23SVikram Hegde kmem_free(nexp, sizeof (iommulib_nex_t)); 329*20906b23SVikram Hegde 330*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NEXUS (%s) handle successfully " 331*20906b23SVikram Hegde "unregistered from IOMMULIB", f, driver, instance, 332*20906b23SVikram Hegde ddi_node_name(dip)); 333*20906b23SVikram Hegde 334*20906b23SVikram Hegde ndi_rele_devi(dip); 335*20906b23SVikram Hegde 336*20906b23SVikram Hegde return (DDI_SUCCESS); 337*20906b23SVikram Hegde } 338*20906b23SVikram Hegde 339*20906b23SVikram Hegde static iommulib_nexops_t * 340*20906b23SVikram Hegde lookup_nexops(dev_info_t *dip) 341*20906b23SVikram Hegde { 342*20906b23SVikram Hegde iommulib_nex_t *nexp; 343*20906b23SVikram Hegde 344*20906b23SVikram Hegde mutex_enter(&iommulib_nexus_lock); 345*20906b23SVikram Hegde nexp = iommulib_nexus_list; 346*20906b23SVikram Hegde while (nexp) { 347*20906b23SVikram Hegde if (nexp->nex_dip == dip) 348*20906b23SVikram Hegde break; 349*20906b23SVikram Hegde nexp = nexp->nex_next; 350*20906b23SVikram Hegde } 351*20906b23SVikram Hegde mutex_exit(&iommulib_nexus_lock); 352*20906b23SVikram Hegde 353*20906b23SVikram Hegde return (nexp ? &nexp->nex_ops : NULL); 354*20906b23SVikram Hegde } 355*20906b23SVikram Hegde 356*20906b23SVikram Hegde int 357*20906b23SVikram Hegde iommulib_iommu_register(dev_info_t *dip, iommulib_ops_t *ops, 358*20906b23SVikram Hegde iommulib_handle_t *handle) 359*20906b23SVikram Hegde { 360*20906b23SVikram Hegde const char *vendor; 361*20906b23SVikram Hegde iommulib_unit_t *unitp; 362*20906b23SVikram Hegde int instance = ddi_get_instance(dip); 363*20906b23SVikram Hegde const char *driver = ddi_driver_name(dip); 364*20906b23SVikram Hegde dev_info_t *pdip = ddi_get_parent(dip); 365*20906b23SVikram Hegde const char *f = "iommulib_register"; 366*20906b23SVikram Hegde 367*20906b23SVikram Hegde ASSERT(ops); 368*20906b23SVikram Hegde ASSERT(handle); 369*20906b23SVikram Hegde 370*20906b23SVikram Hegde if (i_ddi_node_state(dip) < DS_PROBED || !DEVI_BUSY_OWNED(pdip)) { 371*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: devinfo node not in DS_PROBED or " 372*20906b23SVikram Hegde "busy held for ops vector (%p). Failing registration", 373*20906b23SVikram Hegde f, (void *)ops); 374*20906b23SVikram Hegde return (DDI_FAILURE); 375*20906b23SVikram Hegde } 376*20906b23SVikram Hegde 377*20906b23SVikram Hegde 378*20906b23SVikram Hegde if (ops->ilops_vers != IOMMU_OPS_VERSION) { 379*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid IOMMULIB ops version " 380*20906b23SVikram Hegde "in ops vector (%p). Failing registration", f, driver, 381*20906b23SVikram Hegde instance, (void *)ops); 382*20906b23SVikram Hegde return (DDI_FAILURE); 383*20906b23SVikram Hegde } 384*20906b23SVikram Hegde 385*20906b23SVikram Hegde switch (ops->ilops_vendor) { 386*20906b23SVikram Hegde case AMD_IOMMU: 387*20906b23SVikram Hegde vendor = "AMD"; 388*20906b23SVikram Hegde break; 389*20906b23SVikram Hegde case INTEL_IOMMU: 390*20906b23SVikram Hegde vendor = "Intel"; 391*20906b23SVikram Hegde break; 392*20906b23SVikram Hegde case INVALID_VENDOR: 393*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: vendor field (%x) not initialized. " 394*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 395*20906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 396*20906b23SVikram Hegde return (DDI_FAILURE); 397*20906b23SVikram Hegde default: 398*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: Invalid vendor field (%x). " 399*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 400*20906b23SVikram Hegde driver, instance, ops->ilops_vendor, (void *)ops); 401*20906b23SVikram Hegde return (DDI_FAILURE); 402*20906b23SVikram Hegde } 403*20906b23SVikram Hegde 404*20906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: Detected IOMMU registration from vendor %s", 405*20906b23SVikram Hegde f, driver, instance, vendor); 406*20906b23SVikram Hegde 407*20906b23SVikram Hegde if (ops->ilops_data == NULL) { 408*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL IOMMU data field. " 409*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 410*20906b23SVikram Hegde driver, instance, (void *)ops); 411*20906b23SVikram Hegde return (DDI_FAILURE); 412*20906b23SVikram Hegde } 413*20906b23SVikram Hegde 414*20906b23SVikram Hegde if (ops->ilops_id == NULL) { 415*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL ID field. " 416*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 417*20906b23SVikram Hegde driver, instance, (void *)ops); 418*20906b23SVikram Hegde return (DDI_FAILURE); 419*20906b23SVikram Hegde } 420*20906b23SVikram Hegde 421*20906b23SVikram Hegde if (ops->ilops_probe == NULL) { 422*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL probe op. " 423*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 424*20906b23SVikram Hegde driver, instance, (void *)ops); 425*20906b23SVikram Hegde return (DDI_FAILURE); 426*20906b23SVikram Hegde } 427*20906b23SVikram Hegde 428*20906b23SVikram Hegde if (ops->ilops_dma_allochdl == NULL) { 429*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_allochdl op. " 430*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 431*20906b23SVikram Hegde driver, instance, (void *)ops); 432*20906b23SVikram Hegde return (DDI_FAILURE); 433*20906b23SVikram Hegde } 434*20906b23SVikram Hegde 435*20906b23SVikram Hegde if (ops->ilops_dma_freehdl == NULL) { 436*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_freehdl op. " 437*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 438*20906b23SVikram Hegde driver, instance, (void *)ops); 439*20906b23SVikram Hegde return (DDI_FAILURE); 440*20906b23SVikram Hegde } 441*20906b23SVikram Hegde 442*20906b23SVikram Hegde if (ops->ilops_dma_bindhdl == NULL) { 443*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_bindhdl op. " 444*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 445*20906b23SVikram Hegde driver, instance, (void *)ops); 446*20906b23SVikram Hegde return (DDI_FAILURE); 447*20906b23SVikram Hegde } 448*20906b23SVikram Hegde 449*20906b23SVikram Hegde if (ops->ilops_dma_sync == NULL) { 450*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_sync op. " 451*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 452*20906b23SVikram Hegde driver, instance, (void *)ops); 453*20906b23SVikram Hegde return (DDI_FAILURE); 454*20906b23SVikram Hegde } 455*20906b23SVikram Hegde 456*20906b23SVikram Hegde if (ops->ilops_dma_win == NULL) { 457*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL dma_win op. " 458*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 459*20906b23SVikram Hegde driver, instance, (void *)ops); 460*20906b23SVikram Hegde return (DDI_FAILURE); 461*20906b23SVikram Hegde } 462*20906b23SVikram Hegde 463*20906b23SVikram Hegde /* Check for legacy ops */ 464*20906b23SVikram Hegde if (ops->ilops_dma_map == NULL) { 465*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_map op. " 466*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 467*20906b23SVikram Hegde driver, instance, (void *)ops); 468*20906b23SVikram Hegde return (DDI_FAILURE); 469*20906b23SVikram Hegde } 470*20906b23SVikram Hegde 471*20906b23SVikram Hegde if (ops->ilops_dma_mctl == NULL) { 472*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: NULL legacy dma_mctl op. " 473*20906b23SVikram Hegde "Failing registration for ops vector: %p", f, 474*20906b23SVikram Hegde driver, instance, (void *)ops); 475*20906b23SVikram Hegde return (DDI_FAILURE); 476*20906b23SVikram Hegde } 477*20906b23SVikram Hegde 478*20906b23SVikram Hegde unitp = kmem_zalloc(sizeof (iommulib_unit_t), KM_SLEEP); 479*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 480*20906b23SVikram Hegde if (iommulib_fini == 1) { 481*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 482*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: IOMMULIB unloading. Failing register.", 483*20906b23SVikram Hegde f); 484*20906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 485*20906b23SVikram Hegde return (DDI_FAILURE); 486*20906b23SVikram Hegde } 487*20906b23SVikram Hegde 488*20906b23SVikram Hegde /* 489*20906b23SVikram Hegde * fini/register race conditions have been handled. Now create the 490*20906b23SVikram Hegde * IOMMU unit 491*20906b23SVikram Hegde */ 492*20906b23SVikram Hegde mutex_init(&unitp->ilu_lock, NULL, MUTEX_DEFAULT, NULL); 493*20906b23SVikram Hegde 494*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 495*20906b23SVikram Hegde unitp->ilu_unitid = ++iommulib_unit_ids; 496*20906b23SVikram Hegde unitp->ilu_ref = 0; 497*20906b23SVikram Hegde ndi_hold_devi(dip); 498*20906b23SVikram Hegde unitp->ilu_dip = dip; 499*20906b23SVikram Hegde unitp->ilu_ops = ops; 500*20906b23SVikram Hegde unitp->ilu_data = ops->ilops_data; 501*20906b23SVikram Hegde 502*20906b23SVikram Hegde unitp->ilu_next = iommulib_list; 503*20906b23SVikram Hegde unitp->ilu_prev = NULL; 504*20906b23SVikram Hegde iommulib_list->ilu_prev = unitp; 505*20906b23SVikram Hegde iommulib_list = unitp; 506*20906b23SVikram Hegde 507*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 508*20906b23SVikram Hegde 509*20906b23SVikram Hegde iommulib_num_units++; 510*20906b23SVikram Hegde 511*20906b23SVikram Hegde *handle = unitp; 512*20906b23SVikram Hegde 513*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 514*20906b23SVikram Hegde 515*20906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: Succesfully registered IOMMU unit " 516*20906b23SVikram Hegde "from vendor=%s, ops=%p, data=%p, IOMMULIB unitid=%u", 517*20906b23SVikram Hegde f, driver, instance, vendor, (void *)ops, (void *)unitp->ilu_data, 518*20906b23SVikram Hegde unitp->ilu_unitid); 519*20906b23SVikram Hegde 520*20906b23SVikram Hegde return (DDI_SUCCESS); 521*20906b23SVikram Hegde } 522*20906b23SVikram Hegde 523*20906b23SVikram Hegde int 524*20906b23SVikram Hegde iommulib_iommu_unregister(iommulib_handle_t handle) 525*20906b23SVikram Hegde { 526*20906b23SVikram Hegde uint32_t unitid; 527*20906b23SVikram Hegde dev_info_t *dip; 528*20906b23SVikram Hegde int instance; 529*20906b23SVikram Hegde const char *driver; 530*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 531*20906b23SVikram Hegde const char *f = "iommulib_unregister"; 532*20906b23SVikram Hegde 533*20906b23SVikram Hegde ASSERT(unitp); 534*20906b23SVikram Hegde 535*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 536*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 537*20906b23SVikram Hegde 538*20906b23SVikram Hegde unitid = unitp->ilu_unitid; 539*20906b23SVikram Hegde dip = unitp->ilu_dip; 540*20906b23SVikram Hegde driver = ddi_driver_name(dip); 541*20906b23SVikram Hegde instance = ddi_get_instance(dip); 542*20906b23SVikram Hegde 543*20906b23SVikram Hegde if (unitp->ilu_ref != 0) { 544*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 545*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 546*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle is busy. Cannot " 547*20906b23SVikram Hegde "unregister IOMMULIB unitid %u", 548*20906b23SVikram Hegde f, driver, instance, unitid); 549*20906b23SVikram Hegde return (DDI_FAILURE); 550*20906b23SVikram Hegde } 551*20906b23SVikram Hegde unitp->ilu_unitid = 0; 552*20906b23SVikram Hegde ASSERT(unitp->ilu_ref == 0); 553*20906b23SVikram Hegde 554*20906b23SVikram Hegde if (unitp->ilu_prev == NULL) { 555*20906b23SVikram Hegde iommulib_list = unitp->ilu_next; 556*20906b23SVikram Hegde unitp->ilu_next->ilu_prev = NULL; 557*20906b23SVikram Hegde } else { 558*20906b23SVikram Hegde unitp->ilu_prev->ilu_next = unitp->ilu_next; 559*20906b23SVikram Hegde unitp->ilu_next->ilu_prev = unitp->ilu_prev; 560*20906b23SVikram Hegde } 561*20906b23SVikram Hegde 562*20906b23SVikram Hegde iommulib_num_units--; 563*20906b23SVikram Hegde 564*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 565*20906b23SVikram Hegde 566*20906b23SVikram Hegde mutex_destroy(&unitp->ilu_lock); 567*20906b23SVikram Hegde kmem_free(unitp, sizeof (iommulib_unit_t)); 568*20906b23SVikram Hegde 569*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 570*20906b23SVikram Hegde 571*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: IOMMULIB handle (unitid=%u) successfully " 572*20906b23SVikram Hegde "unregistered", f, driver, instance, unitid); 573*20906b23SVikram Hegde 574*20906b23SVikram Hegde ndi_rele_devi(dip); 575*20906b23SVikram Hegde 576*20906b23SVikram Hegde return (DDI_SUCCESS); 577*20906b23SVikram Hegde } 578*20906b23SVikram Hegde 579*20906b23SVikram Hegde int 580*20906b23SVikram Hegde iommulib_nex_open(dev_info_t *rdip, uint_t *errorp) 581*20906b23SVikram Hegde { 582*20906b23SVikram Hegde iommulib_unit_t *unitp; 583*20906b23SVikram Hegde int instance = ddi_get_instance(rdip); 584*20906b23SVikram Hegde const char *driver = ddi_driver_name(rdip); 585*20906b23SVikram Hegde const char *f = "iommulib_nex_open"; 586*20906b23SVikram Hegde 587*20906b23SVikram Hegde *errorp = 0; 588*20906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = NULL; 589*20906b23SVikram Hegde 590*20906b23SVikram Hegde /* prevent use of IOMMU for AMD IOMMU's DMA */ 591*20906b23SVikram Hegde if (strcmp(driver, "amd_iommu") == 0) { 592*20906b23SVikram Hegde *errorp = ENOTSUP; 593*20906b23SVikram Hegde return (DDI_FAILURE); 594*20906b23SVikram Hegde } 595*20906b23SVikram Hegde 596*20906b23SVikram Hegde if (lookup_cache(rdip, &unitp) == DDI_SUCCESS) { 597*20906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = 598*20906b23SVikram Hegde (iommulib_handle_t)unitp; 599*20906b23SVikram Hegde return (DDI_SUCCESS); 600*20906b23SVikram Hegde } 601*20906b23SVikram Hegde 602*20906b23SVikram Hegde 603*20906b23SVikram Hegde /* 604*20906b23SVikram Hegde * Ok this dip is not in the cache. Use the probe entry point 605*20906b23SVikram Hegde * to determine in a hardware specific manner whether this 606*20906b23SVikram Hegde * dip is controlled by an IOMMU. If yes, insert it into the 607*20906b23SVikram Hegde * cache and return the handle corresponding to the IOMMU unit. 608*20906b23SVikram Hegde */ 609*20906b23SVikram Hegde 610*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 611*20906b23SVikram Hegde for (unitp = iommulib_list; unitp; unitp = unitp->ilu_next) { 612*20906b23SVikram Hegde if (unitp->ilu_ops->ilops_probe(rdip) == DDI_SUCCESS) 613*20906b23SVikram Hegde break; 614*20906b23SVikram Hegde } 615*20906b23SVikram Hegde 616*20906b23SVikram Hegde if (unitp == NULL) { 617*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 618*20906b23SVikram Hegde if (iommulib_debug) { 619*20906b23SVikram Hegde char buf[MAXPATHLEN]; 620*20906b23SVikram Hegde cmn_err(CE_WARN, "%s: %s%d: devinfo node (%p): is not " 621*20906b23SVikram Hegde "controlled by an IOMMU: path=%s", f, driver, 622*20906b23SVikram Hegde instance, (void *)rdip, ddi_pathname(rdip, buf)); 623*20906b23SVikram Hegde } 624*20906b23SVikram Hegde *errorp = ENOTSUP; 625*20906b23SVikram Hegde return (DDI_FAILURE); 626*20906b23SVikram Hegde } 627*20906b23SVikram Hegde 628*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 629*20906b23SVikram Hegde unitp->ilu_ref++; 630*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 631*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 632*20906b23SVikram Hegde 633*20906b23SVikram Hegde insert_cache(rdip, unitp); 634*20906b23SVikram Hegde 635*20906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = unitp; 636*20906b23SVikram Hegde 637*20906b23SVikram Hegde return (DDI_SUCCESS); 638*20906b23SVikram Hegde } 639*20906b23SVikram Hegde 640*20906b23SVikram Hegde void 641*20906b23SVikram Hegde iommulib_nex_close(dev_info_t *rdip) 642*20906b23SVikram Hegde { 643*20906b23SVikram Hegde char buf[MAXPATHLEN]; 644*20906b23SVikram Hegde iommulib_unit_t *unitp; 645*20906b23SVikram Hegde const char *driver; 646*20906b23SVikram Hegde int instance; 647*20906b23SVikram Hegde uint32_t unitid; 648*20906b23SVikram Hegde const char *f = "iommulib_nex_close"; 649*20906b23SVikram Hegde 650*20906b23SVikram Hegde unitp = (iommulib_unit_t *)DEVI(rdip)->devi_iommulib_handle; 651*20906b23SVikram Hegde if (unitp == NULL) 652*20906b23SVikram Hegde return; 653*20906b23SVikram Hegde 654*20906b23SVikram Hegde DEVI(rdip)->devi_iommulib_handle = NULL; 655*20906b23SVikram Hegde 656*20906b23SVikram Hegde /* 657*20906b23SVikram Hegde * Assume we don't support DR of IOMMUs. The mapping of 658*20906b23SVikram Hegde * dips to IOMMU units should not change. Let the mapping 659*20906b23SVikram Hegde * persist in the cache. 660*20906b23SVikram Hegde */ 661*20906b23SVikram Hegde 662*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 663*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 664*20906b23SVikram Hegde unitid = unitp->ilu_unitid; 665*20906b23SVikram Hegde driver = ddi_driver_name(unitp->ilu_dip); 666*20906b23SVikram Hegde instance = ddi_get_instance(unitp->ilu_dip); 667*20906b23SVikram Hegde (void) ddi_pathname(rdip, buf); 668*20906b23SVikram Hegde unitp->ilu_ref--; 669*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 670*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 671*20906b23SVikram Hegde 672*20906b23SVikram Hegde if (iommulib_debug) { 673*20906b23SVikram Hegde cmn_err(CE_NOTE, "%s: %s%d: closing IOMMU for dip (%p), " 674*20906b23SVikram Hegde "unitid=%u rdip path = %s", f, driver, instance, 675*20906b23SVikram Hegde (void *)rdip, unitid, buf); 676*20906b23SVikram Hegde } 677*20906b23SVikram Hegde } 678*20906b23SVikram Hegde 679*20906b23SVikram Hegde int 680*20906b23SVikram Hegde iommulib_nexdma_allochdl(dev_info_t *dip, dev_info_t *rdip, 681*20906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), 682*20906b23SVikram Hegde caddr_t arg, ddi_dma_handle_t *dma_handlep) 683*20906b23SVikram Hegde { 684*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 685*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 686*20906b23SVikram Hegde 687*20906b23SVikram Hegde ASSERT(unitp); 688*20906b23SVikram Hegde 689*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 690*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_allochdl(handle, dip, rdip, 691*20906b23SVikram Hegde attr, waitfp, arg, dma_handlep)); 692*20906b23SVikram Hegde } 693*20906b23SVikram Hegde 694*20906b23SVikram Hegde int 695*20906b23SVikram Hegde iommulib_nexdma_freehdl(dev_info_t *dip, dev_info_t *rdip, 696*20906b23SVikram Hegde ddi_dma_handle_t dma_handle) 697*20906b23SVikram Hegde { 698*20906b23SVikram Hegde int error; 699*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 700*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 701*20906b23SVikram Hegde 702*20906b23SVikram Hegde ASSERT(unitp); 703*20906b23SVikram Hegde 704*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 705*20906b23SVikram Hegde error = unitp->ilu_ops->ilops_dma_freehdl(handle, dip, 706*20906b23SVikram Hegde rdip, dma_handle); 707*20906b23SVikram Hegde 708*20906b23SVikram Hegde iommulib_nex_close(rdip); 709*20906b23SVikram Hegde 710*20906b23SVikram Hegde return (error); 711*20906b23SVikram Hegde } 712*20906b23SVikram Hegde 713*20906b23SVikram Hegde int 714*20906b23SVikram Hegde iommulib_nexdma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 715*20906b23SVikram Hegde ddi_dma_handle_t dma_handle, struct ddi_dma_req *dmareq, 716*20906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 717*20906b23SVikram Hegde { 718*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 719*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 720*20906b23SVikram Hegde 721*20906b23SVikram Hegde ASSERT(unitp); 722*20906b23SVikram Hegde 723*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 724*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_bindhdl(handle, dip, rdip, dma_handle, 725*20906b23SVikram Hegde dmareq, cookiep, ccountp)); 726*20906b23SVikram Hegde } 727*20906b23SVikram Hegde 728*20906b23SVikram Hegde int 729*20906b23SVikram Hegde iommulib_nexdma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 730*20906b23SVikram Hegde ddi_dma_handle_t dma_handle) 731*20906b23SVikram Hegde { 732*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 733*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 734*20906b23SVikram Hegde 735*20906b23SVikram Hegde ASSERT(unitp); 736*20906b23SVikram Hegde 737*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 738*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_unbindhdl(handle, dip, rdip, 739*20906b23SVikram Hegde dma_handle)); 740*20906b23SVikram Hegde } 741*20906b23SVikram Hegde 742*20906b23SVikram Hegde int 743*20906b23SVikram Hegde iommulib_nexdma_sync(dev_info_t *dip, dev_info_t *rdip, 744*20906b23SVikram Hegde ddi_dma_handle_t dma_handle, off_t off, size_t len, 745*20906b23SVikram Hegde uint_t cache_flags) 746*20906b23SVikram Hegde { 747*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 748*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 749*20906b23SVikram Hegde 750*20906b23SVikram Hegde ASSERT(unitp); 751*20906b23SVikram Hegde 752*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 753*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_sync(handle, dip, rdip, dma_handle, 754*20906b23SVikram Hegde off, len, cache_flags)); 755*20906b23SVikram Hegde } 756*20906b23SVikram Hegde 757*20906b23SVikram Hegde int 758*20906b23SVikram Hegde iommulib_nexdma_win(dev_info_t *dip, dev_info_t *rdip, 759*20906b23SVikram Hegde ddi_dma_handle_t dma_handle, uint_t win, off_t *offp, size_t *lenp, 760*20906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 761*20906b23SVikram Hegde { 762*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 763*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 764*20906b23SVikram Hegde 765*20906b23SVikram Hegde ASSERT(unitp); 766*20906b23SVikram Hegde 767*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 768*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_win(handle, dip, rdip, dma_handle, 769*20906b23SVikram Hegde win, offp, lenp, cookiep, ccountp)); 770*20906b23SVikram Hegde } 771*20906b23SVikram Hegde 772*20906b23SVikram Hegde /* Obsolete DMA routines */ 773*20906b23SVikram Hegde 774*20906b23SVikram Hegde int 775*20906b23SVikram Hegde iommulib_nexdma_map(dev_info_t *dip, dev_info_t *rdip, 776*20906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *dma_handle) 777*20906b23SVikram Hegde { 778*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 779*20906b23SVikram Hegde iommulib_unit_t *unitp = handle; 780*20906b23SVikram Hegde 781*20906b23SVikram Hegde ASSERT(unitp); 782*20906b23SVikram Hegde 783*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 784*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_map(handle, dip, rdip, dmareq, 785*20906b23SVikram Hegde dma_handle)); 786*20906b23SVikram Hegde } 787*20906b23SVikram Hegde 788*20906b23SVikram Hegde int 789*20906b23SVikram Hegde iommulib_nexdma_mctl(dev_info_t *dip, dev_info_t *rdip, 790*20906b23SVikram Hegde ddi_dma_handle_t dma_handle, enum ddi_dma_ctlops request, 791*20906b23SVikram Hegde off_t *offp, size_t *lenp, caddr_t *objpp, uint_t cache_flags) 792*20906b23SVikram Hegde { 793*20906b23SVikram Hegde iommulib_handle_t handle = DEVI(rdip)->devi_iommulib_handle; 794*20906b23SVikram Hegde iommulib_unit_t *unitp = (iommulib_unit_t *)handle; 795*20906b23SVikram Hegde 796*20906b23SVikram Hegde ASSERT(unitp); 797*20906b23SVikram Hegde 798*20906b23SVikram Hegde /* No need to grab lock - the handle is reference counted */ 799*20906b23SVikram Hegde return (unitp->ilu_ops->ilops_dma_mctl(handle, dip, rdip, dma_handle, 800*20906b23SVikram Hegde request, offp, lenp, objpp, cache_flags)); 801*20906b23SVikram Hegde } 802*20906b23SVikram Hegde 803*20906b23SVikram Hegde /* Utility routines invoked by IOMMU drivers */ 804*20906b23SVikram Hegde int 805*20906b23SVikram Hegde iommulib_iommu_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 806*20906b23SVikram Hegde ddi_dma_attr_t *attr, int (*waitfp)(caddr_t), caddr_t arg, 807*20906b23SVikram Hegde ddi_dma_handle_t *handlep) 808*20906b23SVikram Hegde { 809*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 810*20906b23SVikram Hegde if (nexops == NULL) 811*20906b23SVikram Hegde return (DDI_FAILURE); 812*20906b23SVikram Hegde return (nexops->nops_dma_allochdl(dip, rdip, attr, waitfp, arg, 813*20906b23SVikram Hegde handlep)); 814*20906b23SVikram Hegde } 815*20906b23SVikram Hegde 816*20906b23SVikram Hegde int 817*20906b23SVikram Hegde iommulib_iommu_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, 818*20906b23SVikram Hegde ddi_dma_handle_t handle) 819*20906b23SVikram Hegde { 820*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 821*20906b23SVikram Hegde if (nexops == NULL) 822*20906b23SVikram Hegde return (DDI_FAILURE); 823*20906b23SVikram Hegde return (nexops->nops_dma_freehdl(dip, rdip, handle)); 824*20906b23SVikram Hegde } 825*20906b23SVikram Hegde 826*20906b23SVikram Hegde int 827*20906b23SVikram Hegde iommulib_iommu_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip, 828*20906b23SVikram Hegde ddi_dma_handle_t handle, struct ddi_dma_req *dmareq, 829*20906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 830*20906b23SVikram Hegde { 831*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 832*20906b23SVikram Hegde if (nexops == NULL) 833*20906b23SVikram Hegde return (DDI_FAILURE); 834*20906b23SVikram Hegde return (nexops->nops_dma_bindhdl(dip, rdip, handle, dmareq, 835*20906b23SVikram Hegde cookiep, ccountp)); 836*20906b23SVikram Hegde } 837*20906b23SVikram Hegde 838*20906b23SVikram Hegde int 839*20906b23SVikram Hegde iommulib_iommu_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip, 840*20906b23SVikram Hegde ddi_dma_handle_t handle) 841*20906b23SVikram Hegde { 842*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 843*20906b23SVikram Hegde if (nexops == NULL) 844*20906b23SVikram Hegde return (DDI_FAILURE); 845*20906b23SVikram Hegde return (nexops->nops_dma_unbindhdl(dip, rdip, handle)); 846*20906b23SVikram Hegde } 847*20906b23SVikram Hegde 848*20906b23SVikram Hegde void 849*20906b23SVikram Hegde iommulib_iommu_dma_reset_cookies(dev_info_t *dip, ddi_dma_handle_t handle) 850*20906b23SVikram Hegde { 851*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 852*20906b23SVikram Hegde nexops->nops_dma_reset_cookies(dip, handle); 853*20906b23SVikram Hegde } 854*20906b23SVikram Hegde 855*20906b23SVikram Hegde int 856*20906b23SVikram Hegde iommulib_iommu_dma_get_cookies(dev_info_t *dip, ddi_dma_handle_t handle, 857*20906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 858*20906b23SVikram Hegde { 859*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 860*20906b23SVikram Hegde if (nexops == NULL) 861*20906b23SVikram Hegde return (DDI_FAILURE); 862*20906b23SVikram Hegde return (nexops->nops_dma_get_cookies(dip, handle, cookiep, ccountp)); 863*20906b23SVikram Hegde } 864*20906b23SVikram Hegde 865*20906b23SVikram Hegde int 866*20906b23SVikram Hegde iommulib_iommu_dma_sync(dev_info_t *dip, dev_info_t *rdip, 867*20906b23SVikram Hegde ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) 868*20906b23SVikram Hegde { 869*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 870*20906b23SVikram Hegde if (nexops == NULL) 871*20906b23SVikram Hegde return (DDI_FAILURE); 872*20906b23SVikram Hegde return (nexops->nops_dma_sync(dip, rdip, handle, off, len, 873*20906b23SVikram Hegde cache_flags)); 874*20906b23SVikram Hegde } 875*20906b23SVikram Hegde 876*20906b23SVikram Hegde int 877*20906b23SVikram Hegde iommulib_iommu_dma_win(dev_info_t *dip, dev_info_t *rdip, 878*20906b23SVikram Hegde ddi_dma_handle_t handle, uint_t win, off_t *offp, size_t *lenp, 879*20906b23SVikram Hegde ddi_dma_cookie_t *cookiep, uint_t *ccountp) 880*20906b23SVikram Hegde { 881*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 882*20906b23SVikram Hegde if (nexops == NULL) 883*20906b23SVikram Hegde return (DDI_FAILURE); 884*20906b23SVikram Hegde return (nexops->nops_dma_win(dip, rdip, handle, win, offp, lenp, 885*20906b23SVikram Hegde cookiep, ccountp)); 886*20906b23SVikram Hegde } 887*20906b23SVikram Hegde 888*20906b23SVikram Hegde int 889*20906b23SVikram Hegde iommulib_iommu_dma_map(dev_info_t *dip, dev_info_t *rdip, 890*20906b23SVikram Hegde struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep) 891*20906b23SVikram Hegde { 892*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 893*20906b23SVikram Hegde if (nexops == NULL) 894*20906b23SVikram Hegde return (DDI_FAILURE); 895*20906b23SVikram Hegde return (nexops->nops_dma_map(dip, rdip, dmareq, handlep)); 896*20906b23SVikram Hegde } 897*20906b23SVikram Hegde 898*20906b23SVikram Hegde int 899*20906b23SVikram Hegde iommulib_iommu_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 900*20906b23SVikram Hegde ddi_dma_handle_t handle, enum ddi_dma_ctlops request, off_t *offp, 901*20906b23SVikram Hegde size_t *lenp, caddr_t *objpp, uint_t cache_flags) 902*20906b23SVikram Hegde { 903*20906b23SVikram Hegde iommulib_nexops_t *nexops = lookup_nexops(dip); 904*20906b23SVikram Hegde if (nexops == NULL) 905*20906b23SVikram Hegde return (DDI_FAILURE); 906*20906b23SVikram Hegde return (nexops->nops_dma_mctl(dip, rdip, handle, request, offp, lenp, 907*20906b23SVikram Hegde objpp, cache_flags)); 908*20906b23SVikram Hegde } 909*20906b23SVikram Hegde 910*20906b23SVikram Hegde int 911*20906b23SVikram Hegde iommulib_iommu_getunitid(iommulib_handle_t handle, uint64_t *unitidp) 912*20906b23SVikram Hegde { 913*20906b23SVikram Hegde iommulib_unit_t *unitp; 914*20906b23SVikram Hegde uint64_t unitid; 915*20906b23SVikram Hegde 916*20906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 917*20906b23SVikram Hegde 918*20906b23SVikram Hegde ASSERT(unitp); 919*20906b23SVikram Hegde ASSERT(unitidp); 920*20906b23SVikram Hegde 921*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 922*20906b23SVikram Hegde unitid = unitp->ilu_unitid; 923*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 924*20906b23SVikram Hegde 925*20906b23SVikram Hegde ASSERT(unitid > 0); 926*20906b23SVikram Hegde *unitidp = (uint64_t)unitid; 927*20906b23SVikram Hegde 928*20906b23SVikram Hegde return (DDI_SUCCESS); 929*20906b23SVikram Hegde } 930*20906b23SVikram Hegde 931*20906b23SVikram Hegde dev_info_t * 932*20906b23SVikram Hegde iommulib_iommu_getdip(iommulib_handle_t handle) 933*20906b23SVikram Hegde { 934*20906b23SVikram Hegde iommulib_unit_t *unitp; 935*20906b23SVikram Hegde dev_info_t *dip; 936*20906b23SVikram Hegde 937*20906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 938*20906b23SVikram Hegde 939*20906b23SVikram Hegde ASSERT(unitp); 940*20906b23SVikram Hegde 941*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 942*20906b23SVikram Hegde dip = unitp->ilu_dip; 943*20906b23SVikram Hegde ASSERT(dip); 944*20906b23SVikram Hegde ndi_hold_devi(dip); 945*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 946*20906b23SVikram Hegde 947*20906b23SVikram Hegde return (dip); 948*20906b23SVikram Hegde } 949*20906b23SVikram Hegde 950*20906b23SVikram Hegde iommulib_ops_t * 951*20906b23SVikram Hegde iommulib_iommu_getops(iommulib_handle_t handle) 952*20906b23SVikram Hegde { 953*20906b23SVikram Hegde iommulib_unit_t *unitp; 954*20906b23SVikram Hegde iommulib_ops_t *ops; 955*20906b23SVikram Hegde 956*20906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 957*20906b23SVikram Hegde 958*20906b23SVikram Hegde ASSERT(unitp); 959*20906b23SVikram Hegde 960*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 961*20906b23SVikram Hegde ops = unitp->ilu_ops; 962*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 963*20906b23SVikram Hegde 964*20906b23SVikram Hegde ASSERT(ops); 965*20906b23SVikram Hegde 966*20906b23SVikram Hegde return (ops); 967*20906b23SVikram Hegde } 968*20906b23SVikram Hegde 969*20906b23SVikram Hegde void * 970*20906b23SVikram Hegde iommulib_iommu_getdata(iommulib_handle_t handle) 971*20906b23SVikram Hegde { 972*20906b23SVikram Hegde iommulib_unit_t *unitp; 973*20906b23SVikram Hegde void *data; 974*20906b23SVikram Hegde 975*20906b23SVikram Hegde unitp = (iommulib_unit_t *)handle; 976*20906b23SVikram Hegde 977*20906b23SVikram Hegde ASSERT(unitp); 978*20906b23SVikram Hegde 979*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 980*20906b23SVikram Hegde data = unitp->ilu_data; 981*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 982*20906b23SVikram Hegde 983*20906b23SVikram Hegde ASSERT(data); 984*20906b23SVikram Hegde 985*20906b23SVikram Hegde return (data); 986*20906b23SVikram Hegde } 987*20906b23SVikram Hegde 988*20906b23SVikram Hegde /* 989*20906b23SVikram Hegde * Internal routines 990*20906b23SVikram Hegde */ 991*20906b23SVikram Hegde 992*20906b23SVikram Hegde static uint32_t 993*20906b23SVikram Hegde hashfn(uint64_t ptr) 994*20906b23SVikram Hegde { 995*20906b23SVikram Hegde return (ptr % iommulib_cache_size); 996*20906b23SVikram Hegde } 997*20906b23SVikram Hegde 998*20906b23SVikram Hegde static int 999*20906b23SVikram Hegde lookup_cache(dev_info_t *rdip, iommulib_unit_t **unitpp) 1000*20906b23SVikram Hegde { 1001*20906b23SVikram Hegde uint64_t idx; 1002*20906b23SVikram Hegde iommulib_cache_t *cachep; 1003*20906b23SVikram Hegde iommulib_unit_t *unitp; 1004*20906b23SVikram Hegde int retval = DDI_FAILURE; 1005*20906b23SVikram Hegde 1006*20906b23SVikram Hegde *unitpp = NULL; 1007*20906b23SVikram Hegde 1008*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 1009*20906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 1010*20906b23SVikram Hegde 1011*20906b23SVikram Hegde ASSERT(iommulib_cache); 1012*20906b23SVikram Hegde 1013*20906b23SVikram Hegde idx = hashfn((uint64_t)(uintptr_t)rdip); 1014*20906b23SVikram Hegde 1015*20906b23SVikram Hegde ASSERT(idx < iommulib_cache_size); 1016*20906b23SVikram Hegde 1017*20906b23SVikram Hegde for (cachep = iommulib_cache[idx]; cachep; 1018*20906b23SVikram Hegde cachep = cachep->cache_next) { 1019*20906b23SVikram Hegde if (cachep->cache_rdip == rdip) 1020*20906b23SVikram Hegde break; 1021*20906b23SVikram Hegde } 1022*20906b23SVikram Hegde 1023*20906b23SVikram Hegde if (cachep != NULL) { 1024*20906b23SVikram Hegde unitp = cachep->cache_unit; 1025*20906b23SVikram Hegde mutex_enter(&unitp->ilu_lock); 1026*20906b23SVikram Hegde unitp->ilu_ref++; 1027*20906b23SVikram Hegde mutex_exit(&unitp->ilu_lock); 1028*20906b23SVikram Hegde *unitpp = unitp; 1029*20906b23SVikram Hegde retval = DDI_SUCCESS; 1030*20906b23SVikram Hegde } 1031*20906b23SVikram Hegde 1032*20906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 1033*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 1034*20906b23SVikram Hegde return (retval); 1035*20906b23SVikram Hegde } 1036*20906b23SVikram Hegde 1037*20906b23SVikram Hegde static void 1038*20906b23SVikram Hegde insert_cache(dev_info_t *rdip, iommulib_unit_t *unitp) 1039*20906b23SVikram Hegde { 1040*20906b23SVikram Hegde uint32_t idx; 1041*20906b23SVikram Hegde iommulib_cache_t *cachep; 1042*20906b23SVikram Hegde 1043*20906b23SVikram Hegde mutex_enter(&iommulib_lock); 1044*20906b23SVikram Hegde mutex_enter(&iommulib_cache_lock); 1045*20906b23SVikram Hegde 1046*20906b23SVikram Hegde ASSERT(iommulib_cache); 1047*20906b23SVikram Hegde 1048*20906b23SVikram Hegde idx = hashfn((uint64_t)(uintptr_t)rdip); 1049*20906b23SVikram Hegde 1050*20906b23SVikram Hegde ASSERT(idx < iommulib_cache_size); 1051*20906b23SVikram Hegde 1052*20906b23SVikram Hegde for (cachep = iommulib_cache[idx]; cachep; 1053*20906b23SVikram Hegde cachep = cachep->cache_next) { 1054*20906b23SVikram Hegde if (cachep->cache_rdip == rdip) 1055*20906b23SVikram Hegde break; 1056*20906b23SVikram Hegde } 1057*20906b23SVikram Hegde 1058*20906b23SVikram Hegde if (cachep == NULL) { 1059*20906b23SVikram Hegde cachep = kmem_zalloc(sizeof (iommulib_cache_t), KM_SLEEP); 1060*20906b23SVikram Hegde cachep->cache_rdip = rdip; 1061*20906b23SVikram Hegde cachep->cache_unit = unitp; /* ref-count set by caller */ 1062*20906b23SVikram Hegde cachep->cache_prev = NULL; 1063*20906b23SVikram Hegde cachep->cache_next = iommulib_cache[idx]; 1064*20906b23SVikram Hegde if (cachep->cache_next) 1065*20906b23SVikram Hegde cachep->cache_next->cache_prev = cachep; 1066*20906b23SVikram Hegde iommulib_cache[idx] = cachep; 1067*20906b23SVikram Hegde } 1068*20906b23SVikram Hegde 1069*20906b23SVikram Hegde mutex_exit(&iommulib_cache_lock); 1070*20906b23SVikram Hegde mutex_exit(&iommulib_lock); 1071*20906b23SVikram Hegde } 1072