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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "dapl.h" 28 #include "dapl_tavor_wr.h" 29 #include "dapl_hash.h" 30 #include "dapl_tavor_ibtf_impl.h" 31 32 static dapls_tavor_wrid_entry_t *dapli_tavor_wrid_find_match( 33 dapls_tavor_workq_hdr_t *, tavor_hw_cqe_t *); 34 static dapls_tavor_wrid_list_hdr_t *dapli_tavor_wrid_get_list(uint32_t, int); 35 static void dapli_tavor_wrid_reaplist_add(ib_cq_handle_t, 36 dapls_tavor_workq_hdr_t *); 37 static dapls_tavor_workq_hdr_t *dapli_tavor_wrid_wqhdr_find(ib_cq_handle_t, 38 uint_t, uint_t); 39 static uint32_t dapli_tavor_wrid_get_wqeaddrsz(dapls_tavor_workq_hdr_t *); 40 static dapls_tavor_workq_hdr_t *dapli_tavor_wrid_list_reap( 41 dapls_tavor_wrid_list_hdr_t *); 42 static dapls_tavor_workq_hdr_t *dapli_tavor_wrid_wqhdr_create(ib_cq_handle_t, 43 uint_t, uint_t, uint_t); 44 static void dapli_tavor_wrid_wqhdr_add(dapls_tavor_workq_hdr_t *, 45 dapls_tavor_wrid_list_hdr_t *); 46 static void dapli_tavor_wrid_wqhdr_remove(dapls_tavor_workq_hdr_t *, 47 dapls_tavor_wrid_list_hdr_t *); 48 static void dapli_tavor_wrid_wqhdr_lock_both(ib_qp_handle_t); 49 static void dapli_tavor_wrid_wqhdr_unlock_both(ib_qp_handle_t); 50 static DAT_RETURN dapli_tavor_cq_wqhdr_add(ib_cq_handle_t, 51 dapls_tavor_workq_hdr_t *); 52 static void dapli_tavor_cq_wqhdr_remove(ib_cq_handle_t, 53 dapls_tavor_workq_hdr_t *); 54 55 /* 56 * dapls_tavor_wrid_get_entry() 57 */ 58 uint64_t 59 dapls_tavor_wrid_get_entry(ib_cq_handle_t cq, tavor_hw_cqe_t *cqe, 60 uint_t send_or_recv, uint_t error, dapls_tavor_wrid_entry_t *wre) 61 { 62 dapls_tavor_workq_hdr_t *wq; 63 dapls_tavor_wrid_entry_t *wre_tmp; 64 uint64_t wrid; 65 uint_t qpnum; 66 67 /* Lock the list of work queues associated with this CQ */ 68 dapl_os_lock(&cq->cq_wrid_wqhdr_lock); 69 70 /* Find the work queue for this QP number (send or receive side) */ 71 qpnum = TAVOR_CQE_QPNUM_GET(cqe); 72 wq = dapli_tavor_wrid_wqhdr_find(cq, qpnum, send_or_recv); 73 74 dapl_os_assert(wq != NULL); 75 76 /* 77 * Regardless of whether the completion is the result of a "success" 78 * or a "failure", we lock the list of "containers" and attempt to 79 * search for the the first matching completion (i.e. the first WR 80 * with a matching WQE addr and size). Once we find it, we pull out 81 * the "wrid" field and return it (see below). Note: One possible 82 * future enhancement would be to enable this routine to skip over 83 * any "unsignaled" completions to go directly to the next "signaled" 84 * entry on success. XXX 85 */ 86 dapl_os_lock(&wq->wq_wrid_lock->wrl_lock); 87 wre_tmp = dapli_tavor_wrid_find_match(wq, cqe); 88 89 /* 90 * If this is a "successful" completion, then we assert that this 91 * completion must be a "signaled" completion. 92 */ 93 dapl_os_assert(error || (wre_tmp->wr_signaled_dbd & 94 TAVOR_WRID_ENTRY_SIGNALED)); 95 96 /* 97 * If the completion is a "failed" completion, then we save away the 98 * contents of the entry (into the "wre" field passed in) for use 99 * in later CQE processing. Note: We use the 100 * dapli_tavor_wrid_get_wqeaddrsz() function to grab "wqeaddrsz" from 101 * the next entry in the container. 102 * This is required for error processing (where updating these fields 103 * properly is necessary to correct handling of the "error" CQE) 104 */ 105 if (error && (wre != NULL)) { 106 *wre = *wre_tmp; 107 wre->wr_wqeaddrsz = dapli_tavor_wrid_get_wqeaddrsz(wq); 108 } 109 110 /* Pull out the WRID and return it */ 111 wrid = wre_tmp->wr_wrid; 112 113 dapl_os_unlock(&wq->wq_wrid_lock->wrl_lock); 114 dapl_os_unlock(&cq->cq_wrid_wqhdr_lock); 115 116 return (wrid); 117 } 118 119 120 /* 121 * dapli_tavor_wrid_find_match() 122 */ 123 static dapls_tavor_wrid_entry_t * 124 dapli_tavor_wrid_find_match(dapls_tavor_workq_hdr_t *wq, tavor_hw_cqe_t *cqe) 125 { 126 dapls_tavor_wrid_entry_t *curr = NULL; 127 dapls_tavor_wrid_list_hdr_t *container; 128 uint32_t wqeaddr_size; 129 uint32_t head, tail, size; 130 int found = 0, last_container; 131 132 /* dapl_os_assert(MUTEX_HELD(&wq->wq_wrid_lock)); */ 133 134 /* Pull the "wqeaddrsz" information from the CQE */ 135 wqeaddr_size = TAVOR_CQE_WQEADDRSZ_GET(cqe); 136 137 /* 138 * Walk the "containers" list(s), find first WR with a matching WQE 139 * addr. If the current "container" is not the last one on the list, 140 * i.e. not the current one to which we are posting new WRID entries, 141 * then we do not attempt to update the "q_head", "q_tail", and 142 * "q_full" indicators on the main work queue header. We do, however, 143 * update the "head" and "full" indicators on the individual containers 144 * as we go. This is imperative because we need to be able to 145 * determine when the current container has been emptied (so that we 146 * can move on to the next container). 147 */ 148 container = wq->wq_wrid_poll; 149 while (container != NULL) { 150 151 /* Is this the last/only "container" on the list */ 152 last_container = (container != wq->wq_wrid_post) ? 0 : 1; 153 154 /* 155 * First check if we are on an SRQ. If so, we grab the entry 156 * and break out. Since SRQ wridlist's are never added to 157 * reaplist, they can only be the last container. 158 */ 159 if (container->wl_srq_en) { 160 dapl_os_assert(last_container == 1); 161 curr = dapli_tavor_wrid_find_match_srq(container, cqe); 162 break; 163 } 164 165 /* 166 * Grab the current "head", "tail" and "size" fields before 167 * walking the list in the current container. Note: the "size" 168 * field here must always be a power-of-2. The "full" 169 * parameter is checked (and updated) here to distinguish the 170 * "queue full" condition from "queue empty". 171 */ 172 head = container->wl_head; 173 tail = container->wl_tail; 174 size = container->wl_size; 175 while ((head != tail) || (container->wl_full)) { 176 container->wl_full = 0; 177 curr = &container->wl_wre[head]; 178 head = ((head + 1) & (size - 1)); 179 /* 180 * If the current entry's "wqeaddrsz" matches the one 181 * we're searching for, then this must correspond to 182 * the work request that caused the completion. Set 183 * the "found" flag and bail out. 184 */ 185 if (curr->wr_wqeaddrsz == wqeaddr_size) { 186 found = 1; 187 break; 188 } 189 } 190 191 /* 192 * If the current container is empty (having reached here the 193 * "head == tail" condition can only mean that the container 194 * is empty), then NULL out the "wrid_old_tail" field (see 195 * tavor_post_send() and tavor_post_recv() for more details) 196 * and (potentially) remove the current container from future 197 * searches. 198 */ 199 if (head == tail) { 200 container->wl_wre_old_tail = NULL; 201 /* 202 * If this wasn't the last "container" on the chain, 203 * i.e. the one to which new WRID entries will be 204 * added, then remove it from the list. 205 * Note: we don't "lose" the memory pointed to by this 206 * because we should have already put this container 207 * on the "reapable" list (from where it will later be 208 * pulled). 209 */ 210 if (!last_container) { 211 wq->wq_wrid_poll = container->wl_next; 212 } 213 } 214 215 /* Update the head index for the container */ 216 container->wl_head = head; 217 218 /* 219 * If the entry was found in this container, then continue to 220 * bail out. Else reset the "curr" pointer and move on to the 221 * next container (if there is one). Note: the only real 222 * reason for setting "curr = NULL" here is so that the ASSERT 223 * below can catch the case where no matching entry was found 224 * on any of the lists. 225 */ 226 if (found) { 227 break; 228 } else { 229 curr = NULL; 230 container = container->wl_next; 231 } 232 } 233 234 /* 235 * Update work queue header's "head" and "full" conditions to match 236 * the last entry on the container list. (Note: Only if we're pulling 237 * entries from the last work queue portion of the list, i.e. not from 238 * the previous portions that may be the "reapable" list.) 239 */ 240 if (last_container) { 241 wq->wq_head = wq->wq_wrid_post->wl_head; 242 wq->wq_full = wq->wq_wrid_post->wl_full; 243 } 244 245 /* Ensure that we've actually found what we were searching for */ 246 dapl_os_assert(curr != NULL); 247 248 return (curr); 249 } 250 251 /* 252 * tavor_wrid_find_match_srq() 253 * Context: Can be called from interrupt or base context. 254 */ 255 dapls_tavor_wrid_entry_t * 256 dapli_tavor_wrid_find_match_srq(dapls_tavor_wrid_list_hdr_t *wl, 257 tavor_hw_cqe_t *cqe) 258 { 259 dapls_tavor_wrid_entry_t *wre; 260 uint32_t wqe_index; 261 uint32_t wqe_addr; 262 uint32_t qsize_msk; 263 uint32_t tail, next_tail; 264 265 /* Grab the WQE addr out of the CQE */ 266 wqe_addr = TAVOR_CQE_WQEADDRSZ_GET(cqe) & 0xFFFFFFC0; 267 268 /* 269 * Given the 'wqe_addr' just calculated and the srq buf address, we 270 * find the 'wqe_index'. The 'wre' returned below contains the WRID 271 * that we are looking for. This indexes into the wre_list for this 272 * specific WQE. 273 */ 274 wqe_index = TAVOR_SRQ_WQ_INDEX(wl->wl_srq_desc_addr, wqe_addr, 275 wl->wl_srq_wqesz); 276 277 /* ASSERT on impossible wqe_index values */ 278 dapl_os_assert(wqe_index < wl->wl_size); 279 280 /* Put this WQE back on the free list */ 281 282 qsize_msk = wl->wl_size - 1; 283 tail = wl->wl_freel_tail; 284 285 next_tail = (tail + 1) & qsize_msk; 286 wl->wl_freel_entries++; 287 288 dapl_os_assert(wl->wl_freel_entries <= wl->wl_size); 289 290 /* Get the descriptor (IO Address) of the WQE to be built */ 291 wl->wl_free_list[tail] = wqe_addr; 292 wl->wl_freel_tail = next_tail; 293 /* Using the index, return the Work Request ID Entry (wre) */ 294 wre = &wl->wl_wre[wqe_index]; 295 296 return (wre); 297 } 298 299 /* 300 * dapls_tavor_wrid_cq_reap() 301 */ 302 void 303 dapls_tavor_wrid_cq_reap(ib_cq_handle_t cq) 304 { 305 dapls_tavor_workq_hdr_t *consume_wqhdr; 306 dapls_tavor_wrid_list_hdr_t *container, *to_free; 307 308 309 /* dapl_os_assert(MUTEX_HELD(&cq->cq_lock)); */ 310 311 /* Lock the list of work queues associated with this CQ */ 312 dapl_os_lock(&cq->cq_wrid_wqhdr_lock); 313 314 /* Walk the "reapable" list and free up containers */ 315 container = cq->cq_wrid_reap_head; 316 while (container != NULL) { 317 to_free = container; 318 container = container->wl_reap_next; 319 /* 320 * If reaping the WRID list containers pulls the last 321 * container from the given work queue header, then we free 322 * the work queue header as well. 323 */ 324 consume_wqhdr = dapli_tavor_wrid_list_reap(to_free); 325 if (consume_wqhdr != NULL) { 326 dapli_tavor_cq_wqhdr_remove(cq, consume_wqhdr); 327 } 328 } 329 330 /* Once finished reaping, we reset the CQ's reap list */ 331 cq->cq_wrid_reap_head = cq->cq_wrid_reap_tail = NULL; 332 333 dapl_os_unlock(&cq->cq_wrid_wqhdr_lock); 334 } 335 336 337 /* 338 * dapls_tavor_wrid_cq_force_reap() 339 */ 340 void 341 dapls_tavor_wrid_cq_force_reap(ib_cq_handle_t cq) 342 { 343 DAPL_HASH_DATA curr; 344 DAT_RETURN retval; 345 dapls_tavor_workq_hdr_t *to_free_wqhdr; 346 dapls_tavor_wrid_list_hdr_t *container, *to_free; 347 348 /* dapl_os_assert(MUTEX_HELD(&cq->cq_lock)); */ 349 350 /* 351 * The first step is to walk the "reapable" list and free up those 352 * containers. This is necessary because the containers on the 353 * reapable list are not otherwise connected to the work queue headers 354 * anymore. 355 */ 356 dapls_tavor_wrid_cq_reap(cq); 357 358 /* Now lock the list of work queues associated with this CQ */ 359 dapl_os_lock(&cq->cq_wrid_wqhdr_lock); 360 361 /* 362 * Walk the list of work queue headers and free up all the WRID list 363 * containers chained to it. Note: We don't need to grab the locks 364 * for each of the individual WRID lists here because the only way 365 * things can be added or removed from the list at this point would be 366 * through post a work request to a QP. But if we've come this far, 367 * then we can be assured that there are no longer any QP associated 368 * with the CQ that we are trying to free. 369 */ 370 retval = dapls_hash_iterate(cq->cq_wrid_wqhdr_list, 371 DAPL_HASH_ITERATE_INIT, &curr); 372 dapl_os_assert(retval == DAT_SUCCESS); 373 374 while (curr != NULL) { 375 to_free_wqhdr = (dapls_tavor_workq_hdr_t *)curr; 376 container = ((dapls_tavor_workq_hdr_t *)curr)->wq_wrid_poll; 377 retval = dapls_hash_iterate(cq->cq_wrid_wqhdr_list, 378 DAPL_HASH_ITERATE_NEXT, &curr); 379 dapl_os_assert(retval == DAT_SUCCESS); 380 while (container != NULL) { 381 to_free = container; 382 container = container->wl_next; 383 /* 384 * If reaping the WRID list containers pulls the last 385 * container from the given work queue header, then 386 * we free the work queue header as well. Note: we 387 * ignore the return value because we know that the 388 * work queue header should always be freed once the 389 * list of containers has come to an end. 390 */ 391 (void) dapli_tavor_wrid_list_reap(to_free); 392 if (container == NULL) { 393 dapli_tavor_cq_wqhdr_remove(cq, to_free_wqhdr); 394 } 395 } 396 } 397 398 dapl_os_lock(&cq->cq_wrid_wqhdr_lock); 399 } 400 401 402 /* 403 * dapli_tavor_wrid_get_list() 404 */ 405 static dapls_tavor_wrid_list_hdr_t * 406 dapli_tavor_wrid_get_list(uint32_t qsize, int wrid_for_srq) 407 { 408 dapls_tavor_wrid_list_hdr_t *wridlist; 409 dapls_tavor_wrid_entry_t *wl_wre; 410 uint32_t *wl_freel; 411 uint32_t size; 412 uint32_t wl_wre_size; 413 uint32_t wl_freel_size; 414 415 wridlist = NULL; 416 wl_wre = NULL; 417 wl_freel = NULL; 418 size = wl_wre_size = wl_freel_size = 0; 419 /* 420 * The WRID list "container" consists of the dapls_tavor_wrid_list_hdr_t 421 * which holds the pointers necessary for maintaining the "reapable" 422 * list, chaining together multiple "containers" old and new, and 423 * tracking the head, tail, size, etc. for each container. The 424 * "container" also holds all the tavor_wrid_entry_t's, one for 425 * each entry on the corresponding work queue. 426 */ 427 428 /* 429 * For wridlist associated with SRQs the wridlock needs to be 430 * allocated and initialized here. 431 */ 432 size = sizeof (dapls_tavor_wrid_list_hdr_t); 433 if (wrid_for_srq) { 434 size = size + sizeof (dapls_tavor_wrid_lock_t); 435 } 436 wridlist = dapl_os_alloc(size); 437 if (wridlist == NULL) { 438 goto bail; 439 } 440 if (wrid_for_srq) { 441 wridlist->wl_lock = (dapls_tavor_wrid_lock_t *)( 442 (uintptr_t)wridlist + sizeof (dapls_tavor_wrid_list_hdr_t)); 443 dapl_os_lock_init(&wridlist->wl_lock->wrl_lock); 444 wridlist->wl_lock->wrl_on_srq = wrid_for_srq; 445 } else { 446 wridlist->wl_lock = NULL; 447 } 448 wl_wre_size = qsize * sizeof (dapls_tavor_wrid_entry_t); 449 wl_wre = dapl_os_alloc(wl_wre_size); 450 if (wl_wre == NULL) { 451 goto bail; 452 } 453 if (wrid_for_srq) { /* memory for the SRQ free list */ 454 wl_freel_size = qsize * sizeof (uint32_t); 455 wl_freel = dapl_os_alloc(wl_freel_size); 456 if (wl_freel == NULL) { 457 goto bail; 458 } 459 } 460 461 462 /* Complete the "container" initialization */ 463 wridlist->wl_size = qsize; 464 wridlist->wl_full = 0; 465 wridlist->wl_head = 0; 466 wridlist->wl_tail = 0; 467 wridlist->wl_wre = wl_wre; 468 wridlist->wl_wre_old_tail = NULL; 469 wridlist->wl_reap_next = NULL; 470 wridlist->wl_next = NULL; 471 wridlist->wl_prev = NULL; 472 if (wrid_for_srq) { 473 wridlist->wl_srq_en = 1; 474 wridlist->wl_free_list = (uint32_t *)wl_freel; 475 wridlist->wl_freel_head = 0; 476 wridlist->wl_freel_tail = 0; 477 wridlist->wl_freel_entries = qsize; 478 } else { 479 wridlist->wl_srq_en = 0; 480 wridlist->wl_free_list = NULL; 481 wridlist->wl_freel_head = 0; 482 wridlist->wl_freel_tail = 0; 483 wridlist->wl_freel_entries = 0; 484 wridlist->wl_srq_wqesz = 0; 485 wridlist->wl_srq_desc_addr = 0; 486 } 487 return (wridlist); 488 bail: 489 if (wridlist) { 490 if (wrid_for_srq) { 491 dapl_os_lock_destroy(&wridlist->wl_lock->wrl_lock); 492 } 493 dapl_os_free(wridlist, size); 494 } 495 if (wl_wre) { 496 dapl_os_free(wl_wre, wl_wre_size); 497 } 498 if (wl_freel) { 499 dapl_os_free(wl_freel, wl_freel_size); 500 } 501 return (NULL); 502 } 503 504 505 /* 506 * dapli_tavor_wrid_reaplist_add() 507 */ 508 static void 509 dapli_tavor_wrid_reaplist_add(ib_cq_handle_t cq, dapls_tavor_workq_hdr_t *wq) 510 { 511 /* dapl_os_assert(MUTEX_HELD(&cq->cq_wrid_wqhdr_lock)); */ 512 513 dapl_os_lock(&wq->wq_wrid_lock->wrl_lock); 514 515 /* 516 * Add the "post" container (the last one on the current chain) to 517 * the CQ's "reapable" list 518 */ 519 if ((cq->cq_wrid_reap_head == NULL) && 520 (cq->cq_wrid_reap_tail == NULL)) { 521 cq->cq_wrid_reap_head = wq->wq_wrid_post; 522 cq->cq_wrid_reap_tail = wq->wq_wrid_post; 523 } else { 524 cq->cq_wrid_reap_tail->wl_reap_next = wq->wq_wrid_post; 525 cq->cq_wrid_reap_tail = wq->wq_wrid_post; 526 } 527 528 dapl_os_unlock(&wq->wq_wrid_lock->wrl_lock); 529 } 530 531 532 /* 533 * dapli_tavor_wrid_wqhdr_find() 534 */ 535 static dapls_tavor_workq_hdr_t * 536 dapli_tavor_wrid_wqhdr_find(ib_cq_handle_t cq, uint_t qpn, uint_t send_or_recv) 537 { 538 DAPL_HASH_DATA curr; 539 DAPL_HASH_KEY key; 540 DAT_RETURN status; 541 542 /* dapl_os_assert(MUTEX_HELD(&cq->cq_wrid_wqhdr_lock)); */ 543 544 /* 545 * Walk the CQ's work queue list, trying to find a send or recv queue 546 * with the same QP number. We do this even if we are going to later 547 * create a new entry because it helps us easily find the end of the 548 * list. 549 */ 550 key = (DAPL_HASH_KEY)(((uint64_t)send_or_recv << 32) | (uint32_t)qpn); 551 552 status = dapls_hash_search(cq->cq_wrid_wqhdr_list, key, &curr); 553 if (status == DAT_SUCCESS) { 554 return ((dapls_tavor_workq_hdr_t *)curr); 555 } else { 556 return (NULL); 557 } 558 } 559 560 561 562 563 /* 564 * dapli_tavor_wrid_get_wqeaddrsz() 565 */ 566 static uint32_t 567 dapli_tavor_wrid_get_wqeaddrsz(dapls_tavor_workq_hdr_t *wq) 568 { 569 dapls_tavor_wrid_entry_t *wre; 570 uint32_t wqeaddrsz; 571 uint32_t head; 572 573 /* 574 * If the container is empty, then there is no next entry. So just 575 * return zero. Note: the "head == tail" condition here can only 576 * mean that the container is empty because we have previously pulled 577 * something from the container. 578 * 579 * If the container is not empty, then find the next entry and return 580 * the contents of its "wqeaddrsz" field. 581 */ 582 if (wq->wq_wrid_poll->wl_head == wq->wq_wrid_poll->wl_tail) { 583 wqeaddrsz = 0; 584 } else { 585 /* 586 * We don't need to calculate the "next" head pointer here 587 * because "head" should already point to the next entry on 588 * the list (since we just pulled something off - in 589 * dapli_tavor_wrid_find_match() - and moved the head index 590 * forward.) 591 */ 592 head = wq->wq_wrid_poll->wl_head; 593 wre = &wq->wq_wrid_poll->wl_wre[head]; 594 wqeaddrsz = wre->wr_wqeaddrsz; 595 } 596 return (wqeaddrsz); 597 } 598 599 600 601 /* 602 * dapli_tavor_wrid_list_reap() 603 * Note: The "wqhdr_list_lock" must be held. 604 */ 605 static dapls_tavor_workq_hdr_t * 606 dapli_tavor_wrid_list_reap(dapls_tavor_wrid_list_hdr_t *wridlist) 607 { 608 dapls_tavor_workq_hdr_t *wqhdr, *consume_wqhdr = NULL; 609 dapls_tavor_wrid_list_hdr_t *prev, *next; 610 611 /* Get the back pointer to the work queue header (see below) */ 612 wqhdr = wridlist->wl_wqhdr; 613 dapl_os_lock(&wqhdr->wq_wrid_lock->wrl_lock); 614 615 /* Unlink the WRID list "container" from the work queue list */ 616 prev = wridlist->wl_prev; 617 next = wridlist->wl_next; 618 if (prev != NULL) { 619 prev->wl_next = next; 620 } 621 if (next != NULL) { 622 next->wl_prev = prev; 623 } 624 625 /* 626 * If the back pointer to the work queue header shows that it 627 * was pointing to the entry we are about to remove, then the work 628 * queue header is reapable as well. 629 */ 630 if ((wqhdr->wq_wrid_poll == wridlist) && 631 (wqhdr->wq_wrid_post == wridlist)) { 632 consume_wqhdr = wqhdr; 633 } 634 635 /* Be sure to update the "poll" and "post" container pointers */ 636 if (wqhdr->wq_wrid_poll == wridlist) { 637 wqhdr->wq_wrid_poll = next; 638 } 639 if (wqhdr->wq_wrid_post == wridlist) { 640 wqhdr->wq_wrid_post = NULL; 641 } 642 643 /* 644 * Calculate the size and free the container, for SRQ wridlist is 645 * freed when srq gets freed 646 */ 647 if (!wridlist->wl_srq_en) { 648 if (wridlist->wl_wre) { 649 dapl_os_free(wridlist->wl_wre, wridlist->wl_size * 650 sizeof (dapls_tavor_wrid_entry_t)); 651 } 652 dapl_os_assert(wridlist->wl_free_list == NULL); 653 dapl_os_free(wridlist, sizeof (dapls_tavor_wrid_list_hdr_t)); 654 } 655 656 dapl_os_unlock(&wqhdr->wq_wrid_lock->wrl_lock); 657 658 return (consume_wqhdr); 659 } 660 661 /* 662 * dapls_tavor_srq_wrid_init() 663 */ 664 DAT_RETURN 665 dapls_tavor_srq_wrid_init(ib_srq_handle_t srq) 666 { 667 dapls_tavor_wrid_list_hdr_t *wridlist; 668 int i; 669 670 wridlist = dapli_tavor_wrid_get_list(srq->srq_wq_numwqe, 1); 671 672 673 if (wridlist == NULL) { 674 srq->srq_wridlist = NULL; 675 return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); 676 } 677 678 /* initialize the free list with the descriptor addresses */ 679 wridlist->wl_free_list[0] = srq->srq_wq_desc_addr; 680 for (i = 1; i < srq->srq_wq_numwqe; i++) { 681 wridlist->wl_free_list[i] = wridlist->wl_free_list[i-1] + 682 srq->srq_wq_wqesz; 683 } 684 wridlist->wl_srq_wqesz = srq->srq_wq_wqesz; 685 wridlist->wl_srq_desc_addr = srq->srq_wq_desc_addr; 686 687 srq->srq_wridlist = wridlist; 688 return (DAT_SUCCESS); 689 } 690 691 void 692 dapls_tavor_srq_wrid_free(ib_srq_handle_t srq) 693 { 694 dapls_tavor_wrid_list_hdr_t *wridlist; 695 size_t size = 0; 696 697 wridlist = srq->srq_wridlist; 698 if (wridlist) { 699 dapl_os_assert(wridlist->wl_srq_en == 1); 700 if (wridlist->wl_wre) { 701 dapl_os_free(wridlist->wl_wre, wridlist->wl_size * 702 sizeof (dapls_tavor_wrid_entry_t)); 703 } 704 if (wridlist->wl_free_list) { 705 dapl_os_free(wridlist->wl_free_list, wridlist->wl_size * 706 sizeof (uint32_t)); 707 } 708 if (wridlist->wl_lock) { 709 dapl_os_assert(wridlist->wl_lock->wrl_on_srq == 1); 710 dapl_os_lock_destroy(&wridlist->wl_lock->wrl_lock); 711 size = sizeof (dapls_tavor_wrid_lock_t); 712 } 713 size = size; /* pacify lint */ 714 dapl_os_free(wridlist, size + 715 sizeof (dapls_tavor_wrid_list_hdr_t)); 716 srq->srq_wridlist = NULL; 717 } 718 } 719 720 721 /* 722 * dapls_tavor_wrid_init() 723 */ 724 DAT_RETURN 725 dapls_tavor_wrid_init(ib_qp_handle_t qp) 726 { 727 dapls_tavor_workq_hdr_t *swq; 728 dapls_tavor_workq_hdr_t *rwq; 729 dapls_tavor_wrid_list_hdr_t *s_wridlist; 730 dapls_tavor_wrid_list_hdr_t *r_wridlist; 731 uint_t create_new_swq = 0; 732 uint_t create_new_rwq = 0; 733 734 /* 735 * For each of this QP's Work Queues, make sure we have a (properly 736 * initialized) Work Request ID list attached to the relevant 737 * completion queue. Grab the CQ lock(s) before manipulating the 738 * lists. 739 */ 740 dapli_tavor_wrid_wqhdr_lock_both(qp); 741 swq = dapli_tavor_wrid_wqhdr_find(qp->qp_sq_cqhdl, qp->qp_num, 742 TAVOR_WR_SEND); 743 if (swq == NULL) { 744 /* Couldn't find matching work queue header, create it */ 745 create_new_swq = 1; 746 swq = dapli_tavor_wrid_wqhdr_create(qp->qp_sq_cqhdl, 747 qp->qp_num, TAVOR_WR_SEND, 1); 748 if (swq == NULL) { 749 /* 750 * If we couldn't find/allocate space for the workq 751 * header, then drop the lock(s) and return failure. 752 */ 753 dapli_tavor_wrid_wqhdr_unlock_both(qp); 754 return (DAT_INSUFFICIENT_RESOURCES); 755 } 756 } 757 qp->qp_sq_wqhdr = swq; 758 swq->wq_size = qp->qp_sq_numwqe; 759 swq->wq_head = 0; 760 swq->wq_tail = 0; 761 swq->wq_full = 0; 762 763 /* 764 * Allocate space for the dapls_tavor_wrid_entry_t container 765 */ 766 s_wridlist = dapli_tavor_wrid_get_list(swq->wq_size, 0); 767 if (s_wridlist == NULL) { 768 /* 769 * If we couldn't allocate space for tracking the WRID 770 * entries, then cleanup the workq header from above (if 771 * necessary, i.e. if we created the workq header). Then 772 * drop the lock(s) and return failure. 773 */ 774 if (create_new_swq) { 775 dapli_tavor_cq_wqhdr_remove(qp->qp_sq_cqhdl, swq); 776 } 777 778 dapli_tavor_wrid_wqhdr_unlock_both(qp); 779 return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); 780 } 781 s_wridlist->wl_wqhdr = swq; 782 /* Chain the new WRID list container to the workq hdr list */ 783 dapl_os_lock(&swq->wq_wrid_lock->wrl_lock); 784 dapli_tavor_wrid_wqhdr_add(swq, s_wridlist); 785 dapl_os_unlock(&swq->wq_wrid_lock->wrl_lock); 786 787 788 /* 789 * Now we repeat all the above operations for the receive work queue 790 */ 791 rwq = dapli_tavor_wrid_wqhdr_find(qp->qp_rq_cqhdl, qp->qp_num, 792 TAVOR_WR_RECV); 793 if (rwq == NULL) { 794 create_new_rwq = 1; 795 /* if qp is attached to an SRQ don't need to alloc wrid_lock */ 796 rwq = dapli_tavor_wrid_wqhdr_create(qp->qp_rq_cqhdl, 797 qp->qp_num, TAVOR_WR_RECV, qp->qp_srq_enabled ? 0 : 1); 798 if (rwq == NULL) { 799 /* 800 * If we couldn't find/allocate space for the workq 801 * header, then free all the send queue resources we 802 * just allocated and setup (above), drop the lock(s) 803 * and return failure. 804 */ 805 dapl_os_lock(&swq->wq_wrid_lock->wrl_lock); 806 dapli_tavor_wrid_wqhdr_remove(swq, s_wridlist); 807 dapl_os_unlock(&swq->wq_wrid_lock->wrl_lock); 808 if (create_new_swq) { 809 dapli_tavor_cq_wqhdr_remove(qp->qp_sq_cqhdl, 810 swq); 811 } 812 813 dapli_tavor_wrid_wqhdr_unlock_both(qp); 814 return (DAT_INSUFFICIENT_RESOURCES | 815 DAT_RESOURCE_MEMORY); 816 } 817 } 818 qp->qp_rq_wqhdr = rwq; 819 rwq->wq_size = qp->qp_rq_numwqe; 820 rwq->wq_head = 0; 821 rwq->wq_tail = 0; 822 rwq->wq_full = 0; 823 824 /* 825 * Allocate space for the dapls_tavor_wrid_entry_t container 826 * For qp associated with SRQs the SRQ wridlist is used 827 */ 828 if (qp->qp_srq_enabled) { 829 /* Use existing srq_wridlist pointer */ 830 r_wridlist = qp->qp_srq->srq_wridlist; 831 dapl_os_assert(r_wridlist != NULL); 832 /* store the wl_lock in the wqhdr */ 833 rwq->wq_wrid_lock = r_wridlist->wl_lock; 834 dapl_os_assert(rwq->wq_wrid_lock != NULL); 835 } else { 836 /* Allocate memory for the r_wridlist */ 837 r_wridlist = dapli_tavor_wrid_get_list(rwq->wq_size, 0); 838 } 839 if (r_wridlist == NULL) { 840 /* 841 * If we couldn't allocate space for tracking the WRID 842 * entries, then cleanup all the stuff from above. Then 843 * drop the lock(s) and return failure. 844 */ 845 dapl_os_lock(&swq->wq_wrid_lock->wrl_lock); 846 dapli_tavor_wrid_wqhdr_remove(swq, s_wridlist); 847 dapl_os_unlock(&swq->wq_wrid_lock->wrl_lock); 848 if (create_new_swq) { 849 dapli_tavor_cq_wqhdr_remove(qp->qp_sq_cqhdl, swq); 850 } 851 if (create_new_rwq) { 852 dapli_tavor_cq_wqhdr_remove(qp->qp_rq_cqhdl, rwq); 853 } 854 855 dapli_tavor_wrid_wqhdr_unlock_both(qp); 856 return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); 857 } 858 859 /* For SRQ based QPs r_wridlist does not point to recv wqhdr */ 860 if (!qp->qp_srq_enabled) { 861 r_wridlist->wl_wqhdr = rwq; 862 } 863 864 /* Chain the new WRID list "container" to the workq hdr list */ 865 dapl_os_lock(&rwq->wq_wrid_lock->wrl_lock); 866 dapli_tavor_wrid_wqhdr_add(rwq, r_wridlist); 867 dapl_os_unlock(&rwq->wq_wrid_lock->wrl_lock); 868 869 dapli_tavor_wrid_wqhdr_unlock_both(qp); 870 871 return (DAT_SUCCESS); 872 } 873 874 875 /* 876 * dapls_tavor_wrid_cleanup() 877 */ 878 void 879 dapls_tavor_wrid_cleanup(DAPL_EP *ep, ib_qp_handle_t qp) 880 { 881 /* 882 * For each of this QP's Work Queues, move the WRID "container" to 883 * the "reapable" list. Although there may still be unpolled 884 * entries in these containers, it is not a big deal. We will not 885 * reap the list until either the Poll CQ command detects an empty 886 * condition or the CQ itself is freed. Grab the CQ lock(s) before 887 * manipulating the lists. 888 */ 889 dapli_tavor_wrid_wqhdr_lock_both(qp); 890 dapli_tavor_wrid_reaplist_add(qp->qp_sq_cqhdl, qp->qp_sq_wqhdr); 891 892 /* 893 * Repeat the above operation for the Recv work queue "container". 894 * However for qps with SRQ we flush the cq entries, remove the 895 * wridlist and wqhdr. 896 * Then drop the CQ lock(s) and return 897 */ 898 if (qp->qp_srq_enabled) { 899 /* 900 * Pull off all (if any) entries for this QP from CQ. This 901 * only includes entries that have not yet been polled 902 */ 903 dapl_os_lock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock); 904 DAPL_FLUSH(ep)(qp); 905 906 /* Remove wridlist from WQHDR */ 907 dapli_tavor_wrid_wqhdr_remove(qp->qp_rq_wqhdr, 908 qp->qp_rq_wqhdr->wq_wrid_post); 909 910 dapl_os_assert(qp->qp_rq_wqhdr->wq_wrid_post == NULL); 911 912 dapl_os_unlock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock); 913 914 /* Free the WQHDR */ 915 dapli_tavor_cq_wqhdr_remove(qp->qp_rq_cqhdl, qp->qp_rq_wqhdr); 916 } else { 917 dapli_tavor_wrid_reaplist_add(qp->qp_rq_cqhdl, qp->qp_rq_wqhdr); 918 } 919 dapli_tavor_wrid_wqhdr_unlock_both(qp); 920 } 921 922 /* 923 * dapli_tavor_wrid_wqhdr_create() 924 */ 925 static dapls_tavor_workq_hdr_t * 926 dapli_tavor_wrid_wqhdr_create(ib_cq_handle_t cq, uint_t qpn, 927 uint_t send_or_recv, uint_t alloc_wrl) 928 { 929 dapls_tavor_workq_hdr_t *wqhdr_tmp; 930 size_t size, aligned_size; 931 932 /* dapl_os_assert(MUTEX_HELD(&cq->cq_wrid_wqhdr_lock)); */ 933 934 /* 935 * Allocate space for a work queue header structure and initialize it. 936 * Each work queue header structure includes a "wq_wrid_lock" 937 * which needs to be initialized. 938 * 939 * Note: the address smashing is needed to ensure wq_wrid_lock is 940 * 8-byte aligned, which is not always the case on 32-bit sparc. 941 */ 942 size = (sizeof (dapls_tavor_workq_hdr_t) + 0x7) & ~0x7; 943 aligned_size = size; 944 if (alloc_wrl) { 945 /* for non-srq wqhdr the lock is allocated with the wqhdr */ 946 size = size + sizeof (dapls_tavor_wrid_lock_t); 947 } 948 wqhdr_tmp = dapl_os_alloc(size); 949 if (wqhdr_tmp == NULL) { 950 return (NULL); 951 } 952 if (alloc_wrl) { 953 wqhdr_tmp->wq_wrid_lock = (dapls_tavor_wrid_lock_t *) 954 (((uintptr_t)wqhdr_tmp + aligned_size) & ~0x7); 955 dapl_os_lock_init(&wqhdr_tmp->wq_wrid_lock->wrl_lock); 956 /* wrl allocated with wqhdr don't have srq enabled */ 957 wqhdr_tmp->wq_wrid_lock->wrl_on_srq = 0; 958 } 959 960 wqhdr_tmp->wq_qpn = qpn; 961 wqhdr_tmp->wq_send_or_recv = send_or_recv; 962 963 wqhdr_tmp->wq_wrid_poll = NULL; 964 wqhdr_tmp->wq_wrid_post = NULL; 965 966 /* Chain the newly allocated work queue header to the CQ's list */ 967 if (dapli_tavor_cq_wqhdr_add(cq, wqhdr_tmp) != DAT_SUCCESS) { 968 if (alloc_wrl) { 969 dapl_os_lock_destroy(&wqhdr_tmp->wq_wrid_lock-> 970 wrl_lock); 971 } 972 dapl_os_free(wqhdr_tmp, size); 973 wqhdr_tmp = NULL; 974 } 975 976 return (wqhdr_tmp); 977 } 978 979 /* 980 * dapli_tavor_wrid_wqhdr_add() 981 */ 982 static void 983 dapli_tavor_wrid_wqhdr_add(dapls_tavor_workq_hdr_t *wqhdr, 984 dapls_tavor_wrid_list_hdr_t *wridlist) 985 { 986 /* dapl_os_assert(MUTEX_HELD(&wqhdr->wq_wrid_lock)); */ 987 988 /* Chain the new WRID list "container" to the work queue list */ 989 if ((wqhdr->wq_wrid_post == NULL) && 990 (wqhdr->wq_wrid_poll == NULL)) { 991 wqhdr->wq_wrid_poll = wridlist; 992 wqhdr->wq_wrid_post = wridlist; 993 } else { 994 wqhdr->wq_wrid_post->wl_next = wridlist; 995 wridlist->wl_prev = wqhdr->wq_wrid_post; 996 wqhdr->wq_wrid_post = wridlist; 997 } 998 } 999 1000 1001 /* 1002 * dapli_tavor_wrid_wqhdr_remove() 1003 * Note: this is only called to remove the most recently added WRID list 1004 * container. 1005 */ 1006 static void 1007 dapli_tavor_wrid_wqhdr_remove(dapls_tavor_workq_hdr_t *wqhdr, 1008 dapls_tavor_wrid_list_hdr_t *wridlist) 1009 { 1010 dapls_tavor_wrid_list_hdr_t *prev, *next; 1011 1012 /* dapl_os_assert(MUTEX_HELD(&wqhdr->wq_wrid_lock)); */ 1013 1014 /* Unlink the WRID list "container" from the work queue list */ 1015 prev = wridlist->wl_prev; 1016 next = wridlist->wl_next; 1017 if (prev != NULL) { 1018 prev->wl_next = next; 1019 } 1020 if (next != NULL) { 1021 next->wl_prev = prev; 1022 } 1023 1024 /* 1025 * Update any pointers in the work queue hdr that may point to this 1026 * WRID list container 1027 */ 1028 if (wqhdr->wq_wrid_post == wridlist) { 1029 wqhdr->wq_wrid_post = prev; 1030 } 1031 if (wqhdr->wq_wrid_poll == wridlist) { 1032 wqhdr->wq_wrid_poll = NULL; 1033 } 1034 } 1035 1036 1037 /* 1038 * dapli_tavor_wrid_wqhdr_lock_both() 1039 */ 1040 static void 1041 dapli_tavor_wrid_wqhdr_lock_both(ib_qp_handle_t qp) 1042 { 1043 ib_cq_handle_t sq_cq, rq_cq; 1044 1045 sq_cq = qp->qp_sq_cqhdl; 1046 rq_cq = qp->qp_rq_cqhdl; 1047 1048 /* 1049 * If both work queues (send and recv) share a completion queue, then 1050 * grab the common lock. If they use different CQs (hence different 1051 * "cq_wrid_wqhdr_list" locks), then grab the send one first, then the 1052 * receive. We do this consistently and correctly in 1053 * tavor_wrid_wqhdr_unlock_both() below to avoid introducing any kind 1054 * of dead lock condition. 1055 */ 1056 if (sq_cq == rq_cq) { 1057 dapl_os_lock(&sq_cq->cq_wrid_wqhdr_lock); 1058 } else { 1059 dapl_os_lock(&sq_cq->cq_wrid_wqhdr_lock); 1060 dapl_os_lock(&rq_cq->cq_wrid_wqhdr_lock); 1061 } 1062 } 1063 1064 /* 1065 * dapli_tavor_wrid_wqhdr_unlock_both() 1066 */ 1067 static void 1068 dapli_tavor_wrid_wqhdr_unlock_both(ib_qp_handle_t qp) 1069 { 1070 ib_cq_handle_t sq_cq, rq_cq; 1071 1072 sq_cq = qp->qp_sq_cqhdl; 1073 rq_cq = qp->qp_rq_cqhdl; 1074 1075 /* 1076 * See tavor_wrid_wqhdr_lock_both() above for more detail 1077 */ 1078 if (sq_cq == rq_cq) { 1079 dapl_os_unlock(&sq_cq->cq_wrid_wqhdr_lock); 1080 } else { 1081 dapl_os_unlock(&rq_cq->cq_wrid_wqhdr_lock); 1082 dapl_os_unlock(&sq_cq->cq_wrid_wqhdr_lock); 1083 } 1084 } 1085 1086 1087 /* 1088 * dapli_tavor_cq_wqhdr_add() 1089 */ 1090 static DAT_RETURN 1091 dapli_tavor_cq_wqhdr_add(ib_cq_handle_t cq, dapls_tavor_workq_hdr_t *wqhdr) 1092 { 1093 DAPL_HASH_KEY key; 1094 1095 /* dapl_os_assert(MUTEX_HELD(&cq->cq_wrid_wqhdr_lock)); */ 1096 1097 /* 1098 * If the CQ's work queue list is empty, then just add it. 1099 * Otherwise, chain it to the beginning of the list. 1100 */ 1101 key = (DAPL_HASH_KEY)(((uint64_t)wqhdr->wq_send_or_recv << 32) | 1102 wqhdr->wq_qpn); 1103 1104 return (dapls_hash_insert(cq->cq_wrid_wqhdr_list, key, wqhdr)); 1105 } 1106 1107 1108 /* 1109 * dapli_tavor_cq_wqhdr_remove 1110 */ 1111 static void 1112 dapli_tavor_cq_wqhdr_remove(ib_cq_handle_t cq, dapls_tavor_workq_hdr_t *wqhdr) 1113 { 1114 DAPL_HASH_DATA curr; 1115 DAPL_HASH_KEY key; 1116 size_t size = 0; 1117 1118 /* dapl_os_assert(MUTEX_HELD(&cq->cq_wrid_wqhdr_lock)); */ 1119 1120 /* Remove "wqhdr" from the work queue header list on "cq" */ 1121 1122 key = (DAPL_HASH_KEY)(((uint64_t)wqhdr->wq_send_or_recv << 32) | 1123 wqhdr->wq_qpn); 1124 1125 (void) dapls_hash_remove(cq->cq_wrid_wqhdr_list, key, &curr); 1126 1127 size = (sizeof (dapls_tavor_workq_hdr_t) + 0x7) & ~0x7; 1128 if (wqhdr->wq_wrid_lock && (!wqhdr->wq_wrid_lock->wrl_on_srq)) { 1129 dapl_os_lock_destroy(&wqhdr->wq_wrid_lock->wrl_lock); 1130 size += sizeof (dapls_tavor_wrid_lock_t); 1131 } 1132 1133 /* Free the memory associated with "wqhdr" */ 1134 dapl_os_free(wqhdr, size); 1135 } 1136 1137 /* 1138 * dapls_tavor_srq_wrid_resize() is called to resize the wridlist 1139 * associated with SRQS as a result of dat_srq_resize(). 1140 * 1141 * Returns: DAT_TRUE if successful, otherwise DAT_FALSE 1142 */ 1143 DAT_BOOLEAN 1144 dapls_tavor_srq_wrid_resize(ib_srq_handle_t srq_handle, uint32_t new_size) 1145 { 1146 dapls_tavor_wrid_list_hdr_t *wridlist; 1147 dapls_tavor_wrid_entry_t *old_wl_wre; 1148 dapls_tavor_wrid_entry_t *new_wl_wre; 1149 uint32_t *old_wl_freel; 1150 uint32_t *new_wl_freel; 1151 uint32_t old_size; 1152 uint32_t idx; 1153 uint32_t prev_idx; 1154 uint32_t i; 1155 1156 wridlist = srq_handle->srq_wridlist; 1157 1158 if (wridlist == NULL) { 1159 return (DAT_FALSE); 1160 } 1161 dapl_os_assert(wridlist->wl_srq_en); 1162 1163 dapl_os_lock(&wridlist->wl_lock->wrl_lock); 1164 1165 old_wl_wre = wridlist->wl_wre; 1166 old_wl_freel = wridlist->wl_free_list; 1167 old_size = wridlist->wl_size; 1168 1169 new_wl_wre = (dapls_tavor_wrid_entry_t *)dapl_os_alloc(new_size * 1170 sizeof (dapls_tavor_wrid_entry_t)); 1171 if (new_wl_wre == NULL) { 1172 goto bail; 1173 } 1174 new_wl_freel = dapl_os_alloc(new_size * sizeof (uint32_t)); 1175 if (new_wl_freel == NULL) { 1176 goto bail; 1177 } 1178 /* 1179 * we just need to copy the old WREs to the new array. Since the 1180 * descriptors are relatively addressed the descriptor to index 1181 * mapping doesn't change. 1182 */ 1183 (void) dapl_os_memcpy(&new_wl_wre[0], &old_wl_wre[0], 1184 old_size * sizeof (dapls_tavor_wrid_entry_t)); 1185 /* 1186 * Copy the old free list to the new one 1187 */ 1188 idx = wridlist->wl_freel_head; 1189 for (i = 0; i < wridlist->wl_freel_entries; i++) { 1190 new_wl_freel[i] = old_wl_freel[idx]; 1191 idx = (idx + 1) % old_size; 1192 } 1193 /* 1194 * Add the new entries in wl_wre to the new free list 1195 */ 1196 idx = wridlist->wl_freel_entries; 1197 new_wl_freel[idx] = wridlist->wl_srq_desc_addr + old_size * 1198 wridlist->wl_srq_wqesz; 1199 prev_idx = idx; 1200 idx = (idx + 1) % new_size; 1201 for (i = 0; i < new_size - old_size - 1; i++) { 1202 new_wl_freel[idx] = new_wl_freel[prev_idx] + 1203 wridlist->wl_srq_wqesz; 1204 prev_idx = idx; 1205 idx = (idx + 1) % new_size; 1206 } 1207 wridlist->wl_size = new_size; 1208 wridlist->wl_wre = new_wl_wre; 1209 wridlist->wl_free_list = new_wl_freel; 1210 wridlist->wl_freel_head = 0; 1211 wridlist->wl_freel_tail = idx; 1212 wridlist->wl_freel_entries = wridlist->wl_freel_entries + new_size - 1213 old_size; 1214 1215 dapl_os_unlock(&wridlist->wl_lock->wrl_lock); 1216 1217 if (old_wl_wre) { 1218 dapl_os_free(old_wl_wre, old_size * 1219 sizeof (dapls_tavor_wrid_entry_t)); 1220 } 1221 if (old_wl_freel) { 1222 dapl_os_free(old_wl_freel, old_size * sizeof (uint32_t)); 1223 } 1224 return (DAT_TRUE); 1225 bail: 1226 dapl_os_unlock(&wridlist->wl_lock->wrl_lock); 1227 if (new_wl_wre) { 1228 dapl_os_free(new_wl_wre, new_size * 1229 sizeof (dapls_tavor_wrid_entry_t)); 1230 } 1231 return (DAT_FALSE); 1232 } 1233