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 }