1*9e39c5baSBill Taylor /*
2*9e39c5baSBill Taylor  * CDDL HEADER START
3*9e39c5baSBill Taylor  *
4*9e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
5*9e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
6*9e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
7*9e39c5baSBill Taylor  *
8*9e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
10*9e39c5baSBill Taylor  * See the License for the specific language governing permissions
11*9e39c5baSBill Taylor  * and limitations under the License.
12*9e39c5baSBill Taylor  *
13*9e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
14*9e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
16*9e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
17*9e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9e39c5baSBill Taylor  *
19*9e39c5baSBill Taylor  * CDDL HEADER END
20*9e39c5baSBill Taylor  */
21*9e39c5baSBill Taylor 
22*9e39c5baSBill Taylor /*
23*9e39c5baSBill Taylor  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*9e39c5baSBill Taylor  * Use is subject to license terms.
25*9e39c5baSBill Taylor  */
26*9e39c5baSBill Taylor 
27*9e39c5baSBill Taylor /*
28*9e39c5baSBill Taylor  * tavor_umap.c
29*9e39c5baSBill Taylor  *    Tavor Userland Mapping Routines
30*9e39c5baSBill Taylor  *
31*9e39c5baSBill Taylor  *    Implements all the routines necessary for enabling direct userland
32*9e39c5baSBill Taylor  *    access to the Tavor hardware.  This includes all routines necessary for
33*9e39c5baSBill Taylor  *    maintaining the "userland resources database" and all the support routines
34*9e39c5baSBill Taylor  *    for the devmap calls.
35*9e39c5baSBill Taylor  */
36*9e39c5baSBill Taylor 
37*9e39c5baSBill Taylor #include <sys/types.h>
38*9e39c5baSBill Taylor #include <sys/conf.h>
39*9e39c5baSBill Taylor #include <sys/ddi.h>
40*9e39c5baSBill Taylor #include <sys/sunddi.h>
41*9e39c5baSBill Taylor #include <sys/modctl.h>
42*9e39c5baSBill Taylor #include <sys/file.h>
43*9e39c5baSBill Taylor #include <sys/avl.h>
44*9e39c5baSBill Taylor #include <sys/sysmacros.h>
45*9e39c5baSBill Taylor 
46*9e39c5baSBill Taylor #include <sys/ib/adapters/tavor/tavor.h>
47*9e39c5baSBill Taylor 
48*9e39c5baSBill Taylor /* Tavor HCA state pointer (extern) */
49*9e39c5baSBill Taylor extern void *tavor_statep;
50*9e39c5baSBill Taylor 
51*9e39c5baSBill Taylor /* Tavor HCA Userland Resource Database (extern) */
52*9e39c5baSBill Taylor extern tavor_umap_db_t tavor_userland_rsrc_db;
53*9e39c5baSBill Taylor 
54*9e39c5baSBill Taylor static int tavor_umap_uarpg(tavor_state_t *state, devmap_cookie_t dhp,
55*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, size_t *maplen, int *err);
56*9e39c5baSBill Taylor static int tavor_umap_cqmem(tavor_state_t *state, devmap_cookie_t dhp,
57*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
58*9e39c5baSBill Taylor static int tavor_umap_qpmem(tavor_state_t *state, devmap_cookie_t dhp,
59*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
60*9e39c5baSBill Taylor static int tavor_umap_srqmem(tavor_state_t *state, devmap_cookie_t dhp,
61*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
62*9e39c5baSBill Taylor static int tavor_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
63*9e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp);
64*9e39c5baSBill Taylor static int tavor_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
65*9e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp);
66*9e39c5baSBill Taylor static void tavor_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
67*9e39c5baSBill Taylor     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
68*9e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2);
69*9e39c5baSBill Taylor static int tavor_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
70*9e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp);
71*9e39c5baSBill Taylor static int tavor_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
72*9e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp);
73*9e39c5baSBill Taylor static void tavor_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
74*9e39c5baSBill Taylor     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
75*9e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2);
76*9e39c5baSBill Taylor static ibt_status_t tavor_umap_mr_data_in(tavor_mrhdl_t mr,
77*9e39c5baSBill Taylor     ibt_mr_data_in_t *data, size_t data_sz);
78*9e39c5baSBill Taylor static ibt_status_t tavor_umap_cq_data_out(tavor_cqhdl_t cq,
79*9e39c5baSBill Taylor     mlnx_umap_cq_data_out_t *data, size_t data_sz);
80*9e39c5baSBill Taylor static ibt_status_t tavor_umap_qp_data_out(tavor_qphdl_t qp,
81*9e39c5baSBill Taylor     mlnx_umap_qp_data_out_t *data, size_t data_sz);
82*9e39c5baSBill Taylor static ibt_status_t tavor_umap_srq_data_out(tavor_srqhdl_t srq,
83*9e39c5baSBill Taylor     mlnx_umap_srq_data_out_t *data, size_t data_sz);
84*9e39c5baSBill Taylor static int tavor_umap_db_compare(const void *query, const void *entry);
85*9e39c5baSBill Taylor static ibt_status_t tavor_umap_pd_data_out(tavor_pdhdl_t pd,
86*9e39c5baSBill Taylor     mlnx_umap_pd_data_out_t *data, size_t data_sz);
87*9e39c5baSBill Taylor 
88*9e39c5baSBill Taylor 
89*9e39c5baSBill Taylor /*
90*9e39c5baSBill Taylor  * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
91*9e39c5baSBill Taylor  * respectively.  They are used to handle (among other things) partial
92*9e39c5baSBill Taylor  * unmappings and to provide a method for invalidating mappings inherited
93*9e39c5baSBill Taylor  * as a result of a fork(2) system call.
94*9e39c5baSBill Taylor  */
95*9e39c5baSBill Taylor static struct devmap_callback_ctl tavor_devmap_umem_cbops = {
96*9e39c5baSBill Taylor 	DEVMAP_OPS_REV,
97*9e39c5baSBill Taylor 	tavor_devmap_umem_map,
98*9e39c5baSBill Taylor 	NULL,
99*9e39c5baSBill Taylor 	tavor_devmap_umem_dup,
100*9e39c5baSBill Taylor 	tavor_devmap_umem_unmap
101*9e39c5baSBill Taylor };
102*9e39c5baSBill Taylor static struct devmap_callback_ctl tavor_devmap_devmem_cbops = {
103*9e39c5baSBill Taylor 	DEVMAP_OPS_REV,
104*9e39c5baSBill Taylor 	tavor_devmap_devmem_map,
105*9e39c5baSBill Taylor 	NULL,
106*9e39c5baSBill Taylor 	tavor_devmap_devmem_dup,
107*9e39c5baSBill Taylor 	tavor_devmap_devmem_unmap
108*9e39c5baSBill Taylor };
109*9e39c5baSBill Taylor 
110*9e39c5baSBill Taylor /*
111*9e39c5baSBill Taylor  * tavor_devmap()
112*9e39c5baSBill Taylor  *    Context: Can be called from user context.
113*9e39c5baSBill Taylor  */
114*9e39c5baSBill Taylor /* ARGSUSED */
115*9e39c5baSBill Taylor int
tavor_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)116*9e39c5baSBill Taylor tavor_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
117*9e39c5baSBill Taylor     size_t *maplen, uint_t model)
118*9e39c5baSBill Taylor {
119*9e39c5baSBill Taylor 	tavor_state_t	*state;
120*9e39c5baSBill Taylor 	tavor_rsrc_t 	*rsrcp;
121*9e39c5baSBill Taylor 	minor_t		instance;
122*9e39c5baSBill Taylor 	uint64_t	key, value;
123*9e39c5baSBill Taylor 	uint_t		type;
124*9e39c5baSBill Taylor 	int		err, status;
125*9e39c5baSBill Taylor 
126*9e39c5baSBill Taylor 	/* Get Tavor softstate structure from instance */
127*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
128*9e39c5baSBill Taylor 	state = ddi_get_soft_state(tavor_statep, instance);
129*9e39c5baSBill Taylor 	if (state == NULL) {
130*9e39c5baSBill Taylor 		return (ENXIO);
131*9e39c5baSBill Taylor 	}
132*9e39c5baSBill Taylor 
133*9e39c5baSBill Taylor 	/*
134*9e39c5baSBill Taylor 	 * Access to Tavor devmap interface is not allowed in
135*9e39c5baSBill Taylor 	 * "maintenance mode".
136*9e39c5baSBill Taylor 	 */
137*9e39c5baSBill Taylor 	if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
138*9e39c5baSBill Taylor 		return (EFAULT);
139*9e39c5baSBill Taylor 	}
140*9e39c5baSBill Taylor 
141*9e39c5baSBill Taylor 	/*
142*9e39c5baSBill Taylor 	 * The bottom bits of "offset" are undefined (number depends on
143*9e39c5baSBill Taylor 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
144*9e39c5baSBill Taylor 	 * The "key" is actually a combination of both a real key value
145*9e39c5baSBill Taylor 	 * (for the purpose of database lookup) and a "type" value.  We
146*9e39c5baSBill Taylor 	 * extract this information before doing the database lookup.
147*9e39c5baSBill Taylor 	 */
148*9e39c5baSBill Taylor 	key  = off >> PAGESHIFT;
149*9e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
150*9e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
151*9e39c5baSBill Taylor 	status = tavor_umap_db_find(instance, key, type, &value, 0, NULL);
152*9e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
153*9e39c5baSBill Taylor 		rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
154*9e39c5baSBill Taylor 
155*9e39c5baSBill Taylor 		switch (type) {
156*9e39c5baSBill Taylor 		case MLNX_UMAP_UARPG_RSRC:
157*9e39c5baSBill Taylor 			/*
158*9e39c5baSBill Taylor 			 * Double check that process who open()'d Tavor is
159*9e39c5baSBill Taylor 			 * same process attempting to mmap() UAR page.
160*9e39c5baSBill Taylor 			 */
161*9e39c5baSBill Taylor 			if (key != ddi_get_pid()) {
162*9e39c5baSBill Taylor 				return (EINVAL);
163*9e39c5baSBill Taylor 			}
164*9e39c5baSBill Taylor 
165*9e39c5baSBill Taylor 			/* Map the UAR page out for userland access */
166*9e39c5baSBill Taylor 			status = tavor_umap_uarpg(state, dhp, rsrcp, maplen,
167*9e39c5baSBill Taylor 			    &err);
168*9e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
169*9e39c5baSBill Taylor 				return (err);
170*9e39c5baSBill Taylor 			}
171*9e39c5baSBill Taylor 			break;
172*9e39c5baSBill Taylor 
173*9e39c5baSBill Taylor 		case MLNX_UMAP_CQMEM_RSRC:
174*9e39c5baSBill Taylor 			/* Map the CQ memory out for userland access */
175*9e39c5baSBill Taylor 			status = tavor_umap_cqmem(state, dhp, rsrcp, off,
176*9e39c5baSBill Taylor 			    maplen, &err);
177*9e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
178*9e39c5baSBill Taylor 				return (err);
179*9e39c5baSBill Taylor 			}
180*9e39c5baSBill Taylor 			break;
181*9e39c5baSBill Taylor 
182*9e39c5baSBill Taylor 		case MLNX_UMAP_QPMEM_RSRC:
183*9e39c5baSBill Taylor 			/* Map the QP memory out for userland access */
184*9e39c5baSBill Taylor 			status = tavor_umap_qpmem(state, dhp, rsrcp, off,
185*9e39c5baSBill Taylor 			    maplen, &err);
186*9e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
187*9e39c5baSBill Taylor 				return (err);
188*9e39c5baSBill Taylor 			}
189*9e39c5baSBill Taylor 			break;
190*9e39c5baSBill Taylor 
191*9e39c5baSBill Taylor 		case MLNX_UMAP_SRQMEM_RSRC:
192*9e39c5baSBill Taylor 			/* Map the SRQ memory out for userland access */
193*9e39c5baSBill Taylor 			status = tavor_umap_srqmem(state, dhp, rsrcp, off,
194*9e39c5baSBill Taylor 			    maplen, &err);
195*9e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
196*9e39c5baSBill Taylor 				return (err);
197*9e39c5baSBill Taylor 			}
198*9e39c5baSBill Taylor 			break;
199*9e39c5baSBill Taylor 
200*9e39c5baSBill Taylor 		default:
201*9e39c5baSBill Taylor 			TAVOR_WARNING(state, "unexpected rsrc type in devmap");
202*9e39c5baSBill Taylor 			return (EINVAL);
203*9e39c5baSBill Taylor 		}
204*9e39c5baSBill Taylor 	} else {
205*9e39c5baSBill Taylor 		return (EINVAL);
206*9e39c5baSBill Taylor 	}
207*9e39c5baSBill Taylor 
208*9e39c5baSBill Taylor 	return (0);
209*9e39c5baSBill Taylor }
210*9e39c5baSBill Taylor 
211*9e39c5baSBill Taylor 
212*9e39c5baSBill Taylor /*
213*9e39c5baSBill Taylor  * tavor_umap_uarpg()
214*9e39c5baSBill Taylor  *    Context: Can be called from user context.
215*9e39c5baSBill Taylor  */
216*9e39c5baSBill Taylor static int
tavor_umap_uarpg(tavor_state_t * state,devmap_cookie_t dhp,tavor_rsrc_t * rsrcp,size_t * maplen,int * err)217*9e39c5baSBill Taylor tavor_umap_uarpg(tavor_state_t *state, devmap_cookie_t dhp,
218*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, size_t *maplen, int *err)
219*9e39c5baSBill Taylor {
220*9e39c5baSBill Taylor 	int		status;
221*9e39c5baSBill Taylor 	uint_t		maxprot;
222*9e39c5baSBill Taylor 
223*9e39c5baSBill Taylor 	/* Map out the UAR page (doorbell page) */
224*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
225*9e39c5baSBill Taylor 	status = devmap_devmem_setup(dhp, state->ts_dip,
226*9e39c5baSBill Taylor 	    &tavor_devmap_devmem_cbops, TAVOR_UAR_BAR, (rsrcp->tr_indx <<
227*9e39c5baSBill Taylor 	    PAGESHIFT), PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
228*9e39c5baSBill Taylor 	    &state->ts_reg_accattr);
229*9e39c5baSBill Taylor 	if (status < 0) {
230*9e39c5baSBill Taylor 		*err = status;
231*9e39c5baSBill Taylor 		return (DDI_FAILURE);
232*9e39c5baSBill Taylor 	}
233*9e39c5baSBill Taylor 
234*9e39c5baSBill Taylor 	*maplen = PAGESIZE;
235*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
236*9e39c5baSBill Taylor }
237*9e39c5baSBill Taylor 
238*9e39c5baSBill Taylor 
239*9e39c5baSBill Taylor /*
240*9e39c5baSBill Taylor  * tavor_umap_cqmem()
241*9e39c5baSBill Taylor  *    Context: Can be called from user context.
242*9e39c5baSBill Taylor  */
243*9e39c5baSBill Taylor /* ARGSUSED */
244*9e39c5baSBill Taylor static int
tavor_umap_cqmem(tavor_state_t * state,devmap_cookie_t dhp,tavor_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)245*9e39c5baSBill Taylor tavor_umap_cqmem(tavor_state_t *state, devmap_cookie_t dhp,
246*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
247*9e39c5baSBill Taylor {
248*9e39c5baSBill Taylor 	tavor_cqhdl_t	cq;
249*9e39c5baSBill Taylor 	size_t		size;
250*9e39c5baSBill Taylor 	uint_t		maxprot;
251*9e39c5baSBill Taylor 	int		status;
252*9e39c5baSBill Taylor 
253*9e39c5baSBill Taylor 	/* Extract the Tavor CQ handle pointer from the tavor_rsrc_t */
254*9e39c5baSBill Taylor 	cq = (tavor_cqhdl_t)rsrcp->tr_addr;
255*9e39c5baSBill Taylor 
256*9e39c5baSBill Taylor 	/* Round-up the CQ size to system page size */
257*9e39c5baSBill Taylor 	size = ptob(btopr(cq->cq_cqinfo.qa_size));
258*9e39c5baSBill Taylor 
259*9e39c5baSBill Taylor 	/* Map out the CQ memory */
260*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
261*9e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->ts_dip,
262*9e39c5baSBill Taylor 	    &tavor_devmap_umem_cbops, cq->cq_cqinfo.qa_umemcookie, 0, size,
263*9e39c5baSBill Taylor 	    maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
264*9e39c5baSBill Taylor 	if (status < 0) {
265*9e39c5baSBill Taylor 		*err = status;
266*9e39c5baSBill Taylor 		return (DDI_FAILURE);
267*9e39c5baSBill Taylor 	}
268*9e39c5baSBill Taylor 	*maplen = size;
269*9e39c5baSBill Taylor 
270*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
271*9e39c5baSBill Taylor }
272*9e39c5baSBill Taylor 
273*9e39c5baSBill Taylor 
274*9e39c5baSBill Taylor /*
275*9e39c5baSBill Taylor  * tavor_umap_qpmem()
276*9e39c5baSBill Taylor  *    Context: Can be called from user context.
277*9e39c5baSBill Taylor  */
278*9e39c5baSBill Taylor /* ARGSUSED */
279*9e39c5baSBill Taylor static int
tavor_umap_qpmem(tavor_state_t * state,devmap_cookie_t dhp,tavor_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)280*9e39c5baSBill Taylor tavor_umap_qpmem(tavor_state_t *state, devmap_cookie_t dhp,
281*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
282*9e39c5baSBill Taylor {
283*9e39c5baSBill Taylor 	tavor_qphdl_t	qp;
284*9e39c5baSBill Taylor 	offset_t	offset;
285*9e39c5baSBill Taylor 	size_t		size;
286*9e39c5baSBill Taylor 	uint_t		maxprot;
287*9e39c5baSBill Taylor 	int		status;
288*9e39c5baSBill Taylor 
289*9e39c5baSBill Taylor 	/* Extract the Tavor QP handle pointer from the tavor_rsrc_t */
290*9e39c5baSBill Taylor 	qp = (tavor_qphdl_t)rsrcp->tr_addr;
291*9e39c5baSBill Taylor 
292*9e39c5baSBill Taylor 	/*
293*9e39c5baSBill Taylor 	 * Calculate the offset of the first work queue (send or recv) into
294*9e39c5baSBill Taylor 	 * the memory (ddi_umem_alloc()) allocated previously for the QP.
295*9e39c5baSBill Taylor 	 */
296*9e39c5baSBill Taylor 	offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
297*9e39c5baSBill Taylor 	    (uintptr_t)qp->qp_wqinfo.qa_buf_real);
298*9e39c5baSBill Taylor 
299*9e39c5baSBill Taylor 	/* Round-up the QP work queue sizes to system page size */
300*9e39c5baSBill Taylor 	size = ptob(btopr(qp->qp_wqinfo.qa_size));
301*9e39c5baSBill Taylor 
302*9e39c5baSBill Taylor 	/* Map out the QP memory */
303*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
304*9e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->ts_dip,
305*9e39c5baSBill Taylor 	    &tavor_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
306*9e39c5baSBill Taylor 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
307*9e39c5baSBill Taylor 	if (status < 0) {
308*9e39c5baSBill Taylor 		*err = status;
309*9e39c5baSBill Taylor 		return (DDI_FAILURE);
310*9e39c5baSBill Taylor 	}
311*9e39c5baSBill Taylor 	*maplen = size;
312*9e39c5baSBill Taylor 
313*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
314*9e39c5baSBill Taylor }
315*9e39c5baSBill Taylor 
316*9e39c5baSBill Taylor 
317*9e39c5baSBill Taylor /*
318*9e39c5baSBill Taylor  * tavor_umap_srqmem()
319*9e39c5baSBill Taylor  *    Context: Can be called from user context.
320*9e39c5baSBill Taylor  */
321*9e39c5baSBill Taylor /* ARGSUSED */
322*9e39c5baSBill Taylor static int
tavor_umap_srqmem(tavor_state_t * state,devmap_cookie_t dhp,tavor_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)323*9e39c5baSBill Taylor tavor_umap_srqmem(tavor_state_t *state, devmap_cookie_t dhp,
324*9e39c5baSBill Taylor     tavor_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
325*9e39c5baSBill Taylor {
326*9e39c5baSBill Taylor 	tavor_srqhdl_t	srq;
327*9e39c5baSBill Taylor 	offset_t	offset;
328*9e39c5baSBill Taylor 	size_t		size;
329*9e39c5baSBill Taylor 	uint_t		maxprot;
330*9e39c5baSBill Taylor 	int		status;
331*9e39c5baSBill Taylor 
332*9e39c5baSBill Taylor 	/* Extract the Tavor SRQ handle pointer from the tavor_rsrc_t */
333*9e39c5baSBill Taylor 	srq = (tavor_srqhdl_t)rsrcp->tr_addr;
334*9e39c5baSBill Taylor 
335*9e39c5baSBill Taylor 	/*
336*9e39c5baSBill Taylor 	 * Calculate the offset of the first shared recv queue into the memory
337*9e39c5baSBill Taylor 	 * (ddi_umem_alloc()) allocated previously for the SRQ.
338*9e39c5baSBill Taylor 	 */
339*9e39c5baSBill Taylor 	offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
340*9e39c5baSBill Taylor 	    (uintptr_t)srq->srq_wqinfo.qa_buf_real);
341*9e39c5baSBill Taylor 
342*9e39c5baSBill Taylor 	/* Round-up the SRQ work queue sizes to system page size */
343*9e39c5baSBill Taylor 	size = ptob(btopr(srq->srq_wqinfo.qa_size));
344*9e39c5baSBill Taylor 
345*9e39c5baSBill Taylor 	/* Map out the QP memory */
346*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
347*9e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->ts_dip,
348*9e39c5baSBill Taylor 	    &tavor_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
349*9e39c5baSBill Taylor 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
350*9e39c5baSBill Taylor 	if (status < 0) {
351*9e39c5baSBill Taylor 		*err = status;
352*9e39c5baSBill Taylor 		return (DDI_FAILURE);
353*9e39c5baSBill Taylor 	}
354*9e39c5baSBill Taylor 	*maplen = size;
355*9e39c5baSBill Taylor 
356*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
357*9e39c5baSBill Taylor }
358*9e39c5baSBill Taylor 
359*9e39c5baSBill Taylor 
360*9e39c5baSBill Taylor /*
361*9e39c5baSBill Taylor  * tavor_devmap_umem_map()
362*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
363*9e39c5baSBill Taylor  */
364*9e39c5baSBill Taylor /* ARGSUSED */
365*9e39c5baSBill Taylor static int
tavor_devmap_umem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)366*9e39c5baSBill Taylor tavor_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
367*9e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp)
368*9e39c5baSBill Taylor {
369*9e39c5baSBill Taylor 	tavor_state_t		*state;
370*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track;
371*9e39c5baSBill Taylor 	tavor_cqhdl_t		cq;
372*9e39c5baSBill Taylor 	tavor_qphdl_t		qp;
373*9e39c5baSBill Taylor 	tavor_srqhdl_t		srq;
374*9e39c5baSBill Taylor 	minor_t			instance;
375*9e39c5baSBill Taylor 	uint64_t		key;
376*9e39c5baSBill Taylor 	uint_t			type;
377*9e39c5baSBill Taylor 
378*9e39c5baSBill Taylor 	/* Get Tavor softstate structure from instance */
379*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
380*9e39c5baSBill Taylor 	state = ddi_get_soft_state(tavor_statep, instance);
381*9e39c5baSBill Taylor 	if (state == NULL) {
382*9e39c5baSBill Taylor 		return (ENXIO);
383*9e39c5baSBill Taylor 	}
384*9e39c5baSBill Taylor 
385*9e39c5baSBill Taylor 	/*
386*9e39c5baSBill Taylor 	 * The bottom bits of "offset" are undefined (number depends on
387*9e39c5baSBill Taylor 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
388*9e39c5baSBill Taylor 	 * The "key" is actually a combination of both a real key value
389*9e39c5baSBill Taylor 	 * (for the purpose of database lookup) and a "type" value.  Although
390*9e39c5baSBill Taylor 	 * we are not going to do any database lookup per se, we do want
391*9e39c5baSBill Taylor 	 * to extract the "key" and the "type" (to enable faster lookup of
392*9e39c5baSBill Taylor 	 * the appropriate CQ or QP handle).
393*9e39c5baSBill Taylor 	 */
394*9e39c5baSBill Taylor 	key  = off >> PAGESHIFT;
395*9e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
396*9e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
397*9e39c5baSBill Taylor 
398*9e39c5baSBill Taylor 	/*
399*9e39c5baSBill Taylor 	 * Allocate an entry to track the mapping and unmapping (specifically,
400*9e39c5baSBill Taylor 	 * partial unmapping) of this resource.
401*9e39c5baSBill Taylor 	 */
402*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
403*9e39c5baSBill Taylor 	    sizeof (tavor_devmap_track_t), KM_SLEEP);
404*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
405*9e39c5baSBill Taylor 	dvm_track->tdt_offset = off;
406*9e39c5baSBill Taylor 	dvm_track->tdt_state  = state;
407*9e39c5baSBill Taylor 	dvm_track->tdt_refcnt = 1;
408*9e39c5baSBill Taylor 	mutex_init(&dvm_track->tdt_lock, NULL, MUTEX_DRIVER,
409*9e39c5baSBill Taylor 	    DDI_INTR_PRI(state->ts_intrmsi_pri));
410*9e39c5baSBill Taylor 
411*9e39c5baSBill Taylor 	/*
412*9e39c5baSBill Taylor 	 * Depending of the type of resource that has been mapped out, we
413*9e39c5baSBill Taylor 	 * need to update the QP or CQ handle to reflect that it has, in
414*9e39c5baSBill Taylor 	 * fact, been mapped.  This allows the driver code which frees a QP
415*9e39c5baSBill Taylor 	 * or a CQ to know whether it is appropriate to do a
416*9e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the userland mapping for the
417*9e39c5baSBill Taylor 	 * corresponding queue's memory.
418*9e39c5baSBill Taylor 	 */
419*9e39c5baSBill Taylor 	if (type == MLNX_UMAP_CQMEM_RSRC) {
420*9e39c5baSBill Taylor 
421*9e39c5baSBill Taylor 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
422*9e39c5baSBill Taylor 		cq = tavor_cqhdl_from_cqnum(state, key);
423*9e39c5baSBill Taylor 
424*9e39c5baSBill Taylor 		/*
425*9e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
426*9e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
427*9e39c5baSBill Taylor 		 * and return failure.
428*9e39c5baSBill Taylor 		 */
429*9e39c5baSBill Taylor 		mutex_enter(&cq->cq_lock);
430*9e39c5baSBill Taylor 		if (cq->cq_umap_dhp == NULL) {
431*9e39c5baSBill Taylor 			cq->cq_umap_dhp = dhp;
432*9e39c5baSBill Taylor 			dvm_track->tdt_size = cq->cq_cqinfo.qa_size;
433*9e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
434*9e39c5baSBill Taylor 		} else {
435*9e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
436*9e39c5baSBill Taylor 			goto umem_map_fail;
437*9e39c5baSBill Taylor 		}
438*9e39c5baSBill Taylor 
439*9e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
440*9e39c5baSBill Taylor 
441*9e39c5baSBill Taylor 		/* Use "key" (QP number) to do fast lookup of QP handle */
442*9e39c5baSBill Taylor 		qp = tavor_qphdl_from_qpnum(state, key);
443*9e39c5baSBill Taylor 
444*9e39c5baSBill Taylor 		/*
445*9e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
446*9e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
447*9e39c5baSBill Taylor 		 * and return failure.
448*9e39c5baSBill Taylor 		 */
449*9e39c5baSBill Taylor 		mutex_enter(&qp->qp_lock);
450*9e39c5baSBill Taylor 		if (qp->qp_umap_dhp == NULL) {
451*9e39c5baSBill Taylor 			qp->qp_umap_dhp = dhp;
452*9e39c5baSBill Taylor 			dvm_track->tdt_size = qp->qp_wqinfo.qa_size;
453*9e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
454*9e39c5baSBill Taylor 		} else {
455*9e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
456*9e39c5baSBill Taylor 			goto umem_map_fail;
457*9e39c5baSBill Taylor 		}
458*9e39c5baSBill Taylor 
459*9e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
460*9e39c5baSBill Taylor 
461*9e39c5baSBill Taylor 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
462*9e39c5baSBill Taylor 		srq = tavor_srqhdl_from_srqnum(state, key);
463*9e39c5baSBill Taylor 
464*9e39c5baSBill Taylor 		/*
465*9e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If the
466*9e39c5baSBill Taylor 		 * SRQ already has a valid userland mapping, then stop and
467*9e39c5baSBill Taylor 		 * return failure.
468*9e39c5baSBill Taylor 		 */
469*9e39c5baSBill Taylor 		mutex_enter(&srq->srq_lock);
470*9e39c5baSBill Taylor 		if (srq->srq_umap_dhp == NULL) {
471*9e39c5baSBill Taylor 			srq->srq_umap_dhp = dhp;
472*9e39c5baSBill Taylor 			dvm_track->tdt_size = srq->srq_wqinfo.qa_size;
473*9e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
474*9e39c5baSBill Taylor 		} else {
475*9e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
476*9e39c5baSBill Taylor 			goto umem_map_fail;
477*9e39c5baSBill Taylor 		}
478*9e39c5baSBill Taylor 	}
479*9e39c5baSBill Taylor 
480*9e39c5baSBill Taylor 	/*
481*9e39c5baSBill Taylor 	 * Pass the private "Tavor devmap tracking structure" back.  This
482*9e39c5baSBill Taylor 	 * pointer will be returned in subsequent "unmap" callbacks.
483*9e39c5baSBill Taylor 	 */
484*9e39c5baSBill Taylor 	*pvtp = dvm_track;
485*9e39c5baSBill Taylor 
486*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
487*9e39c5baSBill Taylor 
488*9e39c5baSBill Taylor umem_map_fail:
489*9e39c5baSBill Taylor 	mutex_destroy(&dvm_track->tdt_lock);
490*9e39c5baSBill Taylor 	kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
491*9e39c5baSBill Taylor 	return (DDI_FAILURE);
492*9e39c5baSBill Taylor }
493*9e39c5baSBill Taylor 
494*9e39c5baSBill Taylor 
495*9e39c5baSBill Taylor /*
496*9e39c5baSBill Taylor  * tavor_devmap_umem_dup()
497*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
498*9e39c5baSBill Taylor  */
499*9e39c5baSBill Taylor /* ARGSUSED */
500*9e39c5baSBill Taylor static int
tavor_devmap_umem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)501*9e39c5baSBill Taylor tavor_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
502*9e39c5baSBill Taylor     void **new_pvtp)
503*9e39c5baSBill Taylor {
504*9e39c5baSBill Taylor 	tavor_state_t		*state;
505*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track, *new_dvm_track;
506*9e39c5baSBill Taylor 	uint_t			maxprot;
507*9e39c5baSBill Taylor 	int			status;
508*9e39c5baSBill Taylor 
509*9e39c5baSBill Taylor 	/*
510*9e39c5baSBill Taylor 	 * Extract the Tavor softstate pointer from "Tavor devmap tracking
511*9e39c5baSBill Taylor 	 * structure" (in "pvtp").
512*9e39c5baSBill Taylor 	 */
513*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)pvtp;
514*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
515*9e39c5baSBill Taylor 	state = dvm_track->tdt_state;
516*9e39c5baSBill Taylor 
517*9e39c5baSBill Taylor 	/*
518*9e39c5baSBill Taylor 	 * Since this devmap_dup() entry point is generally called
519*9e39c5baSBill Taylor 	 * when a process does fork(2), it is incumbent upon the driver
520*9e39c5baSBill Taylor 	 * to insure that the child does not inherit a valid copy of
521*9e39c5baSBill Taylor 	 * the parent's QP or CQ resource.  This is accomplished by using
522*9e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the child's mapping to the
523*9e39c5baSBill Taylor 	 * kernel memory.
524*9e39c5baSBill Taylor 	 */
525*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
526*9e39c5baSBill Taylor 	status = devmap_devmem_remap(new_dhp, state->ts_dip, 0, 0,
527*9e39c5baSBill Taylor 	    dvm_track->tdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
528*9e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
529*9e39c5baSBill Taylor 		TAVOR_WARNING(state, "failed in tavor_devmap_umem_dup()");
530*9e39c5baSBill Taylor 		return (status);
531*9e39c5baSBill Taylor 	}
532*9e39c5baSBill Taylor 
533*9e39c5baSBill Taylor 	/*
534*9e39c5baSBill Taylor 	 * Allocate a new entry to track the subsequent unmapping
535*9e39c5baSBill Taylor 	 * (specifically, all partial unmappings) of the child's newly
536*9e39c5baSBill Taylor 	 * invalidated resource.  Note: Setting the "tdt_size" field to
537*9e39c5baSBill Taylor 	 * zero here is an indication to the devmap_unmap() entry point
538*9e39c5baSBill Taylor 	 * that this mapping is invalid, and that its subsequent unmapping
539*9e39c5baSBill Taylor 	 * should not affect any of the parent's CQ or QP resources.
540*9e39c5baSBill Taylor 	 */
541*9e39c5baSBill Taylor 	new_dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
542*9e39c5baSBill Taylor 	    sizeof (tavor_devmap_track_t), KM_SLEEP);
543*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
544*9e39c5baSBill Taylor 	new_dvm_track->tdt_offset = 0;
545*9e39c5baSBill Taylor 	new_dvm_track->tdt_state  = state;
546*9e39c5baSBill Taylor 	new_dvm_track->tdt_refcnt = 1;
547*9e39c5baSBill Taylor 	new_dvm_track->tdt_size	  = 0;
548*9e39c5baSBill Taylor 	mutex_init(&new_dvm_track->tdt_lock, NULL, MUTEX_DRIVER,
549*9e39c5baSBill Taylor 	    DDI_INTR_PRI(state->ts_intrmsi_pri));
550*9e39c5baSBill Taylor 	*new_pvtp = new_dvm_track;
551*9e39c5baSBill Taylor 
552*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
553*9e39c5baSBill Taylor }
554*9e39c5baSBill Taylor 
555*9e39c5baSBill Taylor 
556*9e39c5baSBill Taylor /*
557*9e39c5baSBill Taylor  * tavor_devmap_umem_unmap()
558*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
559*9e39c5baSBill Taylor  */
560*9e39c5baSBill Taylor /* ARGSUSED */
561*9e39c5baSBill Taylor static void
tavor_devmap_umem_unmap(devmap_cookie_t dhp,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** pvtp1,devmap_cookie_t new_dhp2,void ** pvtp2)562*9e39c5baSBill Taylor tavor_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
563*9e39c5baSBill Taylor     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
564*9e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2)
565*9e39c5baSBill Taylor {
566*9e39c5baSBill Taylor 	tavor_state_t 		*state;
567*9e39c5baSBill Taylor 	tavor_rsrc_t 		*rsrcp;
568*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track;
569*9e39c5baSBill Taylor 	tavor_cqhdl_t		cq;
570*9e39c5baSBill Taylor 	tavor_qphdl_t		qp;
571*9e39c5baSBill Taylor 	tavor_srqhdl_t		srq;
572*9e39c5baSBill Taylor 	uint64_t		key, value;
573*9e39c5baSBill Taylor 	uint_t			type;
574*9e39c5baSBill Taylor 	uint_t			size;
575*9e39c5baSBill Taylor 	int			status;
576*9e39c5baSBill Taylor 
577*9e39c5baSBill Taylor 	/*
578*9e39c5baSBill Taylor 	 * Extract the Tavor softstate pointer from "Tavor devmap tracking
579*9e39c5baSBill Taylor 	 * structure" (in "pvtp").
580*9e39c5baSBill Taylor 	 */
581*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)pvtp;
582*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
583*9e39c5baSBill Taylor 	state	  = dvm_track->tdt_state;
584*9e39c5baSBill Taylor 
585*9e39c5baSBill Taylor 	/*
586*9e39c5baSBill Taylor 	 * Extract the "offset" from the "Tavor devmap tracking structure".
587*9e39c5baSBill Taylor 	 * Note: The input argument "off" is ignored here because the
588*9e39c5baSBill Taylor 	 * Tavor mapping interfaces define a very specific meaning to
589*9e39c5baSBill Taylor 	 * each "logical offset".  Also extract the "key" and "type" encoded
590*9e39c5baSBill Taylor 	 * in the logical offset.
591*9e39c5baSBill Taylor 	 */
592*9e39c5baSBill Taylor 	key  = dvm_track->tdt_offset >> PAGESHIFT;
593*9e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
594*9e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
595*9e39c5baSBill Taylor 
596*9e39c5baSBill Taylor 	/*
597*9e39c5baSBill Taylor 	 * Extract the "size" of the mapping.  If this size is determined
598*9e39c5baSBill Taylor 	 * to be zero, then it is an indication of a previously invalidated
599*9e39c5baSBill Taylor 	 * mapping, and no CQ or QP resources should be affected.
600*9e39c5baSBill Taylor 	 */
601*9e39c5baSBill Taylor 	size = dvm_track->tdt_size;
602*9e39c5baSBill Taylor 
603*9e39c5baSBill Taylor 	/*
604*9e39c5baSBill Taylor 	 * If only the "middle portion of a given mapping is being unmapped,
605*9e39c5baSBill Taylor 	 * then we are effectively creating one new piece of mapped memory.
606*9e39c5baSBill Taylor 	 * (Original region is divided into three pieces of which the middle
607*9e39c5baSBill Taylor 	 * piece is being removed.  This leaves two pieces.  Since we started
608*9e39c5baSBill Taylor 	 * with one piece and now have two pieces, we need to increment the
609*9e39c5baSBill Taylor 	 * counter in the "Tavor devmap tracking structure".
610*9e39c5baSBill Taylor 	 *
611*9e39c5baSBill Taylor 	 * If, however, the whole mapped region is being unmapped, then we
612*9e39c5baSBill Taylor 	 * have started with one region which we are completely removing.
613*9e39c5baSBill Taylor 	 * In this case, we need to decrement the counter in the "Tavor
614*9e39c5baSBill Taylor 	 * devmap tracking structure".
615*9e39c5baSBill Taylor 	 *
616*9e39c5baSBill Taylor 	 * In each of the remaining cases, we will have started with one
617*9e39c5baSBill Taylor 	 * mapped region and ended with one (different) region.  So no counter
618*9e39c5baSBill Taylor 	 * modification is necessary.
619*9e39c5baSBill Taylor 	 */
620*9e39c5baSBill Taylor 	mutex_enter(&dvm_track->tdt_lock);
621*9e39c5baSBill Taylor 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
622*9e39c5baSBill Taylor 		dvm_track->tdt_refcnt--;
623*9e39c5baSBill Taylor 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
624*9e39c5baSBill Taylor 		dvm_track->tdt_refcnt++;
625*9e39c5baSBill Taylor 	}
626*9e39c5baSBill Taylor 	mutex_exit(&dvm_track->tdt_lock);
627*9e39c5baSBill Taylor 
628*9e39c5baSBill Taylor 	/*
629*9e39c5baSBill Taylor 	 * For each of the cases where the region is being divided, then we
630*9e39c5baSBill Taylor 	 * need to pass back the "Tavor devmap tracking structure".  This way
631*9e39c5baSBill Taylor 	 * we get it back when each of the remaining pieces is subsequently
632*9e39c5baSBill Taylor 	 * unmapped.
633*9e39c5baSBill Taylor 	 */
634*9e39c5baSBill Taylor 	if (new_dhp1 != NULL) {
635*9e39c5baSBill Taylor 		*pvtp1 = pvtp;
636*9e39c5baSBill Taylor 	}
637*9e39c5baSBill Taylor 	if (new_dhp2 != NULL) {
638*9e39c5baSBill Taylor 		*pvtp2 = pvtp;
639*9e39c5baSBill Taylor 	}
640*9e39c5baSBill Taylor 
641*9e39c5baSBill Taylor 	/*
642*9e39c5baSBill Taylor 	 * If the "Tavor devmap tracking structure" is no longer being
643*9e39c5baSBill Taylor 	 * referenced, then free it up.  Otherwise, return.
644*9e39c5baSBill Taylor 	 */
645*9e39c5baSBill Taylor 	if (dvm_track->tdt_refcnt == 0) {
646*9e39c5baSBill Taylor 		mutex_destroy(&dvm_track->tdt_lock);
647*9e39c5baSBill Taylor 		kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
648*9e39c5baSBill Taylor 
649*9e39c5baSBill Taylor 		/*
650*9e39c5baSBill Taylor 		 * If the mapping was invalid (see explanation above), then
651*9e39c5baSBill Taylor 		 * no further processing is necessary.
652*9e39c5baSBill Taylor 		 */
653*9e39c5baSBill Taylor 		if (size == 0) {
654*9e39c5baSBill Taylor 			return;
655*9e39c5baSBill Taylor 		}
656*9e39c5baSBill Taylor 	} else {
657*9e39c5baSBill Taylor 		return;
658*9e39c5baSBill Taylor 	}
659*9e39c5baSBill Taylor 
660*9e39c5baSBill Taylor 	/*
661*9e39c5baSBill Taylor 	 * Now that we can guarantee that the user memory is fully unmapped,
662*9e39c5baSBill Taylor 	 * we can use the "key" and "type" values to try to find the entry
663*9e39c5baSBill Taylor 	 * in the "userland resources database".  If it's found, then it
664*9e39c5baSBill Taylor 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
665*9e39c5baSBill Taylor 	 * In this case, we update the corresponding CQ or QP handle to
666*9e39c5baSBill Taylor 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
667*9e39c5baSBill Taylor 	 * If it's _not_ found, then it indicates that the CQ or QP memory
668*9e39c5baSBill Taylor 	 * was, in fact, freed before it was unmapped (thus requiring a
669*9e39c5baSBill Taylor 	 * previous invalidation by remapping - which will already have
670*9e39c5baSBill Taylor 	 * been done in the free routine).
671*9e39c5baSBill Taylor 	 */
672*9e39c5baSBill Taylor 	status = tavor_umap_db_find(state->ts_instance, key, type, &value,
673*9e39c5baSBill Taylor 	    0, NULL);
674*9e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
675*9e39c5baSBill Taylor 		/*
676*9e39c5baSBill Taylor 		 * Depending on the type of the mapped resource (CQ or QP),
677*9e39c5baSBill Taylor 		 * update handle to indicate that no invalidation remapping
678*9e39c5baSBill Taylor 		 * will be necessary.
679*9e39c5baSBill Taylor 		 */
680*9e39c5baSBill Taylor 		if (type == MLNX_UMAP_CQMEM_RSRC) {
681*9e39c5baSBill Taylor 
682*9e39c5baSBill Taylor 			/* Use "value" to convert to CQ handle */
683*9e39c5baSBill Taylor 			rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
684*9e39c5baSBill Taylor 			cq = (tavor_cqhdl_t)rsrcp->tr_addr;
685*9e39c5baSBill Taylor 
686*9e39c5baSBill Taylor 			/*
687*9e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
688*9e39c5baSBill Taylor 			 * Note: We must ensure that the mapping being
689*9e39c5baSBill Taylor 			 * unmapped here is the current one for the CQ.  It
690*9e39c5baSBill Taylor 			 * is possible that it might not be if this CQ has
691*9e39c5baSBill Taylor 			 * been resized and the previous CQ memory has not
692*9e39c5baSBill Taylor 			 * yet been unmapped.  But in that case, because of
693*9e39c5baSBill Taylor 			 * the devmap_devmem_remap(), there is no longer any
694*9e39c5baSBill Taylor 			 * association between the mapping and the real CQ
695*9e39c5baSBill Taylor 			 * kernel memory.
696*9e39c5baSBill Taylor 			 */
697*9e39c5baSBill Taylor 			mutex_enter(&cq->cq_lock);
698*9e39c5baSBill Taylor 			if (cq->cq_umap_dhp == dhp) {
699*9e39c5baSBill Taylor 				cq->cq_umap_dhp = (devmap_cookie_t)NULL;
700*9e39c5baSBill Taylor 			}
701*9e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
702*9e39c5baSBill Taylor 
703*9e39c5baSBill Taylor 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
704*9e39c5baSBill Taylor 
705*9e39c5baSBill Taylor 			/* Use "value" to convert to QP handle */
706*9e39c5baSBill Taylor 			rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
707*9e39c5baSBill Taylor 			qp = (tavor_qphdl_t)rsrcp->tr_addr;
708*9e39c5baSBill Taylor 
709*9e39c5baSBill Taylor 			/*
710*9e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
711*9e39c5baSBill Taylor 			 * Note: we ensure that the mapping being unmapped
712*9e39c5baSBill Taylor 			 * here is the current one for the QP.  This is
713*9e39c5baSBill Taylor 			 * more of a sanity check here since, unlike CQs
714*9e39c5baSBill Taylor 			 * (above) we do not support resize of QPs.
715*9e39c5baSBill Taylor 			 */
716*9e39c5baSBill Taylor 			mutex_enter(&qp->qp_lock);
717*9e39c5baSBill Taylor 			if (qp->qp_umap_dhp == dhp) {
718*9e39c5baSBill Taylor 				qp->qp_umap_dhp = (devmap_cookie_t)NULL;
719*9e39c5baSBill Taylor 			}
720*9e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
721*9e39c5baSBill Taylor 
722*9e39c5baSBill Taylor 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
723*9e39c5baSBill Taylor 
724*9e39c5baSBill Taylor 			/* Use "value" to convert to SRQ handle */
725*9e39c5baSBill Taylor 			rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
726*9e39c5baSBill Taylor 			srq = (tavor_srqhdl_t)rsrcp->tr_addr;
727*9e39c5baSBill Taylor 
728*9e39c5baSBill Taylor 			/*
729*9e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
730*9e39c5baSBill Taylor 			 * Note: we ensure that the mapping being unmapped
731*9e39c5baSBill Taylor 			 * here is the current one for the QP.  This is
732*9e39c5baSBill Taylor 			 * more of a sanity check here since, unlike CQs
733*9e39c5baSBill Taylor 			 * (above) we do not support resize of QPs.
734*9e39c5baSBill Taylor 			 */
735*9e39c5baSBill Taylor 			mutex_enter(&srq->srq_lock);
736*9e39c5baSBill Taylor 			if (srq->srq_umap_dhp == dhp) {
737*9e39c5baSBill Taylor 				srq->srq_umap_dhp = (devmap_cookie_t)NULL;
738*9e39c5baSBill Taylor 			}
739*9e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
740*9e39c5baSBill Taylor 		}
741*9e39c5baSBill Taylor 	}
742*9e39c5baSBill Taylor }
743*9e39c5baSBill Taylor 
744*9e39c5baSBill Taylor 
745*9e39c5baSBill Taylor /*
746*9e39c5baSBill Taylor  * tavor_devmap_devmem_map()
747*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
748*9e39c5baSBill Taylor  */
749*9e39c5baSBill Taylor /* ARGSUSED */
750*9e39c5baSBill Taylor static int
tavor_devmap_devmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)751*9e39c5baSBill Taylor tavor_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
752*9e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp)
753*9e39c5baSBill Taylor {
754*9e39c5baSBill Taylor 	tavor_state_t		*state;
755*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track;
756*9e39c5baSBill Taylor 	minor_t			instance;
757*9e39c5baSBill Taylor 
758*9e39c5baSBill Taylor 	/* Get Tavor softstate structure from instance */
759*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
760*9e39c5baSBill Taylor 	state = ddi_get_soft_state(tavor_statep, instance);
761*9e39c5baSBill Taylor 	if (state == NULL) {
762*9e39c5baSBill Taylor 		return (ENXIO);
763*9e39c5baSBill Taylor 	}
764*9e39c5baSBill Taylor 
765*9e39c5baSBill Taylor 	/*
766*9e39c5baSBill Taylor 	 * Allocate an entry to track the mapping and unmapping of this
767*9e39c5baSBill Taylor 	 * resource.  Note:  We don't need to initialize the "refcnt" or
768*9e39c5baSBill Taylor 	 * "offset" fields here, nor do we need to initialize the mutex
769*9e39c5baSBill Taylor 	 * used with the "refcnt".  Since UAR pages are single pages, they
770*9e39c5baSBill Taylor 	 * are not subject to "partial" unmappings.  This makes these other
771*9e39c5baSBill Taylor 	 * fields unnecessary.
772*9e39c5baSBill Taylor 	 */
773*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)kmem_zalloc(
774*9e39c5baSBill Taylor 	    sizeof (tavor_devmap_track_t), KM_SLEEP);
775*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
776*9e39c5baSBill Taylor 	dvm_track->tdt_state  = state;
777*9e39c5baSBill Taylor 	dvm_track->tdt_size   = PAGESIZE;
778*9e39c5baSBill Taylor 
779*9e39c5baSBill Taylor 	/*
780*9e39c5baSBill Taylor 	 * Pass the private "Tavor devmap tracking structure" back.  This
781*9e39c5baSBill Taylor 	 * pointer will be returned in a subsequent "unmap" callback.
782*9e39c5baSBill Taylor 	 */
783*9e39c5baSBill Taylor 	*pvtp = dvm_track;
784*9e39c5baSBill Taylor 
785*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
786*9e39c5baSBill Taylor }
787*9e39c5baSBill Taylor 
788*9e39c5baSBill Taylor 
789*9e39c5baSBill Taylor /*
790*9e39c5baSBill Taylor  * tavor_devmap_devmem_dup()
791*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
792*9e39c5baSBill Taylor  */
793*9e39c5baSBill Taylor /* ARGSUSED */
794*9e39c5baSBill Taylor static int
tavor_devmap_devmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)795*9e39c5baSBill Taylor tavor_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
796*9e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp)
797*9e39c5baSBill Taylor {
798*9e39c5baSBill Taylor 	tavor_state_t		*state;
799*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track;
800*9e39c5baSBill Taylor 	uint_t			maxprot;
801*9e39c5baSBill Taylor 	int			status;
802*9e39c5baSBill Taylor 
803*9e39c5baSBill Taylor 	/*
804*9e39c5baSBill Taylor 	 * Extract the Tavor softstate pointer from "Tavor devmap tracking
805*9e39c5baSBill Taylor 	 * structure" (in "pvtp").  Note: If the tracking structure is NULL
806*9e39c5baSBill Taylor 	 * here, it means that the mapping corresponds to an invalid mapping.
807*9e39c5baSBill Taylor 	 * In this case, it can be safely ignored ("new_pvtp" set to NULL).
808*9e39c5baSBill Taylor 	 */
809*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)pvtp;
810*9e39c5baSBill Taylor 	if (dvm_track == NULL) {
811*9e39c5baSBill Taylor 		*new_pvtp = NULL;
812*9e39c5baSBill Taylor 		return (DDI_SUCCESS);
813*9e39c5baSBill Taylor 	}
814*9e39c5baSBill Taylor 
815*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
816*9e39c5baSBill Taylor 	state = dvm_track->tdt_state;
817*9e39c5baSBill Taylor 
818*9e39c5baSBill Taylor 	/*
819*9e39c5baSBill Taylor 	 * Since this devmap_dup() entry point is generally called
820*9e39c5baSBill Taylor 	 * when a process does fork(2), it is incumbent upon the driver
821*9e39c5baSBill Taylor 	 * to insure that the child does not inherit a valid copy of
822*9e39c5baSBill Taylor 	 * the parent's resource.  This is accomplished by using
823*9e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the child's mapping to the
824*9e39c5baSBill Taylor 	 * kernel memory.
825*9e39c5baSBill Taylor 	 */
826*9e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
827*9e39c5baSBill Taylor 	status = devmap_devmem_remap(new_dhp, state->ts_dip, 0, 0,
828*9e39c5baSBill Taylor 	    dvm_track->tdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
829*9e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
830*9e39c5baSBill Taylor 		TAVOR_WARNING(state, "failed in tavor_devmap_devmem_dup()");
831*9e39c5baSBill Taylor 		return (status);
832*9e39c5baSBill Taylor 	}
833*9e39c5baSBill Taylor 
834*9e39c5baSBill Taylor 	/*
835*9e39c5baSBill Taylor 	 * Since the region is invalid, there is no need for us to
836*9e39c5baSBill Taylor 	 * allocate and continue to track an additional "Tavor devmap
837*9e39c5baSBill Taylor 	 * tracking structure".  Instead we return NULL here, which is an
838*9e39c5baSBill Taylor 	 * indication to the devmap_unmap() entry point that this entry
839*9e39c5baSBill Taylor 	 * can be safely ignored.
840*9e39c5baSBill Taylor 	 */
841*9e39c5baSBill Taylor 	*new_pvtp = NULL;
842*9e39c5baSBill Taylor 
843*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
844*9e39c5baSBill Taylor }
845*9e39c5baSBill Taylor 
846*9e39c5baSBill Taylor 
847*9e39c5baSBill Taylor /*
848*9e39c5baSBill Taylor  * tavor_devmap_devmem_unmap()
849*9e39c5baSBill Taylor  *    Context: Can be called from kernel context.
850*9e39c5baSBill Taylor  */
851*9e39c5baSBill Taylor /* ARGSUSED */
852*9e39c5baSBill Taylor static void
tavor_devmap_devmem_unmap(devmap_cookie_t dhp,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** pvtp1,devmap_cookie_t new_dhp2,void ** pvtp2)853*9e39c5baSBill Taylor tavor_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
854*9e39c5baSBill Taylor     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
855*9e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2)
856*9e39c5baSBill Taylor {
857*9e39c5baSBill Taylor 	tavor_devmap_track_t	*dvm_track;
858*9e39c5baSBill Taylor 
859*9e39c5baSBill Taylor 	/*
860*9e39c5baSBill Taylor 	 * Free up the "Tavor devmap tracking structure" (in "pvtp").
861*9e39c5baSBill Taylor 	 * There cannot be "partial" unmappings here because all UAR pages
862*9e39c5baSBill Taylor 	 * are single pages.  Note: If the tracking structure is NULL here,
863*9e39c5baSBill Taylor 	 * it means that the mapping corresponds to an invalid mapping.  In
864*9e39c5baSBill Taylor 	 * this case, it can be safely ignored.
865*9e39c5baSBill Taylor 	 */
866*9e39c5baSBill Taylor 	dvm_track = (tavor_devmap_track_t *)pvtp;
867*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
868*9e39c5baSBill Taylor 	if (dvm_track == NULL) {
869*9e39c5baSBill Taylor 		return;
870*9e39c5baSBill Taylor 	}
871*9e39c5baSBill Taylor 
872*9e39c5baSBill Taylor 	kmem_free(dvm_track, sizeof (tavor_devmap_track_t));
873*9e39c5baSBill Taylor }
874*9e39c5baSBill Taylor 
875*9e39c5baSBill Taylor 
876*9e39c5baSBill Taylor /*
877*9e39c5baSBill Taylor  * tavor_umap_ci_data_in()
878*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
879*9e39c5baSBill Taylor  */
880*9e39c5baSBill Taylor /* ARGSUSED */
881*9e39c5baSBill Taylor ibt_status_t
tavor_umap_ci_data_in(tavor_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)882*9e39c5baSBill Taylor tavor_umap_ci_data_in(tavor_state_t *state, ibt_ci_data_flags_t flags,
883*9e39c5baSBill Taylor     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
884*9e39c5baSBill Taylor {
885*9e39c5baSBill Taylor 	int	status;
886*9e39c5baSBill Taylor 
887*9e39c5baSBill Taylor 	/*
888*9e39c5baSBill Taylor 	 * Depending on the type of object about which additional information
889*9e39c5baSBill Taylor 	 * is being provided (currently only MR is supported), we call the
890*9e39c5baSBill Taylor 	 * appropriate resource-specific function.
891*9e39c5baSBill Taylor 	 */
892*9e39c5baSBill Taylor 	switch (object) {
893*9e39c5baSBill Taylor 	case IBT_HDL_MR:
894*9e39c5baSBill Taylor 		status = tavor_umap_mr_data_in((tavor_mrhdl_t)hdl,
895*9e39c5baSBill Taylor 		    (ibt_mr_data_in_t *)data_p, data_sz);
896*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
897*9e39c5baSBill Taylor 			return (status);
898*9e39c5baSBill Taylor 		}
899*9e39c5baSBill Taylor 		break;
900*9e39c5baSBill Taylor 
901*9e39c5baSBill Taylor 	/*
902*9e39c5baSBill Taylor 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
903*9e39c5baSBill Taylor 	 * since the Tavor driver does not support these.
904*9e39c5baSBill Taylor 	 */
905*9e39c5baSBill Taylor 	case IBT_HDL_HCA:
906*9e39c5baSBill Taylor 	case IBT_HDL_QP:
907*9e39c5baSBill Taylor 	case IBT_HDL_CQ:
908*9e39c5baSBill Taylor 	case IBT_HDL_PD:
909*9e39c5baSBill Taylor 	case IBT_HDL_MW:
910*9e39c5baSBill Taylor 	case IBT_HDL_AH:
911*9e39c5baSBill Taylor 	case IBT_HDL_SCHED:
912*9e39c5baSBill Taylor 	case IBT_HDL_EEC:
913*9e39c5baSBill Taylor 	case IBT_HDL_RDD:
914*9e39c5baSBill Taylor 	case IBT_HDL_SRQ:
915*9e39c5baSBill Taylor 		return (IBT_NOT_SUPPORTED);
916*9e39c5baSBill Taylor 
917*9e39c5baSBill Taylor 	/*
918*9e39c5baSBill Taylor 	 * Any other types are invalid.
919*9e39c5baSBill Taylor 	 */
920*9e39c5baSBill Taylor 	default:
921*9e39c5baSBill Taylor 		return (IBT_INVALID_PARAM);
922*9e39c5baSBill Taylor 	}
923*9e39c5baSBill Taylor 
924*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
925*9e39c5baSBill Taylor }
926*9e39c5baSBill Taylor 
927*9e39c5baSBill Taylor 
928*9e39c5baSBill Taylor /*
929*9e39c5baSBill Taylor  * tavor_umap_mr_data_in()
930*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
931*9e39c5baSBill Taylor  */
932*9e39c5baSBill Taylor static ibt_status_t
tavor_umap_mr_data_in(tavor_mrhdl_t mr,ibt_mr_data_in_t * data,size_t data_sz)933*9e39c5baSBill Taylor tavor_umap_mr_data_in(tavor_mrhdl_t mr, ibt_mr_data_in_t *data,
934*9e39c5baSBill Taylor     size_t data_sz)
935*9e39c5baSBill Taylor {
936*9e39c5baSBill Taylor 	if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
937*9e39c5baSBill Taylor 		return (IBT_NOT_SUPPORTED);
938*9e39c5baSBill Taylor 	}
939*9e39c5baSBill Taylor 
940*9e39c5baSBill Taylor 	/* Check for valid MR handle pointer */
941*9e39c5baSBill Taylor 	if (mr == NULL) {
942*9e39c5baSBill Taylor 		return (IBT_MR_HDL_INVALID);
943*9e39c5baSBill Taylor 	}
944*9e39c5baSBill Taylor 
945*9e39c5baSBill Taylor 	/* Check for valid MR input structure size */
946*9e39c5baSBill Taylor 	if (data_sz < sizeof (ibt_mr_data_in_t)) {
947*9e39c5baSBill Taylor 		return (IBT_INSUFF_RESOURCE);
948*9e39c5baSBill Taylor 	}
949*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
950*9e39c5baSBill Taylor 
951*9e39c5baSBill Taylor 	/*
952*9e39c5baSBill Taylor 	 * Ensure that the MR corresponds to userland memory and that it is
953*9e39c5baSBill Taylor 	 * a currently valid memory region as well.
954*9e39c5baSBill Taylor 	 */
955*9e39c5baSBill Taylor 	mutex_enter(&mr->mr_lock);
956*9e39c5baSBill Taylor 	if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
957*9e39c5baSBill Taylor 		mutex_exit(&mr->mr_lock);
958*9e39c5baSBill Taylor 		return (IBT_MR_HDL_INVALID);
959*9e39c5baSBill Taylor 	}
960*9e39c5baSBill Taylor 
961*9e39c5baSBill Taylor 	/*
962*9e39c5baSBill Taylor 	 * If it has passed all the above checks, then extract the callback
963*9e39c5baSBill Taylor 	 * function and argument from the input structure.  Copy them into
964*9e39c5baSBill Taylor 	 * the MR handle.  This function will be called only if the memory
965*9e39c5baSBill Taylor 	 * corresponding to the MR handle gets a umem_lockmemory() callback.
966*9e39c5baSBill Taylor 	 */
967*9e39c5baSBill Taylor 	mr->mr_umem_cbfunc = data->mr_func;
968*9e39c5baSBill Taylor 	mr->mr_umem_cbarg1 = data->mr_arg1;
969*9e39c5baSBill Taylor 	mr->mr_umem_cbarg2 = data->mr_arg2;
970*9e39c5baSBill Taylor 	mutex_exit(&mr->mr_lock);
971*9e39c5baSBill Taylor 
972*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
973*9e39c5baSBill Taylor }
974*9e39c5baSBill Taylor 
975*9e39c5baSBill Taylor 
976*9e39c5baSBill Taylor /*
977*9e39c5baSBill Taylor  * tavor_umap_ci_data_out()
978*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
979*9e39c5baSBill Taylor  */
980*9e39c5baSBill Taylor /* ARGSUSED */
981*9e39c5baSBill Taylor ibt_status_t
tavor_umap_ci_data_out(tavor_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)982*9e39c5baSBill Taylor tavor_umap_ci_data_out(tavor_state_t *state, ibt_ci_data_flags_t flags,
983*9e39c5baSBill Taylor     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
984*9e39c5baSBill Taylor {
985*9e39c5baSBill Taylor 	int	status;
986*9e39c5baSBill Taylor 
987*9e39c5baSBill Taylor 	/*
988*9e39c5baSBill Taylor 	 * Depending on the type of object about which additional information
989*9e39c5baSBill Taylor 	 * is being requested (CQ or QP), we call the appropriate resource-
990*9e39c5baSBill Taylor 	 * specific mapping function.
991*9e39c5baSBill Taylor 	 */
992*9e39c5baSBill Taylor 	switch (object) {
993*9e39c5baSBill Taylor 	case IBT_HDL_CQ:
994*9e39c5baSBill Taylor 		status = tavor_umap_cq_data_out((tavor_cqhdl_t)hdl,
995*9e39c5baSBill Taylor 		    (mlnx_umap_cq_data_out_t *)data_p, data_sz);
996*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
997*9e39c5baSBill Taylor 			return (status);
998*9e39c5baSBill Taylor 		}
999*9e39c5baSBill Taylor 		break;
1000*9e39c5baSBill Taylor 
1001*9e39c5baSBill Taylor 	case IBT_HDL_QP:
1002*9e39c5baSBill Taylor 		status = tavor_umap_qp_data_out((tavor_qphdl_t)hdl,
1003*9e39c5baSBill Taylor 		    (mlnx_umap_qp_data_out_t *)data_p, data_sz);
1004*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
1005*9e39c5baSBill Taylor 			return (status);
1006*9e39c5baSBill Taylor 		}
1007*9e39c5baSBill Taylor 		break;
1008*9e39c5baSBill Taylor 
1009*9e39c5baSBill Taylor 	case IBT_HDL_SRQ:
1010*9e39c5baSBill Taylor 		status = tavor_umap_srq_data_out((tavor_srqhdl_t)hdl,
1011*9e39c5baSBill Taylor 		    (mlnx_umap_srq_data_out_t *)data_p, data_sz);
1012*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
1013*9e39c5baSBill Taylor 			return (status);
1014*9e39c5baSBill Taylor 		}
1015*9e39c5baSBill Taylor 		break;
1016*9e39c5baSBill Taylor 
1017*9e39c5baSBill Taylor 	/*
1018*9e39c5baSBill Taylor 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1019*9e39c5baSBill Taylor 	 * since the Tavor driver does not support these.
1020*9e39c5baSBill Taylor 	 */
1021*9e39c5baSBill Taylor 	case IBT_HDL_PD:
1022*9e39c5baSBill Taylor 		status = tavor_umap_pd_data_out((tavor_pdhdl_t)hdl,
1023*9e39c5baSBill Taylor 		    (mlnx_umap_pd_data_out_t *)data_p, data_sz);
1024*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
1025*9e39c5baSBill Taylor 			return (status);
1026*9e39c5baSBill Taylor 		}
1027*9e39c5baSBill Taylor 		break;
1028*9e39c5baSBill Taylor 
1029*9e39c5baSBill Taylor 	case IBT_HDL_HCA:
1030*9e39c5baSBill Taylor 	case IBT_HDL_MR:
1031*9e39c5baSBill Taylor 	case IBT_HDL_MW:
1032*9e39c5baSBill Taylor 	case IBT_HDL_AH:
1033*9e39c5baSBill Taylor 	case IBT_HDL_SCHED:
1034*9e39c5baSBill Taylor 	case IBT_HDL_EEC:
1035*9e39c5baSBill Taylor 	case IBT_HDL_RDD:
1036*9e39c5baSBill Taylor 		return (IBT_NOT_SUPPORTED);
1037*9e39c5baSBill Taylor 
1038*9e39c5baSBill Taylor 	/*
1039*9e39c5baSBill Taylor 	 * Any other types are invalid.
1040*9e39c5baSBill Taylor 	 */
1041*9e39c5baSBill Taylor 	default:
1042*9e39c5baSBill Taylor 		return (IBT_INVALID_PARAM);
1043*9e39c5baSBill Taylor 	}
1044*9e39c5baSBill Taylor 
1045*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1046*9e39c5baSBill Taylor }
1047*9e39c5baSBill Taylor 
1048*9e39c5baSBill Taylor 
1049*9e39c5baSBill Taylor /*
1050*9e39c5baSBill Taylor  * tavor_umap_cq_data_out()
1051*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1052*9e39c5baSBill Taylor  */
1053*9e39c5baSBill Taylor static ibt_status_t
tavor_umap_cq_data_out(tavor_cqhdl_t cq,mlnx_umap_cq_data_out_t * data,size_t data_sz)1054*9e39c5baSBill Taylor tavor_umap_cq_data_out(tavor_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
1055*9e39c5baSBill Taylor     size_t data_sz)
1056*9e39c5baSBill Taylor {
1057*9e39c5baSBill Taylor 	/* Check for valid CQ handle pointer */
1058*9e39c5baSBill Taylor 	if (cq == NULL) {
1059*9e39c5baSBill Taylor 		return (IBT_CQ_HDL_INVALID);
1060*9e39c5baSBill Taylor 	}
1061*9e39c5baSBill Taylor 
1062*9e39c5baSBill Taylor 	/* Check for valid CQ mapping structure size */
1063*9e39c5baSBill Taylor 	if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
1064*9e39c5baSBill Taylor 		return (IBT_INSUFF_RESOURCE);
1065*9e39c5baSBill Taylor 	}
1066*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1067*9e39c5baSBill Taylor 
1068*9e39c5baSBill Taylor 	/*
1069*9e39c5baSBill Taylor 	 * If it has passed all the above checks, then fill in all the useful
1070*9e39c5baSBill Taylor 	 * mapping information (including the mapping offset that will be
1071*9e39c5baSBill Taylor 	 * passed back to the devmap() interface during a subsequent mmap()
1072*9e39c5baSBill Taylor 	 * call.
1073*9e39c5baSBill Taylor 	 *
1074*9e39c5baSBill Taylor 	 * The "offset" for CQ mmap()'s looks like this:
1075*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1076*9e39c5baSBill Taylor 	 * |		   CQ Number		    |  0x33  | Reserved (0) |
1077*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1078*9e39c5baSBill Taylor 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1079*9e39c5baSBill Taylor 	 *
1080*9e39c5baSBill Taylor 	 * This returns information about the mapping offset, the length of
1081*9e39c5baSBill Taylor 	 * the CQ memory, the CQ number (for use in later CQ doorbells), the
1082*9e39c5baSBill Taylor 	 * number of CQEs the CQ memory can hold, and the size of each CQE.
1083*9e39c5baSBill Taylor 	 */
1084*9e39c5baSBill Taylor 	data->mcq_rev		= MLNX_UMAP_IF_VERSION;
1085*9e39c5baSBill Taylor 	data->mcq_mapoffset	= ((((uint64_t)cq->cq_cqnum <<
1086*9e39c5baSBill Taylor 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
1087*9e39c5baSBill Taylor 	data->mcq_maplen	= cq->cq_cqinfo.qa_size;
1088*9e39c5baSBill Taylor 	data->mcq_cqnum		= cq->cq_cqnum;
1089*9e39c5baSBill Taylor 	data->mcq_numcqe	= cq->cq_bufsz;
1090*9e39c5baSBill Taylor 	data->mcq_cqesz		= sizeof (tavor_hw_cqe_t);
1091*9e39c5baSBill Taylor 
1092*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1093*9e39c5baSBill Taylor }
1094*9e39c5baSBill Taylor 
1095*9e39c5baSBill Taylor 
1096*9e39c5baSBill Taylor /*
1097*9e39c5baSBill Taylor  * tavor_umap_qp_data_out()
1098*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1099*9e39c5baSBill Taylor  */
1100*9e39c5baSBill Taylor static ibt_status_t
tavor_umap_qp_data_out(tavor_qphdl_t qp,mlnx_umap_qp_data_out_t * data,size_t data_sz)1101*9e39c5baSBill Taylor tavor_umap_qp_data_out(tavor_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
1102*9e39c5baSBill Taylor     size_t data_sz)
1103*9e39c5baSBill Taylor {
1104*9e39c5baSBill Taylor 	/* Check for valid QP handle pointer */
1105*9e39c5baSBill Taylor 	if (qp == NULL) {
1106*9e39c5baSBill Taylor 		return (IBT_QP_HDL_INVALID);
1107*9e39c5baSBill Taylor 	}
1108*9e39c5baSBill Taylor 
1109*9e39c5baSBill Taylor 	/* Check for valid QP mapping structure size */
1110*9e39c5baSBill Taylor 	if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
1111*9e39c5baSBill Taylor 		return (IBT_INSUFF_RESOURCE);
1112*9e39c5baSBill Taylor 	}
1113*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1114*9e39c5baSBill Taylor 
1115*9e39c5baSBill Taylor 	/*
1116*9e39c5baSBill Taylor 	 * If it has passed all the checks, then fill in all the useful
1117*9e39c5baSBill Taylor 	 * mapping information (including the mapping offset that will be
1118*9e39c5baSBill Taylor 	 * passed back to the devmap() interface during a subsequent mmap()
1119*9e39c5baSBill Taylor 	 * call.
1120*9e39c5baSBill Taylor 	 *
1121*9e39c5baSBill Taylor 	 * The "offset" for QP mmap()'s looks like this:
1122*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1123*9e39c5baSBill Taylor 	 * |		   QP Number		    |  0x44  | Reserved (0) |
1124*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1125*9e39c5baSBill Taylor 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1126*9e39c5baSBill Taylor 	 *
1127*9e39c5baSBill Taylor 	 * This returns information about the mapping offset, the length of
1128*9e39c5baSBill Taylor 	 * the QP memory, and the QP number (for use in later send and recv
1129*9e39c5baSBill Taylor 	 * doorbells).  It also returns the following information for both
1130*9e39c5baSBill Taylor 	 * the receive work queue and the send work queue, respectively:  the
1131*9e39c5baSBill Taylor 	 * offset (from the base mapped address) of the start of the given
1132*9e39c5baSBill Taylor 	 * work queue, the 64-bit IB virtual address that corresponds to
1133*9e39c5baSBill Taylor 	 * the base mapped address (needed for posting WQEs though the
1134*9e39c5baSBill Taylor 	 * QP doorbells), the number of WQEs the given work queue can hold,
1135*9e39c5baSBill Taylor 	 * and the size of each WQE for the given work queue.
1136*9e39c5baSBill Taylor 	 */
1137*9e39c5baSBill Taylor 	data->mqp_rev		= MLNX_UMAP_IF_VERSION;
1138*9e39c5baSBill Taylor 	data->mqp_mapoffset	= ((((uint64_t)qp->qp_qpnum <<
1139*9e39c5baSBill Taylor 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
1140*9e39c5baSBill Taylor 	data->mqp_maplen	= qp->qp_wqinfo.qa_size;
1141*9e39c5baSBill Taylor 	data->mqp_qpnum		= qp->qp_qpnum;
1142*9e39c5baSBill Taylor 
1143*9e39c5baSBill Taylor 	/*
1144*9e39c5baSBill Taylor 	 * If this QP is associated with a shared receive queue (SRQ),
1145*9e39c5baSBill Taylor 	 * then return invalid RecvQ parameters.  Otherwise, return
1146*9e39c5baSBill Taylor 	 * the proper parameter values.
1147*9e39c5baSBill Taylor 	 */
1148*9e39c5baSBill Taylor 	if (qp->qp_srq_en == TAVOR_QP_SRQ_ENABLED) {
1149*9e39c5baSBill Taylor 		data->mqp_rq_off	= (uint32_t)qp->qp_wqinfo.qa_size;
1150*9e39c5baSBill Taylor 		data->mqp_rq_desc_addr	= (uint32_t)qp->qp_wqinfo.qa_size;
1151*9e39c5baSBill Taylor 		data->mqp_rq_numwqe	= 0;
1152*9e39c5baSBill Taylor 		data->mqp_rq_wqesz	= 0;
1153*9e39c5baSBill Taylor 	} else {
1154*9e39c5baSBill Taylor 		data->mqp_rq_off	= (uintptr_t)qp->qp_rq_buf -
1155*9e39c5baSBill Taylor 		    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1156*9e39c5baSBill Taylor 		data->mqp_rq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_rq_buf -
1157*9e39c5baSBill Taylor 		    qp->qp_desc_off);
1158*9e39c5baSBill Taylor 		data->mqp_rq_numwqe	= qp->qp_rq_bufsz;
1159*9e39c5baSBill Taylor 		data->mqp_rq_wqesz	= (1 << qp->qp_rq_log_wqesz);
1160*9e39c5baSBill Taylor 	}
1161*9e39c5baSBill Taylor 	data->mqp_sq_off	= (uintptr_t)qp->qp_sq_buf -
1162*9e39c5baSBill Taylor 	    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1163*9e39c5baSBill Taylor 	data->mqp_sq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_sq_buf -
1164*9e39c5baSBill Taylor 	    qp->qp_desc_off);
1165*9e39c5baSBill Taylor 	data->mqp_sq_numwqe	= qp->qp_sq_bufsz;
1166*9e39c5baSBill Taylor 	data->mqp_sq_wqesz	= (1 << qp->qp_sq_log_wqesz);
1167*9e39c5baSBill Taylor 
1168*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1169*9e39c5baSBill Taylor }
1170*9e39c5baSBill Taylor 
1171*9e39c5baSBill Taylor 
1172*9e39c5baSBill Taylor /*
1173*9e39c5baSBill Taylor  * tavor_umap_srq_data_out()
1174*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1175*9e39c5baSBill Taylor  */
1176*9e39c5baSBill Taylor static ibt_status_t
tavor_umap_srq_data_out(tavor_srqhdl_t srq,mlnx_umap_srq_data_out_t * data,size_t data_sz)1177*9e39c5baSBill Taylor tavor_umap_srq_data_out(tavor_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
1178*9e39c5baSBill Taylor     size_t data_sz)
1179*9e39c5baSBill Taylor {
1180*9e39c5baSBill Taylor 	/* Check for valid SRQ handle pointer */
1181*9e39c5baSBill Taylor 	if (srq == NULL) {
1182*9e39c5baSBill Taylor 		return (IBT_SRQ_HDL_INVALID);
1183*9e39c5baSBill Taylor 	}
1184*9e39c5baSBill Taylor 
1185*9e39c5baSBill Taylor 	/* Check for valid SRQ mapping structure size */
1186*9e39c5baSBill Taylor 	if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
1187*9e39c5baSBill Taylor 		return (IBT_INSUFF_RESOURCE);
1188*9e39c5baSBill Taylor 	}
1189*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1190*9e39c5baSBill Taylor 
1191*9e39c5baSBill Taylor 	/*
1192*9e39c5baSBill Taylor 	 * If it has passed all the checks, then fill in all the useful
1193*9e39c5baSBill Taylor 	 * mapping information (including the mapping offset that will be
1194*9e39c5baSBill Taylor 	 * passed back to the devmap() interface during a subsequent mmap()
1195*9e39c5baSBill Taylor 	 * call.
1196*9e39c5baSBill Taylor 	 *
1197*9e39c5baSBill Taylor 	 * The "offset" for SRQ mmap()'s looks like this:
1198*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1199*9e39c5baSBill Taylor 	 * |		   SRQ Number		    |  0x66  | Reserved (0) |
1200*9e39c5baSBill Taylor 	 * +----------------------------------------+--------+--------------+
1201*9e39c5baSBill Taylor 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1202*9e39c5baSBill Taylor 	 *
1203*9e39c5baSBill Taylor 	 * This returns information about the mapping offset, the length of the
1204*9e39c5baSBill Taylor 	 * SRQ memory, and the SRQ number (for use in later send and recv
1205*9e39c5baSBill Taylor 	 * doorbells).  It also returns the following information for the
1206*9e39c5baSBill Taylor 	 * shared receive queue: the offset (from the base mapped address) of
1207*9e39c5baSBill Taylor 	 * the start of the given work queue, the 64-bit IB virtual address
1208*9e39c5baSBill Taylor 	 * that corresponds to the base mapped address (needed for posting WQEs
1209*9e39c5baSBill Taylor 	 * though the QP doorbells), the number of WQEs the given work queue
1210*9e39c5baSBill Taylor 	 * can hold, and the size of each WQE for the given work queue.
1211*9e39c5baSBill Taylor 	 */
1212*9e39c5baSBill Taylor 	data->msrq_rev		= MLNX_UMAP_IF_VERSION;
1213*9e39c5baSBill Taylor 	data->msrq_mapoffset	= ((((uint64_t)srq->srq_srqnum <<
1214*9e39c5baSBill Taylor 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
1215*9e39c5baSBill Taylor 	data->msrq_maplen	= srq->srq_wqinfo.qa_size;
1216*9e39c5baSBill Taylor 	data->msrq_srqnum	= srq->srq_srqnum;
1217*9e39c5baSBill Taylor 
1218*9e39c5baSBill Taylor 	data->msrq_desc_addr	= (uint32_t)((uintptr_t)srq->srq_wq_buf -
1219*9e39c5baSBill Taylor 	    srq->srq_desc_off);
1220*9e39c5baSBill Taylor 	data->msrq_numwqe	= srq->srq_wq_bufsz;
1221*9e39c5baSBill Taylor 	data->msrq_wqesz	= (1 << srq->srq_wq_log_wqesz);
1222*9e39c5baSBill Taylor 
1223*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1224*9e39c5baSBill Taylor }
1225*9e39c5baSBill Taylor 
1226*9e39c5baSBill Taylor /*
1227*9e39c5baSBill Taylor  * tavor_umap_pd_data_out()
1228*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1229*9e39c5baSBill Taylor  */
1230*9e39c5baSBill Taylor static ibt_status_t
tavor_umap_pd_data_out(tavor_pdhdl_t pd,mlnx_umap_pd_data_out_t * data,size_t data_sz)1231*9e39c5baSBill Taylor tavor_umap_pd_data_out(tavor_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
1232*9e39c5baSBill Taylor     size_t data_sz)
1233*9e39c5baSBill Taylor {
1234*9e39c5baSBill Taylor 	/* Check for valid PD handle pointer */
1235*9e39c5baSBill Taylor 	if (pd == NULL) {
1236*9e39c5baSBill Taylor 		return (IBT_PD_HDL_INVALID);
1237*9e39c5baSBill Taylor 	}
1238*9e39c5baSBill Taylor 
1239*9e39c5baSBill Taylor 	/* Check for valid PD mapping structure size */
1240*9e39c5baSBill Taylor 	if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
1241*9e39c5baSBill Taylor 		return (IBT_INSUFF_RESOURCE);
1242*9e39c5baSBill Taylor 	}
1243*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1244*9e39c5baSBill Taylor 
1245*9e39c5baSBill Taylor 	/*
1246*9e39c5baSBill Taylor 	 * If it has passed all the checks, then fill the PD table index
1247*9e39c5baSBill Taylor 	 * (the PD table allocated index for the PD pd_pdnum)
1248*9e39c5baSBill Taylor 	 */
1249*9e39c5baSBill Taylor 	data->mpd_rev	= MLNX_UMAP_IF_VERSION;
1250*9e39c5baSBill Taylor 	data->mpd_pdnum	= pd->pd_pdnum;
1251*9e39c5baSBill Taylor 
1252*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1253*9e39c5baSBill Taylor }
1254*9e39c5baSBill Taylor 
1255*9e39c5baSBill Taylor /*
1256*9e39c5baSBill Taylor  * tavor_umap_db_init()
1257*9e39c5baSBill Taylor  *    Context: Only called from attach() path context
1258*9e39c5baSBill Taylor  */
1259*9e39c5baSBill Taylor void
tavor_umap_db_init(void)1260*9e39c5baSBill Taylor tavor_umap_db_init(void)
1261*9e39c5baSBill Taylor {
1262*9e39c5baSBill Taylor 	/*
1263*9e39c5baSBill Taylor 	 * Initialize the lock used by the Tavor "userland resources database"
1264*9e39c5baSBill Taylor 	 * This is used to ensure atomic access to add, remove, and find
1265*9e39c5baSBill Taylor 	 * entries in the database.
1266*9e39c5baSBill Taylor 	 */
1267*9e39c5baSBill Taylor 	mutex_init(&tavor_userland_rsrc_db.tdl_umapdb_lock, NULL,
1268*9e39c5baSBill Taylor 	    MUTEX_DRIVER, NULL);
1269*9e39c5baSBill Taylor 
1270*9e39c5baSBill Taylor 	/*
1271*9e39c5baSBill Taylor 	 * Initialize the AVL tree used for the "userland resources
1272*9e39c5baSBill Taylor 	 * database".  Using an AVL tree here provides the ability to
1273*9e39c5baSBill Taylor 	 * scale the database size to large numbers of resources.  The
1274*9e39c5baSBill Taylor 	 * entries in the tree are "tavor_umap_db_entry_t".
1275*9e39c5baSBill Taylor 	 * The tree is searched with the help of the
1276*9e39c5baSBill Taylor 	 * tavor_umap_db_compare() routine.
1277*9e39c5baSBill Taylor 	 */
1278*9e39c5baSBill Taylor 	avl_create(&tavor_userland_rsrc_db.tdl_umapdb_avl,
1279*9e39c5baSBill Taylor 	    tavor_umap_db_compare, sizeof (tavor_umap_db_entry_t),
1280*9e39c5baSBill Taylor 	    offsetof(tavor_umap_db_entry_t, tdbe_avlnode));
1281*9e39c5baSBill Taylor }
1282*9e39c5baSBill Taylor 
1283*9e39c5baSBill Taylor 
1284*9e39c5baSBill Taylor /*
1285*9e39c5baSBill Taylor  * tavor_umap_db_fini()
1286*9e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
1287*9e39c5baSBill Taylor  */
1288*9e39c5baSBill Taylor void
tavor_umap_db_fini(void)1289*9e39c5baSBill Taylor tavor_umap_db_fini(void)
1290*9e39c5baSBill Taylor {
1291*9e39c5baSBill Taylor 	/* Destroy the AVL tree for the "userland resources database" */
1292*9e39c5baSBill Taylor 	avl_destroy(&tavor_userland_rsrc_db.tdl_umapdb_avl);
1293*9e39c5baSBill Taylor 
1294*9e39c5baSBill Taylor 	/* Destroy the lock for the "userland resources database" */
1295*9e39c5baSBill Taylor 	mutex_destroy(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1296*9e39c5baSBill Taylor }
1297*9e39c5baSBill Taylor 
1298*9e39c5baSBill Taylor 
1299*9e39c5baSBill Taylor /*
1300*9e39c5baSBill Taylor  * tavor_umap_db_alloc()
1301*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1302*9e39c5baSBill Taylor  */
1303*9e39c5baSBill Taylor tavor_umap_db_entry_t *
tavor_umap_db_alloc(uint_t instance,uint64_t key,uint_t type,uint64_t value)1304*9e39c5baSBill Taylor tavor_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
1305*9e39c5baSBill Taylor {
1306*9e39c5baSBill Taylor 	tavor_umap_db_entry_t	*umapdb;
1307*9e39c5baSBill Taylor 
1308*9e39c5baSBill Taylor 	/* Allocate an entry to add to the "userland resources database" */
1309*9e39c5baSBill Taylor 	umapdb = kmem_zalloc(sizeof (tavor_umap_db_entry_t), KM_NOSLEEP);
1310*9e39c5baSBill Taylor 	if (umapdb == NULL) {
1311*9e39c5baSBill Taylor 		return (NULL);
1312*9e39c5baSBill Taylor 	}
1313*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1314*9e39c5baSBill Taylor 
1315*9e39c5baSBill Taylor 	/* Fill in the fields in the database entry */
1316*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_instance  = instance;
1317*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_type	  = type;
1318*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_key	  = key;
1319*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_value	  = value;
1320*9e39c5baSBill Taylor 
1321*9e39c5baSBill Taylor 	return (umapdb);
1322*9e39c5baSBill Taylor }
1323*9e39c5baSBill Taylor 
1324*9e39c5baSBill Taylor 
1325*9e39c5baSBill Taylor /*
1326*9e39c5baSBill Taylor  * tavor_umap_db_free()
1327*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1328*9e39c5baSBill Taylor  */
1329*9e39c5baSBill Taylor void
tavor_umap_db_free(tavor_umap_db_entry_t * umapdb)1330*9e39c5baSBill Taylor tavor_umap_db_free(tavor_umap_db_entry_t *umapdb)
1331*9e39c5baSBill Taylor {
1332*9e39c5baSBill Taylor 	/* Free the database entry */
1333*9e39c5baSBill Taylor 	kmem_free(umapdb, sizeof (tavor_umap_db_entry_t));
1334*9e39c5baSBill Taylor }
1335*9e39c5baSBill Taylor 
1336*9e39c5baSBill Taylor 
1337*9e39c5baSBill Taylor /*
1338*9e39c5baSBill Taylor  * tavor_umap_db_add()
1339*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1340*9e39c5baSBill Taylor  */
1341*9e39c5baSBill Taylor void
tavor_umap_db_add(tavor_umap_db_entry_t * umapdb)1342*9e39c5baSBill Taylor tavor_umap_db_add(tavor_umap_db_entry_t *umapdb)
1343*9e39c5baSBill Taylor {
1344*9e39c5baSBill Taylor 	mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1345*9e39c5baSBill Taylor 	tavor_umap_db_add_nolock(umapdb);
1346*9e39c5baSBill Taylor 	mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1347*9e39c5baSBill Taylor }
1348*9e39c5baSBill Taylor 
1349*9e39c5baSBill Taylor 
1350*9e39c5baSBill Taylor /*
1351*9e39c5baSBill Taylor  * tavor_umap_db_add_nolock()
1352*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1353*9e39c5baSBill Taylor  */
1354*9e39c5baSBill Taylor void
tavor_umap_db_add_nolock(tavor_umap_db_entry_t * umapdb)1355*9e39c5baSBill Taylor tavor_umap_db_add_nolock(tavor_umap_db_entry_t *umapdb)
1356*9e39c5baSBill Taylor {
1357*9e39c5baSBill Taylor 	tavor_umap_db_query_t	query;
1358*9e39c5baSBill Taylor 	avl_index_t		where;
1359*9e39c5baSBill Taylor 
1360*9e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
1361*9e39c5baSBill Taylor 
1362*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1363*9e39c5baSBill Taylor 
1364*9e39c5baSBill Taylor 	/*
1365*9e39c5baSBill Taylor 	 * Copy the common portion of the "to-be-added" database entry
1366*9e39c5baSBill Taylor 	 * into the "tavor_umap_db_query_t" structure.  We use this structure
1367*9e39c5baSBill Taylor 	 * (with no flags set) to find the appropriate location in the
1368*9e39c5baSBill Taylor 	 * "userland resources database" for the new entry to be added.
1369*9e39c5baSBill Taylor 	 *
1370*9e39c5baSBill Taylor 	 * Note: we expect that this entry should not be found in the
1371*9e39c5baSBill Taylor 	 * database (unless something bad has happened).
1372*9e39c5baSBill Taylor 	 */
1373*9e39c5baSBill Taylor 	query.tqdb_common = umapdb->tdbe_common;
1374*9e39c5baSBill Taylor 	query.tqdb_flags  = 0;
1375*9e39c5baSBill Taylor 	(void) avl_find(&tavor_userland_rsrc_db.tdl_umapdb_avl, &query,
1376*9e39c5baSBill Taylor 	    &where);
1377*9e39c5baSBill Taylor 
1378*9e39c5baSBill Taylor 	/*
1379*9e39c5baSBill Taylor 	 * Now, using the "where" field from the avl_find() operation
1380*9e39c5baSBill Taylor 	 * above, we will insert the new database entry ("umapdb").
1381*9e39c5baSBill Taylor 	 */
1382*9e39c5baSBill Taylor 	avl_insert(&tavor_userland_rsrc_db.tdl_umapdb_avl, umapdb,
1383*9e39c5baSBill Taylor 	    where);
1384*9e39c5baSBill Taylor }
1385*9e39c5baSBill Taylor 
1386*9e39c5baSBill Taylor 
1387*9e39c5baSBill Taylor /*
1388*9e39c5baSBill Taylor  * tavor_umap_db_find()
1389*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1390*9e39c5baSBill Taylor  */
1391*9e39c5baSBill Taylor int
tavor_umap_db_find(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flag,tavor_umap_db_entry_t ** umapdb)1392*9e39c5baSBill Taylor tavor_umap_db_find(uint_t instance, uint64_t key, uint_t type,
1393*9e39c5baSBill Taylor     uint64_t *value, uint_t flag, tavor_umap_db_entry_t	**umapdb)
1394*9e39c5baSBill Taylor {
1395*9e39c5baSBill Taylor 	int	status;
1396*9e39c5baSBill Taylor 
1397*9e39c5baSBill Taylor 	mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1398*9e39c5baSBill Taylor 	status = tavor_umap_db_find_nolock(instance, key, type, value, flag,
1399*9e39c5baSBill Taylor 	    umapdb);
1400*9e39c5baSBill Taylor 	mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1401*9e39c5baSBill Taylor 
1402*9e39c5baSBill Taylor 	return (status);
1403*9e39c5baSBill Taylor }
1404*9e39c5baSBill Taylor 
1405*9e39c5baSBill Taylor 
1406*9e39c5baSBill Taylor /*
1407*9e39c5baSBill Taylor  * tavor_umap_db_find_nolock()
1408*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1409*9e39c5baSBill Taylor  */
1410*9e39c5baSBill Taylor int
tavor_umap_db_find_nolock(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flags,tavor_umap_db_entry_t ** umapdb)1411*9e39c5baSBill Taylor tavor_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
1412*9e39c5baSBill Taylor     uint64_t *value, uint_t flags, tavor_umap_db_entry_t **umapdb)
1413*9e39c5baSBill Taylor {
1414*9e39c5baSBill Taylor 	tavor_umap_db_query_t	query;
1415*9e39c5baSBill Taylor 	tavor_umap_db_entry_t	*entry;
1416*9e39c5baSBill Taylor 	avl_index_t		where;
1417*9e39c5baSBill Taylor 
1418*9e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
1419*9e39c5baSBill Taylor 
1420*9e39c5baSBill Taylor 	/*
1421*9e39c5baSBill Taylor 	 * Fill in key, type, instance, and flags values of the
1422*9e39c5baSBill Taylor 	 * tavor_umap_db_query_t in preparation for the database
1423*9e39c5baSBill Taylor 	 * lookup.
1424*9e39c5baSBill Taylor 	 */
1425*9e39c5baSBill Taylor 	query.tqdb_flags		= flags;
1426*9e39c5baSBill Taylor 	query.tqdb_common.tdb_key	= key;
1427*9e39c5baSBill Taylor 	query.tqdb_common.tdb_type	= type;
1428*9e39c5baSBill Taylor 	query.tqdb_common.tdb_instance	= instance;
1429*9e39c5baSBill Taylor 
1430*9e39c5baSBill Taylor 	/*
1431*9e39c5baSBill Taylor 	 * Perform the database query.  If no entry is found, then
1432*9e39c5baSBill Taylor 	 * return failure, else continue.
1433*9e39c5baSBill Taylor 	 */
1434*9e39c5baSBill Taylor 	entry = (tavor_umap_db_entry_t *)avl_find(
1435*9e39c5baSBill Taylor 	    &tavor_userland_rsrc_db.tdl_umapdb_avl, &query, &where);
1436*9e39c5baSBill Taylor 	if (entry == NULL) {
1437*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1438*9e39c5baSBill Taylor 	}
1439*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
1440*9e39c5baSBill Taylor 
1441*9e39c5baSBill Taylor 	/*
1442*9e39c5baSBill Taylor 	 * If the flags argument specifies that the entry should
1443*9e39c5baSBill Taylor 	 * be removed if found, then call avl_remove() to remove
1444*9e39c5baSBill Taylor 	 * the entry from the database.
1445*9e39c5baSBill Taylor 	 */
1446*9e39c5baSBill Taylor 	if (flags & TAVOR_UMAP_DB_REMOVE) {
1447*9e39c5baSBill Taylor 
1448*9e39c5baSBill Taylor 		avl_remove(&tavor_userland_rsrc_db.tdl_umapdb_avl, entry);
1449*9e39c5baSBill Taylor 
1450*9e39c5baSBill Taylor 		/*
1451*9e39c5baSBill Taylor 		 * The database entry is returned with the expectation
1452*9e39c5baSBill Taylor 		 * that the caller will use tavor_umap_db_free() to
1453*9e39c5baSBill Taylor 		 * free the entry's memory.  ASSERT that this is non-NULL.
1454*9e39c5baSBill Taylor 		 * NULL pointer should never be passed for the
1455*9e39c5baSBill Taylor 		 * TAVOR_UMAP_DB_REMOVE case.
1456*9e39c5baSBill Taylor 		 */
1457*9e39c5baSBill Taylor 		ASSERT(umapdb != NULL);
1458*9e39c5baSBill Taylor 	}
1459*9e39c5baSBill Taylor 
1460*9e39c5baSBill Taylor 	/*
1461*9e39c5baSBill Taylor 	 * If the caller would like visibility to the database entry
1462*9e39c5baSBill Taylor 	 * (indicated through the use of a non-NULL "umapdb" argument),
1463*9e39c5baSBill Taylor 	 * then fill it in.
1464*9e39c5baSBill Taylor 	 */
1465*9e39c5baSBill Taylor 	if (umapdb != NULL) {
1466*9e39c5baSBill Taylor 		*umapdb = entry;
1467*9e39c5baSBill Taylor 	}
1468*9e39c5baSBill Taylor 
1469*9e39c5baSBill Taylor 	/* Extract value field from database entry and return success */
1470*9e39c5baSBill Taylor 	*value = entry->tdbe_common.tdb_value;
1471*9e39c5baSBill Taylor 
1472*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1473*9e39c5baSBill Taylor }
1474*9e39c5baSBill Taylor 
1475*9e39c5baSBill Taylor 
1476*9e39c5baSBill Taylor /*
1477*9e39c5baSBill Taylor  * tavor_umap_umemlock_cb()
1478*9e39c5baSBill Taylor  *    Context: Can be called from callback context.
1479*9e39c5baSBill Taylor  */
1480*9e39c5baSBill Taylor void
tavor_umap_umemlock_cb(ddi_umem_cookie_t * umem_cookie)1481*9e39c5baSBill Taylor tavor_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
1482*9e39c5baSBill Taylor {
1483*9e39c5baSBill Taylor 	tavor_umap_db_entry_t	*umapdb;
1484*9e39c5baSBill Taylor 	tavor_state_t		*state;
1485*9e39c5baSBill Taylor 	tavor_rsrc_t 		*rsrcp;
1486*9e39c5baSBill Taylor 	tavor_mrhdl_t		mr;
1487*9e39c5baSBill Taylor 	uint64_t		value;
1488*9e39c5baSBill Taylor 	uint_t			instance;
1489*9e39c5baSBill Taylor 	int			status;
1490*9e39c5baSBill Taylor 	void			(*mr_callback)(void *, void *);
1491*9e39c5baSBill Taylor 	void			*mr_cbarg1, *mr_cbarg2;
1492*9e39c5baSBill Taylor 
1493*9e39c5baSBill Taylor 	/*
1494*9e39c5baSBill Taylor 	 * If this was userland memory, then we need to remove its entry
1495*9e39c5baSBill Taylor 	 * from the "userland resources database".  Note:  We use the
1496*9e39c5baSBill Taylor 	 * TAVOR_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
1497*9e39c5baSBill Taylor 	 * which instance was used when the entry was added (but we want
1498*9e39c5baSBill Taylor 	 * to know after the entry is found using the other search criteria).
1499*9e39c5baSBill Taylor 	 */
1500*9e39c5baSBill Taylor 	status = tavor_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
1501*9e39c5baSBill Taylor 	    MLNX_UMAP_MRMEM_RSRC, &value, (TAVOR_UMAP_DB_REMOVE |
1502*9e39c5baSBill Taylor 	    TAVOR_UMAP_DB_IGNORE_INSTANCE), &umapdb);
1503*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1504*9e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
1505*9e39c5baSBill Taylor 		instance = umapdb->tdbe_common.tdb_instance;
1506*9e39c5baSBill Taylor 		state = ddi_get_soft_state(tavor_statep, instance);
1507*9e39c5baSBill Taylor 		if (state == NULL) {
1508*9e39c5baSBill Taylor 			cmn_err(CE_WARN, "Unable to match Tavor instance\n");
1509*9e39c5baSBill Taylor 			return;
1510*9e39c5baSBill Taylor 		}
1511*9e39c5baSBill Taylor 
1512*9e39c5baSBill Taylor 		/* Free the database entry */
1513*9e39c5baSBill Taylor 		tavor_umap_db_free(umapdb);
1514*9e39c5baSBill Taylor 
1515*9e39c5baSBill Taylor 		/* Use "value" to convert to an MR handle */
1516*9e39c5baSBill Taylor 		rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
1517*9e39c5baSBill Taylor 		mr = (tavor_mrhdl_t)rsrcp->tr_addr;
1518*9e39c5baSBill Taylor 
1519*9e39c5baSBill Taylor 		/*
1520*9e39c5baSBill Taylor 		 * If a callback has been provided, call it first.  This
1521*9e39c5baSBill Taylor 		 * callback is expected to do any cleanup necessary to
1522*9e39c5baSBill Taylor 		 * guarantee that the subsequent MR deregister (below)
1523*9e39c5baSBill Taylor 		 * will succeed.  Specifically, this means freeing up memory
1524*9e39c5baSBill Taylor 		 * windows which might have been associated with the MR.
1525*9e39c5baSBill Taylor 		 */
1526*9e39c5baSBill Taylor 		mutex_enter(&mr->mr_lock);
1527*9e39c5baSBill Taylor 		mr_callback = mr->mr_umem_cbfunc;
1528*9e39c5baSBill Taylor 		mr_cbarg1   = mr->mr_umem_cbarg1;
1529*9e39c5baSBill Taylor 		mr_cbarg2   = mr->mr_umem_cbarg2;
1530*9e39c5baSBill Taylor 		mutex_exit(&mr->mr_lock);
1531*9e39c5baSBill Taylor 		if (mr_callback != NULL) {
1532*9e39c5baSBill Taylor 			mr_callback(mr_cbarg1, mr_cbarg2);
1533*9e39c5baSBill Taylor 		}
1534*9e39c5baSBill Taylor 
1535*9e39c5baSBill Taylor 		/*
1536*9e39c5baSBill Taylor 		 * Then call tavor_mr_deregister() to release the resources
1537*9e39c5baSBill Taylor 		 * associated with the MR handle.  Note: Because this routine
1538*9e39c5baSBill Taylor 		 * will also check for whether the ddi_umem_cookie_t is in the
1539*9e39c5baSBill Taylor 		 * database, it will take responsibility for disabling the
1540*9e39c5baSBill Taylor 		 * memory region and calling ddi_umem_unlock().
1541*9e39c5baSBill Taylor 		 */
1542*9e39c5baSBill Taylor 		status = tavor_mr_deregister(state, &mr, TAVOR_MR_DEREG_ALL,
1543*9e39c5baSBill Taylor 		    TAVOR_SLEEP);
1544*9e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
1545*9e39c5baSBill Taylor 			TAVOR_WARNING(state, "Unexpected failure in "
1546*9e39c5baSBill Taylor 			    "deregister from callback\n");
1547*9e39c5baSBill Taylor 		}
1548*9e39c5baSBill Taylor 	}
1549*9e39c5baSBill Taylor }
1550*9e39c5baSBill Taylor 
1551*9e39c5baSBill Taylor 
1552*9e39c5baSBill Taylor /*
1553*9e39c5baSBill Taylor  * tavor_umap_db_compare()
1554*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1555*9e39c5baSBill Taylor  */
1556*9e39c5baSBill Taylor static int
tavor_umap_db_compare(const void * q,const void * e)1557*9e39c5baSBill Taylor tavor_umap_db_compare(const void *q, const void *e)
1558*9e39c5baSBill Taylor {
1559*9e39c5baSBill Taylor 	tavor_umap_db_common_t	*entry_common, *query_common;
1560*9e39c5baSBill Taylor 	uint_t			query_flags;
1561*9e39c5baSBill Taylor 
1562*9e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((tavor_umap_db_query_t *)q)))
1563*9e39c5baSBill Taylor 
1564*9e39c5baSBill Taylor 	entry_common = &((tavor_umap_db_entry_t *)e)->tdbe_common;
1565*9e39c5baSBill Taylor 	query_common = &((tavor_umap_db_query_t *)q)->tqdb_common;
1566*9e39c5baSBill Taylor 	query_flags  = ((tavor_umap_db_query_t *)q)->tqdb_flags;
1567*9e39c5baSBill Taylor 
1568*9e39c5baSBill Taylor 	/*
1569*9e39c5baSBill Taylor 	 * The first comparison is done on the "key" value in "query"
1570*9e39c5baSBill Taylor 	 * and "entry".  If they are not equal, then the appropriate
1571*9e39c5baSBill Taylor 	 * search direction is returned.  Else, we continue by
1572*9e39c5baSBill Taylor 	 * comparing "type".
1573*9e39c5baSBill Taylor 	 */
1574*9e39c5baSBill Taylor 	if (query_common->tdb_key < entry_common->tdb_key) {
1575*9e39c5baSBill Taylor 		return (-1);
1576*9e39c5baSBill Taylor 	} else if (query_common->tdb_key > entry_common->tdb_key) {
1577*9e39c5baSBill Taylor 		return (+1);
1578*9e39c5baSBill Taylor 	}
1579*9e39c5baSBill Taylor 
1580*9e39c5baSBill Taylor 	/*
1581*9e39c5baSBill Taylor 	 * If the search reaches this point, then "query" and "entry"
1582*9e39c5baSBill Taylor 	 * have equal key values.  So we continue be comparing their
1583*9e39c5baSBill Taylor 	 * "type" values.  Again, if they are not equal, then the
1584*9e39c5baSBill Taylor 	 * appropriate search direction is returned.  Else, we continue
1585*9e39c5baSBill Taylor 	 * by comparing "instance".
1586*9e39c5baSBill Taylor 	 */
1587*9e39c5baSBill Taylor 	if (query_common->tdb_type < entry_common->tdb_type) {
1588*9e39c5baSBill Taylor 		return (-1);
1589*9e39c5baSBill Taylor 	} else if (query_common->tdb_type > entry_common->tdb_type) {
1590*9e39c5baSBill Taylor 		return (+1);
1591*9e39c5baSBill Taylor 	}
1592*9e39c5baSBill Taylor 
1593*9e39c5baSBill Taylor 	/*
1594*9e39c5baSBill Taylor 	 * If the search reaches this point, then "query" and "entry"
1595*9e39c5baSBill Taylor 	 * have exactly the same key and type values.  Now we consult
1596*9e39c5baSBill Taylor 	 * the "flags" field in the query to determine whether the
1597*9e39c5baSBill Taylor 	 * "instance" is relevant to the search.  If the
1598*9e39c5baSBill Taylor 	 * TAVOR_UMAP_DB_IGNORE_INSTANCE flags is set, then return
1599*9e39c5baSBill Taylor 	 * success (0) here.  Otherwise, continue the search by comparing
1600*9e39c5baSBill Taylor 	 * instance values and returning the appropriate search direction.
1601*9e39c5baSBill Taylor 	 */
1602*9e39c5baSBill Taylor 	if (query_flags & TAVOR_UMAP_DB_IGNORE_INSTANCE) {
1603*9e39c5baSBill Taylor 		return (0);
1604*9e39c5baSBill Taylor 	}
1605*9e39c5baSBill Taylor 
1606*9e39c5baSBill Taylor 	/*
1607*9e39c5baSBill Taylor 	 * If the search has reached this point, then "query" and "entry"
1608*9e39c5baSBill Taylor 	 * can only be differentiated by their instance values.  If these
1609*9e39c5baSBill Taylor 	 * are not equal, then return the appropriate search direction.
1610*9e39c5baSBill Taylor 	 * Else, we return success (0).
1611*9e39c5baSBill Taylor 	 */
1612*9e39c5baSBill Taylor 	if (query_common->tdb_instance < entry_common->tdb_instance) {
1613*9e39c5baSBill Taylor 		return (-1);
1614*9e39c5baSBill Taylor 	} else if (query_common->tdb_instance > entry_common->tdb_instance) {
1615*9e39c5baSBill Taylor 		return (+1);
1616*9e39c5baSBill Taylor 	}
1617*9e39c5baSBill Taylor 
1618*9e39c5baSBill Taylor 	/* Everything matches... so return success */
1619*9e39c5baSBill Taylor 	return (0);
1620*9e39c5baSBill Taylor }
1621*9e39c5baSBill Taylor 
1622*9e39c5baSBill Taylor 
1623*9e39c5baSBill Taylor /*
1624*9e39c5baSBill Taylor  * tavor_umap_db_set_onclose_cb()
1625*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1626*9e39c5baSBill Taylor  */
1627*9e39c5baSBill Taylor int
tavor_umap_db_set_onclose_cb(dev_t dev,uint64_t flag,void (* callback)(void *),void * arg)1628*9e39c5baSBill Taylor tavor_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
1629*9e39c5baSBill Taylor     void (*callback)(void *), void *arg)
1630*9e39c5baSBill Taylor {
1631*9e39c5baSBill Taylor 	tavor_umap_db_priv_t	*priv;
1632*9e39c5baSBill Taylor 	tavor_umap_db_entry_t	*umapdb;
1633*9e39c5baSBill Taylor 	minor_t			instance;
1634*9e39c5baSBill Taylor 	uint64_t		value;
1635*9e39c5baSBill Taylor 	int			status;
1636*9e39c5baSBill Taylor 
1637*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
1638*9e39c5baSBill Taylor 	if (instance == -1) {
1639*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1640*9e39c5baSBill Taylor 	}
1641*9e39c5baSBill Taylor 
1642*9e39c5baSBill Taylor 	if (flag != TAVOR_ONCLOSE_FLASH_INPROGRESS) {
1643*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1644*9e39c5baSBill Taylor 	}
1645*9e39c5baSBill Taylor 
1646*9e39c5baSBill Taylor 	/*
1647*9e39c5baSBill Taylor 	 * Grab the lock for the "userland resources database" and find
1648*9e39c5baSBill Taylor 	 * the entry corresponding to this minor number.  Once it's found,
1649*9e39c5baSBill Taylor 	 * allocate (if necessary) and add an entry (in the "tdb_priv"
1650*9e39c5baSBill Taylor 	 * field) to indicate that further processing may be needed during
1651*9e39c5baSBill Taylor 	 * Tavor's close() handling.
1652*9e39c5baSBill Taylor 	 */
1653*9e39c5baSBill Taylor 	mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1654*9e39c5baSBill Taylor 	status = tavor_umap_db_find_nolock(instance, dev,
1655*9e39c5baSBill Taylor 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
1656*9e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
1657*9e39c5baSBill Taylor 		mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1658*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1659*9e39c5baSBill Taylor 	}
1660*9e39c5baSBill Taylor 
1661*9e39c5baSBill Taylor 	priv = (tavor_umap_db_priv_t *)umapdb->tdbe_common.tdb_priv;
1662*9e39c5baSBill Taylor 	if (priv == NULL) {
1663*9e39c5baSBill Taylor 		priv = (tavor_umap_db_priv_t *)kmem_zalloc(
1664*9e39c5baSBill Taylor 		    sizeof (tavor_umap_db_priv_t), KM_NOSLEEP);
1665*9e39c5baSBill Taylor 		if (priv == NULL) {
1666*9e39c5baSBill Taylor 			mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1667*9e39c5baSBill Taylor 			return (DDI_FAILURE);
1668*9e39c5baSBill Taylor 		}
1669*9e39c5baSBill Taylor 	}
1670*9e39c5baSBill Taylor 
1671*9e39c5baSBill Taylor 	/*
1672*9e39c5baSBill Taylor 	 * Save away the callback and argument to be used during Tavor's
1673*9e39c5baSBill Taylor 	 * close() processing.
1674*9e39c5baSBill Taylor 	 */
1675*9e39c5baSBill Taylor 	priv->tdp_cb	= callback;
1676*9e39c5baSBill Taylor 	priv->tdp_arg	= arg;
1677*9e39c5baSBill Taylor 
1678*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_priv = (void *)priv;
1679*9e39c5baSBill Taylor 	mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1680*9e39c5baSBill Taylor 
1681*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1682*9e39c5baSBill Taylor }
1683*9e39c5baSBill Taylor 
1684*9e39c5baSBill Taylor 
1685*9e39c5baSBill Taylor /*
1686*9e39c5baSBill Taylor  * tavor_umap_db_clear_onclose_cb()
1687*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1688*9e39c5baSBill Taylor  */
1689*9e39c5baSBill Taylor int
tavor_umap_db_clear_onclose_cb(dev_t dev,uint64_t flag)1690*9e39c5baSBill Taylor tavor_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
1691*9e39c5baSBill Taylor {
1692*9e39c5baSBill Taylor 	tavor_umap_db_priv_t	*priv;
1693*9e39c5baSBill Taylor 	tavor_umap_db_entry_t	*umapdb;
1694*9e39c5baSBill Taylor 	minor_t			instance;
1695*9e39c5baSBill Taylor 	uint64_t		value;
1696*9e39c5baSBill Taylor 	int			status;
1697*9e39c5baSBill Taylor 
1698*9e39c5baSBill Taylor 	instance = TAVOR_DEV_INSTANCE(dev);
1699*9e39c5baSBill Taylor 	if (instance == -1) {
1700*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1701*9e39c5baSBill Taylor 	}
1702*9e39c5baSBill Taylor 
1703*9e39c5baSBill Taylor 	if (flag != TAVOR_ONCLOSE_FLASH_INPROGRESS) {
1704*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1705*9e39c5baSBill Taylor 	}
1706*9e39c5baSBill Taylor 
1707*9e39c5baSBill Taylor 	/*
1708*9e39c5baSBill Taylor 	 * Grab the lock for the "userland resources database" and find
1709*9e39c5baSBill Taylor 	 * the entry corresponding to this minor number.  Once it's found,
1710*9e39c5baSBill Taylor 	 * remove the entry (in the "tdb_priv" field) that indicated the
1711*9e39c5baSBill Taylor 	 * need for further processing during Tavor's close().  Free the
1712*9e39c5baSBill Taylor 	 * entry, if appropriate.
1713*9e39c5baSBill Taylor 	 */
1714*9e39c5baSBill Taylor 	mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1715*9e39c5baSBill Taylor 	status = tavor_umap_db_find_nolock(instance, dev,
1716*9e39c5baSBill Taylor 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
1717*9e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
1718*9e39c5baSBill Taylor 		mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1719*9e39c5baSBill Taylor 		return (DDI_FAILURE);
1720*9e39c5baSBill Taylor 	}
1721*9e39c5baSBill Taylor 
1722*9e39c5baSBill Taylor 	priv = (tavor_umap_db_priv_t *)umapdb->tdbe_common.tdb_priv;
1723*9e39c5baSBill Taylor 	if (priv != NULL) {
1724*9e39c5baSBill Taylor 		kmem_free(priv, sizeof (tavor_umap_db_priv_t));
1725*9e39c5baSBill Taylor 		priv = NULL;
1726*9e39c5baSBill Taylor 	}
1727*9e39c5baSBill Taylor 
1728*9e39c5baSBill Taylor 	umapdb->tdbe_common.tdb_priv = (void *)priv;
1729*9e39c5baSBill Taylor 	mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
1730*9e39c5baSBill Taylor 	return (DDI_SUCCESS);
1731*9e39c5baSBill Taylor }
1732*9e39c5baSBill Taylor 
1733*9e39c5baSBill Taylor 
1734*9e39c5baSBill Taylor /*
1735*9e39c5baSBill Taylor  * tavor_umap_db_clear_onclose_cb()
1736*9e39c5baSBill Taylor  *    Context: Can be called from user or kernel context.
1737*9e39c5baSBill Taylor  */
1738*9e39c5baSBill Taylor void
tavor_umap_db_handle_onclose_cb(tavor_umap_db_priv_t * priv)1739*9e39c5baSBill Taylor tavor_umap_db_handle_onclose_cb(tavor_umap_db_priv_t *priv)
1740*9e39c5baSBill Taylor {
1741*9e39c5baSBill Taylor 	void	(*callback)(void *);
1742*9e39c5baSBill Taylor 
1743*9e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&tavor_userland_rsrc_db.tdl_umapdb_lock));
1744*9e39c5baSBill Taylor 
1745*9e39c5baSBill Taylor 	/*
1746*9e39c5baSBill Taylor 	 * Call the callback.
1747*9e39c5baSBill Taylor 	 *    Note: Currently there is only one callback (in "tdp_cb"), but
1748*9e39c5baSBill Taylor 	 *    in the future there may be more, depending on what other types
1749*9e39c5baSBill Taylor 	 *    of interaction there are between userland processes and the
1750*9e39c5baSBill Taylor 	 *    driver.
1751*9e39c5baSBill Taylor 	 */
1752*9e39c5baSBill Taylor 	callback = priv->tdp_cb;
1753*9e39c5baSBill Taylor 	callback(priv->tdp_arg);
1754*9e39c5baSBill Taylor }
1755