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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 }