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