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