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 /* 28 * tavor_cmd.c 29 * Tavor Firmware Command Routines 30 * 31 * Implements all the routines necessary for allocating, posting, and 32 * freeing commands for the Tavor firmware. These routines manage a 33 * preallocated list of command mailboxes and provide interfaces to post 34 * each of the several dozen commands to the Tavor firmware. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/conf.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 #include <sys/modctl.h> 42 43 #include <sys/ib/adapters/tavor/tavor.h> 44 45 static int tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist, 46 tavor_mbox_t **mb, uint_t mbox_wait); 47 static void tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb); 48 static int tavor_impl_mboxlist_init(tavor_state_t *state, 49 tavor_mboxlist_t *mblist, uint_t num_mbox, tavor_rsrc_type_t type); 50 static void tavor_impl_mboxlist_fini(tavor_state_t *state, 51 tavor_mboxlist_t *mblist); 52 static int tavor_outstanding_cmd_alloc(tavor_state_t *state, 53 tavor_cmd_t **cmd_ptr, uint_t cmd_wait); 54 static void tavor_outstanding_cmd_free(tavor_state_t *state, 55 tavor_cmd_t **cmd_ptr); 56 static int tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost, 57 uint16_t token); 58 static void tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset, 59 uint_t length, uint_t flag); 60 61 /* 62 * tavor_cmd_post() 63 * Context: Can be called from interrupt or base context. 64 * 65 * The "cp_flags" field in cmdpost 66 * is used to determine whether to wait for an available 67 * outstanding command (if necessary) or to return error. 68 */ 69 int 70 tavor_cmd_post(tavor_state_t *state, tavor_cmd_post_t *cmdpost) 71 { 72 tavor_cmd_t *cmdptr; 73 int status; 74 uint16_t token; 75 76 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost)) 77 78 /* Determine if we are going to spin until completion */ 79 if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) { 80 81 /* Write the command to the HCR */ 82 status = tavor_write_hcr(state, cmdpost, 0); 83 if (status != TAVOR_CMD_SUCCESS) { 84 return (status); 85 } 86 87 return (TAVOR_CMD_SUCCESS); 88 89 } else { /* "TAVOR_CMD_SLEEP_NOSPIN" */ 90 91 ASSERT(TAVOR_SLEEPFLAG_FOR_CONTEXT() != TAVOR_NOSLEEP); 92 93 /* NOTE: Expect threads to be waiting in here */ 94 status = tavor_outstanding_cmd_alloc(state, &cmdptr, 95 cmdpost->cp_flags); 96 if (status != TAVOR_CMD_SUCCESS) { 97 return (status); 98 } 99 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr)) 100 101 /* 102 * Set status to "TAVOR_CMD_INVALID_STATUS". It is 103 * appropriate to do this here without the "cmd_comp_lock" 104 * because this register is overloaded. Later it will be 105 * used to indicate - through a change from this invalid 106 * value to some other value - that the condition variable 107 * has been signaled. Once it has, status will then contain 108 * the _real_ completion status 109 */ 110 cmdptr->cmd_status = TAVOR_CMD_INVALID_STATUS; 111 112 /* Write the command to the HCR */ 113 token = (uint16_t)cmdptr->cmd_indx; 114 status = tavor_write_hcr(state, cmdpost, token); 115 if (status != TAVOR_CMD_SUCCESS) { 116 tavor_outstanding_cmd_free(state, &cmdptr); 117 return (status); 118 } 119 120 /* 121 * cv_wait() on the "command_complete" condition variable. 122 * Note: We have the "__lock_lint" here to workaround warlock. 123 * Since warlock doesn't know that other parts of the Tavor 124 * may occasionally call this routine while holding their own 125 * locks, it complains about this cv_wait. In reality, 126 * however, the rest of the driver never calls this routine 127 * with a lock held unless they pass TAVOR_CMD_NOSLEEP. 128 */ 129 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr)) 130 mutex_enter(&cmdptr->cmd_comp_lock); 131 while (cmdptr->cmd_status == TAVOR_CMD_INVALID_STATUS) { 132 #ifndef __lock_lint 133 cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock); 134 /* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */ 135 #endif 136 } 137 mutex_exit(&cmdptr->cmd_comp_lock); 138 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr)) 139 140 /* 141 * Wake up after command completes (cv_signal). Read status 142 * from the command (success, fail, etc.). It is appropriate 143 * here (as above) to read the status field without the 144 * "cmd_comp_lock" because it is no longer being used to 145 * indicate whether the condition variable has been signaled 146 * (i.e. at this point we are certain that it already has). 147 */ 148 status = cmdptr->cmd_status; 149 150 /* Save the "outparam" values into the cmdpost struct */ 151 cmdpost->cp_outparm = cmdptr->cmd_outparm; 152 153 /* 154 * Add the command back to the "outstanding commands list". 155 * Signal the "cmd_list" condition variable, if necessary. 156 */ 157 tavor_outstanding_cmd_free(state, &cmdptr); 158 159 if (status != TAVOR_CMD_SUCCESS) { 160 return (status); 161 } 162 163 return (TAVOR_CMD_SUCCESS); 164 } 165 } 166 167 168 /* 169 * tavor_mbox_alloc() 170 * Context: Can be called from interrupt or base context. 171 * 172 * The "mbox_wait" parameter is used to determine whether to 173 * wait for a mailbox to become available or not. 174 */ 175 int 176 tavor_mbox_alloc(tavor_state_t *state, tavor_mbox_info_t *mbox_info, 177 uint_t mbox_wait) 178 { 179 int status; 180 uint_t sleep_context; 181 182 sleep_context = TAVOR_SLEEPFLAG_FOR_CONTEXT(); 183 184 /* Allocate an "In" mailbox */ 185 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) { 186 /* Determine correct mboxlist based on calling context */ 187 if (sleep_context == TAVOR_NOSLEEP) { 188 status = tavor_impl_mbox_alloc(state, 189 &state->ts_in_intr_mblist, 190 &mbox_info->mbi_in, mbox_wait); 191 192 ASSERT(status == TAVOR_CMD_SUCCESS); 193 } else { 194 /* NOTE: Expect threads to be waiting in here */ 195 status = tavor_impl_mbox_alloc(state, 196 &state->ts_in_mblist, &mbox_info->mbi_in, 197 mbox_wait); 198 if (status != TAVOR_CMD_SUCCESS) { 199 return (status); 200 } 201 } 202 203 } 204 205 /* Allocate an "Out" mailbox */ 206 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) { 207 /* Determine correct mboxlist based on calling context */ 208 if (sleep_context == TAVOR_NOSLEEP) { 209 status = tavor_impl_mbox_alloc(state, 210 &state->ts_out_intr_mblist, 211 &mbox_info->mbi_out, mbox_wait); 212 213 ASSERT(status == TAVOR_CMD_SUCCESS); 214 } else { 215 /* NOTE: Expect threads to be waiting in here */ 216 status = tavor_impl_mbox_alloc(state, 217 &state->ts_out_mblist, &mbox_info->mbi_out, 218 mbox_wait); 219 if (status != TAVOR_CMD_SUCCESS) { 220 /* If we allocated an "In" mailbox, free it */ 221 if (mbox_info->mbi_alloc_flags & 222 TAVOR_ALLOC_INMBOX) { 223 tavor_impl_mbox_free( 224 &state->ts_in_mblist, 225 &mbox_info->mbi_in); 226 } 227 return (status); 228 } 229 } 230 } 231 232 /* Store appropriate context in mbox_info */ 233 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context)) 234 mbox_info->mbi_sleep_context = sleep_context; 235 236 return (TAVOR_CMD_SUCCESS); 237 } 238 239 240 /* 241 * tavor_mbox_free() 242 * Context: Can be called from interrupt or base context. 243 */ 244 void 245 tavor_mbox_free(tavor_state_t *state, tavor_mbox_info_t *mbox_info) 246 { 247 /* 248 * The mailbox has to be freed in the same context from which it was 249 * allocated. The context is stored in the mbox_info at 250 * tavor_mbox_alloc() time. We check the stored context against the 251 * current context here. 252 */ 253 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context)) 254 ASSERT(mbox_info->mbi_sleep_context == TAVOR_SLEEPFLAG_FOR_CONTEXT()); 255 256 /* Determine correct mboxlist based on calling context */ 257 if (mbox_info->mbi_sleep_context == TAVOR_NOSLEEP) { 258 /* Free the intr "In" mailbox */ 259 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) { 260 tavor_impl_mbox_free(&state->ts_in_intr_mblist, 261 &mbox_info->mbi_in); 262 } 263 264 /* Free the intr "Out" mailbox */ 265 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) { 266 tavor_impl_mbox_free(&state->ts_out_intr_mblist, 267 &mbox_info->mbi_out); 268 } 269 } else { 270 /* Free the "In" mailbox */ 271 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) { 272 tavor_impl_mbox_free(&state->ts_in_mblist, 273 &mbox_info->mbi_in); 274 } 275 276 /* Free the "Out" mailbox */ 277 if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) { 278 tavor_impl_mbox_free(&state->ts_out_mblist, 279 &mbox_info->mbi_out); 280 } 281 } 282 } 283 284 285 /* 286 * tavor_cmd_complete_handler() 287 * Context: Called only from interrupt context. 288 */ 289 int 290 tavor_cmd_complete_handler(tavor_state_t *state, tavor_eqhdl_t eq, 291 tavor_hw_eqe_t *eqe) 292 { 293 tavor_cmd_t *cmdp; 294 uint_t eqe_evttype; 295 296 eqe_evttype = TAVOR_EQE_EVTTYPE_GET(eq, eqe); 297 298 ASSERT(eqe_evttype == TAVOR_EVT_COMMAND_INTF_COMP || 299 eqe_evttype == TAVOR_EVT_EQ_OVERFLOW); 300 301 if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) { 302 tavor_eq_overflow_handler(state, eq, eqe); 303 304 return (DDI_FAILURE); 305 } 306 307 /* 308 * Find the outstanding command pointer based on value returned 309 * in "token" 310 */ 311 cmdp = &state->ts_cmd_list.cml_cmd[TAVOR_EQE_CMDTOKEN_GET(eq, eqe)]; 312 313 /* Signal the waiting thread */ 314 mutex_enter(&cmdp->cmd_comp_lock); 315 cmdp->cmd_outparm = ((uint64_t)TAVOR_EQE_CMDOUTP0_GET(eq, eqe) << 32) | 316 TAVOR_EQE_CMDOUTP1_GET(eq, eqe); 317 cmdp->cmd_status = TAVOR_EQE_CMDSTATUS_GET(eq, eqe); 318 319 cv_signal(&cmdp->cmd_comp_cv); 320 mutex_exit(&cmdp->cmd_comp_lock); 321 322 return (DDI_SUCCESS); 323 } 324 325 326 /* 327 * tavor_inmbox_list_init() 328 * Context: Only called from attach() path context 329 */ 330 int 331 tavor_inmbox_list_init(tavor_state_t *state) 332 { 333 int status; 334 uint_t num_inmbox; 335 336 /* Initialize the "In" mailbox list */ 337 num_inmbox = (1 << state->ts_cfg_profile->cp_log_num_inmbox); 338 status = tavor_impl_mboxlist_init(state, &state->ts_in_mblist, 339 num_inmbox, TAVOR_IN_MBOX); 340 if (status != DDI_SUCCESS) { 341 return (DDI_FAILURE); 342 } 343 344 return (DDI_SUCCESS); 345 } 346 347 348 /* 349 * tavor_intr_inmbox_list_init() 350 * Context: Only called from attach() path context 351 */ 352 int 353 tavor_intr_inmbox_list_init(tavor_state_t *state) 354 { 355 int status; 356 uint_t num_inmbox; 357 358 /* Initialize the interrupt "In" mailbox list */ 359 num_inmbox = (1 << state->ts_cfg_profile->cp_log_num_intr_inmbox); 360 status = tavor_impl_mboxlist_init(state, &state->ts_in_intr_mblist, 361 num_inmbox, TAVOR_INTR_IN_MBOX); 362 if (status != DDI_SUCCESS) { 363 return (DDI_FAILURE); 364 } 365 366 return (DDI_SUCCESS); 367 } 368 369 370 /* 371 * tavor_outmbox_list_init() 372 * Context: Only called from attach() path context 373 */ 374 int 375 tavor_outmbox_list_init(tavor_state_t *state) 376 { 377 int status; 378 uint_t num_outmbox; 379 380 /* Initialize the "Out" mailbox list */ 381 num_outmbox = (1 << state->ts_cfg_profile->cp_log_num_outmbox); 382 status = tavor_impl_mboxlist_init(state, &state->ts_out_mblist, 383 num_outmbox, TAVOR_OUT_MBOX); 384 if (status != DDI_SUCCESS) { 385 return (DDI_FAILURE); 386 } 387 388 return (DDI_SUCCESS); 389 } 390 391 392 /* 393 * tavor_intr_outmbox_list_init() 394 * Context: Only called from attach() path context 395 */ 396 int 397 tavor_intr_outmbox_list_init(tavor_state_t *state) 398 { 399 int status; 400 uint_t num_outmbox; 401 402 /* Initialize the interrupts "Out" mailbox list */ 403 num_outmbox = (1 << state->ts_cfg_profile->cp_log_num_intr_outmbox); 404 status = tavor_impl_mboxlist_init(state, &state->ts_out_intr_mblist, 405 num_outmbox, TAVOR_INTR_OUT_MBOX); 406 if (status != DDI_SUCCESS) { 407 return (DDI_FAILURE); 408 } 409 410 return (DDI_SUCCESS); 411 } 412 413 414 /* 415 * tavor_inmbox_list_fini() 416 * Context: Only called from attach() and/or detach() path contexts 417 */ 418 void 419 tavor_inmbox_list_fini(tavor_state_t *state) 420 { 421 /* Free up the "In" mailbox list */ 422 tavor_impl_mboxlist_fini(state, &state->ts_in_mblist); 423 } 424 425 426 /* 427 * tavor_intr_inmbox_list_fini() 428 * Context: Only called from attach() and/or detach() path contexts 429 */ 430 void 431 tavor_intr_inmbox_list_fini(tavor_state_t *state) 432 { 433 /* Free up the interupts "In" mailbox list */ 434 tavor_impl_mboxlist_fini(state, &state->ts_in_intr_mblist); 435 } 436 437 438 /* 439 * tavor_outmbox_list_fini() 440 * Context: Only called from attach() and/or detach() path contexts 441 */ 442 void 443 tavor_outmbox_list_fini(tavor_state_t *state) 444 { 445 /* Free up the "Out" mailbox list */ 446 tavor_impl_mboxlist_fini(state, &state->ts_out_mblist); 447 } 448 449 450 /* 451 * tavor_intr_outmbox_list_fini() 452 * Context: Only called from attach() and/or detach() path contexts 453 */ 454 void 455 tavor_intr_outmbox_list_fini(tavor_state_t *state) 456 { 457 /* Free up the interrupt "Out" mailbox list */ 458 tavor_impl_mboxlist_fini(state, &state->ts_out_intr_mblist); 459 } 460 461 462 /* 463 * tavor_impl_mbox_alloc() 464 * Context: Can be called from interrupt or base context. 465 */ 466 static int 467 tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist, 468 tavor_mbox_t **mb, uint_t mbox_wait) 469 { 470 tavor_mbox_t *mbox_ptr; 471 uint_t index, next, prev; 472 uint_t count, countmax; 473 474 /* 475 * If the mailbox list is empty, then wait (if appropriate in the 476 * current context). Otherwise, grab the next available mailbox. 477 */ 478 if (mbox_wait == TAVOR_NOSLEEP) { 479 count = 0; 480 countmax = state->ts_cfg_profile->cp_cmd_poll_max; 481 482 mutex_enter(&mblist->mbl_lock); 483 mblist->mbl_pollers++; 484 while (mblist->mbl_entries_free == 0) { 485 mutex_exit(&mblist->mbl_lock); 486 /* Delay loop polling for an available mbox */ 487 if (++count > countmax) { 488 return (TAVOR_CMD_INSUFF_RSRC); 489 } 490 491 /* Delay before polling for mailbox again */ 492 drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay); 493 mutex_enter(&mblist->mbl_lock); 494 } 495 mblist->mbl_pollers--; 496 497 /* TAVOR_SLEEP */ 498 } else { 499 /* 500 * Grab lock here as we prepare to cv_wait if needed. 501 */ 502 mutex_enter(&mblist->mbl_lock); 503 while (mblist->mbl_entries_free == 0) { 504 /* 505 * Wait (on cv) for a mailbox to become free. Note: 506 * Just as we do above in tavor_cmd_post(), we also 507 * have the "__lock_lint" here to workaround warlock. 508 * Warlock doesn't know that other parts of the Tavor 509 * may occasionally call this routine while holding 510 * their own locks, so it complains about this cv_wait. 511 * In reality, however, the rest of the driver never 512 * calls this routine with a lock held unless they pass 513 * TAVOR_CMD_NOSLEEP. 514 */ 515 mblist->mbl_waiters++; 516 #ifndef __lock_lint 517 cv_wait(&mblist->mbl_cv, &mblist->mbl_lock); 518 #endif 519 } 520 } 521 522 /* Grab the next available mailbox from list */ 523 mbox_ptr = mblist->mbl_mbox; 524 index = mblist->mbl_head_indx; 525 next = mbox_ptr[index].mb_next; 526 prev = mbox_ptr[index].mb_prev; 527 528 /* Remove it from the mailbox list */ 529 mblist->mbl_mbox[next].mb_prev = prev; 530 mblist->mbl_mbox[prev].mb_next = next; 531 mblist->mbl_head_indx = next; 532 533 /* Update the "free" count and return the mailbox pointer */ 534 mblist->mbl_entries_free--; 535 *mb = &mbox_ptr[index]; 536 537 mutex_exit(&mblist->mbl_lock); 538 539 return (TAVOR_CMD_SUCCESS); 540 } 541 542 543 /* 544 * tavor_impl_mbox_free() 545 * Context: Can be called from interrupt or base context. 546 */ 547 static void 548 tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb) 549 { 550 uint_t mbox_indx; 551 552 mutex_enter(&mblist->mbl_lock); 553 554 /* Pull the "index" from mailbox entry */ 555 mbox_indx = (*mb)->mb_indx; 556 557 /* 558 * If mailbox list is not empty, then insert the entry. Otherwise, 559 * this is the only entry. So update the pointers appropriately. 560 */ 561 if (mblist->mbl_entries_free++ != 0) { 562 /* Update the current mailbox */ 563 (*mb)->mb_next = mblist->mbl_head_indx; 564 (*mb)->mb_prev = mblist->mbl_tail_indx; 565 566 /* Update head and tail mailboxes */ 567 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx; 568 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx; 569 570 /* Update tail index */ 571 mblist->mbl_tail_indx = mbox_indx; 572 573 } else { 574 /* Update the current mailbox */ 575 (*mb)->mb_next = mbox_indx; 576 (*mb)->mb_prev = mbox_indx; 577 578 /* Update head and tail indexes */ 579 mblist->mbl_tail_indx = mbox_indx; 580 mblist->mbl_head_indx = mbox_indx; 581 } 582 583 /* 584 * Because we can have both waiters (SLEEP treads waiting for a 585 * cv_signal to continue processing) and pollers (NOSLEEP treads 586 * polling for a mailbox to become available), we try to share CPU time 587 * between them. We do this by signalling the waiters only every other 588 * call to mbox_free. This gives the pollers a chance to get some CPU 589 * time to do their command. If we signalled every time, the pollers 590 * would have a much harder time getting CPU time. 591 * 592 * If there are waiters and no pollers, then we signal always. 593 * 594 * Otherwise, if there are either no waiters, there may in fact be 595 * pollers, so we do not signal in that case. 596 */ 597 if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) { 598 /* flip the signal value */ 599 mblist->mbl_signal = (mblist->mbl_signal + 1) % 2; 600 } else if (mblist->mbl_waiters > 0) { 601 mblist->mbl_signal = 1; 602 } else { 603 mblist->mbl_signal = 0; 604 } 605 606 /* 607 * Depending on the conditions in the previous check, we signal only if 608 * we are supposed to. 609 */ 610 if (mblist->mbl_signal) { 611 mblist->mbl_waiters--; 612 cv_signal(&mblist->mbl_cv); 613 } 614 615 /* Clear out the mailbox entry pointer */ 616 *mb = NULL; 617 618 mutex_exit(&mblist->mbl_lock); 619 } 620 621 622 /* 623 * tavor_impl_mboxlist_init() 624 * Context: Only called from attach() path context 625 */ 626 static int 627 tavor_impl_mboxlist_init(tavor_state_t *state, tavor_mboxlist_t *mblist, 628 uint_t num_mbox, tavor_rsrc_type_t type) 629 { 630 tavor_rsrc_t *rsrc; 631 ddi_dma_cookie_t dma_cookie; 632 uint_t dma_cookiecnt, flag, sync; 633 int status, i; 634 635 /* Allocate the memory for the mailbox entries list */ 636 mblist->mbl_list_sz = num_mbox; 637 mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz * 638 sizeof (tavor_mbox_t), KM_SLEEP); 639 640 /* Initialize the mailbox entries list */ 641 mblist->mbl_head_indx = 0; 642 mblist->mbl_tail_indx = mblist->mbl_list_sz - 1; 643 mblist->mbl_entries_free = mblist->mbl_list_sz; 644 mblist->mbl_waiters = 0; 645 mblist->mbl_num_alloc = 0; 646 647 /* Set up the mailbox list's cv and mutex */ 648 mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER, 649 DDI_INTR_PRI(state->ts_intrmsi_pri)); 650 cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL); 651 652 /* Determine if syncs will be necessary */ 653 sync = TAVOR_MBOX_IS_SYNC_REQ(state, type); 654 655 /* Determine whether to map DDI_DMA_STREAMING or DDI_DMA_CONSISTENT */ 656 flag = state->ts_cfg_profile->cp_streaming_consistent; 657 658 /* Initialize the mailbox list entries */ 659 for (i = 0; i < mblist->mbl_list_sz; i++) { 660 /* Allocate resources for the mailbox */ 661 status = tavor_rsrc_alloc(state, type, 1, TAVOR_SLEEP, 662 &rsrc); 663 if (status != DDI_SUCCESS) { 664 /* Jump to cleanup and return error */ 665 goto mboxlist_init_fail; 666 } 667 668 /* Save away the mailbox resource info */ 669 mblist->mbl_mbox[i].mb_rsrcptr = rsrc; 670 mblist->mbl_mbox[i].mb_addr = rsrc->tr_addr; 671 mblist->mbl_mbox[i].mb_acchdl = rsrc->tr_acchdl; 672 673 /* 674 * Get a PCI mapped address for each mailbox. Note: this 675 * uses the ddi_dma_handle return from the resource 676 * allocation routine 677 */ 678 status = ddi_dma_addr_bind_handle(rsrc->tr_dmahdl, NULL, 679 rsrc->tr_addr, rsrc->tr_len, (DDI_DMA_RDWR | flag), 680 DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt); 681 if (status != DDI_SUCCESS) { 682 /* Jump to cleanup and return error */ 683 tavor_rsrc_free(state, &rsrc); 684 goto mboxlist_init_fail; 685 } 686 687 /* Save away the mapped address for the mailbox */ 688 mblist->mbl_mbox[i].mb_mapaddr = dma_cookie.dmac_laddress; 689 690 /* Set sync flag appropriately */ 691 mblist->mbl_mbox[i].mb_sync = sync; 692 693 /* Make each entry point to the "next" and "prev" entries */ 694 mblist->mbl_mbox[i].mb_next = i+1; 695 mblist->mbl_mbox[i].mb_prev = i-1; 696 mblist->mbl_mbox[i].mb_indx = i; 697 mblist->mbl_num_alloc = i + 1; 698 } 699 700 /* Make the "head" and "tail" entries point to each other */ 701 mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = 702 mblist->mbl_tail_indx; 703 mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = 704 mblist->mbl_head_indx; 705 706 return (DDI_SUCCESS); 707 708 mboxlist_init_fail: 709 tavor_impl_mboxlist_fini(state, mblist); 710 711 return (DDI_FAILURE); 712 } 713 714 715 /* 716 * tavor_impl_mboxlist_fini() 717 * Context: Only called from attach() and/or detach() path contexts 718 */ 719 static void 720 tavor_impl_mboxlist_fini(tavor_state_t *state, tavor_mboxlist_t *mblist) 721 { 722 tavor_rsrc_t *rsrc; 723 int i, status; 724 725 /* Release the resources for each of the mailbox list entries */ 726 for (i = 0; i < mblist->mbl_num_alloc; i++) { 727 rsrc = mblist->mbl_mbox[i].mb_rsrcptr; 728 729 /* 730 * First, unbind the DMA memory for the mailbox 731 * 732 * Note: The only way ddi_dma_unbind_handle() currently 733 * can return an error is if the handle passed in is invalid. 734 * Since this should never happen, we choose to return void 735 * from this function! If this does return an error, 736 * however, then we print a warning message to the console. 737 */ 738 status = ddi_dma_unbind_handle(rsrc->tr_dmahdl); 739 if (status != DDI_SUCCESS) { 740 TAVOR_WARNING(state, "failed to unbind DMA mapping"); 741 return; 742 } 743 744 /* Next, free the mailbox resource */ 745 tavor_rsrc_free(state, &rsrc); 746 } 747 748 /* Destroy the mailbox list mutex and cv */ 749 mutex_destroy(&mblist->mbl_lock); 750 cv_destroy(&mblist->mbl_cv); 751 752 /* Free up the memory for tracking the mailbox list */ 753 kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz * 754 sizeof (tavor_mbox_t)); 755 } 756 757 758 /* 759 * tavor_outstanding_cmd_alloc() 760 * Context: Can be called only from base context. 761 */ 762 static int 763 tavor_outstanding_cmd_alloc(tavor_state_t *state, tavor_cmd_t **cmd_ptr, 764 uint_t cmd_wait) 765 { 766 tavor_cmdlist_t *cmd_list; 767 uint_t next, prev, head; 768 769 cmd_list = &state->ts_cmd_list; 770 mutex_enter(&cmd_list->cml_lock); 771 772 /* Ensure that outstanding commands are supported */ 773 ASSERT(cmd_list->cml_num_alloc != 0); 774 775 /* 776 * If the outstanding command list is empty, then wait (if 777 * appropriate in the current context). Otherwise, grab the 778 * next available command. 779 */ 780 while (cmd_list->cml_entries_free == 0) { 781 /* No free commands */ 782 if (cmd_wait == TAVOR_NOSLEEP) { 783 mutex_exit(&cmd_list->cml_lock); 784 return (TAVOR_CMD_INSUFF_RSRC); 785 } 786 787 /* 788 * Wait (on cv) for a command to become free. Note: Just 789 * as we do above in tavor_cmd_post(), we also have the 790 * "__lock_lint" here to workaround warlock. Warlock doesn't 791 * know that other parts of the Tavor may occasionally call 792 * this routine while holding their own locks, so it complains 793 * about this cv_wait. In reality, however, the rest of the 794 * driver never calls this routine with a lock held unless 795 * they pass TAVOR_CMD_NOSLEEP. 796 */ 797 cmd_list->cml_waiters++; 798 #ifndef __lock_lint 799 cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock); 800 #endif 801 } 802 803 /* Grab the next available command from the list */ 804 head = cmd_list->cml_head_indx; 805 *cmd_ptr = &cmd_list->cml_cmd[head]; 806 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr)) 807 next = (*cmd_ptr)->cmd_next; 808 prev = (*cmd_ptr)->cmd_prev; 809 (*cmd_ptr)->cmd_status = TAVOR_CMD_INVALID_STATUS; 810 811 /* Remove it from the command list */ 812 cmd_list->cml_cmd[next].cmd_prev = prev; 813 cmd_list->cml_cmd[prev].cmd_next = next; 814 cmd_list->cml_head_indx = next; 815 816 /* Update the "free" count and return */ 817 cmd_list->cml_entries_free--; 818 819 mutex_exit(&cmd_list->cml_lock); 820 821 return (TAVOR_CMD_SUCCESS); 822 } 823 824 825 /* 826 * tavor_outstanding_cmd_free() 827 * Context: Can be called only from base context. 828 */ 829 static void 830 tavor_outstanding_cmd_free(tavor_state_t *state, tavor_cmd_t **cmd_ptr) 831 { 832 tavor_cmdlist_t *cmd_list; 833 uint_t cmd_indx; 834 835 cmd_list = &state->ts_cmd_list; 836 mutex_enter(&cmd_list->cml_lock); 837 838 /* Pull the "index" from command entry */ 839 cmd_indx = (*cmd_ptr)->cmd_indx; 840 841 /* 842 * If outstanding command list is not empty, then insert the entry. 843 * Otherwise, this is the only entry. So update the pointers 844 * appropriately. 845 */ 846 if (cmd_list->cml_entries_free++ != 0) { 847 /* Update the current command */ 848 (*cmd_ptr)->cmd_next = cmd_list->cml_head_indx; 849 (*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx; 850 851 /* Update head and tail commands */ 852 cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx; 853 cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx; 854 855 /* Update tail index */ 856 cmd_list->cml_tail_indx = cmd_indx; 857 858 } else { 859 /* Update the current command */ 860 (*cmd_ptr)->cmd_next = cmd_indx; 861 (*cmd_ptr)->cmd_prev = cmd_indx; 862 863 /* Update head and tail indexes */ 864 cmd_list->cml_head_indx = cmd_indx; 865 cmd_list->cml_tail_indx = cmd_indx; 866 } 867 868 /* If there are threads waiting, signal one of them */ 869 if (cmd_list->cml_waiters > 0) { 870 cmd_list->cml_waiters--; 871 cv_signal(&cmd_list->cml_cv); 872 } 873 874 /* Clear out the command entry pointer */ 875 *cmd_ptr = NULL; 876 877 mutex_exit(&cmd_list->cml_lock); 878 } 879 880 881 /* 882 * tavor_write_hcr() 883 * Context: Can be called from interrupt or base context. 884 */ 885 static int 886 tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost, 887 uint16_t token) 888 { 889 tavor_hw_hcr_t *hcr; 890 uint_t status, count, countmax; 891 uint64_t hcrreg; 892 893 /* 894 * Grab the "HCR access" lock if the driver is not in 895 * fastreboot. In fastreboot, this function is called 896 * with the single thread but in high interrupt context 897 * (so that this mutex lock cannot be used). 898 */ 899 #ifdef __lock_lint 900 mutex_enter(&state->ts_cmd_regs.hcr_lock); 901 #else 902 if (!TAVOR_IN_FASTREBOOT(state)) { 903 mutex_enter(&state->ts_cmd_regs.hcr_lock); 904 } 905 #endif 906 907 hcr = state->ts_cmd_regs.hcr; 908 909 /* 910 * First, check the "go" bit to see if the previous hcr usage is 911 * complete. As long as it is set then we must continue to poll. 912 */ 913 count = 0; 914 countmax = state->ts_cfg_profile->cp_cmd_poll_max; 915 for (;;) { 916 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd); 917 918 /* If "go" bit is clear, then done */ 919 if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) { 920 break; 921 } 922 /* Delay before polling the "go" bit again */ 923 drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay); 924 925 /* 926 * If we poll more than the maximum number of times, then 927 * return a "timeout" error. 928 */ 929 if (++count > countmax) { 930 #ifdef __lock_lint 931 mutex_exit(&state->ts_cmd_regs.hcr_lock); 932 #else 933 if (!TAVOR_IN_FASTREBOOT(state)) { 934 mutex_exit(&state->ts_cmd_regs.hcr_lock); 935 } 936 #endif 937 return (TAVOR_CMD_TIMEOUT); 938 } 939 } 940 941 /* Write "inparam" as a 64-bit quantity */ 942 ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->in_param0, 943 cmdpost->cp_inparm); 944 945 /* Write "inmod" and 32-bits of "outparam" as 64-bit */ 946 hcrreg = ((uint64_t)cmdpost->cp_inmod << 32); 947 hcrreg = hcrreg | (cmdpost->cp_outparm >> 32); 948 ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->input_modifier, 949 hcrreg); 950 951 /* Write the other 32-bits of "outparam" and "token" as 64-bit */ 952 hcrreg = (cmdpost->cp_outparm << 32); 953 hcrreg = hcrreg | ((uint32_t)token << TAVOR_HCR_TOKEN_SHIFT); 954 ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->out_param1, 955 hcrreg); 956 957 /* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */ 958 hcrreg = TAVOR_HCR_CMD_GO_MASK; 959 if (cmdpost->cp_flags == TAVOR_CMD_SLEEP_NOSPIN) 960 hcrreg = hcrreg | TAVOR_HCR_CMD_E_MASK; 961 hcrreg = hcrreg | (cmdpost->cp_opmod << TAVOR_HCR_CMD_OPMOD_SHFT); 962 hcrreg = hcrreg | (cmdpost->cp_opcode); 963 964 /* Write the doorbell to the HCR */ 965 ddi_put32(state->ts_reg_cmdhdl, &hcr->cmd, hcrreg); 966 967 /* 968 * In the SPIN case we read the HCR and check the "go" bit. For the 969 * NOSPIN case we do not have to poll, we simply release the HCR lock 970 * and return. 971 */ 972 if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) { 973 count = 0; 974 countmax = state->ts_cfg_profile->cp_cmd_poll_max; 975 976 for (;;) { 977 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd); 978 979 /* If "go" bit is clear, then done */ 980 if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) { 981 break; 982 } 983 /* Delay before polling the "go" bit again */ 984 drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay); 985 986 /* 987 * If we poll more than the maximum number of times, 988 * then return a "timeout" error. 989 */ 990 if (++count > countmax) { 991 #ifdef __lock_lint 992 mutex_exit(&state-> ts_cmd_regs.hcr_lock); 993 #else 994 if (!TAVOR_IN_FASTREBOOT(state)) { 995 mutex_exit(&state-> 996 ts_cmd_regs.hcr_lock); 997 } 998 #endif 999 return (TAVOR_CMD_TIMEOUT); 1000 } 1001 } 1002 1003 /* Pull out the "status" bits from the HCR */ 1004 status = (hcrreg >> TAVOR_HCR_CMD_STATUS_SHFT); 1005 1006 /* 1007 * Read the "outparam" value. Note: we have to read "outparam" 1008 * as two separate 32-bit reads because the field in the HCR is 1009 * not 64-bit aligned. 1010 */ 1011 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param0); 1012 cmdpost->cp_outparm = hcrreg << 32; 1013 hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param1); 1014 cmdpost->cp_outparm |= hcrreg; 1015 1016 /* NOSPIN */ 1017 } else { 1018 status = TAVOR_CMD_SUCCESS; 1019 } 1020 1021 /* Drop the "HCR access" lock */ 1022 #ifdef __lock_lint 1023 mutex_exit(&state->ts_cmd_regs.hcr_lock); 1024 #else 1025 if (!TAVOR_IN_FASTREBOOT(state)) { 1026 mutex_exit(&state->ts_cmd_regs.hcr_lock); 1027 } 1028 #endif 1029 1030 return (status); 1031 } 1032 1033 1034 /* 1035 * tavor_outstanding_cmdlist_init() 1036 * Context: Only called from attach() path context 1037 */ 1038 int 1039 tavor_outstanding_cmdlist_init(tavor_state_t *state) 1040 { 1041 uint_t num_outstanding_cmds, head, tail; 1042 int i; 1043 1044 /* 1045 * Determine the number of the outstanding commands supported 1046 * by the Tavor device (obtained from the QUERY_FW command). Note: 1047 * Because we handle both SLEEP and NOSLEEP cases around the tavor HCR, 1048 * we know that when an interrupt comes in it will be next on the 1049 * command register, and will at most have to wait one commands time. 1050 * We do not have to reserve an outstanding command here for 1051 * interrupts. 1052 */ 1053 num_outstanding_cmds = (1 << state->ts_fw.log_max_cmd); 1054 1055 /* Initialize the outstanding command list */ 1056 state->ts_cmd_list.cml_list_sz = num_outstanding_cmds; 1057 state->ts_cmd_list.cml_head_indx = 0; 1058 state->ts_cmd_list.cml_tail_indx = state->ts_cmd_list.cml_list_sz - 1; 1059 state->ts_cmd_list.cml_entries_free = state->ts_cmd_list.cml_list_sz; 1060 state->ts_cmd_list.cml_waiters = 0; 1061 state->ts_cmd_list.cml_num_alloc = 0; 1062 1063 /* Allocate the memory for the outstanding command list */ 1064 if (num_outstanding_cmds) { 1065 state->ts_cmd_list.cml_cmd = 1066 kmem_zalloc(state->ts_cmd_list.cml_list_sz * 1067 sizeof (tavor_cmd_t), KM_SLEEP); 1068 } 1069 mutex_init(&state->ts_cmd_list.cml_lock, NULL, MUTEX_DRIVER, 1070 DDI_INTR_PRI(state->ts_intrmsi_pri)); 1071 cv_init(&state->ts_cmd_list.cml_cv, NULL, CV_DRIVER, NULL); 1072 1073 /* Initialize the individual outstanding command list entries */ 1074 for (i = 0; i < state->ts_cmd_list.cml_list_sz; i++) { 1075 mutex_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock, 1076 NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->ts_intrmsi_pri)); 1077 cv_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv, NULL, 1078 CV_DRIVER, NULL); 1079 1080 state->ts_cmd_list.cml_cmd[i].cmd_next = i+1; 1081 state->ts_cmd_list.cml_cmd[i].cmd_prev = i-1; 1082 state->ts_cmd_list.cml_cmd[i].cmd_indx = i; 1083 state->ts_cmd_list.cml_num_alloc = i + 1; 1084 } 1085 if (num_outstanding_cmds) { 1086 head = state->ts_cmd_list.cml_head_indx; 1087 tail = state->ts_cmd_list.cml_tail_indx; 1088 state->ts_cmd_list.cml_cmd[head].cmd_prev = 1089 state->ts_cmd_list.cml_tail_indx; 1090 state->ts_cmd_list.cml_cmd[tail].cmd_next = 1091 state->ts_cmd_list.cml_head_indx; 1092 } 1093 1094 return (DDI_SUCCESS); 1095 } 1096 1097 1098 /* 1099 * tavor_outstanding_cmdlist_fini() 1100 * Context: Only called from attach() and/or detach() path contexts 1101 */ 1102 void 1103 tavor_outstanding_cmdlist_fini(tavor_state_t *state) 1104 { 1105 int i; 1106 1107 /* Destroy the outstanding command list entries */ 1108 for (i = 0; i < state->ts_cmd_list.cml_num_alloc; i++) { 1109 mutex_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock); 1110 cv_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv); 1111 } 1112 1113 /* Destroy the lock (and cv) and free up memory for list */ 1114 mutex_destroy(&state->ts_cmd_list.cml_lock); 1115 cv_destroy(&state->ts_cmd_list.cml_cv); 1116 if (state->ts_cmd_list.cml_num_alloc) { 1117 kmem_free(state->ts_cmd_list.cml_cmd, 1118 state->ts_cmd_list.cml_list_sz * sizeof (tavor_cmd_t)); 1119 } 1120 1121 } 1122 1123 1124 /* 1125 * tavor_mbox_sync() 1126 */ 1127 static void 1128 tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset, uint_t length, 1129 uint_t flag) 1130 { 1131 ddi_dma_handle_t dmahdl; 1132 int status; 1133 1134 /* Determine if mailbox needs to be synced or not */ 1135 if (mbox->mb_sync == 0) { 1136 return; 1137 } 1138 1139 /* Get the DMA handle from mailbox */ 1140 dmahdl = mbox->mb_rsrcptr->tr_dmahdl; 1141 1142 /* Calculate offset into mailbox */ 1143 status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag); 1144 if (status != DDI_SUCCESS) { 1145 return; 1146 } 1147 } 1148 1149 1150 /* 1151 * tavor_sys_en_cmd_post() 1152 * Context: Can be called from interrupt or base context. 1153 * (Currently called only from attach() path context) 1154 */ 1155 int 1156 tavor_sys_en_cmd_post(tavor_state_t *state, uint_t flags, 1157 uint64_t *errorcode, uint_t sleepflag) 1158 { 1159 tavor_cmd_post_t cmd; 1160 int status; 1161 1162 /* Make sure we are called with the correct flag */ 1163 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1164 1165 /* Setup and post the Tavor "SYS_EN" command */ 1166 cmd.cp_inparm = 0; 1167 cmd.cp_outparm = 0; 1168 cmd.cp_inmod = 0; 1169 cmd.cp_opcode = SYS_EN; 1170 cmd.cp_opmod = flags; 1171 cmd.cp_flags = sleepflag; 1172 status = tavor_cmd_post(state, &cmd); 1173 if (status != TAVOR_CMD_SUCCESS) { 1174 /* 1175 * When the SYS_EN command fails, the "outparam" field may 1176 * contain more detailed information about what caused the 1177 * failure. 1178 */ 1179 *errorcode = cmd.cp_outparm; 1180 } 1181 1182 return (status); 1183 } 1184 1185 1186 /* 1187 * tavor_sys_dis_cmd_post() 1188 * Context: Can be called from interrupt or base context. 1189 * (Currently called only from attach() and/or detach() path contexts) 1190 */ 1191 int 1192 tavor_sys_dis_cmd_post(tavor_state_t *state, uint_t sleepflag) 1193 { 1194 tavor_cmd_post_t cmd; 1195 int status; 1196 1197 /* Make sure we are called with the correct flag */ 1198 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1199 1200 /* Setup and post the Tavor "SYS_DIS" command */ 1201 cmd.cp_inparm = 0; 1202 cmd.cp_outparm = 0; 1203 cmd.cp_inmod = 0; 1204 cmd.cp_opcode = SYS_DIS; 1205 cmd.cp_opmod = 0; 1206 cmd.cp_flags = sleepflag; 1207 status = tavor_cmd_post(state, &cmd); 1208 1209 return (status); 1210 } 1211 1212 1213 /* 1214 * tavor_init_hca_cmd_post() 1215 * Context: Can be called from interrupt or base context. 1216 * (Currently called only from attach() path context) 1217 */ 1218 int 1219 tavor_init_hca_cmd_post(tavor_state_t *state, 1220 tavor_hw_initqueryhca_t *inithca, uint_t sleepflag) 1221 { 1222 tavor_mbox_info_t mbox_info; 1223 tavor_cmd_post_t cmd; 1224 uint64_t data; 1225 uint_t size; 1226 int status, i; 1227 1228 /* Make sure we are called with the correct flag */ 1229 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1230 1231 /* Get an "In" mailbox for the command */ 1232 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 1233 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1234 if (status != TAVOR_CMD_SUCCESS) { 1235 return (status); 1236 } 1237 1238 /* Copy the Tavor "INIT_HCA" command into the mailbox */ 1239 size = sizeof (tavor_hw_initqueryhca_t); 1240 for (i = 0; i < (size >> 3); i++) { 1241 data = ((uint64_t *)inithca)[i]; 1242 ddi_put64(mbox_info.mbi_in->mb_acchdl, 1243 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 1244 } 1245 1246 /* Sync the mailbox for the device to read */ 1247 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1248 1249 /* Setup and post the Tavor "INIT_HCA" command */ 1250 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1251 cmd.cp_outparm = 0; 1252 cmd.cp_inmod = 0; 1253 cmd.cp_opcode = INIT_HCA; 1254 cmd.cp_opmod = 0; 1255 cmd.cp_flags = sleepflag; 1256 status = tavor_cmd_post(state, &cmd); 1257 1258 /* Free the mailbox */ 1259 tavor_mbox_free(state, &mbox_info); 1260 1261 return (status); 1262 } 1263 1264 1265 /* 1266 * tavor_close_hca_cmd_post() 1267 * Context: Can be called from interrupt or base context. 1268 * (Currently called only from attach() and/or detach() path contexts) 1269 */ 1270 int 1271 tavor_close_hca_cmd_post(tavor_state_t *state, uint_t sleepflag) 1272 { 1273 tavor_cmd_post_t cmd; 1274 int status; 1275 1276 /* Make sure we are called with the correct flag */ 1277 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1278 1279 /* Setup and post the Tavor "CLOSE_HCA" command */ 1280 cmd.cp_inparm = 0; 1281 cmd.cp_outparm = 0; 1282 cmd.cp_inmod = 0; 1283 cmd.cp_opcode = CLOSE_HCA; 1284 cmd.cp_opmod = 0; 1285 cmd.cp_flags = sleepflag; 1286 status = tavor_cmd_post(state, &cmd); 1287 1288 return (status); 1289 } 1290 1291 1292 /* 1293 * tavor_init_ib_cmd_post() 1294 * Context: Can be called from interrupt or base context. 1295 * (Currently called only from attach() path context) 1296 */ 1297 int 1298 tavor_init_ib_cmd_post(tavor_state_t *state, tavor_hw_initib_t *initib, 1299 uint_t port, uint_t sleepflag) 1300 { 1301 tavor_mbox_info_t mbox_info; 1302 tavor_cmd_post_t cmd; 1303 uint64_t data; 1304 uint_t size; 1305 int status, i; 1306 1307 /* Make sure we are called with the correct flag */ 1308 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1309 1310 /* Get an "In" mailbox for the command */ 1311 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 1312 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1313 if (status != TAVOR_CMD_SUCCESS) { 1314 return (status); 1315 } 1316 1317 /* Copy the Tavor "INIT_IB" command into the mailbox */ 1318 size = sizeof (tavor_hw_initib_t); 1319 for (i = 0; i < (size >> 3); i++) { 1320 data = ((uint64_t *)initib)[i]; 1321 ddi_put64(mbox_info.mbi_in->mb_acchdl, 1322 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 1323 } 1324 1325 /* Sync the mailbox for the device to read */ 1326 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1327 1328 /* Setup and post the Tavor "INIT_IB" command */ 1329 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1330 cmd.cp_outparm = 0; 1331 cmd.cp_inmod = port; 1332 cmd.cp_opcode = INIT_IB; 1333 cmd.cp_opmod = 0; 1334 cmd.cp_flags = sleepflag; 1335 status = tavor_cmd_post(state, &cmd); 1336 1337 /* Free the mailbox */ 1338 tavor_mbox_free(state, &mbox_info); 1339 1340 return (status); 1341 } 1342 1343 1344 /* 1345 * tavor_close_ib_cmd_post() 1346 * Context: Can be called from interrupt or base context. 1347 * (Currently called only from attach() and/or detach() path contexts) 1348 */ 1349 int 1350 tavor_close_ib_cmd_post(tavor_state_t *state, uint_t port, uint_t sleepflag) 1351 { 1352 tavor_cmd_post_t cmd; 1353 int status; 1354 1355 /* Setup and post the Tavor "CLOSE_IB" command */ 1356 cmd.cp_inparm = 0; 1357 cmd.cp_outparm = 0; 1358 cmd.cp_inmod = port; 1359 cmd.cp_opcode = CLOSE_IB; 1360 cmd.cp_opmod = 0; 1361 cmd.cp_flags = sleepflag; 1362 status = tavor_cmd_post(state, &cmd); 1363 1364 return (status); 1365 } 1366 1367 1368 /* 1369 * tavor_set_ib_cmd_post() 1370 * Context: Can be called from interrupt or base context. 1371 */ 1372 int 1373 tavor_set_ib_cmd_post(tavor_state_t *state, uint32_t capmask, uint_t port, 1374 uint_t reset_qkey, uint_t sleepflag) 1375 { 1376 tavor_mbox_info_t mbox_info; 1377 tavor_cmd_post_t cmd; 1378 int status; 1379 1380 /* Get an "In" mailbox for the command */ 1381 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 1382 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1383 if (status != TAVOR_CMD_SUCCESS) { 1384 return (status); 1385 } 1386 1387 /* Copy the Tavor "SET_IB" command into mailbox */ 1388 ddi_put32(mbox_info.mbi_in->mb_acchdl, 1389 ((uint32_t *)mbox_info.mbi_in->mb_addr + 0), reset_qkey); 1390 ddi_put32(mbox_info.mbi_in->mb_acchdl, 1391 ((uint32_t *)mbox_info.mbi_in->mb_addr + 1), capmask); 1392 1393 /* Sync the mailbox for the device to read */ 1394 tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_SETIB_SZ, 1395 DDI_DMA_SYNC_FORDEV); 1396 1397 /* Setup and post the Tavor "SET_IB" command */ 1398 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1399 cmd.cp_outparm = 0; 1400 cmd.cp_inmod = port; 1401 cmd.cp_opcode = SET_IB; 1402 cmd.cp_opmod = 0; 1403 cmd.cp_flags = sleepflag; 1404 status = tavor_cmd_post(state, &cmd); 1405 1406 /* Free the mailbox */ 1407 tavor_mbox_free(state, &mbox_info); 1408 1409 return (status); 1410 } 1411 1412 1413 /* 1414 * tavor_mod_stat_cfg_cmd_post() 1415 * Context: Can be called only from attach() path 1416 */ 1417 int 1418 tavor_mod_stat_cfg_cmd_post(tavor_state_t *state) 1419 { 1420 tavor_mbox_info_t mbox_info; 1421 tavor_cmd_post_t cmd; 1422 tavor_hw_mod_stat_cfg_t *mod; 1423 uint64_t data; 1424 uint_t size; 1425 int status, i; 1426 1427 /* 1428 * "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations 1429 * to do. However, at the point in time that we call this command, the 1430 * DDR has not yet been initialized, and all INMBOX'es are located in 1431 * DDR. Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is 1432 * called, and thus call it before DDR is setup, we simply use an 1433 * OUTMBOX memory location here as our INMBOX parameter. 1434 */ 1435 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX; 1436 status = tavor_mbox_alloc(state, &mbox_info, TAVOR_NOSLEEP); 1437 if (status != TAVOR_CMD_SUCCESS) { 1438 return (status); 1439 } 1440 1441 /* 1442 * Allocate on the heap our 'mod_stat_cfg' structure. We want to 1443 * ideally move all of this on to the stack in the future, but this 1444 * works well for now. 1445 */ 1446 mod = (tavor_hw_mod_stat_cfg_t *)kmem_zalloc( 1447 sizeof (tavor_hw_mod_stat_cfg_t), KM_SLEEP); 1448 1449 /* Setup "MOD_STAT_CFG" settings */ 1450 mod->srq_m = 1; 1451 mod->srq = state->ts_cfg_profile->cp_srq_enable; 1452 1453 if (mod->srq) { 1454 mod->log_max_srq = state->ts_cfg_profile->cp_log_num_srq; 1455 } else { 1456 mod->log_max_srq = 0; 1457 } 1458 1459 /* Copy the "MOD_STAT_CFG" command into the "In" mailbox */ 1460 size = sizeof (tavor_hw_mod_stat_cfg_t); 1461 for (i = 0; i < (size >> 3); i++) { 1462 data = ((uint64_t *)mod)[i]; 1463 ddi_put64(mbox_info.mbi_out->mb_acchdl, 1464 ((uint64_t *)mbox_info.mbi_out->mb_addr + i), data); 1465 } 1466 1467 /* Sync the mailbox for the device to read */ 1468 tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORDEV); 1469 1470 /* Setup and post the Tavor "MOD_STAT_CFG" command */ 1471 cmd.cp_inparm = mbox_info.mbi_out->mb_mapaddr; 1472 cmd.cp_outparm = 0; 1473 cmd.cp_inmod = 0; 1474 cmd.cp_opcode = MOD_STAT_CFG; 1475 cmd.cp_opmod = 0; 1476 cmd.cp_flags = TAVOR_CMD_NOSLEEP_SPIN; 1477 status = tavor_cmd_post(state, &cmd); 1478 1479 /* Free "MOD_STAT_CFG" struct */ 1480 kmem_free(mod, sizeof (tavor_hw_mod_stat_cfg_t)); 1481 1482 /* Free the mailbox */ 1483 tavor_mbox_free(state, &mbox_info); 1484 1485 return (status); 1486 } 1487 1488 1489 /* 1490 * tavor_mad_ifc_cmd_post() 1491 * Context: Can be called from interrupt or base context. 1492 */ 1493 int 1494 tavor_mad_ifc_cmd_post(tavor_state_t *state, uint_t port, 1495 uint_t sleepflag, uint32_t *mad, uint32_t *resp) 1496 { 1497 tavor_mbox_info_t mbox_info; 1498 tavor_cmd_post_t cmd; 1499 uint_t size; 1500 int status; 1501 1502 /* Get "In" and "Out" mailboxes for the command */ 1503 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1504 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1505 if (status != TAVOR_CMD_SUCCESS) { 1506 return (status); 1507 } 1508 1509 /* Copy the request MAD into the "In" mailbox */ 1510 size = TAVOR_CMD_MAD_IFC_SIZE; 1511 bcopy(mad, mbox_info.mbi_in->mb_addr, size); 1512 1513 /* Sync the mailbox for the device to read */ 1514 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1515 1516 /* Setup the Tavor "MAD_IFC" command */ 1517 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1518 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1519 cmd.cp_inmod = port; 1520 cmd.cp_opcode = MAD_IFC; 1521 cmd.cp_opmod = TAVOR_CMD_MKEY_CHECK; /* Enable MKey checking */ 1522 cmd.cp_flags = sleepflag; 1523 status = tavor_cmd_post(state, &cmd); 1524 if (status != TAVOR_CMD_SUCCESS) { 1525 goto mad_ifc_fail; 1526 } 1527 1528 /* Sync the mailbox to read the results */ 1529 tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 1530 1531 /* Copy the response MAD into "resp" */ 1532 bcopy(mbox_info.mbi_out->mb_addr, resp, size); 1533 1534 mad_ifc_fail: 1535 /* Free the mailbox */ 1536 tavor_mbox_free(state, &mbox_info); 1537 1538 return (status); 1539 } 1540 1541 1542 /* 1543 * tavor_getportinfo_cmd_post() 1544 * Context: Can be called from interrupt or base context. 1545 */ 1546 int 1547 tavor_getportinfo_cmd_post(tavor_state_t *state, uint_t port, 1548 uint_t sleepflag, sm_portinfo_t *portinfo) 1549 { 1550 tavor_mbox_info_t mbox_info; 1551 tavor_cmd_post_t cmd; 1552 uint32_t *mbox; 1553 uint_t size; 1554 int status, i; 1555 1556 /* Get "In" and "Out" mailboxes for the command */ 1557 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1558 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1559 if (status != TAVOR_CMD_SUCCESS) { 1560 return (status); 1561 } 1562 1563 /* Build the GetPortInfo request MAD in the "In" mailbox */ 1564 size = TAVOR_CMD_MAD_IFC_SIZE; 1565 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 1566 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0); 1567 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 1568 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 1569 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 1570 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PORTINFO); 1571 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port); 1572 for (i = 6; i < (size >> 2); i++) { 1573 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 1574 } 1575 1576 /* Sync the mailbox for the device to read */ 1577 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1578 1579 /* Setup the Tavor "MAD_IFC" command */ 1580 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1581 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1582 cmd.cp_inmod = port; 1583 cmd.cp_opcode = MAD_IFC; 1584 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK; /* No MKey checking */ 1585 cmd.cp_flags = sleepflag; 1586 status = tavor_cmd_post(state, &cmd); 1587 if (status != TAVOR_CMD_SUCCESS) { 1588 goto getportinfo_fail; 1589 } 1590 1591 /* Sync the mailbox to read the results */ 1592 size = sizeof (sm_portinfo_t); 1593 tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET, 1594 size, DDI_DMA_SYNC_FORCPU); 1595 1596 /* 1597 * Copy GetPortInfo response MAD into "portinfo". Do any endian 1598 * swapping that may be necessary to flip any of the "portinfo" 1599 * fields 1600 */ 1601 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo)) 1602 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 1603 TAVOR_CMD_MADDATA_OFFSET), portinfo, size); 1604 TAVOR_GETPORTINFO_SWAP(portinfo); 1605 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*portinfo)) 1606 1607 getportinfo_fail: 1608 /* Free the mailbox */ 1609 tavor_mbox_free(state, &mbox_info); 1610 1611 return (status); 1612 } 1613 1614 1615 /* 1616 * tavor_getnodeinfo_cmd_post() 1617 * Context: Can be called from interrupt or base context. 1618 * (Currently called only from attach() and detach() path contexts) 1619 */ 1620 int 1621 tavor_getnodeinfo_cmd_post(tavor_state_t *state, uint_t sleepflag, 1622 sm_nodeinfo_t *nodeinfo) 1623 { 1624 tavor_mbox_info_t mbox_info; 1625 tavor_cmd_post_t cmd; 1626 uint32_t *mbox; 1627 uint_t size; 1628 int status, i; 1629 1630 /* Make sure we are called with the correct flag */ 1631 ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN); 1632 1633 /* Get "In" and "Out" mailboxes for the command */ 1634 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1635 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1636 if (status != TAVOR_CMD_SUCCESS) { 1637 return (status); 1638 } 1639 1640 /* Build the GetNodeInfo request MAD into the "In" mailbox */ 1641 size = TAVOR_CMD_MAD_IFC_SIZE; 1642 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 1643 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0); 1644 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 1645 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 1646 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 1647 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEINFO); 1648 for (i = 5; i < (size >> 2); i++) { 1649 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 1650 } 1651 1652 /* Sync the mailbox for the device to read */ 1653 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1654 1655 /* Setup the Tavor "MAD_IFC" command */ 1656 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1657 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1658 cmd.cp_inmod = 1; /* Get NodeInfo from port #1 */ 1659 cmd.cp_opcode = MAD_IFC; 1660 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK; /* No MKey checking */ 1661 cmd.cp_flags = sleepflag; 1662 status = tavor_cmd_post(state, &cmd); 1663 if (status != TAVOR_CMD_SUCCESS) { 1664 goto getnodeinfo_fail; 1665 } 1666 1667 /* Sync the mailbox to read the results */ 1668 size = sizeof (sm_nodeinfo_t); 1669 tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET, 1670 size, DDI_DMA_SYNC_FORCPU); 1671 1672 /* 1673 * Copy GetNodeInfo response MAD into "nodeinfo". Do any endian 1674 * swapping that may be necessary to flip any of the "nodeinfo" 1675 * fields 1676 */ 1677 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 1678 TAVOR_CMD_MADDATA_OFFSET), nodeinfo, size); 1679 TAVOR_GETNODEINFO_SWAP(nodeinfo); 1680 1681 getnodeinfo_fail: 1682 /* Free the mailbox */ 1683 tavor_mbox_free(state, &mbox_info); 1684 1685 return (status); 1686 } 1687 1688 1689 /* 1690 * tavor_getnodedesc_cmd_post() 1691 * Context: Can be called from interrupt or base context. 1692 * (Currently called only from attach() and detach() path contexts) 1693 */ 1694 int 1695 tavor_getnodedesc_cmd_post(tavor_state_t *state, uint_t sleepflag, 1696 sm_nodedesc_t *nodedesc) 1697 { 1698 tavor_mbox_info_t mbox_info; 1699 tavor_cmd_post_t cmd; 1700 uint32_t *mbox; 1701 uint_t size; 1702 int status, i; 1703 1704 /* Get "In" and "Out" mailboxes for the command */ 1705 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1706 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1707 if (status != TAVOR_CMD_SUCCESS) { 1708 return (status); 1709 } 1710 1711 /* Build the GetNodeDesc request MAD into the "In" mailbox */ 1712 size = TAVOR_CMD_MAD_IFC_SIZE; 1713 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 1714 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0); 1715 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 1716 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 1717 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 1718 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEDESC); 1719 for (i = 5; i < (size >> 2); i++) { 1720 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 1721 } 1722 1723 /* Sync the mailbox for the device to read */ 1724 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1725 1726 /* Setup the Tavor "MAD_IFC" command */ 1727 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1728 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1729 cmd.cp_inmod = 1; /* Get NodeDesc from port #1 */ 1730 cmd.cp_opcode = MAD_IFC; 1731 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK; /* No MKey checking */ 1732 cmd.cp_flags = sleepflag; 1733 status = tavor_cmd_post(state, &cmd); 1734 if (status != TAVOR_CMD_SUCCESS) { 1735 goto getnodedesc_fail; 1736 } 1737 1738 /* Sync the mailbox to read the results */ 1739 size = sizeof (sm_nodedesc_t); 1740 tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET, 1741 size, DDI_DMA_SYNC_FORCPU); 1742 1743 /* Copy GetNodeDesc response MAD into "nodedesc" */ 1744 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 1745 TAVOR_CMD_MADDATA_OFFSET), nodedesc, size); 1746 1747 getnodedesc_fail: 1748 /* Free the mailbox */ 1749 tavor_mbox_free(state, &mbox_info); 1750 1751 return (status); 1752 } 1753 1754 1755 /* 1756 * tavor_getguidinfo_cmd_post() 1757 * Context: Can be called from interrupt or base context. 1758 */ 1759 int 1760 tavor_getguidinfo_cmd_post(tavor_state_t *state, uint_t port, 1761 uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo) 1762 { 1763 tavor_mbox_info_t mbox_info; 1764 tavor_cmd_post_t cmd; 1765 uint32_t *mbox; 1766 uint_t size; 1767 int status, i; 1768 1769 /* Get "In" and "Out" mailboxes for the command */ 1770 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1771 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1772 if (status != TAVOR_CMD_SUCCESS) { 1773 return (status); 1774 } 1775 1776 /* Build the GetGUIDInfo request MAD into the "In" mailbox */ 1777 size = TAVOR_CMD_MAD_IFC_SIZE; 1778 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 1779 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0); 1780 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 1781 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 1782 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 1783 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_GUIDINFO); 1784 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock); 1785 for (i = 6; i < (size >> 2); i++) { 1786 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 1787 } 1788 1789 /* Sync the mailbox for the device to read */ 1790 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1791 1792 /* Setup the Tavor "MAD_IFC" command */ 1793 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1794 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1795 cmd.cp_inmod = port; 1796 cmd.cp_opcode = MAD_IFC; 1797 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK; /* No MKey checking */ 1798 cmd.cp_flags = sleepflag; 1799 status = tavor_cmd_post(state, &cmd); 1800 if (status != TAVOR_CMD_SUCCESS) { 1801 goto getguidinfo_fail; 1802 } 1803 1804 /* Sync the mailbox to read the results */ 1805 size = sizeof (sm_guidinfo_t); 1806 tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET, 1807 size, DDI_DMA_SYNC_FORCPU); 1808 1809 /* 1810 * Copy GetGUIDInfo response MAD into "guidinfo". Do any endian 1811 * swapping that may be necessary to flip the "guidinfo" fields 1812 */ 1813 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo)) 1814 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 1815 TAVOR_CMD_MADDATA_OFFSET), guidinfo, size); 1816 TAVOR_GETGUIDINFO_SWAP(guidinfo); 1817 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*guidinfo)) 1818 1819 getguidinfo_fail: 1820 /* Free the mailbox */ 1821 tavor_mbox_free(state, &mbox_info); 1822 1823 return (status); 1824 } 1825 1826 1827 /* 1828 * tavor_getpkeytable_cmd_post() 1829 * Context: Can be called from interrupt or base context. 1830 */ 1831 int 1832 tavor_getpkeytable_cmd_post(tavor_state_t *state, uint_t port, 1833 uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable) 1834 { 1835 tavor_mbox_info_t mbox_info; 1836 tavor_cmd_post_t cmd; 1837 uint32_t *mbox; 1838 uint_t size; 1839 int status, i; 1840 1841 /* Get "In" and "Out" mailboxes for the command */ 1842 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 1843 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 1844 if (status != TAVOR_CMD_SUCCESS) { 1845 return (status); 1846 } 1847 1848 /* Build the GetPkeyTable request MAD into the "In" mailbox */ 1849 size = TAVOR_CMD_MAD_IFC_SIZE; 1850 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 1851 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0); 1852 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 1853 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 1854 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 1855 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PKEYTBLE); 1856 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock); 1857 for (i = 6; i < (size >> 2); i++) { 1858 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0); 1859 } 1860 1861 /* Sync the mailbox for the device to read */ 1862 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1863 1864 /* Setup the Tavor "MAD_IFC" command */ 1865 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 1866 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 1867 cmd.cp_inmod = port; 1868 cmd.cp_opcode = MAD_IFC; 1869 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK; /* No MKey checking */ 1870 cmd.cp_flags = sleepflag; 1871 status = tavor_cmd_post(state, &cmd); 1872 if (status != TAVOR_CMD_SUCCESS) { 1873 goto getpkeytable_fail; 1874 } 1875 1876 /* Sync the mailbox to read the results */ 1877 size = sizeof (sm_pkey_table_t); 1878 tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET, 1879 size, DDI_DMA_SYNC_FORCPU); 1880 1881 /* 1882 * Copy GetPKeyTable response MAD into "pkeytable". Do any endian 1883 * swapping that may be necessary to flip the "pkeytable" fields 1884 */ 1885 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable)) 1886 bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr + 1887 TAVOR_CMD_MADDATA_OFFSET), pkeytable, size); 1888 TAVOR_GETPKEYTABLE_SWAP(pkeytable); 1889 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*pkeytable)) 1890 1891 getpkeytable_fail: 1892 /* Free the mailbox */ 1893 tavor_mbox_free(state, &mbox_info); 1894 1895 return (status); 1896 } 1897 1898 1899 /* 1900 * tavor_write_mtt_cmd_post() 1901 * Context: Can be called from interrupt or base context. 1902 */ 1903 int 1904 tavor_write_mtt_cmd_post(tavor_state_t *state, tavor_mbox_info_t *mbox_info, 1905 uint_t num_mtt, uint_t sleepflag) 1906 { 1907 tavor_cmd_post_t cmd; 1908 uint_t size; 1909 int status; 1910 1911 /* 1912 * The WRITE_MTT command is unlike the other commands we use, in that 1913 * we have intentionally separated the mailbox allocation step from 1914 * the rest of the command posting steps. At this point (when this 1915 * function is called) the "In" mailbox already contains all the MTT 1916 * entries to be copied into the Tavor tables (starting at offset 1917 * 0x10) _and_ the 64-bit address of the destination for the first 1918 * MTT entry in the MTT table. 1919 */ 1920 1921 /* Sync the mailbox for the device to read */ 1922 size = (num_mtt << TAVOR_MTT_SIZE_SHIFT) + TAVOR_CMD_WRITEMTT_RSVD_SZ; 1923 tavor_mbox_sync(mbox_info->mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 1924 1925 /* Setup and post Tavor "WRITE_MTT" command */ 1926 cmd.cp_inparm = mbox_info->mbi_in->mb_mapaddr; 1927 cmd.cp_outparm = 0; 1928 cmd.cp_inmod = num_mtt; 1929 cmd.cp_opcode = WRITE_MTT; 1930 cmd.cp_opmod = 0; 1931 cmd.cp_flags = sleepflag; 1932 status = tavor_cmd_post(state, &cmd); 1933 1934 return (status); 1935 } 1936 1937 1938 /* 1939 * tavor_sync_tpt_cmd_post() 1940 * Context: Can be called from interrupt or base context. 1941 */ 1942 int 1943 tavor_sync_tpt_cmd_post(tavor_state_t *state, uint_t sleepflag) 1944 { 1945 tavor_cmd_post_t cmd; 1946 int status; 1947 1948 /* Setup and post the Tavor "SYNC_TPT" command */ 1949 cmd.cp_inparm = 0; 1950 cmd.cp_outparm = 0; 1951 cmd.cp_inmod = 0; 1952 cmd.cp_opcode = SYNC_TPT; 1953 cmd.cp_opmod = 0; 1954 cmd.cp_flags = sleepflag; 1955 status = tavor_cmd_post(state, &cmd); 1956 1957 return (status); 1958 } 1959 1960 /* 1961 * tavor_map_eq_cmd_post() 1962 * Context: Can be called from interrupt or base context. 1963 * (Currently called only from attach() and/or detach() path contexts) 1964 */ 1965 int 1966 tavor_map_eq_cmd_post(tavor_state_t *state, uint_t map, uint_t eqcindx, 1967 uint64_t eqmapmask, uint_t sleepflag) 1968 { 1969 tavor_cmd_post_t cmd; 1970 int status; 1971 1972 /* Setup and post Tavor "MAP_EQ" command */ 1973 cmd.cp_inparm = eqmapmask; 1974 cmd.cp_outparm = 0; 1975 cmd.cp_inmod = eqcindx; 1976 if (map != TAVOR_CMD_MAP_EQ_EVT_MAP) { 1977 cmd.cp_inmod |= TAVOR_CMD_UNMAP_EQ_MASK; 1978 } 1979 cmd.cp_opcode = MAP_EQ; 1980 cmd.cp_opmod = 0; 1981 cmd.cp_flags = sleepflag; 1982 status = tavor_cmd_post(state, &cmd); 1983 1984 return (status); 1985 } 1986 1987 1988 /* 1989 * tavor_resize_cq_cmd_post() 1990 * Context: Can be called from interrupt or base context. 1991 */ 1992 int 1993 tavor_resize_cq_cmd_post(tavor_state_t *state, tavor_hw_cqc_t *cqc, 1994 uint_t cqcindx, uint32_t *prod_indx, uint_t sleepflag) 1995 { 1996 tavor_mbox_info_t mbox_info; 1997 tavor_cmd_post_t cmd; 1998 uint64_t data; 1999 uint_t size; 2000 int status, i; 2001 2002 /* Get an "In" mailbox for the command */ 2003 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2004 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2005 if (status != TAVOR_CMD_SUCCESS) { 2006 return (status); 2007 } 2008 2009 /* Copy the Tavor "RESIZE_CQ" command into mailbox */ 2010 size = sizeof (tavor_hw_cqc_t); 2011 for (i = 0; i < (size >> 3); i++) { 2012 data = ((uint64_t *)cqc)[i]; 2013 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2014 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 2015 } 2016 2017 /* Sync the mailbox for the device to read */ 2018 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2019 2020 /* Setup and post Tavor "RESIZE_CQ" command */ 2021 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2022 cmd.cp_outparm = 0; 2023 cmd.cp_inmod = cqcindx; 2024 cmd.cp_opcode = RESIZE_CQ; 2025 cmd.cp_opmod = 0; 2026 cmd.cp_flags = sleepflag; 2027 status = tavor_cmd_post(state, &cmd); 2028 2029 /* 2030 * New "producer index" is returned in the upper 32 bits of 2031 * command "outparam" 2032 */ 2033 *prod_indx = (cmd.cp_outparm >> 32); 2034 2035 /* Free the mailbox */ 2036 tavor_mbox_free(state, &mbox_info); 2037 2038 return (status); 2039 } 2040 2041 2042 /* 2043 * tavor_cmn_qp_cmd_post() 2044 * Context: Can be called from interrupt or base context. 2045 * 2046 * This is the common function for posting all the various types of 2047 * QP state transition related Tavor commands. Since some of the 2048 * commands differ from the others in the number (and type) of arguments 2049 * that each require, this routine does checks based on opcode type 2050 * (explained in more detail below). 2051 * 2052 * Note: This common function should be used only with the following 2053 * opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP, 2054 * INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP. 2055 */ 2056 int 2057 tavor_cmn_qp_cmd_post(tavor_state_t *state, uint_t opcode, 2058 tavor_hw_qpc_t *qp, uint_t qpindx, uint32_t opmask, 2059 uint_t sleepflag) 2060 { 2061 tavor_mbox_info_t mbox_info; 2062 tavor_cmd_post_t cmd; 2063 uint64_t data, in_mapaddr, out_mapaddr; 2064 uint_t size, flags, opmod; 2065 int status, i; 2066 2067 /* 2068 * Use the specified opcode type to set the appropriate parameters. 2069 * Specifically, we need to set in_mapaddr, out_mapaddr, flags, and 2070 * opmod (as necessary). Setting these parameters may also require 2071 * us to allocate an "In" or "Out" mailbox depending on the command 2072 * type. 2073 */ 2074 if (opcode == RTS2SQD_QP) { 2075 /* 2076 * Note: For RTS-to-SendQueueDrain state transitions we 2077 * always want to request the event generation from the 2078 * hardware. Though we may not notify the consumer of the 2079 * drained event, the decision to forward (or not) is made 2080 * later in the SQD event handler. 2081 */ 2082 flags = TAVOR_CMD_REQ_SQD_EVENT; 2083 2084 /* 2085 * The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and 2086 * has no special opcode modifiers). 2087 */ 2088 in_mapaddr = 0; 2089 out_mapaddr = 0; 2090 opmod = 0; 2091 2092 } else if (opcode == TOERR_QP) { 2093 /* 2094 * The TOERR_QP command uses no "In" or "Out" mailboxes, has no 2095 * special opcode modifiers, and takes no special flags. 2096 */ 2097 in_mapaddr = 0; 2098 out_mapaddr = 0; 2099 opmod = 0; 2100 flags = 0; 2101 2102 } else if (opcode == TORST_QP) { 2103 /* 2104 * The TORST_QP command could take an "Out" mailbox, but we do 2105 * not require it here. It also does not takes any special 2106 * flags. It does however, take a TAVOR_CMD_DIRECT_TO_RESET 2107 * opcode modifier, which indicates that the transition to 2108 * reset should happen without first moving the QP through the 2109 * Error state (and, hence, without generating any unnecessary 2110 * "flushed-in-error" completions). 2111 */ 2112 in_mapaddr = 0; 2113 out_mapaddr = 0; 2114 opmod = TAVOR_CMD_DIRECT_TO_RESET | TAVOR_CMD_NO_OUTMBOX; 2115 flags = 0; 2116 2117 } else { 2118 /* 2119 * All the other QP state transition commands (RST2INIT_QP, 2120 * INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, 2121 * SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox. 2122 * None of these require any special flags or opcode modifiers. 2123 */ 2124 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2125 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2126 if (status != TAVOR_CMD_SUCCESS) { 2127 return (status); 2128 } 2129 in_mapaddr = mbox_info.mbi_in->mb_mapaddr; 2130 out_mapaddr = 0; 2131 flags = 0; 2132 opmod = 0; 2133 2134 /* Copy the Tavor command into the "In" mailbox */ 2135 size = sizeof (tavor_hw_qpc_t); 2136 for (i = 0; i < (size >> 3); i++) { 2137 data = ((uint64_t *)qp)[i]; 2138 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2139 ((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1), 2140 data); 2141 } 2142 ddi_put32(mbox_info.mbi_in->mb_acchdl, 2143 ((uint32_t *)mbox_info.mbi_in->mb_addr), opmask); 2144 2145 /* 2146 * Sync the mailbox for the device to read. We have to add 2147 * eight bytes here to account for "opt_param_mask" and 2148 * proper alignment. 2149 */ 2150 tavor_mbox_sync(mbox_info.mbi_in, 0, size + 8, 2151 DDI_DMA_SYNC_FORDEV); 2152 } 2153 2154 /* Setup and post Tavor QP state transition command */ 2155 cmd.cp_inparm = in_mapaddr; 2156 cmd.cp_outparm = out_mapaddr; 2157 cmd.cp_inmod = qpindx | flags; 2158 cmd.cp_opcode = opcode; 2159 cmd.cp_opmod = opmod; 2160 cmd.cp_flags = sleepflag; 2161 status = tavor_cmd_post(state, &cmd); 2162 2163 /* 2164 * If we allocated a mailbox (either an "In" or an "Out") above, 2165 * then free it now before returning. 2166 */ 2167 if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) && 2168 (opcode != TORST_QP)) { 2169 /* Free the mailbox */ 2170 tavor_mbox_free(state, &mbox_info); 2171 } 2172 2173 return (status); 2174 } 2175 2176 2177 /* 2178 * tavor_cmn_query_cmd_post() 2179 * Context: Can be called from interrupt or base context. 2180 * 2181 * This is the common function for posting all the various types of 2182 * Tavor query commands. All Tavor query commands require an "Out" 2183 * mailbox to be allocated for the resulting queried data. 2184 * 2185 * Note: This common function should be used only with the following 2186 * opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER, 2187 * QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP. 2188 */ 2189 int 2190 tavor_cmn_query_cmd_post(tavor_state_t *state, uint_t opcode, 2191 uint_t queryindx, void *query, uint_t size, uint_t sleepflag) 2192 { 2193 tavor_mbox_info_t mbox_info; 2194 tavor_cmd_post_t cmd; 2195 uint64_t data; 2196 uint_t offset; 2197 int status, i; 2198 2199 /* Get an "Out" mailbox for the command */ 2200 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX; 2201 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2202 if (status != TAVOR_CMD_SUCCESS) { 2203 return (status); 2204 } 2205 2206 /* Setup and post the Tavor query command */ 2207 cmd.cp_inparm = 0; 2208 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2209 cmd.cp_inmod = queryindx; 2210 cmd.cp_opcode = opcode; 2211 cmd.cp_opmod = 0; 2212 cmd.cp_flags = sleepflag; 2213 status = tavor_cmd_post(state, &cmd); 2214 if (status != TAVOR_CMD_SUCCESS) { 2215 goto cmn_query_fail; 2216 } 2217 2218 /* Sync the mailbox to read the results */ 2219 tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 2220 2221 /* 2222 * QUERY_QP is handled somewhat differently than the other query 2223 * commands. For QUERY_QP, the actual queried data is offset into 2224 * the mailbox (by one 64-bit word). 2225 */ 2226 offset = (opcode == QUERY_QP) ? 1 : 0; 2227 2228 /* Copy query command results into "query" */ 2229 for (i = 0; i < (size >> 3); i++) { 2230 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2231 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset)); 2232 ((uint64_t *)query)[i] = data; 2233 } 2234 2235 cmn_query_fail: 2236 /* Free the mailbox */ 2237 tavor_mbox_free(state, &mbox_info); 2238 2239 return (status); 2240 } 2241 2242 2243 /* 2244 * tavor_cmn_ownership_cmd_post() 2245 * Context: Can be called from interrupt or base context. 2246 * 2247 * This is the common function for posting all the various types of 2248 * Tavor HW/SW resource ownership commands. Since some of the commands 2249 * differ from the others in the direction of ownership change (i.e. 2250 * from HW ownership to SW, or vice versa), they differ in the type of 2251 * mailbox and specific handling that each requires. This routine does 2252 * certain checks based on opcode type to determine the direction of 2253 * the transition and to correctly handle the request. 2254 * 2255 * Note: This common function should be used only with the following 2256 * opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and 2257 * SW2HW_CQ 2258 */ 2259 int 2260 tavor_cmn_ownership_cmd_post(tavor_state_t *state, uint_t opcode, 2261 void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag) 2262 { 2263 tavor_mbox_info_t mbox_info; 2264 tavor_cmd_post_t cmd; 2265 uint64_t data, in_mapaddr, out_mapaddr; 2266 uint_t direction, opmod; 2267 int status, i; 2268 2269 /* 2270 * Determine the direction of the ownership transfer based on the 2271 * provided opcode 2272 */ 2273 if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) || 2274 (opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) { 2275 direction = TAVOR_CMD_RSRC_HW2SW; 2276 2277 } else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) || 2278 (opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) { 2279 direction = TAVOR_CMD_RSRC_SW2HW; 2280 2281 } else { 2282 return (TAVOR_CMD_INVALID_STATUS); 2283 } 2284 2285 /* 2286 * If hwrsrc is NULL then we do not allocate a mailbox. This is used 2287 * in the case of memory deregister where the out mailbox is not 2288 * needed. In the case of re-register, we do use the hwrsrc. 2289 * 2290 * Otherwise, If ownership transfer is going from hardware to software, 2291 * then allocate an "Out" mailbox. This will be filled in later as a 2292 * result of the Tavor command. 2293 * 2294 * And if the ownership transfer is going from software to hardware, 2295 * then we need an "In" mailbox, and we need to fill it in and sync it 2296 * (if necessary). Then the mailbox can be passed to the Tavor 2297 * firmware. 2298 * 2299 * For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is != 2300 * NULL. This implies a re-reg, and the out mbox must be used. If 2301 * hwrsrc is == NULL, then we can save some time and resources by not 2302 * using an out mbox at all. We must set opmod to TAVOR_CMD_DO_OUTMBOX 2303 * and TAVOR_CMD_NO_OUTMBOX appropriately in this case. 2304 * 2305 * For the SW2HW (reg) case, no out mbox is possible. We set opmod to 2306 * 0 anyway, but this field is not used in this case. 2307 */ 2308 if (direction == TAVOR_CMD_RSRC_HW2SW) { 2309 if (hwrsrc != NULL) { 2310 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX; 2311 status = tavor_mbox_alloc(state, &mbox_info, 2312 sleepflag); 2313 if (status != TAVOR_CMD_SUCCESS) { 2314 return (status); 2315 } 2316 in_mapaddr = 0; 2317 out_mapaddr = mbox_info.mbi_out->mb_mapaddr; 2318 opmod = TAVOR_CMD_DO_OUTMBOX; 2319 } else { 2320 in_mapaddr = 0; 2321 out_mapaddr = 0; 2322 opmod = TAVOR_CMD_NO_OUTMBOX; 2323 } 2324 } else { /* TAVOR_CMD_RSRC_SW2HW */ 2325 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2326 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2327 if (status != TAVOR_CMD_SUCCESS) { 2328 return (status); 2329 } 2330 2331 /* Copy the SW2HW ownership command into mailbox */ 2332 for (i = 0; i < (size >> 3); i++) { 2333 data = ((uint64_t *)hwrsrc)[i]; 2334 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2335 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), 2336 data); 2337 } 2338 2339 /* Sync the mailbox for the device to read */ 2340 tavor_mbox_sync(mbox_info.mbi_in, 0, size, 2341 DDI_DMA_SYNC_FORDEV); 2342 2343 in_mapaddr = mbox_info.mbi_in->mb_mapaddr; 2344 out_mapaddr = 0; 2345 opmod = 0; 2346 } 2347 2348 2349 /* Setup and post the Tavor ownership command */ 2350 cmd.cp_inparm = in_mapaddr; 2351 cmd.cp_outparm = out_mapaddr; 2352 cmd.cp_inmod = hwrsrcindx; 2353 cmd.cp_opcode = opcode; 2354 cmd.cp_opmod = opmod; 2355 cmd.cp_flags = sleepflag; 2356 status = tavor_cmd_post(state, &cmd); 2357 if (status != TAVOR_CMD_SUCCESS) { 2358 goto cmn_ownership_fail; 2359 } 2360 2361 /* 2362 * As mentioned above, for HW2SW ownership transfers we need to 2363 * sync (if necessary) and copy out the resulting data from the 2364 * "Out" mailbox" (assuming the above command was successful). 2365 */ 2366 if (direction == TAVOR_CMD_RSRC_HW2SW && hwrsrc != NULL) { 2367 /* Sync the mailbox to read the results */ 2368 tavor_mbox_sync(mbox_info.mbi_out, 0, size, 2369 DDI_DMA_SYNC_FORCPU); 2370 2371 /* Copy HW2SW ownership command results into "hwrsrc" */ 2372 for (i = 0; i < (size >> 3); i++) { 2373 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2374 ((uint64_t *)mbox_info.mbi_out->mb_addr + i)); 2375 ((uint64_t *)hwrsrc)[i] = data; 2376 } 2377 } 2378 2379 cmn_ownership_fail: 2380 if (hwrsrc != NULL) { 2381 /* Free the mailbox */ 2382 tavor_mbox_free(state, &mbox_info); 2383 } 2384 2385 return (status); 2386 } 2387 2388 2389 /* 2390 * tavor_conf_special_qp_cmd_post() 2391 * Context: Can be called from interrupt or base context. 2392 */ 2393 int 2394 tavor_conf_special_qp_cmd_post(tavor_state_t *state, uint_t qpindx, 2395 uint_t qptype, uint_t sleepflag) 2396 { 2397 tavor_cmd_post_t cmd; 2398 int status; 2399 2400 /* Setup and post Tavor "CONF_SPECIAL_QP" command */ 2401 cmd.cp_inparm = 0; 2402 cmd.cp_outparm = 0; 2403 cmd.cp_inmod = qpindx; 2404 cmd.cp_opcode = CONF_SPECIAL_QP; 2405 cmd.cp_opmod = qptype; 2406 cmd.cp_flags = sleepflag; 2407 status = tavor_cmd_post(state, &cmd); 2408 2409 return (status); 2410 } 2411 2412 2413 /* 2414 * tavor_mgid_hash_cmd_post() 2415 * Context: Can be called from interrupt or base context. 2416 */ 2417 int 2418 tavor_mgid_hash_cmd_post(tavor_state_t *state, uint64_t mgid_h, 2419 uint64_t mgid_l, uint64_t *mgid_hash, uint_t sleepflag) 2420 { 2421 tavor_mbox_info_t mbox_info; 2422 tavor_cmd_post_t cmd; 2423 int status; 2424 2425 /* Get an "In" mailbox for the command */ 2426 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2427 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2428 if (status != TAVOR_CMD_SUCCESS) { 2429 return (status); 2430 } 2431 2432 /* Copy the Tavor "MGID_HASH" command into mailbox */ 2433 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2434 ((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h); 2435 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2436 ((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l); 2437 2438 /* Sync the mailbox for the device to read */ 2439 tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_MGIDHASH_SZ, 2440 DDI_DMA_SYNC_FORDEV); 2441 2442 /* Setup and post the Tavor "MGID_HASH" command */ 2443 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2444 cmd.cp_outparm = 0; 2445 cmd.cp_inmod = 0; 2446 cmd.cp_opcode = MGID_HASH; 2447 cmd.cp_opmod = 0; 2448 cmd.cp_flags = sleepflag; 2449 status = tavor_cmd_post(state, &cmd); 2450 2451 /* MGID hash value is returned in command "outparam" */ 2452 *mgid_hash = cmd.cp_outparm; 2453 2454 /* Free the mailbox */ 2455 tavor_mbox_free(state, &mbox_info); 2456 2457 return (status); 2458 } 2459 2460 2461 /* 2462 * tavor_read_mgm_cmd_post() 2463 * Context: Can be called from interrupt or base context. 2464 * 2465 * Note: It is assumed that the "mcg" parameter is actually a pointer to a 2466 * "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t" 2467 * structs. Combined size should be equal to result of TAVOR_MCGMEM_SZ() 2468 * macro. 2469 */ 2470 int 2471 tavor_read_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg, 2472 uint_t mcgindx, uint_t sleepflag) 2473 { 2474 tavor_mbox_info_t mbox_info; 2475 tavor_cmd_post_t cmd; 2476 uint64_t data; 2477 uint_t size, hdrsz, qplistsz; 2478 int status, i; 2479 2480 /* Get an "Out" mailbox for the results */ 2481 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX; 2482 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2483 if (status != TAVOR_CMD_SUCCESS) { 2484 return (status); 2485 } 2486 2487 /* Setup and post Tavor "READ_MGM" command */ 2488 cmd.cp_inparm = 0; 2489 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2490 cmd.cp_inmod = mcgindx; 2491 cmd.cp_opcode = READ_MGM; 2492 cmd.cp_opmod = 0; 2493 cmd.cp_flags = sleepflag; 2494 status = tavor_cmd_post(state, &cmd); 2495 if (status != TAVOR_CMD_SUCCESS) { 2496 goto read_mgm_fail; 2497 } 2498 2499 /* Sync the mailbox to read the results */ 2500 size = TAVOR_MCGMEM_SZ(state); 2501 tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 2502 2503 /* Copy the READ_MGM command results into "mcg" */ 2504 hdrsz = sizeof (tavor_hw_mcg_t); 2505 for (i = 0; i < (hdrsz >> 3); i++) { 2506 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2507 ((uint64_t *)mbox_info.mbi_out->mb_addr + i)); 2508 ((uint64_t *)mcg)[i] = data; 2509 } 2510 qplistsz = size - hdrsz; 2511 for (i = 0; i < (qplistsz >> 2); i++) { 2512 data = ddi_get32(mbox_info.mbi_out->mb_acchdl, 2513 ((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8)); 2514 ((uint32_t *)mcg)[i + 8] = data; 2515 } 2516 2517 read_mgm_fail: 2518 /* Free the mailbox */ 2519 tavor_mbox_free(state, &mbox_info); 2520 2521 return (status); 2522 } 2523 2524 2525 /* 2526 * tavor_write_mgm_cmd_post() 2527 * Context: Can be called from interrupt or base context. 2528 * 2529 * Note: It is assumed that the "mcg" parameter is actually a pointer to a 2530 * "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t" 2531 * structs. Combined size should be equal to result of TAVOR_MCGMEM_SZ() 2532 * macro. 2533 */ 2534 int 2535 tavor_write_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg, 2536 uint_t mcgindx, uint_t sleepflag) 2537 { 2538 tavor_mbox_info_t mbox_info; 2539 tavor_cmd_post_t cmd; 2540 uint64_t data; 2541 uint_t size, hdrsz, qplistsz; 2542 int status, i; 2543 2544 /* Get an "In" mailbox for the command */ 2545 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2546 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2547 if (status != TAVOR_CMD_SUCCESS) { 2548 return (status); 2549 } 2550 2551 /* Copy the Tavor "WRITE_MGM" command into mailbox */ 2552 size = TAVOR_MCGMEM_SZ(state); 2553 hdrsz = sizeof (tavor_hw_mcg_t); 2554 for (i = 0; i < (hdrsz >> 3); i++) { 2555 data = ((uint64_t *)mcg)[i]; 2556 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2557 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 2558 } 2559 qplistsz = size - hdrsz; 2560 for (i = 0; i < (qplistsz >> 2); i++) { 2561 data = ((uint32_t *)mcg)[i + 8]; 2562 ddi_put32(mbox_info.mbi_in->mb_acchdl, 2563 ((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data); 2564 } 2565 2566 /* Sync the mailbox for the device to read */ 2567 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2568 2569 /* Setup and post Tavor "WRITE_MGM" command */ 2570 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2571 cmd.cp_outparm = 0; 2572 cmd.cp_inmod = mcgindx; 2573 cmd.cp_opcode = WRITE_MGM; 2574 cmd.cp_opmod = 0; 2575 cmd.cp_flags = sleepflag; 2576 status = tavor_cmd_post(state, &cmd); 2577 2578 /* Free the mailbox */ 2579 tavor_mbox_free(state, &mbox_info); 2580 2581 return (status); 2582 2583 } 2584 2585 2586 /* 2587 * tavor_modify_mpt_cmd_post() 2588 * Context: Can be called from interrupt or base context. 2589 */ 2590 int 2591 tavor_modify_mpt_cmd_post(tavor_state_t *state, tavor_hw_mpt_t *mpt, 2592 uint_t mptindx, uint_t flags, uint_t sleepflag) 2593 { 2594 tavor_mbox_info_t mbox_info; 2595 tavor_cmd_post_t cmd; 2596 uint64_t data; 2597 uint_t size; 2598 int status, i; 2599 2600 /* Get an "In" mailbox for the command */ 2601 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX; 2602 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2603 if (status != TAVOR_CMD_SUCCESS) { 2604 return (status); 2605 } 2606 2607 /* Copy the Tavor "MODIFY_MPT" command into mailbox */ 2608 size = sizeof (tavor_hw_mpt_t); 2609 for (i = 0; i < (size >> 3); i++) { 2610 data = ((uint64_t *)mpt)[i]; 2611 ddi_put64(mbox_info.mbi_in->mb_acchdl, 2612 ((uint64_t *)mbox_info.mbi_in->mb_addr + i), data); 2613 } 2614 2615 /* Sync the mailbox for the device to read */ 2616 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2617 2618 /* Setup and post Tavor "MODIFY_MPT" command */ 2619 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2620 cmd.cp_outparm = 0; 2621 cmd.cp_inmod = mptindx; 2622 cmd.cp_opcode = MODIFY_MPT; 2623 cmd.cp_opmod = flags; 2624 cmd.cp_flags = sleepflag; 2625 status = tavor_cmd_post(state, &cmd); 2626 2627 /* Free the mailbox */ 2628 tavor_mbox_free(state, &mbox_info); 2629 2630 return (status); 2631 } 2632 2633 /* 2634 * tavor_getpefcntr_cmd_post() 2635 * Context: Can be called from interrupt or base context. 2636 * 2637 * If reset is zero, read the performance counters of the specified port and 2638 * copy them into perfinfo. 2639 * If reset is non-zero reset the performance counters of the specified port. 2640 */ 2641 int 2642 tavor_getperfcntr_cmd_post(tavor_state_t *state, uint_t port, 2643 uint_t sleepflag, tavor_hw_sm_perfcntr_t *perfinfo, int reset) 2644 { 2645 tavor_mbox_info_t mbox_info; 2646 tavor_cmd_post_t cmd; 2647 uint64_t data; 2648 uint32_t *mbox; 2649 uint_t size; 2650 int status, i; 2651 2652 bzero((void *)&cmd, sizeof (tavor_cmd_post_t)); 2653 2654 /* Get "In" and "Out" mailboxes for the command */ 2655 mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX; 2656 status = tavor_mbox_alloc(state, &mbox_info, sleepflag); 2657 if (status != TAVOR_CMD_SUCCESS) { 2658 return (status); 2659 } 2660 2661 /* Build request MAD in the "In" mailbox */ 2662 size = TAVOR_CMD_MAD_IFC_SIZE; 2663 mbox = (uint32_t *)mbox_info.mbi_in->mb_addr; 2664 2665 if (reset) { 2666 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], 2667 TAVOR_CMD_PERF_SET); 2668 } else { 2669 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], 2670 TAVOR_CMD_PERF_GET); 2671 } 2672 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1); 2673 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2); 2674 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3); 2675 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PERFCNTRS); 2676 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], TAVOR_CMD_PERFATTR); 2677 2678 if (reset) { 2679 /* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */ 2680 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], 2681 ((port << 16) | 0xf000)); 2682 2683 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0); 2684 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0); 2685 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0); 2686 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0); 2687 } else 2688 ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16)); 2689 2690 /* Sync the mailbox for the device to read */ 2691 tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV); 2692 2693 /* Setup the Hermon "MAD_IFC" command */ 2694 cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr; 2695 cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr; 2696 cmd.cp_inmod = port; 2697 cmd.cp_opcode = MAD_IFC; 2698 /* No MKey and BKey checking */ 2699 cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK | TAVOR_CMD_BKEY_DONTCHECK; 2700 cmd.cp_flags = TAVOR_CMD_NOSLEEP_SPIN; /* NO SLEEP */ 2701 status = tavor_cmd_post(state, &cmd); 2702 if (status != TAVOR_CMD_SUCCESS) { 2703 goto getperfinfo_fail; 2704 } 2705 2706 /* Sync the mailbox to read the results */ 2707 size = TAVOR_CMD_MAD_IFC_SIZE; 2708 tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU); 2709 2710 if (reset == 0) { 2711 size = sizeof (tavor_hw_sm_perfcntr_t); /* for the copy */ 2712 /* 2713 * Copy Perfcounters into "perfinfo". We can discard the MAD 2714 * header and the 8 Quadword reserved area of the PERM mgmt 2715 * class MAD 2716 */ 2717 2718 for (i = 0; i < size >> 3; i++) { 2719 data = ddi_get64(mbox_info.mbi_out->mb_acchdl, 2720 ((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8)); 2721 ((uint64_t *)(void *)perfinfo)[i] = data; 2722 } 2723 } 2724 2725 getperfinfo_fail: 2726 /* Free the mailbox */ 2727 tavor_mbox_free(state, &mbox_info); 2728 return (status); 2729 } 2730