#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/ib/adapters/tavor/tavor.h>
static int tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
tavor_mbox_t **mb, uint_t mbox_wait);
static void tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb);
static int tavor_impl_mboxlist_init(tavor_state_t *state,
tavor_mboxlist_t *mblist, uint_t num_mbox, tavor_rsrc_type_t type);
static void tavor_impl_mboxlist_fini(tavor_state_t *state,
tavor_mboxlist_t *mblist);
static int tavor_outstanding_cmd_alloc(tavor_state_t *state,
tavor_cmd_t **cmd_ptr, uint_t cmd_wait);
static void tavor_outstanding_cmd_free(tavor_state_t *state,
tavor_cmd_t **cmd_ptr);
static int tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
uint16_t token);
static void tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset,
uint_t length, uint_t flag);
int
tavor_cmd_post(tavor_state_t *state, tavor_cmd_post_t *cmdpost)
{
tavor_cmd_t *cmdptr;
int status;
uint16_t token;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdpost))
if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
status = tavor_write_hcr(state, cmdpost, 0);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
return (TAVOR_CMD_SUCCESS);
} else {
ASSERT(TAVOR_SLEEPFLAG_FOR_CONTEXT() != TAVOR_NOSLEEP);
status = tavor_outstanding_cmd_alloc(state, &cmdptr,
cmdpost->cp_flags);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
cmdptr->cmd_status = TAVOR_CMD_INVALID_STATUS;
token = (uint16_t)cmdptr->cmd_indx;
status = tavor_write_hcr(state, cmdpost, token);
if (status != TAVOR_CMD_SUCCESS) {
tavor_outstanding_cmd_free(state, &cmdptr);
return (status);
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cmdptr))
mutex_enter(&cmdptr->cmd_comp_lock);
while (cmdptr->cmd_status == TAVOR_CMD_INVALID_STATUS) {
#ifndef __lock_lint
cv_wait(&cmdptr->cmd_comp_cv, &cmdptr->cmd_comp_lock);
#endif
}
mutex_exit(&cmdptr->cmd_comp_lock);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cmdptr))
status = cmdptr->cmd_status;
cmdpost->cp_outparm = cmdptr->cmd_outparm;
tavor_outstanding_cmd_free(state, &cmdptr);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
return (TAVOR_CMD_SUCCESS);
}
}
int
tavor_mbox_alloc(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
uint_t mbox_wait)
{
int status;
uint_t sleep_context;
sleep_context = TAVOR_SLEEPFLAG_FOR_CONTEXT();
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
if (sleep_context == TAVOR_NOSLEEP) {
status = tavor_impl_mbox_alloc(state,
&state->ts_in_intr_mblist,
&mbox_info->mbi_in, mbox_wait);
ASSERT(status == TAVOR_CMD_SUCCESS);
} else {
status = tavor_impl_mbox_alloc(state,
&state->ts_in_mblist, &mbox_info->mbi_in,
mbox_wait);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
}
}
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
if (sleep_context == TAVOR_NOSLEEP) {
status = tavor_impl_mbox_alloc(state,
&state->ts_out_intr_mblist,
&mbox_info->mbi_out, mbox_wait);
ASSERT(status == TAVOR_CMD_SUCCESS);
} else {
status = tavor_impl_mbox_alloc(state,
&state->ts_out_mblist, &mbox_info->mbi_out,
mbox_wait);
if (status != TAVOR_CMD_SUCCESS) {
if (mbox_info->mbi_alloc_flags &
TAVOR_ALLOC_INMBOX) {
tavor_impl_mbox_free(
&state->ts_in_mblist,
&mbox_info->mbi_in);
}
return (status);
}
}
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
mbox_info->mbi_sleep_context = sleep_context;
return (TAVOR_CMD_SUCCESS);
}
void
tavor_mbox_free(tavor_state_t *state, tavor_mbox_info_t *mbox_info)
{
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(mbox_info->mbi_sleep_context))
ASSERT(mbox_info->mbi_sleep_context == TAVOR_SLEEPFLAG_FOR_CONTEXT());
if (mbox_info->mbi_sleep_context == TAVOR_NOSLEEP) {
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
tavor_impl_mbox_free(&state->ts_in_intr_mblist,
&mbox_info->mbi_in);
}
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
tavor_impl_mbox_free(&state->ts_out_intr_mblist,
&mbox_info->mbi_out);
}
} else {
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_INMBOX) {
tavor_impl_mbox_free(&state->ts_in_mblist,
&mbox_info->mbi_in);
}
if (mbox_info->mbi_alloc_flags & TAVOR_ALLOC_OUTMBOX) {
tavor_impl_mbox_free(&state->ts_out_mblist,
&mbox_info->mbi_out);
}
}
}
int
tavor_cmd_complete_handler(tavor_state_t *state, tavor_eqhdl_t eq,
tavor_hw_eqe_t *eqe)
{
tavor_cmd_t *cmdp;
uint_t eqe_evttype;
eqe_evttype = TAVOR_EQE_EVTTYPE_GET(eq, eqe);
ASSERT(eqe_evttype == TAVOR_EVT_COMMAND_INTF_COMP ||
eqe_evttype == TAVOR_EVT_EQ_OVERFLOW);
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
tavor_eq_overflow_handler(state, eq, eqe);
return (DDI_FAILURE);
}
cmdp = &state->ts_cmd_list.cml_cmd[TAVOR_EQE_CMDTOKEN_GET(eq, eqe)];
mutex_enter(&cmdp->cmd_comp_lock);
cmdp->cmd_outparm = ((uint64_t)TAVOR_EQE_CMDOUTP0_GET(eq, eqe) << 32) |
TAVOR_EQE_CMDOUTP1_GET(eq, eqe);
cmdp->cmd_status = TAVOR_EQE_CMDSTATUS_GET(eq, eqe);
cv_signal(&cmdp->cmd_comp_cv);
mutex_exit(&cmdp->cmd_comp_lock);
return (DDI_SUCCESS);
}
int
tavor_inmbox_list_init(tavor_state_t *state)
{
int status;
uint_t num_inmbox;
num_inmbox = (1 << state->ts_cfg_profile->cp_log_num_inmbox);
status = tavor_impl_mboxlist_init(state, &state->ts_in_mblist,
num_inmbox, TAVOR_IN_MBOX);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
tavor_intr_inmbox_list_init(tavor_state_t *state)
{
int status;
uint_t num_inmbox;
num_inmbox = (1 << state->ts_cfg_profile->cp_log_num_intr_inmbox);
status = tavor_impl_mboxlist_init(state, &state->ts_in_intr_mblist,
num_inmbox, TAVOR_INTR_IN_MBOX);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
tavor_outmbox_list_init(tavor_state_t *state)
{
int status;
uint_t num_outmbox;
num_outmbox = (1 << state->ts_cfg_profile->cp_log_num_outmbox);
status = tavor_impl_mboxlist_init(state, &state->ts_out_mblist,
num_outmbox, TAVOR_OUT_MBOX);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
tavor_intr_outmbox_list_init(tavor_state_t *state)
{
int status;
uint_t num_outmbox;
num_outmbox = (1 << state->ts_cfg_profile->cp_log_num_intr_outmbox);
status = tavor_impl_mboxlist_init(state, &state->ts_out_intr_mblist,
num_outmbox, TAVOR_INTR_OUT_MBOX);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
tavor_inmbox_list_fini(tavor_state_t *state)
{
tavor_impl_mboxlist_fini(state, &state->ts_in_mblist);
}
void
tavor_intr_inmbox_list_fini(tavor_state_t *state)
{
tavor_impl_mboxlist_fini(state, &state->ts_in_intr_mblist);
}
void
tavor_outmbox_list_fini(tavor_state_t *state)
{
tavor_impl_mboxlist_fini(state, &state->ts_out_mblist);
}
void
tavor_intr_outmbox_list_fini(tavor_state_t *state)
{
tavor_impl_mboxlist_fini(state, &state->ts_out_intr_mblist);
}
static int
tavor_impl_mbox_alloc(tavor_state_t *state, tavor_mboxlist_t *mblist,
tavor_mbox_t **mb, uint_t mbox_wait)
{
tavor_mbox_t *mbox_ptr;
uint_t index, next, prev;
uint_t count, countmax;
if (mbox_wait == TAVOR_NOSLEEP) {
count = 0;
countmax = state->ts_cfg_profile->cp_cmd_poll_max;
mutex_enter(&mblist->mbl_lock);
mblist->mbl_pollers++;
while (mblist->mbl_entries_free == 0) {
mutex_exit(&mblist->mbl_lock);
if (++count > countmax) {
return (TAVOR_CMD_INSUFF_RSRC);
}
drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
mutex_enter(&mblist->mbl_lock);
}
mblist->mbl_pollers--;
} else {
mutex_enter(&mblist->mbl_lock);
while (mblist->mbl_entries_free == 0) {
mblist->mbl_waiters++;
#ifndef __lock_lint
cv_wait(&mblist->mbl_cv, &mblist->mbl_lock);
#endif
}
}
mbox_ptr = mblist->mbl_mbox;
index = mblist->mbl_head_indx;
next = mbox_ptr[index].mb_next;
prev = mbox_ptr[index].mb_prev;
mblist->mbl_mbox[next].mb_prev = prev;
mblist->mbl_mbox[prev].mb_next = next;
mblist->mbl_head_indx = next;
mblist->mbl_entries_free--;
*mb = &mbox_ptr[index];
mutex_exit(&mblist->mbl_lock);
return (TAVOR_CMD_SUCCESS);
}
static void
tavor_impl_mbox_free(tavor_mboxlist_t *mblist, tavor_mbox_t **mb)
{
uint_t mbox_indx;
mutex_enter(&mblist->mbl_lock);
mbox_indx = (*mb)->mb_indx;
if (mblist->mbl_entries_free++ != 0) {
(*mb)->mb_next = mblist->mbl_head_indx;
(*mb)->mb_prev = mblist->mbl_tail_indx;
mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev = mbox_indx;
mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next = mbox_indx;
mblist->mbl_tail_indx = mbox_indx;
} else {
(*mb)->mb_next = mbox_indx;
(*mb)->mb_prev = mbox_indx;
mblist->mbl_tail_indx = mbox_indx;
mblist->mbl_head_indx = mbox_indx;
}
if (mblist->mbl_pollers > 0 && mblist->mbl_waiters > 0) {
mblist->mbl_signal = (mblist->mbl_signal + 1) % 2;
} else if (mblist->mbl_waiters > 0) {
mblist->mbl_signal = 1;
} else {
mblist->mbl_signal = 0;
}
if (mblist->mbl_signal) {
mblist->mbl_waiters--;
cv_signal(&mblist->mbl_cv);
}
*mb = NULL;
mutex_exit(&mblist->mbl_lock);
}
static int
tavor_impl_mboxlist_init(tavor_state_t *state, tavor_mboxlist_t *mblist,
uint_t num_mbox, tavor_rsrc_type_t type)
{
tavor_rsrc_t *rsrc;
ddi_dma_cookie_t dma_cookie;
uint_t dma_cookiecnt, flag, sync;
int status, i;
mblist->mbl_list_sz = num_mbox;
mblist->mbl_mbox = kmem_zalloc(mblist->mbl_list_sz *
sizeof (tavor_mbox_t), KM_SLEEP);
mblist->mbl_head_indx = 0;
mblist->mbl_tail_indx = mblist->mbl_list_sz - 1;
mblist->mbl_entries_free = mblist->mbl_list_sz;
mblist->mbl_waiters = 0;
mblist->mbl_num_alloc = 0;
mutex_init(&mblist->mbl_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(state->ts_intrmsi_pri));
cv_init(&mblist->mbl_cv, NULL, CV_DRIVER, NULL);
sync = TAVOR_MBOX_IS_SYNC_REQ(state, type);
flag = state->ts_cfg_profile->cp_streaming_consistent;
for (i = 0; i < mblist->mbl_list_sz; i++) {
status = tavor_rsrc_alloc(state, type, 1, TAVOR_SLEEP,
&rsrc);
if (status != DDI_SUCCESS) {
goto mboxlist_init_fail;
}
mblist->mbl_mbox[i].mb_rsrcptr = rsrc;
mblist->mbl_mbox[i].mb_addr = rsrc->tr_addr;
mblist->mbl_mbox[i].mb_acchdl = rsrc->tr_acchdl;
status = ddi_dma_addr_bind_handle(rsrc->tr_dmahdl, NULL,
rsrc->tr_addr, rsrc->tr_len, (DDI_DMA_RDWR | flag),
DDI_DMA_SLEEP, NULL, &dma_cookie, &dma_cookiecnt);
if (status != DDI_SUCCESS) {
tavor_rsrc_free(state, &rsrc);
goto mboxlist_init_fail;
}
mblist->mbl_mbox[i].mb_mapaddr = dma_cookie.dmac_laddress;
mblist->mbl_mbox[i].mb_sync = sync;
mblist->mbl_mbox[i].mb_next = i+1;
mblist->mbl_mbox[i].mb_prev = i-1;
mblist->mbl_mbox[i].mb_indx = i;
mblist->mbl_num_alloc = i + 1;
}
mblist->mbl_mbox[mblist->mbl_head_indx].mb_prev =
mblist->mbl_tail_indx;
mblist->mbl_mbox[mblist->mbl_tail_indx].mb_next =
mblist->mbl_head_indx;
return (DDI_SUCCESS);
mboxlist_init_fail:
tavor_impl_mboxlist_fini(state, mblist);
return (DDI_FAILURE);
}
static void
tavor_impl_mboxlist_fini(tavor_state_t *state, tavor_mboxlist_t *mblist)
{
tavor_rsrc_t *rsrc;
int i, status;
for (i = 0; i < mblist->mbl_num_alloc; i++) {
rsrc = mblist->mbl_mbox[i].mb_rsrcptr;
status = ddi_dma_unbind_handle(rsrc->tr_dmahdl);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed to unbind DMA mapping");
return;
}
tavor_rsrc_free(state, &rsrc);
}
mutex_destroy(&mblist->mbl_lock);
cv_destroy(&mblist->mbl_cv);
kmem_free(mblist->mbl_mbox, mblist->mbl_list_sz *
sizeof (tavor_mbox_t));
}
static int
tavor_outstanding_cmd_alloc(tavor_state_t *state, tavor_cmd_t **cmd_ptr,
uint_t cmd_wait)
{
tavor_cmdlist_t *cmd_list;
uint_t next, prev, head;
cmd_list = &state->ts_cmd_list;
mutex_enter(&cmd_list->cml_lock);
ASSERT(cmd_list->cml_num_alloc != 0);
while (cmd_list->cml_entries_free == 0) {
if (cmd_wait == TAVOR_NOSLEEP) {
mutex_exit(&cmd_list->cml_lock);
return (TAVOR_CMD_INSUFF_RSRC);
}
cmd_list->cml_waiters++;
#ifndef __lock_lint
cv_wait(&cmd_list->cml_cv, &cmd_list->cml_lock);
#endif
}
head = cmd_list->cml_head_indx;
*cmd_ptr = &cmd_list->cml_cmd[head];
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(**cmd_ptr))
next = (*cmd_ptr)->cmd_next;
prev = (*cmd_ptr)->cmd_prev;
(*cmd_ptr)->cmd_status = TAVOR_CMD_INVALID_STATUS;
cmd_list->cml_cmd[next].cmd_prev = prev;
cmd_list->cml_cmd[prev].cmd_next = next;
cmd_list->cml_head_indx = next;
cmd_list->cml_entries_free--;
mutex_exit(&cmd_list->cml_lock);
return (TAVOR_CMD_SUCCESS);
}
static void
tavor_outstanding_cmd_free(tavor_state_t *state, tavor_cmd_t **cmd_ptr)
{
tavor_cmdlist_t *cmd_list;
uint_t cmd_indx;
cmd_list = &state->ts_cmd_list;
mutex_enter(&cmd_list->cml_lock);
cmd_indx = (*cmd_ptr)->cmd_indx;
if (cmd_list->cml_entries_free++ != 0) {
(*cmd_ptr)->cmd_next = cmd_list->cml_head_indx;
(*cmd_ptr)->cmd_prev = cmd_list->cml_tail_indx;
cmd_list->cml_cmd[cmd_list->cml_head_indx].cmd_prev = cmd_indx;
cmd_list->cml_cmd[cmd_list->cml_tail_indx].cmd_next = cmd_indx;
cmd_list->cml_tail_indx = cmd_indx;
} else {
(*cmd_ptr)->cmd_next = cmd_indx;
(*cmd_ptr)->cmd_prev = cmd_indx;
cmd_list->cml_head_indx = cmd_indx;
cmd_list->cml_tail_indx = cmd_indx;
}
if (cmd_list->cml_waiters > 0) {
cmd_list->cml_waiters--;
cv_signal(&cmd_list->cml_cv);
}
*cmd_ptr = NULL;
mutex_exit(&cmd_list->cml_lock);
}
static int
tavor_write_hcr(tavor_state_t *state, tavor_cmd_post_t *cmdpost,
uint16_t token)
{
tavor_hw_hcr_t *hcr;
uint_t status, count, countmax;
uint64_t hcrreg;
#ifdef __lock_lint
mutex_enter(&state->ts_cmd_regs.hcr_lock);
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
mutex_enter(&state->ts_cmd_regs.hcr_lock);
}
#endif
hcr = state->ts_cmd_regs.hcr;
count = 0;
countmax = state->ts_cfg_profile->cp_cmd_poll_max;
for (;;) {
hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
break;
}
drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
if (++count > countmax) {
#ifdef __lock_lint
mutex_exit(&state->ts_cmd_regs.hcr_lock);
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
mutex_exit(&state->ts_cmd_regs.hcr_lock);
}
#endif
return (TAVOR_CMD_TIMEOUT);
}
}
ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->in_param0,
cmdpost->cp_inparm);
hcrreg = ((uint64_t)cmdpost->cp_inmod << 32);
hcrreg = hcrreg | (cmdpost->cp_outparm >> 32);
ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->input_modifier,
hcrreg);
hcrreg = (cmdpost->cp_outparm << 32);
hcrreg = hcrreg | ((uint32_t)token << TAVOR_HCR_TOKEN_SHIFT);
ddi_put64(state->ts_reg_cmdhdl, (uint64_t *)&hcr->out_param1,
hcrreg);
hcrreg = TAVOR_HCR_CMD_GO_MASK;
if (cmdpost->cp_flags == TAVOR_CMD_SLEEP_NOSPIN)
hcrreg = hcrreg | TAVOR_HCR_CMD_E_MASK;
hcrreg = hcrreg | (cmdpost->cp_opmod << TAVOR_HCR_CMD_OPMOD_SHFT);
hcrreg = hcrreg | (cmdpost->cp_opcode);
ddi_put32(state->ts_reg_cmdhdl, &hcr->cmd, hcrreg);
if (cmdpost->cp_flags == TAVOR_CMD_NOSLEEP_SPIN) {
count = 0;
countmax = state->ts_cfg_profile->cp_cmd_poll_max;
for (;;) {
hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->cmd);
if ((hcrreg & TAVOR_HCR_CMD_GO_MASK) == 0) {
break;
}
drv_usecwait(state->ts_cfg_profile->cp_cmd_poll_delay);
if (++count > countmax) {
#ifdef __lock_lint
mutex_exit(&state-> ts_cmd_regs.hcr_lock);
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
mutex_exit(&state->
ts_cmd_regs.hcr_lock);
}
#endif
return (TAVOR_CMD_TIMEOUT);
}
}
status = (hcrreg >> TAVOR_HCR_CMD_STATUS_SHFT);
hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param0);
cmdpost->cp_outparm = hcrreg << 32;
hcrreg = ddi_get32(state->ts_reg_cmdhdl, &hcr->out_param1);
cmdpost->cp_outparm |= hcrreg;
} else {
status = TAVOR_CMD_SUCCESS;
}
#ifdef __lock_lint
mutex_exit(&state->ts_cmd_regs.hcr_lock);
#else
if (!TAVOR_IN_FASTREBOOT(state)) {
mutex_exit(&state->ts_cmd_regs.hcr_lock);
}
#endif
return (status);
}
int
tavor_outstanding_cmdlist_init(tavor_state_t *state)
{
uint_t num_outstanding_cmds, head, tail;
int i;
num_outstanding_cmds = (1 << state->ts_fw.log_max_cmd);
state->ts_cmd_list.cml_list_sz = num_outstanding_cmds;
state->ts_cmd_list.cml_head_indx = 0;
state->ts_cmd_list.cml_tail_indx = state->ts_cmd_list.cml_list_sz - 1;
state->ts_cmd_list.cml_entries_free = state->ts_cmd_list.cml_list_sz;
state->ts_cmd_list.cml_waiters = 0;
state->ts_cmd_list.cml_num_alloc = 0;
if (num_outstanding_cmds) {
state->ts_cmd_list.cml_cmd =
kmem_zalloc(state->ts_cmd_list.cml_list_sz *
sizeof (tavor_cmd_t), KM_SLEEP);
}
mutex_init(&state->ts_cmd_list.cml_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(state->ts_intrmsi_pri));
cv_init(&state->ts_cmd_list.cml_cv, NULL, CV_DRIVER, NULL);
for (i = 0; i < state->ts_cmd_list.cml_list_sz; i++) {
mutex_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock,
NULL, MUTEX_DRIVER, DDI_INTR_PRI(state->ts_intrmsi_pri));
cv_init(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv, NULL,
CV_DRIVER, NULL);
state->ts_cmd_list.cml_cmd[i].cmd_next = i+1;
state->ts_cmd_list.cml_cmd[i].cmd_prev = i-1;
state->ts_cmd_list.cml_cmd[i].cmd_indx = i;
state->ts_cmd_list.cml_num_alloc = i + 1;
}
if (num_outstanding_cmds) {
head = state->ts_cmd_list.cml_head_indx;
tail = state->ts_cmd_list.cml_tail_indx;
state->ts_cmd_list.cml_cmd[head].cmd_prev =
state->ts_cmd_list.cml_tail_indx;
state->ts_cmd_list.cml_cmd[tail].cmd_next =
state->ts_cmd_list.cml_head_indx;
}
return (DDI_SUCCESS);
}
void
tavor_outstanding_cmdlist_fini(tavor_state_t *state)
{
int i;
for (i = 0; i < state->ts_cmd_list.cml_num_alloc; i++) {
mutex_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_lock);
cv_destroy(&state->ts_cmd_list.cml_cmd[i].cmd_comp_cv);
}
mutex_destroy(&state->ts_cmd_list.cml_lock);
cv_destroy(&state->ts_cmd_list.cml_cv);
if (state->ts_cmd_list.cml_num_alloc) {
kmem_free(state->ts_cmd_list.cml_cmd,
state->ts_cmd_list.cml_list_sz * sizeof (tavor_cmd_t));
}
}
static void
tavor_mbox_sync(tavor_mbox_t *mbox, uint_t offset, uint_t length,
uint_t flag)
{
ddi_dma_handle_t dmahdl;
int status;
if (mbox->mb_sync == 0) {
return;
}
dmahdl = mbox->mb_rsrcptr->tr_dmahdl;
status = ddi_dma_sync(dmahdl, (off_t)offset, (size_t)length, flag);
if (status != DDI_SUCCESS) {
return;
}
}
int
tavor_sys_en_cmd_post(tavor_state_t *state, uint_t flags,
uint64_t *errorcode, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = SYS_EN;
cmd.cp_opmod = flags;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
*errorcode = cmd.cp_outparm;
}
return (status);
}
int
tavor_sys_dis_cmd_post(tavor_state_t *state, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = SYS_DIS;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
int
tavor_init_hca_cmd_post(tavor_state_t *state,
tavor_hw_initqueryhca_t *inithca, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size;
int status, i;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = sizeof (tavor_hw_initqueryhca_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)inithca)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = INIT_HCA;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_close_hca_cmd_post(tavor_state_t *state, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = CLOSE_HCA;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
int
tavor_init_ib_cmd_post(tavor_state_t *state, tavor_hw_initib_t *initib,
uint_t port, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size;
int status, i;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = sizeof (tavor_hw_initib_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)initib)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = port;
cmd.cp_opcode = INIT_IB;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_close_ib_cmd_post(tavor_state_t *state, uint_t port, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = port;
cmd.cp_opcode = CLOSE_IB;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
int
tavor_set_ib_cmd_post(tavor_state_t *state, uint32_t capmask, uint_t port,
uint_t reset_qkey, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
int status;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
ddi_put32(mbox_info.mbi_in->mb_acchdl,
((uint32_t *)mbox_info.mbi_in->mb_addr + 0), reset_qkey);
ddi_put32(mbox_info.mbi_in->mb_acchdl,
((uint32_t *)mbox_info.mbi_in->mb_addr + 1), capmask);
tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_SETIB_SZ,
DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = port;
cmd.cp_opcode = SET_IB;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_mod_stat_cfg_cmd_post(tavor_state_t *state)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
tavor_hw_mod_stat_cfg_t *mod;
uint64_t data;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, TAVOR_NOSLEEP);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
mod = (tavor_hw_mod_stat_cfg_t *)kmem_zalloc(
sizeof (tavor_hw_mod_stat_cfg_t), KM_SLEEP);
mod->srq_m = 1;
mod->srq = state->ts_cfg_profile->cp_srq_enable;
if (mod->srq) {
mod->log_max_srq = state->ts_cfg_profile->cp_log_num_srq;
} else {
mod->log_max_srq = 0;
}
size = sizeof (tavor_hw_mod_stat_cfg_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)mod)[i];
ddi_put64(mbox_info.mbi_out->mb_acchdl,
((uint64_t *)mbox_info.mbi_out->mb_addr + i), data);
}
tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = MOD_STAT_CFG;
cmd.cp_opmod = 0;
cmd.cp_flags = TAVOR_CMD_NOSLEEP_SPIN;
status = tavor_cmd_post(state, &cmd);
kmem_free(mod, sizeof (tavor_hw_mod_stat_cfg_t));
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_mad_ifc_cmd_post(tavor_state_t *state, uint_t port,
uint_t sleepflag, uint32_t *mad, uint32_t *resp)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint_t size;
int status;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
bcopy(mad, mbox_info.mbi_in->mb_addr, size);
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = port;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_CHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto mad_ifc_fail;
}
tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
bcopy(mbox_info.mbi_out->mb_addr, resp, size);
mad_ifc_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getportinfo_cmd_post(tavor_state_t *state, uint_t port,
uint_t sleepflag, sm_portinfo_t *portinfo)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint32_t *mbox;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PORTINFO);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], port);
for (i = 6; i < (size >> 2); i++) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = port;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getportinfo_fail;
}
size = sizeof (sm_portinfo_t);
tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
size, DDI_DMA_SYNC_FORCPU);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*portinfo))
bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
TAVOR_CMD_MADDATA_OFFSET), portinfo, size);
TAVOR_GETPORTINFO_SWAP(portinfo);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*portinfo))
getportinfo_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getnodeinfo_cmd_post(tavor_state_t *state, uint_t sleepflag,
sm_nodeinfo_t *nodeinfo)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint32_t *mbox;
uint_t size;
int status, i;
ASSERT(sleepflag == TAVOR_CMD_NOSLEEP_SPIN);
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEINFO);
for (i = 5; i < (size >> 2); i++) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = 1;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getnodeinfo_fail;
}
size = sizeof (sm_nodeinfo_t);
tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
size, DDI_DMA_SYNC_FORCPU);
bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
TAVOR_CMD_MADDATA_OFFSET), nodeinfo, size);
TAVOR_GETNODEINFO_SWAP(nodeinfo);
getnodeinfo_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getnodedesc_cmd_post(tavor_state_t *state, uint_t sleepflag,
sm_nodedesc_t *nodedesc)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint32_t *mbox;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_NODEDESC);
for (i = 5; i < (size >> 2); i++) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = 1;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getnodedesc_fail;
}
size = sizeof (sm_nodedesc_t);
tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
size, DDI_DMA_SYNC_FORCPU);
bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
TAVOR_CMD_MADDATA_OFFSET), nodedesc, size);
getnodedesc_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getguidinfo_cmd_post(tavor_state_t *state, uint_t port,
uint_t guidblock, uint_t sleepflag, sm_guidinfo_t *guidinfo)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint32_t *mbox;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_GUIDINFO);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], guidblock);
for (i = 6; i < (size >> 2); i++) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = port;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getguidinfo_fail;
}
size = sizeof (sm_guidinfo_t);
tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
size, DDI_DMA_SYNC_FORCPU);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*guidinfo))
bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
TAVOR_CMD_MADDATA_OFFSET), guidinfo, size);
TAVOR_GETGUIDINFO_SWAP(guidinfo);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*guidinfo))
getguidinfo_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getpkeytable_cmd_post(tavor_state_t *state, uint_t port,
uint_t pkeyblock, uint_t sleepflag, sm_pkey_table_t *pkeytable)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint32_t *mbox;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0], TAVOR_CMD_MADHDR0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PKEYTBLE);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], pkeyblock);
for (i = 6; i < (size >> 2); i++) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[i], 0);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = port;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getpkeytable_fail;
}
size = sizeof (sm_pkey_table_t);
tavor_mbox_sync(mbox_info.mbi_out, TAVOR_CMD_MADDATA_OFFSET,
size, DDI_DMA_SYNC_FORCPU);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pkeytable))
bcopy((void *)((uintptr_t)mbox_info.mbi_out->mb_addr +
TAVOR_CMD_MADDATA_OFFSET), pkeytable, size);
TAVOR_GETPKEYTABLE_SWAP(pkeytable);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*pkeytable))
getpkeytable_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_write_mtt_cmd_post(tavor_state_t *state, tavor_mbox_info_t *mbox_info,
uint_t num_mtt, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
uint_t size;
int status;
size = (num_mtt << TAVOR_MTT_SIZE_SHIFT) + TAVOR_CMD_WRITEMTT_RSVD_SZ;
tavor_mbox_sync(mbox_info->mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info->mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = num_mtt;
cmd.cp_opcode = WRITE_MTT;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
int
tavor_sync_tpt_cmd_post(tavor_state_t *state, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = SYNC_TPT;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
int
tavor_map_eq_cmd_post(tavor_state_t *state, uint_t map, uint_t eqcindx,
uint64_t eqmapmask, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
cmd.cp_inparm = eqmapmask;
cmd.cp_outparm = 0;
cmd.cp_inmod = eqcindx;
if (map != TAVOR_CMD_MAP_EQ_EVT_MAP) {
cmd.cp_inmod |= TAVOR_CMD_UNMAP_EQ_MASK;
}
cmd.cp_opcode = MAP_EQ;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
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)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = sizeof (tavor_hw_cqc_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)cqc)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = cqcindx;
cmd.cp_opcode = RESIZE_CQ;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
*prod_indx = (cmd.cp_outparm >> 32);
tavor_mbox_free(state, &mbox_info);
return (status);
}
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)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data, in_mapaddr, out_mapaddr;
uint_t size, flags, opmod;
int status, i;
if (opcode == RTS2SQD_QP) {
flags = TAVOR_CMD_REQ_SQD_EVENT;
in_mapaddr = 0;
out_mapaddr = 0;
opmod = 0;
} else if (opcode == TOERR_QP) {
in_mapaddr = 0;
out_mapaddr = 0;
opmod = 0;
flags = 0;
} else if (opcode == TORST_QP) {
in_mapaddr = 0;
out_mapaddr = 0;
opmod = TAVOR_CMD_DIRECT_TO_RESET | TAVOR_CMD_NO_OUTMBOX;
flags = 0;
} else {
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
out_mapaddr = 0;
flags = 0;
opmod = 0;
size = sizeof (tavor_hw_qpc_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)qp)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i + 1),
data);
}
ddi_put32(mbox_info.mbi_in->mb_acchdl,
((uint32_t *)mbox_info.mbi_in->mb_addr), opmask);
tavor_mbox_sync(mbox_info.mbi_in, 0, size + 8,
DDI_DMA_SYNC_FORDEV);
}
cmd.cp_inparm = in_mapaddr;
cmd.cp_outparm = out_mapaddr;
cmd.cp_inmod = qpindx | flags;
cmd.cp_opcode = opcode;
cmd.cp_opmod = opmod;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if ((opcode != RTS2SQD_QP) && (opcode != TOERR_QP) &&
(opcode != TORST_QP)) {
tavor_mbox_free(state, &mbox_info);
}
return (status);
}
int
tavor_cmn_query_cmd_post(tavor_state_t *state, uint_t opcode,
uint_t queryindx, void *query, uint_t size, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t offset;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
cmd.cp_inparm = 0;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = queryindx;
cmd.cp_opcode = opcode;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto cmn_query_fail;
}
tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
offset = (opcode == QUERY_QP) ? 1 : 0;
for (i = 0; i < (size >> 3); i++) {
data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
((uint64_t *)mbox_info.mbi_out->mb_addr + i + offset));
((uint64_t *)query)[i] = data;
}
cmn_query_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_cmn_ownership_cmd_post(tavor_state_t *state, uint_t opcode,
void *hwrsrc, uint_t size, uint_t hwrsrcindx, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data, in_mapaddr, out_mapaddr;
uint_t direction, opmod;
int status, i;
if ((opcode == HW2SW_MPT) || (opcode == HW2SW_EQ) ||
(opcode == HW2SW_CQ) || (opcode == HW2SW_SRQ)) {
direction = TAVOR_CMD_RSRC_HW2SW;
} else if ((opcode == SW2HW_MPT) || (opcode == SW2HW_EQ) ||
(opcode == SW2HW_CQ) || (opcode == SW2HW_SRQ)) {
direction = TAVOR_CMD_RSRC_SW2HW;
} else {
return (TAVOR_CMD_INVALID_STATUS);
}
if (direction == TAVOR_CMD_RSRC_HW2SW) {
if (hwrsrc != NULL) {
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info,
sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
in_mapaddr = 0;
out_mapaddr = mbox_info.mbi_out->mb_mapaddr;
opmod = TAVOR_CMD_DO_OUTMBOX;
} else {
in_mapaddr = 0;
out_mapaddr = 0;
opmod = TAVOR_CMD_NO_OUTMBOX;
}
} else {
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)hwrsrc)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i),
data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size,
DDI_DMA_SYNC_FORDEV);
in_mapaddr = mbox_info.mbi_in->mb_mapaddr;
out_mapaddr = 0;
opmod = 0;
}
cmd.cp_inparm = in_mapaddr;
cmd.cp_outparm = out_mapaddr;
cmd.cp_inmod = hwrsrcindx;
cmd.cp_opcode = opcode;
cmd.cp_opmod = opmod;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto cmn_ownership_fail;
}
if (direction == TAVOR_CMD_RSRC_HW2SW && hwrsrc != NULL) {
tavor_mbox_sync(mbox_info.mbi_out, 0, size,
DDI_DMA_SYNC_FORCPU);
for (i = 0; i < (size >> 3); i++) {
data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
((uint64_t *)mbox_info.mbi_out->mb_addr + i));
((uint64_t *)hwrsrc)[i] = data;
}
}
cmn_ownership_fail:
if (hwrsrc != NULL) {
tavor_mbox_free(state, &mbox_info);
}
return (status);
}
int
tavor_conf_special_qp_cmd_post(tavor_state_t *state, uint_t qpindx,
uint_t qptype, uint_t sleepflag)
{
tavor_cmd_post_t cmd;
int status;
cmd.cp_inparm = 0;
cmd.cp_outparm = 0;
cmd.cp_inmod = qpindx;
cmd.cp_opcode = CONF_SPECIAL_QP;
cmd.cp_opmod = qptype;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
return (status);
}
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)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
int status;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + 0), mgid_h);
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + 1), mgid_l);
tavor_mbox_sync(mbox_info.mbi_in, 0, TAVOR_CMD_MGIDHASH_SZ,
DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = 0;
cmd.cp_opcode = MGID_HASH;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
*mgid_hash = cmd.cp_outparm;
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_read_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
uint_t mcgindx, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size, hdrsz, qplistsz;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
cmd.cp_inparm = 0;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = mcgindx;
cmd.cp_opcode = READ_MGM;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto read_mgm_fail;
}
size = TAVOR_MCGMEM_SZ(state);
tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
hdrsz = sizeof (tavor_hw_mcg_t);
for (i = 0; i < (hdrsz >> 3); i++) {
data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
((uint64_t *)mbox_info.mbi_out->mb_addr + i));
((uint64_t *)mcg)[i] = data;
}
qplistsz = size - hdrsz;
for (i = 0; i < (qplistsz >> 2); i++) {
data = ddi_get32(mbox_info.mbi_out->mb_acchdl,
((uint32_t *)mbox_info.mbi_out->mb_addr + i + 8));
((uint32_t *)mcg)[i + 8] = data;
}
read_mgm_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_write_mgm_cmd_post(tavor_state_t *state, tavor_hw_mcg_t *mcg,
uint_t mcgindx, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size, hdrsz, qplistsz;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_MCGMEM_SZ(state);
hdrsz = sizeof (tavor_hw_mcg_t);
for (i = 0; i < (hdrsz >> 3); i++) {
data = ((uint64_t *)mcg)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
}
qplistsz = size - hdrsz;
for (i = 0; i < (qplistsz >> 2); i++) {
data = ((uint32_t *)mcg)[i + 8];
ddi_put32(mbox_info.mbi_in->mb_acchdl,
((uint32_t *)mbox_info.mbi_in->mb_addr + i + 8), data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = mcgindx;
cmd.cp_opcode = WRITE_MGM;
cmd.cp_opmod = 0;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_modify_mpt_cmd_post(tavor_state_t *state, tavor_hw_mpt_t *mpt,
uint_t mptindx, uint_t flags, uint_t sleepflag)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint_t size;
int status, i;
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = sizeof (tavor_hw_mpt_t);
for (i = 0; i < (size >> 3); i++) {
data = ((uint64_t *)mpt)[i];
ddi_put64(mbox_info.mbi_in->mb_acchdl,
((uint64_t *)mbox_info.mbi_in->mb_addr + i), data);
}
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = 0;
cmd.cp_inmod = mptindx;
cmd.cp_opcode = MODIFY_MPT;
cmd.cp_opmod = flags;
cmd.cp_flags = sleepflag;
status = tavor_cmd_post(state, &cmd);
tavor_mbox_free(state, &mbox_info);
return (status);
}
int
tavor_getperfcntr_cmd_post(tavor_state_t *state, uint_t port,
uint_t sleepflag, tavor_hw_sm_perfcntr_t *perfinfo, int reset)
{
tavor_mbox_info_t mbox_info;
tavor_cmd_post_t cmd;
uint64_t data;
uint32_t *mbox;
uint_t size;
int status, i;
bzero((void *)&cmd, sizeof (tavor_cmd_post_t));
mbox_info.mbi_alloc_flags = TAVOR_ALLOC_INMBOX | TAVOR_ALLOC_OUTMBOX;
status = tavor_mbox_alloc(state, &mbox_info, sleepflag);
if (status != TAVOR_CMD_SUCCESS) {
return (status);
}
size = TAVOR_CMD_MAD_IFC_SIZE;
mbox = (uint32_t *)mbox_info.mbi_in->mb_addr;
if (reset) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
TAVOR_CMD_PERF_SET);
} else {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[0],
TAVOR_CMD_PERF_GET);
}
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[1], TAVOR_CMD_MADHDR1);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[2], TAVOR_CMD_MADHDR2);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[3], TAVOR_CMD_MADHDR3);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[4], TAVOR_CMD_PERFCNTRS);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[5], TAVOR_CMD_PERFATTR);
if (reset) {
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16],
((port << 16) | 0xf000));
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[22], 0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[23], 0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[24], 0);
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[25], 0);
} else
ddi_put32(mbox_info.mbi_in->mb_acchdl, &mbox[16], (port << 16));
tavor_mbox_sync(mbox_info.mbi_in, 0, size, DDI_DMA_SYNC_FORDEV);
cmd.cp_inparm = mbox_info.mbi_in->mb_mapaddr;
cmd.cp_outparm = mbox_info.mbi_out->mb_mapaddr;
cmd.cp_inmod = port;
cmd.cp_opcode = MAD_IFC;
cmd.cp_opmod = TAVOR_CMD_MKEY_DONTCHECK | TAVOR_CMD_BKEY_DONTCHECK;
cmd.cp_flags = TAVOR_CMD_NOSLEEP_SPIN;
status = tavor_cmd_post(state, &cmd);
if (status != TAVOR_CMD_SUCCESS) {
goto getperfinfo_fail;
}
size = TAVOR_CMD_MAD_IFC_SIZE;
tavor_mbox_sync(mbox_info.mbi_out, 0, size, DDI_DMA_SYNC_FORCPU);
if (reset == 0) {
size = sizeof (tavor_hw_sm_perfcntr_t);
for (i = 0; i < size >> 3; i++) {
data = ddi_get64(mbox_info.mbi_out->mb_acchdl,
((uint64_t *)mbox_info.mbi_out->mb_addr + i + 8));
((uint64_t *)(void *)perfinfo)[i] = data;
}
}
getperfinfo_fail:
tavor_mbox_free(state, &mbox_info);
return (status);
}