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