tavor_cmd.c revision 2bc987325e3ded1865bff043128661815c4690b9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Tavor Firmware Command Routines
*
* Implements all the routines necessary for allocating, posting, and
* freeing commands for the Tavor firmware. These routines manage a
* preallocated list of command mailboxes and provide interfaces to post
* each of the several dozen commands to the Tavor firmware.
*/
tavor_cmd_t **cmd_ptr);
/*
* tavor_cmd_post()
* Context: Can be called from interrupt or base context.
*
* The "cp_flags" field in cmdpost
* is used to determine whether to wait for an available
* outstanding command (if necessary) or to return error.
*/
int
{
int status;
/* Determine if we are going to spin until completion */
/* Write the command to the HCR */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
return (TAVOR_CMD_SUCCESS);
} else { /* "TAVOR_CMD_SLEEP_NOSPIN" */
/* NOTE: Expect threads to be waiting in here */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/*
* Set status to "TAVOR_CMD_INVALID_STATUS". It is
* appropriate to do this here without the "cmd_comp_lock"
* because this register is overloaded. Later it will be
* used to indicate - through a change from this invalid
* value to some other value - that the condition variable
* has been signaled. Once it has, status will then contain
* the _real_ completion status
*/
/* Write the command to the HCR */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/*
* cv_wait() on the "command_complete" condition variable.
* Note: We have the "__lock_lint" here to workaround warlock.
* Since warlock doesn't know that other parts of the Tavor
* may occasionally call this routine while holding their own
* locks, it complains about this cv_wait. In reality,
* however, the rest of the driver never calls this routine
* with a lock held unless they pass TAVOR_CMD_NOSLEEP.
*/
#ifndef __lock_lint
/* NOTE: EXPECT SEVERAL THREADS TO BE WAITING HERE */
#endif
}
/*
* Wake up after command completes (cv_signal). Read status
* from the command (success, fail, etc.). It is appropriate
* here (as above) to read the status field without the
* "cmd_comp_lock" because it is no longer being used to
* indicate whether the condition variable has been signaled
* (i.e. at this point we are certain that it already has).
*/
/* Save the "outparam" values into the cmdpost struct */
/*
* Add the command back to the "outstanding commands list".
* Signal the "cmd_list" condition variable, if necessary.
*/
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
return (TAVOR_CMD_SUCCESS);
}
}
/*
* tavor_mbox_alloc()
* Context: Can be called from interrupt or base context.
*
* The "mbox_wait" parameter is used to determine whether to
* wait for a mailbox to become available or not.
*/
int
{
int status;
/* Allocate an "In" mailbox */
/* Determine correct mboxlist based on calling context */
if (sleep_context == TAVOR_NOSLEEP) {
} else {
/* NOTE: Expect threads to be waiting in here */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
}
}
/* Allocate an "Out" mailbox */
/* Determine correct mboxlist based on calling context */
if (sleep_context == TAVOR_NOSLEEP) {
} else {
/* NOTE: Expect threads to be waiting in here */
if (status != TAVOR_CMD_SUCCESS) {
/* If we allocated an "In" mailbox, free it */
if (mbox_info->mbi_alloc_flags &
}
return (status);
}
}
}
/* Store appropriate context in mbox_info */
return (TAVOR_CMD_SUCCESS);
}
/*
* tavor_mbox_free()
* Context: Can be called from interrupt or base context.
*/
void
{
/*
* The mailbox has to be freed in the same context from which it was
* allocated. The context is stored in the mbox_info at
* tavor_mbox_alloc() time. We check the stored context against the
* current context here.
*/
/* Determine correct mboxlist based on calling context */
/* Free the intr "In" mailbox */
}
/* Free the intr "Out" mailbox */
}
} else {
/* Free the "In" mailbox */
}
/* Free the "Out" mailbox */
}
}
}
/*
* tavor_cmd_complete_handler()
* Context: Called only from interrupt context.
*/
int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/*
* Find the outstanding command pointer based on value returned
* in "token"
*/
/* Signal the waiting thread */
return (DDI_SUCCESS);
}
/*
* tavor_inmbox_list_init()
* Context: Only called from attach() path context
*/
int
{
int status;
/* Initialize the "In" mailbox list */
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* tavor_intr_inmbox_list_init()
* Context: Only called from attach() path context
*/
int
{
int status;
/* Initialize the interrupt "In" mailbox list */
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* tavor_outmbox_list_init()
* Context: Only called from attach() path context
*/
int
{
int status;
/* Initialize the "Out" mailbox list */
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* tavor_intr_outmbox_list_init()
* Context: Only called from attach() path context
*/
int
{
int status;
/* Initialize the interrupts "Out" mailbox list */
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* tavor_inmbox_list_fini()
*/
void
{
/* Free up the "In" mailbox list */
}
/*
* tavor_intr_inmbox_list_fini()
*/
void
{
/* Free up the interupts "In" mailbox list */
}
/*
* tavor_outmbox_list_fini()
*/
void
{
/* Free up the "Out" mailbox list */
}
/*
* tavor_intr_outmbox_list_fini()
*/
void
{
/* Free up the interrupt "Out" mailbox list */
}
/*
* tavor_impl_mbox_alloc()
* Context: Can be called from interrupt or base context.
*/
static int
{
/*
* If the mailbox list is empty, then wait (if appropriate in the
* current context). Otherwise, grab the next available mailbox.
*/
if (mbox_wait == TAVOR_NOSLEEP) {
count = 0;
mblist->mbl_pollers++;
while (mblist->mbl_entries_free == 0) {
/* Delay loop polling for an available mbox */
TAVOR_TNF_ERROR, "");
return (TAVOR_CMD_INSUFF_RSRC);
}
/* Delay before polling for mailbox again */
}
mblist->mbl_pollers--;
/* TAVOR_SLEEP */
} else {
/*
* Grab lock here as we prepare to cv_wait if needed.
*/
while (mblist->mbl_entries_free == 0) {
/*
* Wait (on cv) for a mailbox to become free. Note:
* Just as we do above in tavor_cmd_post(), we also
* have the "__lock_lint" here to workaround warlock.
* Warlock doesn't know that other parts of the Tavor
* may occasionally call this routine while holding
* their own locks, so it complains about this cv_wait.
* In reality, however, the rest of the driver never
* calls this routine with a lock held unless they pass
* TAVOR_CMD_NOSLEEP.
*/
mblist->mbl_waiters++;
#ifndef __lock_lint
#endif
}
}
/* Grab the next available mailbox from list */
/* Remove it from the mailbox list */
/* Update the "free" count and return the mailbox pointer */
return (TAVOR_CMD_SUCCESS);
}
/*
* tavor_impl_mbox_free()
* Context: Can be called from interrupt or base context.
*/
static void
{
/* Pull the "index" from mailbox entry */
/*
* If mailbox list is not empty, then insert the entry. Otherwise,
* this is the only entry. So update the pointers appropriately.
*/
if (mblist->mbl_entries_free++ != 0) {
/* Update the current mailbox */
/* Update head and tail mailboxes */
/* Update tail index */
} else {
/* Update the current mailbox */
/* Update head and tail indexes */
}
/*
* Because we can have both waiters (SLEEP treads waiting for a
* cv_signal to continue processing) and pollers (NOSLEEP treads
* polling for a mailbox to become available), we try to share CPU time
* between them. We do this by signalling the waiters only every other
* call to mbox_free. This gives the pollers a chance to get some CPU
* time to do their command. If we signalled every time, the pollers
* would have a much harder time getting CPU time.
*
* If there are waiters and no pollers, then we signal always.
*
* Otherwise, if there are either no waiters, there may in fact be
* pollers, so we do not signal in that case.
*/
/* flip the signal value */
} else if (mblist->mbl_waiters > 0) {
} else {
mblist->mbl_signal = 0;
}
/*
* Depending on the conditions in the previous check, we signal only if
* we are supposed to.
*/
if (mblist->mbl_signal) {
mblist->mbl_waiters--;
}
/* Clear out the mailbox entry pointer */
}
/*
* tavor_impl_mboxlist_init()
* Context: Only called from attach() path context
*/
static int
{
int status, i;
/* Allocate the memory for the mailbox entries list */
sizeof (tavor_mbox_t), KM_SLEEP);
/* Initialize the mailbox entries list */
mblist->mbl_head_indx = 0;
mblist->mbl_waiters = 0;
mblist->mbl_num_alloc = 0;
/* Set up the mailbox list's cv and mutex */
/* Determine if syncs will be necessary */
/* Determine whether to map DDI_DMA_STREAMING or DDI_DMA_CONSISTENT */
/* Initialize the mailbox list entries */
for (i = 0; i < mblist->mbl_list_sz; i++) {
/* Allocate resources for the mailbox */
&rsrc);
if (status != DDI_SUCCESS) {
/* Jump to cleanup and return error */
TAVOR_TNF_ERROR, "");
goto mboxlist_init_fail;
}
/* Save away the mailbox resource info */
/*
* Get a PCI mapped address for each mailbox. Note: this
* uses the ddi_dma_handle return from the resource
* allocation routine
*/
if (status != DDI_SUCCESS) {
/* Jump to cleanup and return error */
TAVOR_TNF_ERROR, "");
goto mboxlist_init_fail;
}
/* Save away the mapped address for the mailbox */
/* Set sync flag appropriately */
/* Make each entry point to the "next" and "prev" entries */
}
/* Make the "head" and "tail" entries point to each other */
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* tavor_impl_mboxlist_fini()
*/
static void
{
int i, status;
/* Release the resources for each of the mailbox list entries */
for (i = 0; i < mblist->mbl_num_alloc; i++) {
/*
* First, unbind the DMA memory for the mailbox
*
* Note: The only way ddi_dma_unbind_handle() currently
* can return an error is if the handle passed in is invalid.
* Since this should never happen, we choose to return void
* from this function! If this does return an error,
* however, then we print a warning message to the console.
*/
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return;
}
/* Next, free the mailbox resource */
}
/* Destroy the mailbox list mutex and cv */
/* Free up the memory for tracking the mailbox list */
sizeof (tavor_mbox_t));
}
/*
* tavor_outstanding_cmd_alloc()
* Context: Can be called only from base context.
*/
static int
{
/* Ensure that outstanding commands are supported */
/*
* If the outstanding command list is empty, then wait (if
* appropriate in the current context). Otherwise, grab the
* next available command.
*/
while (cmd_list->cml_entries_free == 0) {
/* No free commands */
if (cmd_wait == TAVOR_NOSLEEP) {
TAVOR_TNF_ERROR, "");
return (TAVOR_CMD_INSUFF_RSRC);
}
/*
* Wait (on cv) for a command to become free. Note: Just
* as we do above in tavor_cmd_post(), we also have the
* "__lock_lint" here to workaround warlock. Warlock doesn't
* know that other parts of the Tavor may occasionally call
* this routine while holding their own locks, so it complains
* about this cv_wait. In reality, however, the rest of the
* driver never calls this routine with a lock held unless
* they pass TAVOR_CMD_NOSLEEP.
*/
cmd_list->cml_waiters++;
#ifndef __lock_lint
#endif
}
/* Grab the next available command from the list */
/* Remove it from the command list */
/* Update the "free" count and return */
return (TAVOR_CMD_SUCCESS);
}
/*
* tavor_outstanding_cmd_free()
* Context: Can be called only from base context.
*/
static void
{
/* Pull the "index" from command entry */
/*
* If outstanding command list is not empty, then insert the entry.
* Otherwise, this is the only entry. So update the pointers
* appropriately.
*/
if (cmd_list->cml_entries_free++ != 0) {
/* Update the current command */
/* Update head and tail commands */
/* Update tail index */
} else {
/* Update the current command */
/* Update head and tail indexes */
}
/* If there are threads waiting, signal one of them */
if (cmd_list->cml_waiters > 0) {
cmd_list->cml_waiters--;
}
/* Clear out the command entry pointer */
}
/*
* tavor_write_hcr()
* Context: Can be called from interrupt or base context.
*/
static int
{
/*
* Grab the "HCR access" lock if the driver is not in
* fastreboot. In fastreboot, this function is called
* with the single thread but in high interrupt context
* (so that this mutex lock cannot be used).
*/
#ifdef __lock_lint
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
}
#endif
/*
* First, check the "go" bit to see if the previous hcr usage is
* complete. As long as it is set then we must continue to poll.
*/
count = 0;
for (;;) {
/* If "go" bit is clear, then done */
if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
count);
break;
}
/* Delay before polling the "go" bit again */
/*
* If we poll more than the maximum number of times, then
* return a "timeout" error.
*/
#ifdef __lock_lint
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
}
#endif
"");
return (TAVOR_CMD_TIMEOUT);
}
}
/* Write "inparam" as a 64-bit quantity */
/* Write "inmod" and 32-bits of "outparam" as 64-bit */
hcrreg);
/* Write the other 32-bits of "outparam" and "token" as 64-bit */
hcrreg);
/* Then setup the final hcrreg to hit doorbell (i.e. "go" bit) */
/* Write the doorbell to the HCR */
/*
* In the SPIN case we read the HCR and check the "go" bit. For the
* NOSPIN case we do not have to poll, we simply release the HCR lock
* and return.
*/
count = 0;
for (;;) {
/* If "go" bit is clear, then done */
if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
break;
}
/* Delay before polling the "go" bit again */
/*
* If we poll more than the maximum number of times,
* then return a "timeout" error.
*/
#ifdef __lock_lint
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
mutex_exit(&state->
}
#endif
TAVOR_TNF_ERROR, "");
return (TAVOR_CMD_TIMEOUT);
}
}
/* Pull out the "status" bits from the HCR */
/*
* Read the "outparam" value. Note: we have to read "outparam"
* as two separate 32-bit reads because the field in the HCR is
* not 64-bit aligned.
*/
/* NOSPIN */
} else {
}
/* Drop the "HCR access" lock */
#ifdef __lock_lint
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
}
#endif
return (status);
}
/*
* tavor_outstanding_cmdlist_init()
* Context: Only called from attach() path context
*/
int
{
int i;
/*
* Determine the number of the outstanding commands supported
* by the Tavor device (obtained from the QUERY_FW command). Note:
* Because we handle both SLEEP and NOSLEEP cases around the tavor HCR,
* we know that when an interrupt comes in it will be next on the
* command register, and will at most have to wait one commands time.
* We do not have to reserve an outstanding command here for
* interrupts.
*/
/* Initialize the outstanding command list */
/* Allocate the memory for the outstanding command list */
if (num_outstanding_cmds) {
sizeof (tavor_cmd_t), KM_SLEEP);
}
/* Initialize the individual outstanding command list entries */
}
if (num_outstanding_cmds) {
}
return (DDI_SUCCESS);
}
/*
* tavor_outstanding_cmdlist_fini()
*/
void
{
int i;
/* Destroy the outstanding command list entries */
}
/* Destroy the lock (and cv) and free up memory for list */
}
}
/*
* tavor_mbox_sync()
*/
static void
{
int status;
/* Determine if mailbox needs to be synced or not */
return;
}
/* Get the DMA handle from mailbox */
/* Calculate offset into mailbox */
if (status != DDI_SUCCESS) {
return;
}
}
/*
* tavor_sys_en_cmd_post()
* Context: Can be called from interrupt or base context.
* (Currently called only from attach() path context)
*/
int
{
int status;
/* Make sure we are called with the correct flag */
/* Setup and post the Tavor "SYS_EN" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
/*
* When the SYS_EN command fails, the "outparam" field may
* contain more detailed information about what caused the
* failure.
*/
}
return (status);
}
/*
* tavor_sys_dis_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Make sure we are called with the correct flag */
/* Setup and post the Tavor "SYS_DIS" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
return (status);
}
/*
* tavor_init_hca_cmd_post()
* Context: Can be called from interrupt or base context.
* (Currently called only from attach() path context)
*/
int
{
int status, i;
/* Make sure we are called with the correct flag */
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "INIT_HCA" command into the mailbox */
size = sizeof (tavor_hw_initqueryhca_t);
for (i = 0; i < (size >> 3); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post the Tavor "INIT_HCA" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
/* Free the mailbox */
return (status);
}
/*
* tavor_close_hca_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Make sure we are called with the correct flag */
/* Setup and post the Tavor "CLOSE_HCA" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
return (status);
}
/*
* tavor_init_ib_cmd_post()
* Context: Can be called from interrupt or base context.
* (Currently called only from attach() path context)
*/
int
{
int status, i;
/* Make sure we are called with the correct flag */
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "INIT_IB" command into the mailbox */
size = sizeof (tavor_hw_initib_t);
for (i = 0; i < (size >> 3); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post the Tavor "INIT_IB" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
/* Free the mailbox */
return (status);
}
/*
* tavor_close_ib_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Setup and post the Tavor "CLOSE_IB" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
return (status);
}
/*
* tavor_set_ib_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "SET_IB" command into mailbox */
/* Sync the mailbox for the device to read */
/* Setup and post the Tavor "SET_IB" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
/* Free the mailbox */
return (status);
}
/*
* tavor_mod_stat_cfg_cmd_post()
* Context: Can be called only from attach() path
*/
int
{
int status, i;
/*
* "MOD_STAT_CFG" needs an INMBOX parameter, to specify what operations
* to do. However, at the point in time that we call this command, the
* DDR has not yet been initialized, and all INMBOX'es are located in
* DDR. Because we want to call MOD_STAT_CFG before QUERY_DEVLIM is
* called, and thus call it before DDR is setup, we simply use an
* OUTMBOX memory location here as our INMBOX parameter.
*/
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/*
* Allocate on the heap our 'mod_stat_cfg' structure. We want to
* ideally move all of this on to the stack in the future, but this
* works well for now.
*/
sizeof (tavor_hw_mod_stat_cfg_t), KM_SLEEP);
/* Setup "MOD_STAT_CFG" settings */
} else {
mod->log_max_srq = 0;
}
/* Copy the "MOD_STAT_CFG" command into the "In" mailbox */
size = sizeof (tavor_hw_mod_stat_cfg_t);
for (i = 0; i < (size >> 3); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post the Tavor "MOD_STAT_CFG" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
"");
}
/* Free "MOD_STAT_CFG" struct */
/* Free the mailbox */
return (status);
}
/*
* tavor_mad_ifc_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the request MAD into the "In" mailbox */
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto mad_ifc_fail;
}
/* Sync the mailbox to read the results */
/* Copy the response MAD into "resp" */
/* Free the mailbox */
return (status);
}
/*
* tavor_getportinfo_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status, i;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
/* Build the GetPortInfo request MAD in the "In" mailbox */
}
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto getportinfo_fail;
}
/* Sync the mailbox to read the results */
size = sizeof (sm_portinfo_t);
/*
* Copy GetPortInfo response MAD into "portinfo". Do any endian
* swapping that may be necessary to flip any of the "portinfo"
* fields
*/
/* Free the mailbox */
return (status);
}
/*
* tavor_getnodeinfo_cmd_post()
* Context: Can be called from interrupt or base context.
* (Currently called only from attach() and detach() path contexts)
*/
int
{
int status, i;
/* Make sure we are called with the correct flag */
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
/* Build the GetNodeInfo request MAD into the "In" mailbox */
}
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto getnodeinfo_fail;
}
/* Sync the mailbox to read the results */
size = sizeof (sm_nodeinfo_t);
/*
* Copy GetNodeInfo response MAD into "nodeinfo". Do any endian
* swapping that may be necessary to flip any of the "nodeinfo"
* fields
*/
/* Free the mailbox */
return (status);
}
/*
* tavor_getnodedesc_cmd_post()
* Context: Can be called from interrupt or base context.
* (Currently called only from attach() and detach() path contexts)
*/
int
{
int status, i;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Build the GetNodeDesc request MAD into the "In" mailbox */
}
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto getnodedesc_fail;
}
/* Sync the mailbox to read the results */
size = sizeof (sm_nodedesc_t);
/* Copy GetNodeDesc response MAD into "nodedesc" */
/* Free the mailbox */
return (status);
}
/*
* tavor_getguidinfo_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status, i;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Build the GetGUIDInfo request MAD into the "In" mailbox */
}
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto getguidinfo_fail;
}
/* Sync the mailbox to read the results */
size = sizeof (sm_guidinfo_t);
/*
* Copy GetGUIDInfo response MAD into "guidinfo". Do any endian
* swapping that may be necessary to flip the "guidinfo" fields
*/
/* Free the mailbox */
return (status);
}
/*
* tavor_getpkeytable_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status, i;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Build the GetPkeyTable request MAD into the "In" mailbox */
}
/* Sync the mailbox for the device to read */
/* Setup the Tavor "MAD_IFC" command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto getpkeytable_fail;
}
/* Sync the mailbox to read the results */
size = sizeof (sm_pkey_table_t);
/*
* Copy GetPKeyTable response MAD into "pkeytable". Do any endian
* swapping that may be necessary to flip the "pkeytable" fields
*/
/* Free the mailbox */
return (status);
}
/*
* tavor_write_mtt_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/*
* The WRITE_MTT command is unlike the other commands we use, in that
* we have intentionally separated the mailbox allocation step from
* the rest of the command posting steps. At this point (when this
* function is called) the "In" mailbox already contains all the MTT
* entries to be copied into the Tavor tables (starting at offset
* 0x10) _and_ the 64-bit address of the destination for the first
* MTT entry in the MTT table.
*/
/* Sync the mailbox for the device to read */
/* Setup and post Tavor "WRITE_MTT" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
return (status);
}
/*
* tavor_sync_tpt_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Setup and post the Tavor "SYNC_TPT" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
return (status);
}
/*
* tavor_map_eq_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Setup and post Tavor "MAP_EQ" command */
cmd.cp_outparm = 0;
if (map != TAVOR_CMD_MAP_EQ_EVT_MAP) {
}
if (status != TAVOR_CMD_SUCCESS) {
}
return (status);
}
/*
* tavor_resize_cq_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status, i;
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "RESIZE_CQ" command into mailbox */
size = sizeof (tavor_hw_cqc_t);
for (i = 0; i < (size >> 3); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post Tavor "RESIZE_CQ" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
/*
* New "producer index" is returned in the upper 32 bits of
* command "outparam"
*/
/* Free the mailbox */
return (status);
}
/*
* tavor_cmn_qp_cmd_post()
* Context: Can be called from interrupt or base context.
*
* This is the common function for posting all the various types of
* QP state transition related Tavor commands. Since some of the
* commands differ from the others in the number (and type) of arguments
* that each require, this routine does checks based on opcode type
* (explained in more detail below).
*
* Note: This common function should be used only with the following
* opcodes: RTS2SQD_QP, TOERR_QP, TORST_QP, RST2INIT_QP, INIT2INIT_QP,
* INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP, SQD2RTS_QP, and SQERR2RTS_QP.
*/
int
{
int status, i;
/*
* Use the specified opcode type to set the appropriate parameters.
* Specifically, we need to set in_mapaddr, out_mapaddr, flags, and
* opmod (as necessary). Setting these parameters may also require
* us to allocate an "In" or "Out" mailbox depending on the command
* type.
*/
if (opcode == RTS2SQD_QP) {
/*
* Note: For RTS-to-SendQueueDrain state transitions we
* always want to request the event generation from the
* hardware. Though we may not notify the consumer of the
* drained event, the decision to forward (or not) is made
* later in the SQD event handler.
*/
/*
* The RTS2SQD_QP command uses no "In" or "Out" mailboxes (and
* has no special opcode modifiers).
*/
in_mapaddr = 0;
out_mapaddr = 0;
opmod = 0;
/*
* The TOERR_QP command uses no "In" or "Out" mailboxes, has no
* special opcode modifiers, and takes no special flags.
*/
in_mapaddr = 0;
out_mapaddr = 0;
opmod = 0;
flags = 0;
/*
* The TORST_QP command could take an "Out" mailbox, but we do
* not require it here. It also does not takes any special
* flags. It does however, take a TAVOR_CMD_DIRECT_TO_RESET
* opcode modifier, which indicates that the transition to
* reset should happen without first moving the QP through the
* Error state (and, hence, without generating any unnecessary
* "flushed-in-error" completions).
*/
in_mapaddr = 0;
out_mapaddr = 0;
flags = 0;
} else {
/*
* All the other QP state transition commands (RST2INIT_QP,
* INIT2INIT_QP, INIT2RTR_QP, RTR2RTS_QP, RTS2RTS_QP,
* SQD2RTS_QP, and SQERR2RTS_QP) require an "In" mailbox.
* None of these require any special flags or opcode modifiers.
*/
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
out_mapaddr = 0;
flags = 0;
opmod = 0;
/* Copy the Tavor command into the "In" mailbox */
size = sizeof (tavor_hw_qpc_t);
for (i = 0; i < (size >> 3); i++) {
data);
}
/*
* Sync the mailbox for the device to read. We have to add
* eight bytes here to account for "opt_param_mask" and
* proper alignment.
*/
}
/* Setup and post Tavor QP state transition command */
if (status != TAVOR_CMD_SUCCESS) {
}
/*
* If we allocated a mailbox (either an "In" or an "Out") above,
* then free it now before returning.
*/
/* Free the mailbox */
}
return (status);
}
/*
* tavor_cmn_query_cmd_post()
* Context: Can be called from interrupt or base context.
*
* This is the common function for posting all the various types of
* Tavor query commands. All Tavor query commands require an "Out"
* mailbox to be allocated for the resulting queried data.
*
* Note: This common function should be used only with the following
* opcodes: QUERY_DEV_LIM, QUERY_FW, QUERY_DDR, QUERY_ADAPTER,
* QUERY_HCA, QUERY_MPT, QUERY_EQ, QUERY_CQ, and QUERY_QP.
*/
int
{
int status, i;
/* Get an "Out" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Setup and post the Tavor query command */
if (status != TAVOR_CMD_SUCCESS) {
goto cmn_query_fail;
}
/* Sync the mailbox to read the results */
/*
* QUERY_QP is handled somewhat differently than the other query
* commands. For QUERY_QP, the actual queried data is offset into
* the mailbox (by one 64-bit word).
*/
/* Copy query command results into "query" */
for (i = 0; i < (size >> 3); i++) {
}
/* Free the mailbox */
return (status);
}
/*
* tavor_cmn_ownership_cmd_post()
* Context: Can be called from interrupt or base context.
*
* This is the common function for posting all the various types of
* differ from the others in the direction of ownership change (i.e.
* from HW ownership to SW, or vice versa), they differ in the type of
* mailbox and specific handling that each requires. This routine does
* certain checks based on opcode type to determine the direction of
* the transition and to correctly handle the request.
*
* Note: This common function should be used only with the following
* opcodes: HW2SW_MPT, HW2SW_EQ, HW2SW_CQ, SW2HW_MPT, SW2HW_EQ, and
* SW2HW_CQ
*/
int
{
int status, i;
/*
* Determine the direction of the ownership transfer based on the
* provided opcode
*/
} else {
TAVOR_TNF_ERROR, "");
return (TAVOR_CMD_INVALID_STATUS);
}
/*
* If hwrsrc is NULL then we do not allocate a mailbox. This is used
* in the case of memory deregister where the out mailbox is not
* needed. In the case of re-register, we do use the hwrsrc.
*
* Otherwise, If ownership transfer is going from hardware to software,
* then allocate an "Out" mailbox. This will be filled in later as a
* result of the Tavor command.
*
* And if the ownership transfer is going from software to hardware,
* then we need an "In" mailbox, and we need to fill it in and sync it
* (if necessary). Then the mailbox can be passed to the Tavor
* firmware.
*
* For the HW2SW (dereg) case, we only use an out mbox if hwrsrc is !=
* NULL. This implies a re-reg, and the out mbox must be used. If
* hwrsrc is == NULL, then we can save some time and resources by not
* using an out mbox at all. We must set opmod to TAVOR_CMD_DO_OUTMBOX
* and TAVOR_CMD_NO_OUTMBOX appropriately in this case.
*
* For the SW2HW (reg) case, no out mbox is possible. We set opmod to
* 0 anyway, but this field is not used in this case.
*/
if (direction == TAVOR_CMD_RSRC_HW2SW) {
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
in_mapaddr = 0;
} else {
in_mapaddr = 0;
out_mapaddr = 0;
}
} else { /* TAVOR_CMD_RSRC_SW2HW */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (status);
}
/* Copy the SW2HW ownership command into mailbox */
for (i = 0; i < (size >> 3); i++) {
data);
}
/* Sync the mailbox for the device to read */
out_mapaddr = 0;
opmod = 0;
}
/* Setup and post the Tavor ownership command */
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
goto cmn_ownership_fail;
}
/*
* As mentioned above, for HW2SW ownership transfers we need to
* sync (if necessary) and copy out the resulting data from the
* "Out" mailbox" (assuming the above command was successful).
*/
/* Sync the mailbox to read the results */
/* Copy HW2SW ownership command results into "hwrsrc" */
for (i = 0; i < (size >> 3); i++) {
}
}
/* Free the mailbox */
}
return (status);
}
/*
* tavor_conf_special_qp_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Setup and post Tavor "CONF_SPECIAL_QP" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
return (status);
}
/*
* tavor_mgid_hash_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status;
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "MGID_HASH" command into mailbox */
/* Sync the mailbox for the device to read */
/* Setup and post the Tavor "MGID_HASH" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
/* MGID hash value is returned in command "outparam" */
/* Free the mailbox */
return (status);
}
/*
* tavor_read_mgm_cmd_post()
* Context: Can be called from interrupt or base context.
*
* Note: It is assumed that the "mcg" parameter is actually a pointer to a
* "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
* structs. Combined size should be equal to result of TAVOR_MCGMEM_SZ()
* macro.
*/
int
{
int status, i;
/* Get an "Out" mailbox for the results */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Setup and post Tavor "READ_MGM" command */
if (status != TAVOR_CMD_SUCCESS) {
goto read_mgm_fail;
}
/* Sync the mailbox to read the results */
/* Copy the READ_MGM command results into "mcg" */
hdrsz = sizeof (tavor_hw_mcg_t);
for (i = 0; i < (hdrsz >> 3); i++) {
}
for (i = 0; i < (qplistsz >> 2); i++) {
}
/* Free the mailbox */
return (status);
}
/*
* tavor_write_mgm_cmd_post()
* Context: Can be called from interrupt or base context.
*
* Note: It is assumed that the "mcg" parameter is actually a pointer to a
* "tavor_hw_mcg_t" struct and some number of "tavor_hw_mcg_qp_list_t"
* structs. Combined size should be equal to result of TAVOR_MCGMEM_SZ()
* macro.
*/
int
{
int status, i;
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "WRITE_MGM" command into mailbox */
hdrsz = sizeof (tavor_hw_mcg_t);
for (i = 0; i < (hdrsz >> 3); i++) {
}
for (i = 0; i < (qplistsz >> 2); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post Tavor "WRITE_MGM" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
}
/* Free the mailbox */
return (status);
}
/*
* tavor_modify_mpt_cmd_post()
* Context: Can be called from interrupt or base context.
*/
int
{
int status, i;
/* Get an "In" mailbox for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Copy the Tavor "MODIFY_MPT" command into mailbox */
size = sizeof (tavor_hw_mpt_t);
for (i = 0; i < (size >> 3); i++) {
}
/* Sync the mailbox for the device to read */
/* Setup and post Tavor "MODIFY_MPT" command */
cmd.cp_outparm = 0;
if (status != TAVOR_CMD_SUCCESS) {
TAVOR_TNF_ERROR, "");
}
/* Free the mailbox */
return (status);
}
/*
* tavor_getpefcntr_cmd_post()
* Context: Can be called from interrupt or base context.
*
* If reset is zero, read the performance counters of the specified port and
* copy them into perfinfo.
* If reset is non-zero reset the performance counters of the specified port.
*/
int
{
int status, i;
/* Get "In" and "Out" mailboxes for the command */
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
/* Build request MAD in the "In" mailbox */
if (reset) {
} else {
}
if (reset) {
/* reset counters for XmitData, RcvData, XmitPkts, RcvPkts */
} else
/* Sync the mailbox for the device to read */
/* Setup the Hermon "MAD_IFC" command */
/* No MKey and BKey checking */
if (status != TAVOR_CMD_SUCCESS) {
goto getperfinfo_fail;
}
/* Sync the mailbox to read the results */
if (reset == 0) {
/*
* Copy Perfcounters into "perfinfo". We can discard the MAD
* header and the 8 Quadword reserved area of the PERM mgmt
* class MAD
*/
for (i = 0; i < size >> 3; i++) {
}
}
/* Free the mailbox */
return (status);
}