1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * hermon_umap.c
28 * Hermon Userland Mapping Routines
29 *
30 * Implements all the routines necessary for enabling direct userland
31 * access to the Hermon hardware. This includes all routines necessary for
32 * maintaining the "userland resources database" and all the support routines
33 * for the devmap calls.
34 */
35
36 #include <sys/types.h>
37 #include <sys/conf.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/modctl.h>
41 #include <sys/file.h>
42 #include <sys/avl.h>
43 #include <sys/sysmacros.h>
44
45 #include <sys/ib/adapters/hermon/hermon.h>
46
47 /* Hermon HCA state pointer (extern) */
48 extern void *hermon_statep;
49
50 /* Hermon HCA Userland Resource Database (extern) */
51 extern hermon_umap_db_t hermon_userland_rsrc_db;
52
53 static int hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
54 hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err);
55 static int hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
56 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
57 static int hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
58 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
59 static int hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
60 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
61 static int hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
62 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
63 static int hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
64 offset_t off, size_t len, void **pvtp);
65 static int hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
66 devmap_cookie_t new_dhp, void **new_pvtp);
67 static void hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
68 offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
69 devmap_cookie_t new_dhp2, void **pvtp2);
70 static int hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev,
71 uint_t flags, offset_t off, size_t len, void **pvtp);
72 static int hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
73 devmap_cookie_t new_dhp, void **new_pvtp);
74 static void hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp,
75 offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
76 devmap_cookie_t new_dhp2, void **pvtp2);
77 static int hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev,
78 uint_t flags, offset_t off, size_t len, void **pvtp);
79 static int hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
80 devmap_cookie_t new_dhp, void **new_pvtp);
81 static void hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
82 offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
83 devmap_cookie_t new_dhp2, void **pvtp2);
84 static ibt_status_t hermon_umap_mr_data_in(hermon_mrhdl_t mr,
85 ibt_mr_data_in_t *data, size_t data_sz);
86 static ibt_status_t hermon_umap_cq_data_out(hermon_cqhdl_t cq,
87 mlnx_umap_cq_data_out_t *data, size_t data_sz);
88 static ibt_status_t hermon_umap_qp_data_out(hermon_qphdl_t qp,
89 mlnx_umap_qp_data_out_t *data, size_t data_sz);
90 static ibt_status_t hermon_umap_srq_data_out(hermon_srqhdl_t srq,
91 mlnx_umap_srq_data_out_t *data, size_t data_sz);
92 static ibt_status_t hermon_umap_pd_data_out(hermon_pdhdl_t pd,
93 mlnx_umap_pd_data_out_t *data, size_t data_sz);
94 static int hermon_umap_db_compare(const void *query, const void *entry);
95
96
97 /*
98 * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
99 * respectively. They are used to handle (among other things) partial
100 * unmappings and to provide a method for invalidating mappings inherited
101 * as a result of a fork(2) system call.
102 */
103 static struct devmap_callback_ctl hermon_devmap_umem_cbops = {
104 DEVMAP_OPS_REV,
105 hermon_devmap_umem_map,
106 NULL,
107 hermon_devmap_umem_dup,
108 hermon_devmap_umem_unmap
109 };
110 static struct devmap_callback_ctl hermon_devmap_devmem_cbops = {
111 DEVMAP_OPS_REV,
112 hermon_devmap_devmem_map,
113 NULL,
114 hermon_devmap_devmem_dup,
115 hermon_devmap_devmem_unmap
116 };
117 static struct devmap_callback_ctl hermon_devmap_dbrecmem_cbops = {
118 DEVMAP_OPS_REV,
119 hermon_devmap_dbrecmem_map,
120 NULL,
121 hermon_devmap_dbrecmem_dup,
122 hermon_devmap_dbrecmem_unmap
123 };
124
125 /*
126 * hermon_devmap()
127 * Context: Can be called from user context.
128 */
129 /* ARGSUSED */
130 int
hermon_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)131 hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
132 size_t *maplen, uint_t model)
133 {
134 hermon_state_t *state;
135 hermon_rsrc_t *rsrcp;
136 minor_t instance;
137 uint64_t key, value;
138 uint64_t bf_offset = 0;
139 uint_t type;
140 int err, status;
141
142 /* Get Hermon softstate structure from instance */
143 instance = HERMON_DEV_INSTANCE(dev);
144 state = ddi_get_soft_state(hermon_statep, instance);
145 if (state == NULL) {
146 return (ENXIO);
147 }
148
149 /*
150 * Access to Hermon devmap interface is not allowed in
151 * "maintenance mode".
152 */
153 if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
154 return (EFAULT);
155 }
156
157 /*
158 * The bottom bits of "offset" are undefined (number depends on
159 * system PAGESIZE). Shifting these off leaves us with a "key".
160 * The "key" is actually a combination of both a real key value
161 * (for the purpose of database lookup) and a "type" value. We
162 * extract this information before doing the database lookup.
163 */
164 key = off >> PAGESHIFT;
165 type = key & MLNX_UMAP_RSRC_TYPE_MASK;
166 key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
167 if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
168 if (state->hs_devlim.blu_flm == 0) {
169 return (EFAULT);
170 }
171 bf_offset = state->hs_bf_offset;
172 type = MLNX_UMAP_UARPG_RSRC;
173 }
174 status = hermon_umap_db_find(instance, key, type, &value, 0, NULL);
175 if (status == DDI_SUCCESS) {
176 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
177
178 switch (type) {
179 case MLNX_UMAP_UARPG_RSRC:
180 /*
181 * Double check that process who open()'d Hermon is
182 * same process attempting to mmap() UAR page.
183 */
184 if (key != ddi_get_pid()) {
185 return (EINVAL);
186 }
187
188 /* Map the UAR page out for userland access */
189 status = hermon_umap_uarpg(state, dhp, rsrcp, bf_offset,
190 maplen, &err);
191 if (status != DDI_SUCCESS) {
192 return (err);
193 }
194 break;
195
196 case MLNX_UMAP_CQMEM_RSRC:
197 /* Map the CQ memory out for userland access */
198 status = hermon_umap_cqmem(state, dhp, rsrcp, off,
199 maplen, &err);
200 if (status != DDI_SUCCESS) {
201 return (err);
202 }
203 break;
204
205 case MLNX_UMAP_QPMEM_RSRC:
206 /* Map the QP memory out for userland access */
207 status = hermon_umap_qpmem(state, dhp, rsrcp, off,
208 maplen, &err);
209 if (status != DDI_SUCCESS) {
210 return (err);
211 }
212 break;
213
214 case MLNX_UMAP_SRQMEM_RSRC:
215 /* Map the SRQ memory out for userland access */
216 status = hermon_umap_srqmem(state, dhp, rsrcp, off,
217 maplen, &err);
218 if (status != DDI_SUCCESS) {
219 return (err);
220 }
221 break;
222
223 case MLNX_UMAP_DBRMEM_RSRC:
224 /*
225 * Map the doorbell record memory out for
226 * userland access
227 */
228 status = hermon_umap_dbrecmem(state, dhp, rsrcp, off,
229 maplen, &err);
230 if (status != DDI_SUCCESS) {
231 return (err);
232 }
233 break;
234
235 default:
236 HERMON_WARNING(state, "unexpected rsrc type in devmap");
237 return (EINVAL);
238 }
239 } else {
240 return (EINVAL);
241 }
242
243 return (0);
244 }
245
246
247 /*
248 * hermon_umap_uarpg()
249 * Context: Can be called from user context.
250 */
251 static int
hermon_umap_uarpg(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,uint64_t offset,size_t * maplen,int * err)252 hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
253 hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err)
254 {
255 int status;
256 uint_t maxprot;
257 ddi_device_acc_attr_t *accattrp = &state->hs_reg_accattr;
258 ddi_device_acc_attr_t accattr;
259
260 if (offset != 0) { /* Hermon Blueflame */
261 /* Try to use write coalescing data ordering */
262 accattr = *accattrp;
263 accattr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
264 accattrp = &accattr;
265 }
266
267 /* Map out the UAR page (doorbell page) */
268 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
269 status = devmap_devmem_setup(dhp, state->hs_dip,
270 &hermon_devmap_devmem_cbops, HERMON_UAR_BAR, (rsrcp->hr_indx <<
271 PAGESHIFT) + offset, PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
272 accattrp);
273 if (status < 0) {
274 *err = status;
275 return (DDI_FAILURE);
276 }
277
278 *maplen = PAGESIZE;
279 return (DDI_SUCCESS);
280 }
281
282
283 /*
284 * hermon_umap_cqmem()
285 * Context: Can be called from user context.
286 */
287 /* ARGSUSED */
288 static int
hermon_umap_cqmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)289 hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
290 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
291 {
292 hermon_cqhdl_t cq;
293 size_t size;
294 uint_t maxprot;
295 int status;
296
297 /* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
298 cq = (hermon_cqhdl_t)rsrcp->hr_addr;
299
300 /* Round-up the CQ size to system page size */
301 size = ptob(btopr(cq->cq_resize_hdl ?
302 cq->cq_resize_hdl->cq_cqinfo.qa_size : cq->cq_cqinfo.qa_size));
303
304 /* Map out the CQ memory - use resize_hdl if non-NULL */
305 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
306 status = devmap_umem_setup(dhp, state->hs_dip,
307 &hermon_devmap_umem_cbops, cq->cq_resize_hdl ?
308 cq->cq_resize_hdl->cq_cqinfo.qa_umemcookie :
309 cq->cq_cqinfo.qa_umemcookie, 0, size,
310 maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
311 if (status < 0) {
312 *err = status;
313 return (DDI_FAILURE);
314 }
315 *maplen = size;
316
317 return (DDI_SUCCESS);
318 }
319
320
321 /*
322 * hermon_umap_qpmem()
323 * Context: Can be called from user context.
324 */
325 /* ARGSUSED */
326 static int
hermon_umap_qpmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)327 hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
328 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
329 {
330 hermon_qphdl_t qp;
331 offset_t offset;
332 size_t size;
333 uint_t maxprot;
334 int status;
335
336 /* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
337 qp = (hermon_qphdl_t)rsrcp->hr_addr;
338
339 /*
340 * Calculate the offset of the first work queue (send or recv) into
341 * the memory (ddi_umem_alloc()) allocated previously for the QP.
342 */
343 offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
344 (uintptr_t)qp->qp_wqinfo.qa_buf_real);
345
346 /* Round-up the QP work queue sizes to system page size */
347 size = ptob(btopr(qp->qp_wqinfo.qa_size));
348
349 /* Map out the QP memory */
350 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
351 status = devmap_umem_setup(dhp, state->hs_dip,
352 &hermon_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
353 size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
354 if (status < 0) {
355 *err = status;
356 return (DDI_FAILURE);
357 }
358 *maplen = size;
359
360 return (DDI_SUCCESS);
361 }
362
363
364 /*
365 * hermon_umap_srqmem()
366 * Context: Can be called from user context.
367 */
368 /* ARGSUSED */
369 static int
hermon_umap_srqmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)370 hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
371 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
372 {
373 hermon_srqhdl_t srq;
374 offset_t offset;
375 size_t size;
376 uint_t maxprot;
377 int status;
378
379 /* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
380 srq = (hermon_srqhdl_t)rsrcp->hr_addr;
381
382 /*
383 * Calculate the offset of the first shared recv queue into the memory
384 * (ddi_umem_alloc()) allocated previously for the SRQ.
385 */
386 offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
387 (uintptr_t)srq->srq_wqinfo.qa_buf_real);
388
389 /* Round-up the SRQ work queue sizes to system page size */
390 size = ptob(btopr(srq->srq_wqinfo.qa_size));
391
392 /* Map out the SRQ memory */
393 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
394 status = devmap_umem_setup(dhp, state->hs_dip,
395 &hermon_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
396 size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
397 if (status < 0) {
398 *err = status;
399 return (DDI_FAILURE);
400 }
401 *maplen = size;
402
403 return (DDI_SUCCESS);
404 }
405
406
407 /*
408 * hermon_devmap_dbrecmem()
409 * Context: Can be called from user context.
410 */
411 /* ARGSUSED */
412 static int
hermon_umap_dbrecmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)413 hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
414 hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
415 {
416 hermon_udbr_page_t *pagep;
417 offset_t offset;
418 size_t size;
419 uint_t maxprot;
420 int status;
421
422 /* We stored the udbr_page pointer, and not a hermon_rsrc_t */
423 pagep = (hermon_udbr_page_t *)rsrcp;
424
425 /*
426 * Calculate the offset of the doorbell records into the memory
427 * (ddi_umem_alloc()) allocated previously for them.
428 */
429 offset = 0;
430
431 /* Round-up the doorbell page to system page size */
432 size = PAGESIZE;
433
434 /* Map out the Doorbell Record memory */
435 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
436 status = devmap_umem_setup(dhp, state->hs_dip,
437 &hermon_devmap_dbrecmem_cbops, pagep->upg_umemcookie, offset,
438 size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
439 if (status < 0) {
440 *err = status;
441 return (DDI_FAILURE);
442 }
443 *maplen = size;
444
445 return (DDI_SUCCESS);
446 }
447
448
449 /*
450 * hermon_devmap_umem_map()
451 * Context: Can be called from kernel context.
452 */
453 /* ARGSUSED */
454 static int
hermon_devmap_umem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)455 hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
456 offset_t off, size_t len, void **pvtp)
457 {
458 hermon_state_t *state;
459 hermon_devmap_track_t *dvm_track;
460 hermon_cqhdl_t cq;
461 hermon_qphdl_t qp;
462 hermon_srqhdl_t srq;
463 minor_t instance;
464 uint64_t key;
465 uint_t type;
466
467 /* Get Hermon softstate structure from instance */
468 instance = HERMON_DEV_INSTANCE(dev);
469 state = ddi_get_soft_state(hermon_statep, instance);
470 if (state == NULL) {
471 return (ENXIO);
472 }
473
474 /*
475 * The bottom bits of "offset" are undefined (number depends on
476 * system PAGESIZE). Shifting these off leaves us with a "key".
477 * The "key" is actually a combination of both a real key value
478 * (for the purpose of database lookup) and a "type" value. Although
479 * we are not going to do any database lookup per se, we do want
480 * to extract the "key" and the "type" (to enable faster lookup of
481 * the appropriate CQ or QP handle).
482 */
483 key = off >> PAGESHIFT;
484 type = key & MLNX_UMAP_RSRC_TYPE_MASK;
485 key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
486
487 /*
488 * Allocate an entry to track the mapping and unmapping (specifically,
489 * partial unmapping) of this resource.
490 */
491 dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
492 sizeof (hermon_devmap_track_t), KM_SLEEP);
493 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
494 dvm_track->hdt_offset = off;
495 dvm_track->hdt_state = state;
496 dvm_track->hdt_refcnt = 1;
497 mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
498 DDI_INTR_PRI(state->hs_intrmsi_pri));
499
500 /*
501 * Depending of the type of resource that has been mapped out, we
502 * need to update the QP or CQ handle to reflect that it has, in
503 * fact, been mapped. This allows the driver code which frees a QP
504 * or a CQ to know whether it is appropriate to do a
505 * devmap_devmem_remap() to invalidate the userland mapping for the
506 * corresponding queue's memory.
507 */
508 if (type == MLNX_UMAP_CQMEM_RSRC) {
509
510 /* Use "key" (CQ number) to do fast lookup of CQ handle */
511 cq = hermon_cqhdl_from_cqnum(state, key);
512
513 /*
514 * Update the handle to the userland mapping. Note: If
515 * the CQ already has a valid userland mapping, then stop
516 * and return failure.
517 */
518 mutex_enter(&cq->cq_lock);
519 if (cq->cq_umap_dhp == NULL) {
520 cq->cq_umap_dhp = dhp;
521 dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
522 mutex_exit(&cq->cq_lock);
523 } else if (cq->cq_resize_hdl &&
524 (cq->cq_resize_hdl->cq_umap_dhp == NULL)) {
525 cq->cq_resize_hdl->cq_umap_dhp = dhp;
526 dvm_track->hdt_size =
527 cq->cq_resize_hdl->cq_cqinfo.qa_size;
528 mutex_exit(&cq->cq_lock);
529 } else {
530 mutex_exit(&cq->cq_lock);
531 goto umem_map_fail;
532 }
533
534 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
535
536 /* Use "key" (QP number) to do fast lookup of QP handle */
537 qp = hermon_qphdl_from_qpnum(state, key);
538
539 /*
540 * Update the handle to the userland mapping. Note: If
541 * the CQ already has a valid userland mapping, then stop
542 * and return failure.
543 */
544 mutex_enter(&qp->qp_lock);
545 if (qp->qp_umap_dhp == NULL) {
546 qp->qp_umap_dhp = dhp;
547 dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
548 mutex_exit(&qp->qp_lock);
549 } else {
550 mutex_exit(&qp->qp_lock);
551 goto umem_map_fail;
552 }
553
554 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
555
556 /* Use "key" (SRQ number) to do fast lookup on SRQ handle */
557 srq = hermon_srqhdl_from_srqnum(state, key);
558
559 /*
560 * Update the handle to the userland mapping. Note: If the
561 * SRQ already has a valid userland mapping, then stop and
562 * return failure.
563 */
564 mutex_enter(&srq->srq_lock);
565 if (srq->srq_umap_dhp == NULL) {
566 srq->srq_umap_dhp = dhp;
567 dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
568 mutex_exit(&srq->srq_lock);
569 } else {
570 mutex_exit(&srq->srq_lock);
571 goto umem_map_fail;
572 }
573 }
574
575 /*
576 * Pass the private "Hermon devmap tracking structure" back. This
577 * pointer will be returned in subsequent "unmap" callbacks.
578 */
579 *pvtp = dvm_track;
580
581 return (DDI_SUCCESS);
582
583 umem_map_fail:
584 mutex_destroy(&dvm_track->hdt_lock);
585 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
586 return (DDI_FAILURE);
587 }
588
589
590 /*
591 * hermon_devmap_umem_dup()
592 * Context: Can be called from kernel context.
593 */
594 /* ARGSUSED */
595 static int
hermon_devmap_umem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)596 hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
597 void **new_pvtp)
598 {
599 hermon_state_t *state;
600 hermon_devmap_track_t *dvm_track, *new_dvm_track;
601 uint_t maxprot;
602 int status;
603
604 /*
605 * Extract the Hermon softstate pointer from "Hermon devmap tracking
606 * structure" (in "pvtp").
607 */
608 dvm_track = (hermon_devmap_track_t *)pvtp;
609 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
610 state = dvm_track->hdt_state;
611
612 /*
613 * Since this devmap_dup() entry point is generally called
614 * when a process does fork(2), it is incumbent upon the driver
615 * to insure that the child does not inherit a valid copy of
616 * the parent's QP or CQ resource. This is accomplished by using
617 * devmap_devmem_remap() to invalidate the child's mapping to the
618 * kernel memory.
619 */
620 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
621 status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
622 dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
623 if (status != DDI_SUCCESS) {
624 HERMON_WARNING(state, "failed in hermon_devmap_umem_dup()");
625 return (status);
626 }
627
628 /*
629 * Allocate a new entry to track the subsequent unmapping
630 * (specifically, all partial unmappings) of the child's newly
631 * invalidated resource. Note: Setting the "hdt_size" field to
632 * zero here is an indication to the devmap_unmap() entry point
633 * that this mapping is invalid, and that its subsequent unmapping
634 * should not affect any of the parent's CQ or QP resources.
635 */
636 new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
637 sizeof (hermon_devmap_track_t), KM_SLEEP);
638 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
639 new_dvm_track->hdt_offset = 0;
640 new_dvm_track->hdt_state = state;
641 new_dvm_track->hdt_refcnt = 1;
642 new_dvm_track->hdt_size = 0;
643 mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
644 DDI_INTR_PRI(state->hs_intrmsi_pri));
645 *new_pvtp = new_dvm_track;
646
647 return (DDI_SUCCESS);
648 }
649
650
651 /*
652 * hermon_devmap_umem_unmap()
653 * Context: Can be called from kernel context.
654 */
655 /* ARGSUSED */
656 static void
hermon_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)657 hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
658 size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
659 devmap_cookie_t new_dhp2, void **pvtp2)
660 {
661 hermon_state_t *state;
662 hermon_rsrc_t *rsrcp;
663 hermon_devmap_track_t *dvm_track;
664 hermon_cqhdl_t cq;
665 hermon_qphdl_t qp;
666 hermon_srqhdl_t srq;
667 uint64_t key, value;
668 uint_t type;
669 uint_t size;
670 int status;
671
672 /*
673 * Extract the Hermon softstate pointer from "Hermon devmap tracking
674 * structure" (in "pvtp").
675 */
676 dvm_track = (hermon_devmap_track_t *)pvtp;
677 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
678 state = dvm_track->hdt_state;
679
680 /*
681 * Extract the "offset" from the "Hermon devmap tracking structure".
682 * Note: The input argument "off" is ignored here because the
683 * Hermon mapping interfaces define a very specific meaning to
684 * each "logical offset". Also extract the "key" and "type" encoded
685 * in the logical offset.
686 */
687 key = dvm_track->hdt_offset >> PAGESHIFT;
688 type = key & MLNX_UMAP_RSRC_TYPE_MASK;
689 key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
690
691 /*
692 * Extract the "size" of the mapping. If this size is determined
693 * to be zero, then it is an indication of a previously invalidated
694 * mapping, and no CQ or QP resources should be affected.
695 */
696 size = dvm_track->hdt_size;
697
698 /*
699 * If only the "middle portion of a given mapping is being unmapped,
700 * then we are effectively creating one new piece of mapped memory.
701 * (Original region is divided into three pieces of which the middle
702 * piece is being removed. This leaves two pieces. Since we started
703 * with one piece and now have two pieces, we need to increment the
704 * counter in the "Hermon devmap tracking structure".
705 *
706 * If, however, the whole mapped region is being unmapped, then we
707 * have started with one region which we are completely removing.
708 * In this case, we need to decrement the counter in the "Hermon
709 * devmap tracking structure".
710 *
711 * In each of the remaining cases, we will have started with one
712 * mapped region and ended with one (different) region. So no counter
713 * modification is necessary.
714 */
715 mutex_enter(&dvm_track->hdt_lock);
716 if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
717 dvm_track->hdt_refcnt--;
718 } else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
719 dvm_track->hdt_refcnt++;
720 }
721 mutex_exit(&dvm_track->hdt_lock);
722
723 /*
724 * For each of the cases where the region is being divided, then we
725 * need to pass back the "Hermon devmap tracking structure". This way
726 * we get it back when each of the remaining pieces is subsequently
727 * unmapped.
728 */
729 if (new_dhp1 != NULL) {
730 *pvtp1 = pvtp;
731 }
732 if (new_dhp2 != NULL) {
733 *pvtp2 = pvtp;
734 }
735
736 /*
737 * If the "Hermon devmap tracking structure" is no longer being
738 * referenced, then free it up. Otherwise, return.
739 */
740 if (dvm_track->hdt_refcnt == 0) {
741 mutex_destroy(&dvm_track->hdt_lock);
742 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
743
744 /*
745 * If the mapping was invalid (see explanation above), then
746 * no further processing is necessary.
747 */
748 if (size == 0) {
749 return;
750 }
751 } else {
752 return;
753 }
754
755 /*
756 * Now that we can guarantee that the user memory is fully unmapped,
757 * we can use the "key" and "type" values to try to find the entry
758 * in the "userland resources database". If it's found, then it
759 * indicates that the queue memory (CQ or QP) has not yet been freed.
760 * In this case, we update the corresponding CQ or QP handle to
761 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
762 * If it's _not_ found, then it indicates that the CQ or QP memory
763 * was, in fact, freed before it was unmapped (thus requiring a
764 * previous invalidation by remapping - which will already have
765 * been done in the free routine).
766 */
767 status = hermon_umap_db_find(state->hs_instance, key, type, &value,
768 0, NULL);
769 if (status == DDI_SUCCESS) {
770 /*
771 * Depending on the type of the mapped resource (CQ or QP),
772 * update handle to indicate that no invalidation remapping
773 * will be necessary.
774 */
775 if (type == MLNX_UMAP_CQMEM_RSRC) {
776
777 /* Use "value" to convert to CQ handle */
778 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
779 cq = (hermon_cqhdl_t)rsrcp->hr_addr;
780
781 /*
782 * Invalidate the handle to the userland mapping.
783 * Note: We must ensure that the mapping being
784 * unmapped here is the current one for the CQ. It
785 * is possible that it might not be if this CQ has
786 * been resized and the previous CQ memory has not
787 * yet been unmapped. But in that case, because of
788 * the devmap_devmem_remap(), there is no longer any
789 * association between the mapping and the real CQ
790 * kernel memory.
791 */
792 mutex_enter(&cq->cq_lock);
793 if (cq->cq_umap_dhp == dhp) {
794 cq->cq_umap_dhp = NULL;
795 if (cq->cq_resize_hdl) {
796 /* resize is DONE, switch queues */
797 hermon_cq_resize_helper(state, cq);
798 }
799 } else {
800 if (cq->cq_resize_hdl &&
801 cq->cq_resize_hdl->cq_umap_dhp == dhp) {
802 /*
803 * Unexpected case. munmap of the
804 * cq_resize buf, and not the
805 * original buf.
806 */
807 cq->cq_resize_hdl->cq_umap_dhp = NULL;
808 }
809 }
810 mutex_exit(&cq->cq_lock);
811
812 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
813
814 /* Use "value" to convert to QP handle */
815 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
816 qp = (hermon_qphdl_t)rsrcp->hr_addr;
817
818 /*
819 * Invalidate the handle to the userland mapping.
820 * Note: we ensure that the mapping being unmapped
821 * here is the current one for the QP. This is
822 * more of a sanity check here since, unlike CQs
823 * (above) we do not support resize of QPs.
824 */
825 mutex_enter(&qp->qp_lock);
826 if (qp->qp_umap_dhp == dhp) {
827 qp->qp_umap_dhp = NULL;
828 }
829 mutex_exit(&qp->qp_lock);
830
831 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
832
833 /* Use "value" to convert to SRQ handle */
834 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
835 srq = (hermon_srqhdl_t)rsrcp->hr_addr;
836
837 /*
838 * Invalidate the handle to the userland mapping.
839 * Note: we ensure that the mapping being unmapped
840 * here is the current one for the QP. This is
841 * more of a sanity check here since, unlike CQs
842 * (above) we do not support resize of QPs.
843 */
844 mutex_enter(&srq->srq_lock);
845 if (srq->srq_umap_dhp == dhp) {
846 srq->srq_umap_dhp = NULL;
847 }
848 mutex_exit(&srq->srq_lock);
849 }
850 }
851 }
852
853
854 /*
855 * hermon_devmap_devmem_map()
856 * Context: Can be called from kernel context.
857 */
858 /* ARGSUSED */
859 static int
hermon_devmap_dbrecmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)860 hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
861 offset_t off, size_t len, void **pvtp)
862 {
863 hermon_state_t *state;
864 hermon_devmap_track_t *dvm_track;
865 hermon_cqhdl_t cq;
866 hermon_qphdl_t qp;
867 hermon_srqhdl_t srq;
868 minor_t instance;
869 uint64_t key;
870 uint_t type;
871
872 /* Get Hermon softstate structure from instance */
873 instance = HERMON_DEV_INSTANCE(dev);
874 state = ddi_get_soft_state(hermon_statep, instance);
875 if (state == NULL) {
876 return (ENXIO);
877 }
878
879 /*
880 * The bottom bits of "offset" are undefined (number depends on
881 * system PAGESIZE). Shifting these off leaves us with a "key".
882 * The "key" is actually a combination of both a real key value
883 * (for the purpose of database lookup) and a "type" value. Although
884 * we are not going to do any database lookup per se, we do want
885 * to extract the "key" and the "type" (to enable faster lookup of
886 * the appropriate CQ or QP handle).
887 */
888 key = off >> PAGESHIFT;
889 type = key & MLNX_UMAP_RSRC_TYPE_MASK;
890 key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
891
892 /*
893 * Allocate an entry to track the mapping and unmapping (specifically,
894 * partial unmapping) of this resource.
895 */
896 dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
897 sizeof (hermon_devmap_track_t), KM_SLEEP);
898 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
899 dvm_track->hdt_offset = off;
900 dvm_track->hdt_state = state;
901 dvm_track->hdt_refcnt = 1;
902 mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
903 DDI_INTR_PRI(state->hs_intrmsi_pri));
904
905 /*
906 * Depending of the type of resource that has been mapped out, we
907 * need to update the QP or CQ handle to reflect that it has, in
908 * fact, been mapped. This allows the driver code which frees a QP
909 * or a CQ to know whether it is appropriate to do a
910 * devmap_devmem_remap() to invalidate the userland mapping for the
911 * corresponding queue's memory.
912 */
913 if (type == MLNX_UMAP_CQMEM_RSRC) {
914
915 /* Use "key" (CQ number) to do fast lookup of CQ handle */
916 cq = hermon_cqhdl_from_cqnum(state, key);
917
918 /*
919 * Update the handle to the userland mapping. Note: If
920 * the CQ already has a valid userland mapping, then stop
921 * and return failure.
922 */
923 mutex_enter(&cq->cq_lock);
924 if (cq->cq_umap_dhp == NULL) {
925 cq->cq_umap_dhp = dhp;
926 dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
927 mutex_exit(&cq->cq_lock);
928 } else {
929 mutex_exit(&cq->cq_lock);
930 goto umem_map_fail;
931 }
932
933 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
934
935 /* Use "key" (QP number) to do fast lookup of QP handle */
936 qp = hermon_qphdl_from_qpnum(state, key);
937
938 /*
939 * Update the handle to the userland mapping. Note: If
940 * the CQ already has a valid userland mapping, then stop
941 * and return failure.
942 */
943 mutex_enter(&qp->qp_lock);
944 if (qp->qp_umap_dhp == NULL) {
945 qp->qp_umap_dhp = dhp;
946 dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
947 mutex_exit(&qp->qp_lock);
948 } else {
949 mutex_exit(&qp->qp_lock);
950 goto umem_map_fail;
951 }
952
953 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
954
955 /* Use "key" (SRQ number) to do fast lookup on SRQ handle */
956 srq = hermon_srqhdl_from_srqnum(state, key);
957
958 /*
959 * Update the handle to the userland mapping. Note: If the
960 * SRQ already has a valid userland mapping, then stop and
961 * return failure.
962 */
963 mutex_enter(&srq->srq_lock);
964 if (srq->srq_umap_dhp == NULL) {
965 srq->srq_umap_dhp = dhp;
966 dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
967 mutex_exit(&srq->srq_lock);
968 } else {
969 mutex_exit(&srq->srq_lock);
970 goto umem_map_fail;
971 }
972 }
973
974 /*
975 * Pass the private "Hermon devmap tracking structure" back. This
976 * pointer will be returned in subsequent "unmap" callbacks.
977 */
978 *pvtp = dvm_track;
979
980 return (DDI_SUCCESS);
981
982 umem_map_fail:
983 mutex_destroy(&dvm_track->hdt_lock);
984 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
985 return (DDI_FAILURE);
986 }
987
988
989 /*
990 * hermon_devmap_dbrecmem_dup()
991 * Context: Can be called from kernel context.
992 */
993 /* ARGSUSED */
994 static int
hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)995 hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
996 devmap_cookie_t new_dhp, void **new_pvtp)
997 {
998 hermon_state_t *state;
999 hermon_devmap_track_t *dvm_track, *new_dvm_track;
1000 uint_t maxprot;
1001 int status;
1002
1003 /*
1004 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1005 * structure" (in "pvtp").
1006 */
1007 dvm_track = (hermon_devmap_track_t *)pvtp;
1008 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1009 state = dvm_track->hdt_state;
1010
1011 /*
1012 * Since this devmap_dup() entry point is generally called
1013 * when a process does fork(2), it is incumbent upon the driver
1014 * to insure that the child does not inherit a valid copy of
1015 * the parent's QP or CQ resource. This is accomplished by using
1016 * devmap_devmem_remap() to invalidate the child's mapping to the
1017 * kernel memory.
1018 */
1019 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1020 status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1021 dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1022 if (status != DDI_SUCCESS) {
1023 HERMON_WARNING(state, "failed in hermon_devmap_dbrecmem_dup()");
1024 return (status);
1025 }
1026
1027 /*
1028 * Allocate a new entry to track the subsequent unmapping
1029 * (specifically, all partial unmappings) of the child's newly
1030 * invalidated resource. Note: Setting the "hdt_size" field to
1031 * zero here is an indication to the devmap_unmap() entry point
1032 * that this mapping is invalid, and that its subsequent unmapping
1033 * should not affect any of the parent's CQ or QP resources.
1034 */
1035 new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1036 sizeof (hermon_devmap_track_t), KM_SLEEP);
1037 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
1038 new_dvm_track->hdt_offset = 0;
1039 new_dvm_track->hdt_state = state;
1040 new_dvm_track->hdt_refcnt = 1;
1041 new_dvm_track->hdt_size = 0;
1042 mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
1043 DDI_INTR_PRI(state->hs_intrmsi_pri));
1044 *new_pvtp = new_dvm_track;
1045
1046 return (DDI_SUCCESS);
1047 }
1048
1049
1050 /*
1051 * hermon_devmap_dbrecmem_unmap()
1052 * Context: Can be called from kernel context.
1053 */
1054 /* ARGSUSED */
1055 static void
hermon_devmap_dbrecmem_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)1056 hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1057 size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1058 devmap_cookie_t new_dhp2, void **pvtp2)
1059 {
1060 hermon_state_t *state;
1061 hermon_rsrc_t *rsrcp;
1062 hermon_devmap_track_t *dvm_track;
1063 hermon_cqhdl_t cq;
1064 hermon_qphdl_t qp;
1065 hermon_srqhdl_t srq;
1066 uint64_t key, value;
1067 uint_t type;
1068 uint_t size;
1069 int status;
1070
1071 /*
1072 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1073 * structure" (in "pvtp").
1074 */
1075 dvm_track = (hermon_devmap_track_t *)pvtp;
1076 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1077 state = dvm_track->hdt_state;
1078
1079 /*
1080 * Extract the "offset" from the "Hermon devmap tracking structure".
1081 * Note: The input argument "off" is ignored here because the
1082 * Hermon mapping interfaces define a very specific meaning to
1083 * each "logical offset". Also extract the "key" and "type" encoded
1084 * in the logical offset.
1085 */
1086 key = dvm_track->hdt_offset >> PAGESHIFT;
1087 type = key & MLNX_UMAP_RSRC_TYPE_MASK;
1088 key = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
1089
1090 /*
1091 * Extract the "size" of the mapping. If this size is determined
1092 * to be zero, then it is an indication of a previously invalidated
1093 * mapping, and no CQ or QP resources should be affected.
1094 */
1095 size = dvm_track->hdt_size;
1096
1097 /*
1098 * If only the "middle portion of a given mapping is being unmapped,
1099 * then we are effectively creating one new piece of mapped memory.
1100 * (Original region is divided into three pieces of which the middle
1101 * piece is being removed. This leaves two pieces. Since we started
1102 * with one piece and now have two pieces, we need to increment the
1103 * counter in the "Hermon devmap tracking structure".
1104 *
1105 * If, however, the whole mapped region is being unmapped, then we
1106 * have started with one region which we are completely removing.
1107 * In this case, we need to decrement the counter in the "Hermon
1108 * devmap tracking structure".
1109 *
1110 * In each of the remaining cases, we will have started with one
1111 * mapped region and ended with one (different) region. So no counter
1112 * modification is necessary.
1113 */
1114 mutex_enter(&dvm_track->hdt_lock);
1115 if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
1116 dvm_track->hdt_refcnt--;
1117 } else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
1118 dvm_track->hdt_refcnt++;
1119 }
1120 mutex_exit(&dvm_track->hdt_lock);
1121
1122 /*
1123 * For each of the cases where the region is being divided, then we
1124 * need to pass back the "Hermon devmap tracking structure". This way
1125 * we get it back when each of the remaining pieces is subsequently
1126 * unmapped.
1127 */
1128 if (new_dhp1 != NULL) {
1129 *pvtp1 = pvtp;
1130 }
1131 if (new_dhp2 != NULL) {
1132 *pvtp2 = pvtp;
1133 }
1134
1135 /*
1136 * If the "Hermon devmap tracking structure" is no longer being
1137 * referenced, then free it up. Otherwise, return.
1138 */
1139 if (dvm_track->hdt_refcnt == 0) {
1140 mutex_destroy(&dvm_track->hdt_lock);
1141 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1142
1143 /*
1144 * If the mapping was invalid (see explanation above), then
1145 * no further processing is necessary.
1146 */
1147 if (size == 0) {
1148 return;
1149 }
1150 } else {
1151 return;
1152 }
1153
1154 /*
1155 * Now that we can guarantee that the user memory is fully unmapped,
1156 * we can use the "key" and "type" values to try to find the entry
1157 * in the "userland resources database". If it's found, then it
1158 * indicates that the queue memory (CQ or QP) has not yet been freed.
1159 * In this case, we update the corresponding CQ or QP handle to
1160 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
1161 * If it's _not_ found, then it indicates that the CQ or QP memory
1162 * was, in fact, freed before it was unmapped (thus requiring a
1163 * previous invalidation by remapping - which will already have
1164 * been done in the free routine).
1165 */
1166 status = hermon_umap_db_find(state->hs_instance, key, type, &value,
1167 0, NULL);
1168 if (status == DDI_SUCCESS) {
1169 /*
1170 * Depending on the type of the mapped resource (CQ or QP),
1171 * update handle to indicate that no invalidation remapping
1172 * will be necessary.
1173 */
1174 if (type == MLNX_UMAP_CQMEM_RSRC) {
1175
1176 /* Use "value" to convert to CQ handle */
1177 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1178 cq = (hermon_cqhdl_t)rsrcp->hr_addr;
1179
1180 /*
1181 * Invalidate the handle to the userland mapping.
1182 * Note: We must ensure that the mapping being
1183 * unmapped here is the current one for the CQ. It
1184 * is possible that it might not be if this CQ has
1185 * been resized and the previous CQ memory has not
1186 * yet been unmapped. But in that case, because of
1187 * the devmap_devmem_remap(), there is no longer any
1188 * association between the mapping and the real CQ
1189 * kernel memory.
1190 */
1191 mutex_enter(&cq->cq_lock);
1192 if (cq->cq_umap_dhp == dhp) {
1193 cq->cq_umap_dhp = NULL;
1194 }
1195 mutex_exit(&cq->cq_lock);
1196
1197 } else if (type == MLNX_UMAP_QPMEM_RSRC) {
1198
1199 /* Use "value" to convert to QP handle */
1200 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1201 qp = (hermon_qphdl_t)rsrcp->hr_addr;
1202
1203 /*
1204 * Invalidate the handle to the userland mapping.
1205 * Note: we ensure that the mapping being unmapped
1206 * here is the current one for the QP. This is
1207 * more of a sanity check here since, unlike CQs
1208 * (above) we do not support resize of QPs.
1209 */
1210 mutex_enter(&qp->qp_lock);
1211 if (qp->qp_umap_dhp == dhp) {
1212 qp->qp_umap_dhp = NULL;
1213 }
1214 mutex_exit(&qp->qp_lock);
1215
1216 } else if (type == MLNX_UMAP_SRQMEM_RSRC) {
1217
1218 /* Use "value" to convert to SRQ handle */
1219 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1220 srq = (hermon_srqhdl_t)rsrcp->hr_addr;
1221
1222 /*
1223 * Invalidate the handle to the userland mapping.
1224 * Note: we ensure that the mapping being unmapped
1225 * here is the current one for the QP. This is
1226 * more of a sanity check here since, unlike CQs
1227 * (above) we do not support resize of QPs.
1228 */
1229 mutex_enter(&srq->srq_lock);
1230 if (srq->srq_umap_dhp == dhp) {
1231 srq->srq_umap_dhp = NULL;
1232 }
1233 mutex_exit(&srq->srq_lock);
1234 }
1235 }
1236 }
1237
1238
1239 /*
1240 * hermon_devmap_devmem_map()
1241 * Context: Can be called from kernel context.
1242 */
1243 /* ARGSUSED */
1244 static int
hermon_devmap_devmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)1245 hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
1246 offset_t off, size_t len, void **pvtp)
1247 {
1248 hermon_state_t *state;
1249 hermon_devmap_track_t *dvm_track;
1250 minor_t instance;
1251
1252 /* Get Hermon softstate structure from instance */
1253 instance = HERMON_DEV_INSTANCE(dev);
1254 state = ddi_get_soft_state(hermon_statep, instance);
1255 if (state == NULL) {
1256 return (ENXIO);
1257 }
1258
1259 /*
1260 * Allocate an entry to track the mapping and unmapping of this
1261 * resource. Note: We don't need to initialize the "refcnt" or
1262 * "offset" fields here, nor do we need to initialize the mutex
1263 * used with the "refcnt". Since UAR pages are single pages, they
1264 * are not subject to "partial" unmappings. This makes these other
1265 * fields unnecessary.
1266 */
1267 dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1268 sizeof (hermon_devmap_track_t), KM_SLEEP);
1269 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1270 dvm_track->hdt_state = state;
1271 dvm_track->hdt_size = (uint_t)PAGESIZE;
1272
1273 /*
1274 * Pass the private "Hermon devmap tracking structure" back. This
1275 * pointer will be returned in a subsequent "unmap" callback.
1276 */
1277 *pvtp = dvm_track;
1278
1279 return (DDI_SUCCESS);
1280 }
1281
1282
1283 /*
1284 * hermon_devmap_devmem_dup()
1285 * Context: Can be called from kernel context.
1286 */
1287 /* ARGSUSED */
1288 static int
hermon_devmap_devmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)1289 hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
1290 devmap_cookie_t new_dhp, void **new_pvtp)
1291 {
1292 hermon_state_t *state;
1293 hermon_devmap_track_t *dvm_track;
1294 uint_t maxprot;
1295 int status;
1296
1297 /*
1298 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1299 * structure" (in "pvtp"). Note: If the tracking structure is NULL
1300 * here, it means that the mapping corresponds to an invalid mapping.
1301 * In this case, it can be safely ignored ("new_pvtp" set to NULL).
1302 */
1303 dvm_track = (hermon_devmap_track_t *)pvtp;
1304 if (dvm_track == NULL) {
1305 *new_pvtp = NULL;
1306 return (DDI_SUCCESS);
1307 }
1308
1309 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1310 state = dvm_track->hdt_state;
1311
1312 /*
1313 * Since this devmap_dup() entry point is generally called
1314 * when a process does fork(2), it is incumbent upon the driver
1315 * to insure that the child does not inherit a valid copy of
1316 * the parent's resource. This is accomplished by using
1317 * devmap_devmem_remap() to invalidate the child's mapping to the
1318 * kernel memory.
1319 */
1320 maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1321 status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1322 dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1323 if (status != DDI_SUCCESS) {
1324 HERMON_WARNING(state, "failed in hermon_devmap_devmem_dup()");
1325 return (status);
1326 }
1327
1328 /*
1329 * Since the region is invalid, there is no need for us to
1330 * allocate and continue to track an additional "Hermon devmap
1331 * tracking structure". Instead we return NULL here, which is an
1332 * indication to the devmap_unmap() entry point that this entry
1333 * can be safely ignored.
1334 */
1335 *new_pvtp = NULL;
1336
1337 return (DDI_SUCCESS);
1338 }
1339
1340
1341 /*
1342 * hermon_devmap_devmem_unmap()
1343 * Context: Can be called from kernel context.
1344 */
1345 /* ARGSUSED */
1346 static void
hermon_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)1347 hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1348 size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1349 devmap_cookie_t new_dhp2, void **pvtp2)
1350 {
1351 hermon_devmap_track_t *dvm_track;
1352
1353 /*
1354 * Free up the "Hermon devmap tracking structure" (in "pvtp").
1355 * There cannot be "partial" unmappings here because all UAR pages
1356 * are single pages. Note: If the tracking structure is NULL here,
1357 * it means that the mapping corresponds to an invalid mapping. In
1358 * this case, it can be safely ignored.
1359 */
1360 dvm_track = (hermon_devmap_track_t *)pvtp;
1361 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1362 if (dvm_track == NULL) {
1363 return;
1364 }
1365
1366 kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1367 }
1368
1369
1370 /*
1371 * hermon_umap_ci_data_in()
1372 * Context: Can be called from user or kernel context.
1373 */
1374 /* ARGSUSED */
1375 ibt_status_t
hermon_umap_ci_data_in(hermon_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)1376 hermon_umap_ci_data_in(hermon_state_t *state, ibt_ci_data_flags_t flags,
1377 ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1378 {
1379 int status;
1380
1381 /*
1382 * Depending on the type of object about which additional information
1383 * is being provided (currently only MR is supported), we call the
1384 * appropriate resource-specific function.
1385 */
1386 switch (object) {
1387 case IBT_HDL_MR:
1388 status = hermon_umap_mr_data_in((hermon_mrhdl_t)hdl,
1389 (ibt_mr_data_in_t *)data_p, data_sz);
1390 if (status != DDI_SUCCESS) {
1391 return (status);
1392 }
1393 break;
1394
1395 /*
1396 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1397 * since the Hermon driver does not support these.
1398 */
1399 case IBT_HDL_HCA:
1400 case IBT_HDL_QP:
1401 case IBT_HDL_CQ:
1402 case IBT_HDL_PD:
1403 case IBT_HDL_MW:
1404 case IBT_HDL_AH:
1405 case IBT_HDL_SCHED:
1406 case IBT_HDL_EEC:
1407 case IBT_HDL_RDD:
1408 case IBT_HDL_SRQ:
1409 return (IBT_NOT_SUPPORTED);
1410
1411 /*
1412 * Any other types are invalid.
1413 */
1414 default:
1415 return (IBT_INVALID_PARAM);
1416 }
1417
1418 return (DDI_SUCCESS);
1419 }
1420
1421
1422 /*
1423 * hermon_umap_mr_data_in()
1424 * Context: Can be called from user or kernel context.
1425 */
1426 static ibt_status_t
hermon_umap_mr_data_in(hermon_mrhdl_t mr,ibt_mr_data_in_t * data,size_t data_sz)1427 hermon_umap_mr_data_in(hermon_mrhdl_t mr, ibt_mr_data_in_t *data,
1428 size_t data_sz)
1429 {
1430 if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
1431 return (IBT_NOT_SUPPORTED);
1432 }
1433
1434 /* Check for valid MR handle pointer */
1435 if (mr == NULL) {
1436 return (IBT_MR_HDL_INVALID);
1437 }
1438
1439 /* Check for valid MR input structure size */
1440 if (data_sz < sizeof (ibt_mr_data_in_t)) {
1441 return (IBT_INSUFF_RESOURCE);
1442 }
1443 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1444
1445 /*
1446 * Ensure that the MR corresponds to userland memory and that it is
1447 * a currently valid memory region as well.
1448 */
1449 mutex_enter(&mr->mr_lock);
1450 if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
1451 mutex_exit(&mr->mr_lock);
1452 return (IBT_MR_HDL_INVALID);
1453 }
1454
1455 /*
1456 * If it has passed all the above checks, then extract the callback
1457 * function and argument from the input structure. Copy them into
1458 * the MR handle. This function will be called only if the memory
1459 * corresponding to the MR handle gets a umem_lockmemory() callback.
1460 */
1461 mr->mr_umem_cbfunc = data->mr_func;
1462 mr->mr_umem_cbarg1 = data->mr_arg1;
1463 mr->mr_umem_cbarg2 = data->mr_arg2;
1464 mutex_exit(&mr->mr_lock);
1465
1466 return (DDI_SUCCESS);
1467 }
1468
1469
1470 /*
1471 * hermon_umap_ci_data_out()
1472 * Context: Can be called from user or kernel context.
1473 */
1474 /* ARGSUSED */
1475 ibt_status_t
hermon_umap_ci_data_out(hermon_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)1476 hermon_umap_ci_data_out(hermon_state_t *state, ibt_ci_data_flags_t flags,
1477 ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1478 {
1479 int status;
1480
1481 /*
1482 * Depending on the type of object about which additional information
1483 * is being requested (CQ or QP), we call the appropriate resource-
1484 * specific mapping function.
1485 */
1486 switch (object) {
1487 case IBT_HDL_CQ:
1488 status = hermon_umap_cq_data_out((hermon_cqhdl_t)hdl,
1489 (mlnx_umap_cq_data_out_t *)data_p, data_sz);
1490 if (status != DDI_SUCCESS) {
1491 return (status);
1492 }
1493 break;
1494
1495 case IBT_HDL_QP:
1496 status = hermon_umap_qp_data_out((hermon_qphdl_t)hdl,
1497 (mlnx_umap_qp_data_out_t *)data_p, data_sz);
1498 if (status != DDI_SUCCESS) {
1499 return (status);
1500 }
1501 break;
1502
1503 case IBT_HDL_SRQ:
1504 status = hermon_umap_srq_data_out((hermon_srqhdl_t)hdl,
1505 (mlnx_umap_srq_data_out_t *)data_p, data_sz);
1506 if (status != DDI_SUCCESS) {
1507 return (status);
1508 }
1509 break;
1510
1511 case IBT_HDL_PD:
1512 status = hermon_umap_pd_data_out((hermon_pdhdl_t)hdl,
1513 (mlnx_umap_pd_data_out_t *)data_p, data_sz);
1514 if (status != DDI_SUCCESS) {
1515 return (status);
1516 }
1517 break;
1518
1519 /*
1520 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1521 * since the Hermon driver does not support these.
1522 */
1523 case IBT_HDL_HCA:
1524 case IBT_HDL_MR:
1525 case IBT_HDL_MW:
1526 case IBT_HDL_AH:
1527 case IBT_HDL_SCHED:
1528 case IBT_HDL_EEC:
1529 case IBT_HDL_RDD:
1530 return (IBT_NOT_SUPPORTED);
1531
1532 /*
1533 * Any other types are invalid.
1534 */
1535 default:
1536 return (IBT_INVALID_PARAM);
1537 }
1538
1539 return (DDI_SUCCESS);
1540 }
1541
1542
1543 /*
1544 * hermon_umap_cq_data_out()
1545 * Context: Can be called from user or kernel context.
1546 */
1547 static ibt_status_t
hermon_umap_cq_data_out(hermon_cqhdl_t cq,mlnx_umap_cq_data_out_t * data,size_t data_sz)1548 hermon_umap_cq_data_out(hermon_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
1549 size_t data_sz)
1550 {
1551 /* Check for valid CQ handle pointer */
1552 if (cq == NULL) {
1553 return (IBT_CQ_HDL_INVALID);
1554 }
1555
1556 /* Check for valid CQ mapping structure size */
1557 if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
1558 return (IBT_INSUFF_RESOURCE);
1559 }
1560 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1561
1562 /* deal with cq_alloc() verses cq_resize() */
1563 if (cq->cq_resize_hdl) {
1564 data->mcq_maplen = cq->cq_resize_hdl->cq_cqinfo.qa_size;
1565 data->mcq_numcqe = cq->cq_resize_hdl->cq_bufsz;
1566 } else {
1567 data->mcq_maplen = cq->cq_cqinfo.qa_size;
1568 data->mcq_numcqe = cq->cq_bufsz;
1569 }
1570
1571 /*
1572 * If it has passed all the above checks, then fill in all the useful
1573 * mapping information (including the mapping offset that will be
1574 * passed back to the devmap() interface during a subsequent mmap()
1575 * call.
1576 *
1577 * The "offset" for CQ mmap()'s looks like this:
1578 * +----------------------------------------+--------+--------------+
1579 * | CQ Number | 0x33 | Reserved (0) |
1580 * +----------------------------------------+--------+--------------+
1581 * (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
1582 *
1583 * This returns information about the mapping offset, the length of
1584 * the CQ memory, the CQ number (for use in later CQ doorbells), the
1585 * number of CQEs the CQ memory can hold, and the size of each CQE.
1586 */
1587 data->mcq_rev = MLNX_UMAP_IF_VERSION;
1588 data->mcq_mapoffset = ((((uint64_t)cq->cq_cqnum <<
1589 MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
1590 data->mcq_cqnum = cq->cq_cqnum;
1591 data->mcq_cqesz = sizeof (hermon_hw_cqe_t);
1592
1593 /* doorbell record fields */
1594 data->mcq_polldbr_mapoffset = cq->cq_dbr_mapoffset;
1595 data->mcq_polldbr_maplen = PAGESIZE;
1596 data->mcq_polldbr_offset = (uintptr_t)cq->cq_arm_ci_vdbr &
1597 PAGEOFFSET;
1598 data->mcq_armdbr_mapoffset = cq->cq_dbr_mapoffset;
1599 data->mcq_armdbr_maplen = PAGESIZE;
1600 data->mcq_armdbr_offset = data->mcq_polldbr_offset + 4;
1601
1602 return (DDI_SUCCESS);
1603 }
1604
1605
1606 /*
1607 * hermon_umap_qp_data_out()
1608 * Context: Can be called from user or kernel context.
1609 */
1610 static ibt_status_t
hermon_umap_qp_data_out(hermon_qphdl_t qp,mlnx_umap_qp_data_out_t * data,size_t data_sz)1611 hermon_umap_qp_data_out(hermon_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
1612 size_t data_sz)
1613 {
1614 /* Check for valid QP handle pointer */
1615 if (qp == NULL) {
1616 return (IBT_QP_HDL_INVALID);
1617 }
1618
1619 /* Check for valid QP mapping structure size */
1620 if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
1621 return (IBT_INSUFF_RESOURCE);
1622 }
1623 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1624
1625 /*
1626 * If it has passed all the checks, then fill in all the useful
1627 * mapping information (including the mapping offset that will be
1628 * passed back to the devmap() interface during a subsequent mmap()
1629 * call.
1630 *
1631 * The "offset" for QP mmap()'s looks like this:
1632 * +----------------------------------------+--------+--------------+
1633 * | QP Number | 0x44 | Reserved (0) |
1634 * +----------------------------------------+--------+--------------+
1635 * (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
1636 *
1637 * This returns information about the mapping offset, the length of
1638 * the QP memory, and the QP number (for use in later send and recv
1639 * doorbells). It also returns the following information for both
1640 * the receive work queue and the send work queue, respectively: the
1641 * offset (from the base mapped address) of the start of the given
1642 * work queue, the 64-bit IB virtual address that corresponds to
1643 * the base mapped address (needed for posting WQEs though the
1644 * QP doorbells), the number of WQEs the given work queue can hold,
1645 * and the size of each WQE for the given work queue.
1646 */
1647 data->mqp_rev = MLNX_UMAP_IF_VERSION;
1648 data->mqp_mapoffset = ((((uint64_t)qp->qp_qpnum <<
1649 MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
1650 data->mqp_maplen = qp->qp_wqinfo.qa_size;
1651 data->mqp_qpnum = qp->qp_qpnum;
1652
1653 /*
1654 * If this QP is associated with a shared receive queue (SRQ),
1655 * then return invalid RecvQ parameters. Otherwise, return
1656 * the proper parameter values.
1657 */
1658 if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
1659 data->mqp_rq_off = (uint32_t)qp->qp_wqinfo.qa_size;
1660 data->mqp_rq_desc_addr = (uint32_t)qp->qp_wqinfo.qa_size;
1661 data->mqp_rq_numwqe = 0;
1662 data->mqp_rq_wqesz = 0;
1663 data->mqp_rdbr_mapoffset = 0;
1664 data->mqp_rdbr_maplen = 0;
1665 data->mqp_rdbr_offset = 0;
1666 } else {
1667 data->mqp_rq_off = (uintptr_t)qp->qp_rq_buf -
1668 (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1669 data->mqp_rq_desc_addr = (uint32_t)((uintptr_t)qp->qp_rq_buf -
1670 qp->qp_desc_off);
1671 data->mqp_rq_numwqe = qp->qp_rq_bufsz;
1672 data->mqp_rq_wqesz = (1 << qp->qp_rq_log_wqesz);
1673
1674 /* doorbell record fields */
1675 data->mqp_rdbr_mapoffset = qp->qp_rdbr_mapoffset;
1676 data->mqp_rdbr_maplen = PAGESIZE;
1677 data->mqp_rdbr_offset = (uintptr_t)qp->qp_rq_vdbr &
1678 PAGEOFFSET;
1679 }
1680 data->mqp_sq_off = (uintptr_t)qp->qp_sq_buf -
1681 (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1682 data->mqp_sq_desc_addr = (uint32_t)((uintptr_t)qp->qp_sq_buf -
1683 qp->qp_desc_off);
1684 data->mqp_sq_numwqe = qp->qp_sq_bufsz;
1685 data->mqp_sq_wqesz = (1 << qp->qp_sq_log_wqesz);
1686 data->mqp_sq_headroomwqes = qp->qp_sq_hdrmwqes;
1687
1688 /* doorbell record fields */
1689 data->mqp_sdbr_mapoffset = 0;
1690 data->mqp_sdbr_maplen = 0;
1691 data->mqp_sdbr_offset = 0;
1692
1693 return (DDI_SUCCESS);
1694 }
1695
1696
1697 /*
1698 * hermon_umap_srq_data_out()
1699 * Context: Can be called from user or kernel context.
1700 */
1701 static ibt_status_t
hermon_umap_srq_data_out(hermon_srqhdl_t srq,mlnx_umap_srq_data_out_t * data,size_t data_sz)1702 hermon_umap_srq_data_out(hermon_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
1703 size_t data_sz)
1704 {
1705 /* Check for valid SRQ handle pointer */
1706 if (srq == NULL) {
1707 return (IBT_SRQ_HDL_INVALID);
1708 }
1709
1710 /* Check for valid SRQ mapping structure size */
1711 if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
1712 return (IBT_INSUFF_RESOURCE);
1713 }
1714 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1715
1716 /*
1717 * If it has passed all the checks, then fill in all the useful
1718 * mapping information (including the mapping offset that will be
1719 * passed back to the devmap() interface during a subsequent mmap()
1720 * call.
1721 *
1722 * The "offset" for SRQ mmap()'s looks like this:
1723 * +----------------------------------------+--------+--------------+
1724 * | SRQ Number | 0x66 | Reserved (0) |
1725 * +----------------------------------------+--------+--------------+
1726 * (64 - 8 - PAGESHIFT) bits 8 bits PAGESHIFT bits
1727 *
1728 * This returns information about the mapping offset, the length of the
1729 * SRQ memory, and the SRQ number (for use in later send and recv
1730 * doorbells). It also returns the following information for the
1731 * shared receive queue: the offset (from the base mapped address) of
1732 * the start of the given work queue, the 64-bit IB virtual address
1733 * that corresponds to the base mapped address (needed for posting WQEs
1734 * though the QP doorbells), the number of WQEs the given work queue
1735 * can hold, and the size of each WQE for the given work queue.
1736 */
1737 data->msrq_rev = MLNX_UMAP_IF_VERSION;
1738 data->msrq_mapoffset = ((((uint64_t)srq->srq_srqnum <<
1739 MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
1740 data->msrq_maplen = srq->srq_wqinfo.qa_size;
1741 data->msrq_srqnum = srq->srq_srqnum;
1742
1743 data->msrq_desc_addr = (uint32_t)((uintptr_t)srq->srq_wq_buf -
1744 srq->srq_desc_off);
1745 data->msrq_numwqe = srq->srq_wq_bufsz;
1746 data->msrq_wqesz = (1 << srq->srq_wq_log_wqesz);
1747
1748 /* doorbell record fields */
1749 data->msrq_rdbr_mapoffset = srq->srq_rdbr_mapoffset;
1750 data->msrq_rdbr_maplen = PAGESIZE;
1751 data->msrq_rdbr_offset = (uintptr_t)srq->srq_wq_vdbr &
1752 PAGEOFFSET;
1753
1754 return (DDI_SUCCESS);
1755 }
1756
1757
1758 /*
1759 * hermon_umap_pd_data_out()
1760 * Context: Can be called from user or kernel context.
1761 */
1762 static ibt_status_t
hermon_umap_pd_data_out(hermon_pdhdl_t pd,mlnx_umap_pd_data_out_t * data,size_t data_sz)1763 hermon_umap_pd_data_out(hermon_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
1764 size_t data_sz)
1765 {
1766 /* Check for valid PD handle pointer */
1767 if (pd == NULL) {
1768 return (IBT_PD_HDL_INVALID);
1769 }
1770
1771 /* Check for valid PD mapping structure size */
1772 if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
1773 return (IBT_INSUFF_RESOURCE);
1774 }
1775 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1776
1777 /*
1778 * If it has passed all the checks, then fill the PD table index
1779 * (the PD table allocated index for the PD pd_pdnum).
1780 */
1781 data->mpd_rev = MLNX_UMAP_IF_VERSION;
1782 data->mpd_pdnum = pd->pd_pdnum;
1783
1784 return (DDI_SUCCESS);
1785 }
1786
1787
1788 /*
1789 * hermon_umap_db_init()
1790 * Context: Only called from attach() path context
1791 */
1792 void
hermon_umap_db_init(void)1793 hermon_umap_db_init(void)
1794 {
1795 /*
1796 * Initialize the lock used by the Hermon "userland resources database"
1797 * This is used to ensure atomic access to add, remove, and find
1798 * entries in the database.
1799 */
1800 mutex_init(&hermon_userland_rsrc_db.hdl_umapdb_lock, NULL,
1801 MUTEX_DRIVER, NULL);
1802
1803 /*
1804 * Initialize the AVL tree used for the "userland resources
1805 * database". Using an AVL tree here provides the ability to
1806 * scale the database size to large numbers of resources. The
1807 * entries in the tree are "hermon_umap_db_entry_t" (see
1808 * hermon_umap.h). The tree is searched with the help of the
1809 * hermon_umap_db_compare() routine.
1810 */
1811 avl_create(&hermon_userland_rsrc_db.hdl_umapdb_avl,
1812 hermon_umap_db_compare, sizeof (hermon_umap_db_entry_t),
1813 offsetof(hermon_umap_db_entry_t, hdbe_avlnode));
1814 }
1815
1816
1817 /*
1818 * hermon_umap_db_fini()
1819 * Context: Only called from attach() and/or detach() path contexts
1820 */
1821 void
hermon_umap_db_fini(void)1822 hermon_umap_db_fini(void)
1823 {
1824 /* Destroy the AVL tree for the "userland resources database" */
1825 avl_destroy(&hermon_userland_rsrc_db.hdl_umapdb_avl);
1826
1827 /* Destroy the lock for the "userland resources database" */
1828 mutex_destroy(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1829 }
1830
1831
1832 /*
1833 * hermon_umap_db_alloc()
1834 * Context: Can be called from user or kernel context.
1835 */
1836 hermon_umap_db_entry_t *
hermon_umap_db_alloc(uint_t instance,uint64_t key,uint_t type,uint64_t value)1837 hermon_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
1838 {
1839 hermon_umap_db_entry_t *umapdb;
1840
1841 /* Allocate an entry to add to the "userland resources database" */
1842 umapdb = kmem_zalloc(sizeof (hermon_umap_db_entry_t), KM_NOSLEEP);
1843 if (umapdb == NULL) {
1844 return (NULL);
1845 }
1846 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1847
1848 /* Fill in the fields in the database entry */
1849 umapdb->hdbe_common.hdb_instance = instance;
1850 umapdb->hdbe_common.hdb_type = type;
1851 umapdb->hdbe_common.hdb_key = key;
1852 umapdb->hdbe_common.hdb_value = value;
1853
1854 return (umapdb);
1855 }
1856
1857
1858 /*
1859 * hermon_umap_db_free()
1860 * Context: Can be called from user or kernel context.
1861 */
1862 void
hermon_umap_db_free(hermon_umap_db_entry_t * umapdb)1863 hermon_umap_db_free(hermon_umap_db_entry_t *umapdb)
1864 {
1865 /* Free the database entry */
1866 kmem_free(umapdb, sizeof (hermon_umap_db_entry_t));
1867 }
1868
1869
1870 /*
1871 * hermon_umap_db_add()
1872 * Context: Can be called from user or kernel context.
1873 */
1874 void
hermon_umap_db_add(hermon_umap_db_entry_t * umapdb)1875 hermon_umap_db_add(hermon_umap_db_entry_t *umapdb)
1876 {
1877 mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1878 hermon_umap_db_add_nolock(umapdb);
1879 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1880 }
1881
1882
1883 /*
1884 * hermon_umap_db_add_nolock()
1885 * Context: Can be called from user or kernel context.
1886 */
1887 void
hermon_umap_db_add_nolock(hermon_umap_db_entry_t * umapdb)1888 hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb)
1889 {
1890 hermon_umap_db_query_t query;
1891 avl_index_t where;
1892
1893 ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1894
1895 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1896
1897 /*
1898 * Copy the common portion of the "to-be-added" database entry
1899 * into the "hermon_umap_db_query_t" structure. We use this structure
1900 * (with no flags set) to find the appropriate location in the
1901 * "userland resources database" for the new entry to be added.
1902 *
1903 * Note: we expect that this entry should not be found in the
1904 * database (unless something bad has happened).
1905 */
1906 query.hqdb_common = umapdb->hdbe_common;
1907 query.hqdb_flags = 0;
1908 (void) avl_find(&hermon_userland_rsrc_db.hdl_umapdb_avl, &query,
1909 &where);
1910
1911 /*
1912 * Now, using the "where" field from the avl_find() operation
1913 * above, we will insert the new database entry ("umapdb").
1914 */
1915 avl_insert(&hermon_userland_rsrc_db.hdl_umapdb_avl, umapdb,
1916 where);
1917 }
1918
1919
1920 /*
1921 * hermon_umap_db_find()
1922 * Context: Can be called from user or kernel context.
1923 */
1924 int
hermon_umap_db_find(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flag,hermon_umap_db_entry_t ** umapdb)1925 hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type,
1926 uint64_t *value, uint_t flag, hermon_umap_db_entry_t **umapdb)
1927 {
1928 int status;
1929
1930 mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1931 status = hermon_umap_db_find_nolock(instance, key, type, value, flag,
1932 umapdb);
1933 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1934
1935 return (status);
1936 }
1937
1938
1939 /*
1940 * hermon_umap_db_find_nolock()
1941 * Context: Can be called from user or kernel context.
1942 */
1943 int
hermon_umap_db_find_nolock(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flags,hermon_umap_db_entry_t ** umapdb)1944 hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
1945 uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb)
1946 {
1947 hermon_umap_db_query_t query;
1948 hermon_umap_db_entry_t *entry;
1949 avl_index_t where;
1950
1951 ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1952
1953 /*
1954 * Fill in key, type, instance, and flags values of the
1955 * hermon_umap_db_query_t in preparation for the database
1956 * lookup.
1957 */
1958 query.hqdb_flags = flags;
1959 query.hqdb_common.hdb_key = key;
1960 query.hqdb_common.hdb_type = type;
1961 query.hqdb_common.hdb_instance = instance;
1962
1963 /*
1964 * Perform the database query. If no entry is found, then
1965 * return failure, else continue.
1966 */
1967 entry = (hermon_umap_db_entry_t *)avl_find(
1968 &hermon_userland_rsrc_db.hdl_umapdb_avl, &query, &where);
1969 if (entry == NULL) {
1970 return (DDI_FAILURE);
1971 }
1972 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
1973
1974 /*
1975 * If the flags argument specifies that the entry should
1976 * be removed if found, then call avl_remove() to remove
1977 * the entry from the database.
1978 */
1979 if (flags & HERMON_UMAP_DB_REMOVE) {
1980
1981 avl_remove(&hermon_userland_rsrc_db.hdl_umapdb_avl, entry);
1982
1983 /*
1984 * The database entry is returned with the expectation
1985 * that the caller will use hermon_umap_db_free() to
1986 * free the entry's memory. ASSERT that this is non-NULL.
1987 * NULL pointer should never be passed for the
1988 * HERMON_UMAP_DB_REMOVE case.
1989 */
1990 ASSERT(umapdb != NULL);
1991 }
1992
1993 /*
1994 * If the caller would like visibility to the database entry
1995 * (indicated through the use of a non-NULL "umapdb" argument),
1996 * then fill it in.
1997 */
1998 if (umapdb != NULL) {
1999 *umapdb = entry;
2000 }
2001
2002 /* Extract value field from database entry and return success */
2003 *value = entry->hdbe_common.hdb_value;
2004
2005 return (DDI_SUCCESS);
2006 }
2007
2008
2009 /*
2010 * hermon_umap_umemlock_cb()
2011 * Context: Can be called from callback context.
2012 */
2013 void
hermon_umap_umemlock_cb(ddi_umem_cookie_t * umem_cookie)2014 hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
2015 {
2016 hermon_umap_db_entry_t *umapdb;
2017 hermon_state_t *state;
2018 hermon_rsrc_t *rsrcp;
2019 hermon_mrhdl_t mr;
2020 uint64_t value;
2021 uint_t instance;
2022 int status;
2023 void (*mr_callback)(void *, void *);
2024 void *mr_cbarg1, *mr_cbarg2;
2025
2026 /*
2027 * If this was userland memory, then we need to remove its entry
2028 * from the "userland resources database". Note: We use the
2029 * HERMON_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
2030 * which instance was used when the entry was added (but we want
2031 * to know after the entry is found using the other search criteria).
2032 */
2033 status = hermon_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
2034 MLNX_UMAP_MRMEM_RSRC, &value, (HERMON_UMAP_DB_REMOVE |
2035 HERMON_UMAP_DB_IGNORE_INSTANCE), &umapdb);
2036 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
2037 if (status == DDI_SUCCESS) {
2038 instance = umapdb->hdbe_common.hdb_instance;
2039 state = ddi_get_soft_state(hermon_statep, instance);
2040 if (state == NULL) {
2041 cmn_err(CE_WARN, "Unable to match Hermon instance\n");
2042 return;
2043 }
2044
2045 /* Free the database entry */
2046 hermon_umap_db_free(umapdb);
2047
2048 /* Use "value" to convert to an MR handle */
2049 rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
2050 mr = (hermon_mrhdl_t)rsrcp->hr_addr;
2051
2052 /*
2053 * If a callback has been provided, call it first. This
2054 * callback is expected to do any cleanup necessary to
2055 * guarantee that the subsequent MR deregister (below)
2056 * will succeed. Specifically, this means freeing up memory
2057 * windows which might have been associated with the MR.
2058 */
2059 mutex_enter(&mr->mr_lock);
2060 mr_callback = mr->mr_umem_cbfunc;
2061 mr_cbarg1 = mr->mr_umem_cbarg1;
2062 mr_cbarg2 = mr->mr_umem_cbarg2;
2063 mutex_exit(&mr->mr_lock);
2064 if (mr_callback != NULL) {
2065 mr_callback(mr_cbarg1, mr_cbarg2);
2066 }
2067
2068 /*
2069 * Then call hermon_mr_deregister() to release the resources
2070 * associated with the MR handle. Note: Because this routine
2071 * will also check for whether the ddi_umem_cookie_t is in the
2072 * database, it will take responsibility for disabling the
2073 * memory region and calling ddi_umem_unlock().
2074 */
2075 status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
2076 HERMON_SLEEP);
2077 if (status != DDI_SUCCESS) {
2078 HERMON_WARNING(state, "Unexpected failure in "
2079 "deregister from callback\n");
2080 }
2081 }
2082 }
2083
2084
2085 /*
2086 * hermon_umap_db_compare()
2087 * Context: Can be called from user or kernel context.
2088 */
2089 static int
hermon_umap_db_compare(const void * q,const void * e)2090 hermon_umap_db_compare(const void *q, const void *e)
2091 {
2092 hermon_umap_db_common_t *entry_common, *query_common;
2093 uint_t query_flags;
2094
2095 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((hermon_umap_db_query_t *)q)))
2096
2097 entry_common = &((hermon_umap_db_entry_t *)e)->hdbe_common;
2098 query_common = &((hermon_umap_db_query_t *)q)->hqdb_common;
2099 query_flags = ((hermon_umap_db_query_t *)q)->hqdb_flags;
2100
2101 /*
2102 * The first comparison is done on the "key" value in "query"
2103 * and "entry". If they are not equal, then the appropriate
2104 * search direction is returned. Else, we continue by
2105 * comparing "type".
2106 */
2107 if (query_common->hdb_key < entry_common->hdb_key) {
2108 return (-1);
2109 } else if (query_common->hdb_key > entry_common->hdb_key) {
2110 return (+1);
2111 }
2112
2113 /*
2114 * If the search reaches this point, then "query" and "entry"
2115 * have equal key values. So we continue be comparing their
2116 * "type" values. Again, if they are not equal, then the
2117 * appropriate search direction is returned. Else, we continue
2118 * by comparing "instance".
2119 */
2120 if (query_common->hdb_type < entry_common->hdb_type) {
2121 return (-1);
2122 } else if (query_common->hdb_type > entry_common->hdb_type) {
2123 return (+1);
2124 }
2125
2126 /*
2127 * If the search reaches this point, then "query" and "entry"
2128 * have exactly the same key and type values. Now we consult
2129 * the "flags" field in the query to determine whether the
2130 * "instance" is relevant to the search. If the
2131 * HERMON_UMAP_DB_IGNORE_INSTANCE flags is set, then return
2132 * success (0) here. Otherwise, continue the search by comparing
2133 * instance values and returning the appropriate search direction.
2134 */
2135 if (query_flags & HERMON_UMAP_DB_IGNORE_INSTANCE) {
2136 return (0);
2137 }
2138
2139 /*
2140 * If the search has reached this point, then "query" and "entry"
2141 * can only be differentiated by their instance values. If these
2142 * are not equal, then return the appropriate search direction.
2143 * Else, we return success (0).
2144 */
2145 if (query_common->hdb_instance < entry_common->hdb_instance) {
2146 return (-1);
2147 } else if (query_common->hdb_instance > entry_common->hdb_instance) {
2148 return (+1);
2149 }
2150
2151 /* Everything matches... so return success */
2152 return (0);
2153 }
2154
2155
2156 /*
2157 * hermon_umap_db_set_onclose_cb()
2158 * Context: Can be called from user or kernel context.
2159 */
2160 int
hermon_umap_db_set_onclose_cb(dev_t dev,uint64_t flag,int (* callback)(void *),void * arg)2161 hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
2162 int (*callback)(void *), void *arg)
2163 {
2164 hermon_umap_db_priv_t *priv;
2165 hermon_umap_db_entry_t *umapdb;
2166 minor_t instance;
2167 uint64_t value;
2168 int status;
2169
2170 instance = HERMON_DEV_INSTANCE(dev);
2171 if (instance == (minor_t)-1) {
2172 return (DDI_FAILURE);
2173 }
2174
2175 if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2176 return (DDI_FAILURE);
2177 }
2178
2179 /*
2180 * Grab the lock for the "userland resources database" and find
2181 * the entry corresponding to this minor number. Once it's found,
2182 * allocate (if necessary) and add an entry (in the "hdb_priv"
2183 * field) to indicate that further processing may be needed during
2184 * Hermon's close() handling.
2185 */
2186 mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2187 status = hermon_umap_db_find_nolock(instance, dev,
2188 MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2189 if (status != DDI_SUCCESS) {
2190 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2191 return (DDI_FAILURE);
2192 }
2193
2194 priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2195 if (priv == NULL) {
2196 priv = (hermon_umap_db_priv_t *)kmem_zalloc(
2197 sizeof (hermon_umap_db_priv_t), KM_NOSLEEP);
2198 if (priv == NULL) {
2199 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2200 return (DDI_FAILURE);
2201 }
2202 }
2203
2204 /*
2205 * Save away the callback and argument to be used during Hermon's
2206 * close() processing.
2207 */
2208 priv->hdp_cb = callback;
2209 priv->hdp_arg = arg;
2210
2211 umapdb->hdbe_common.hdb_priv = (void *)priv;
2212 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2213
2214 return (DDI_SUCCESS);
2215 }
2216
2217
2218 /*
2219 * hermon_umap_db_clear_onclose_cb()
2220 * Context: Can be called from user or kernel context.
2221 */
2222 int
hermon_umap_db_clear_onclose_cb(dev_t dev,uint64_t flag)2223 hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
2224 {
2225 hermon_umap_db_priv_t *priv;
2226 hermon_umap_db_entry_t *umapdb;
2227 minor_t instance;
2228 uint64_t value;
2229 int status;
2230
2231 instance = HERMON_DEV_INSTANCE(dev);
2232 if (instance == (minor_t)-1) {
2233 return (DDI_FAILURE);
2234 }
2235
2236 if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2237 return (DDI_FAILURE);
2238 }
2239
2240 /*
2241 * Grab the lock for the "userland resources database" and find
2242 * the entry corresponding to this minor number. Once it's found,
2243 * remove the entry (in the "hdb_priv" field) that indicated the
2244 * need for further processing during Hermon's close(). Free the
2245 * entry, if appropriate.
2246 */
2247 mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2248 status = hermon_umap_db_find_nolock(instance, dev,
2249 MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2250 if (status != DDI_SUCCESS) {
2251 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2252 return (DDI_FAILURE);
2253 }
2254
2255 priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2256 if (priv != NULL) {
2257 kmem_free(priv, sizeof (hermon_umap_db_priv_t));
2258 priv = NULL;
2259 }
2260
2261 umapdb->hdbe_common.hdb_priv = (void *)priv;
2262 mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2263 return (DDI_SUCCESS);
2264 }
2265
2266
2267 /*
2268 * hermon_umap_db_clear_onclose_cb()
2269 * Context: Can be called from user or kernel context.
2270 */
2271 int
hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t * priv)2272 hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv)
2273 {
2274 int (*callback)(void *);
2275
2276 ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
2277
2278 /*
2279 * Call the callback.
2280 * Note: Currently there is only one callback (in "hdp_cb"), but
2281 * in the future there may be more, depending on what other types
2282 * of interaction there are between userland processes and the
2283 * driver.
2284 */
2285 callback = priv->hdp_cb;
2286 return (callback(priv->hdp_arg));
2287 }
2288