xref: /onnv-gate/usr/src/uts/intel/io/iommulib.c (revision 7717:5793a2b64353)
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