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