#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/bitmap.h>
#include <sys/sysmacros.h>
#include <sys/ib/adapters/tavor/tavor.h>
#include <sys/ib/ib_pkt_hdrs.h>
static int tavor_qp_create_qpn(tavor_state_t *state, tavor_qphdl_t qp,
tavor_rsrc_t *qpc);
static int tavor_qpn_avl_compare(const void *q, const void *e);
static int tavor_special_qp_rsrc_alloc(tavor_state_t *state,
ibt_sqp_type_t type, uint_t port, tavor_rsrc_t **qp_rsrc);
static int tavor_special_qp_rsrc_free(tavor_state_t *state, ibt_sqp_type_t type,
uint_t port);
static void tavor_qp_sgl_to_logwqesz(tavor_state_t *state, uint_t num_sgl,
tavor_qp_wq_type_t wq_type, uint_t *logwqesz, uint_t *max_sgl);
int
tavor_qp_alloc(tavor_state_t *state, tavor_qp_info_t *qpinfo,
uint_t sleepflag, tavor_qp_options_t *op)
{
tavor_rsrc_pool_info_t *rsrc_pool;
tavor_rsrc_t *qpc, *rsrc, *rdb;
tavor_umap_db_entry_t *umapdb;
tavor_qphdl_t qp;
ibt_qp_alloc_attr_t *attr_p;
ibt_qp_type_t type;
ibtl_qp_hdl_t ibt_qphdl;
ibt_chan_sizes_t *queuesz_p;
ib_qpn_t *qpn;
tavor_qphdl_t *qphdl;
ibt_mr_attr_t mr_attr;
tavor_mr_options_t mr_op;
tavor_srqhdl_t srq;
tavor_pdhdl_t pd;
tavor_cqhdl_t sq_cq, rq_cq;
tavor_mrhdl_t mr;
uint64_t value, qp_desc_off;
uint32_t *sq_buf, *rq_buf;
uint32_t log_qp_sq_size, log_qp_rq_size;
uint32_t sq_size, rq_size;
uint32_t sq_wqe_size, rq_wqe_size;
uint32_t max_rdb, max_sgl, uarpg;
uint_t wq_location, dma_xfer_mode, qp_is_umap;
uint_t qp_srq_en;
int status, flag;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr_p, *queuesz_p))
if (op == NULL) {
wq_location = TAVOR_QUEUE_LOCATION_NORMAL;
} else {
wq_location = op->qpo_wq_loc;
}
attr_p = qpinfo->qpi_attrp;
type = qpinfo->qpi_type;
ibt_qphdl = qpinfo->qpi_ibt_qphdl;
queuesz_p = qpinfo->qpi_queueszp;
qpn = qpinfo->qpi_qpn;
qphdl = &qpinfo->qpi_qphdl;
qp_is_umap = (attr_p->qp_alloc_flags & IBT_QP_USER_MAP) ? 1 : 0;
if (qp_is_umap) {
status = tavor_umap_db_find(state->ts_instance, ddi_get_pid(),
MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
if (status != DDI_SUCCESS) {
goto qpalloc_fail;
}
uarpg = ((tavor_rsrc_t *)(uintptr_t)value)->tr_indx;
}
qp_srq_en = (attr_p->qp_alloc_flags & IBT_QP_USES_SRQ) ? 1 : 0;
if (qp_srq_en) {
if (attr_p->qp_ibc_srq_hdl == NULL) {
goto qpalloc_fail;
}
srq = (tavor_srqhdl_t)attr_p->qp_ibc_srq_hdl;
}
if (((type != IBT_UD_RQP) && (type != IBT_RC_RQP) &&
(type != IBT_UC_RQP))) {
goto qpalloc_fail;
}
if (qp_srq_en && type != IBT_RC_RQP) {
goto qpalloc_fail;
}
if (attr_p->qp_pd_hdl == NULL) {
goto qpalloc_fail;
}
pd = (tavor_pdhdl_t)attr_p->qp_pd_hdl;
if (qp_srq_en && (pd->pd_pdnum != srq->srq_pdhdl->pd_pdnum)) {
goto qpalloc_fail;
}
tavor_pd_refcnt_inc(pd);
if ((attr_p->qp_ibc_scq_hdl == NULL) ||
(attr_p->qp_ibc_rcq_hdl == NULL)) {
goto qpalloc_fail1;
}
sq_cq = (tavor_cqhdl_t)attr_p->qp_ibc_scq_hdl;
rq_cq = (tavor_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
status = tavor_cq_refcnt_inc(sq_cq, TAVOR_CQ_IS_NORMAL);
if (status != DDI_SUCCESS) {
goto qpalloc_fail1;
}
status = tavor_cq_refcnt_inc(rq_cq, TAVOR_CQ_IS_NORMAL);
if (status != DDI_SUCCESS) {
goto qpalloc_fail2;
}
status = tavor_rsrc_alloc(state, TAVOR_QPC, 1, sleepflag, &qpc);
if (status != DDI_SUCCESS) {
goto qpalloc_fail3;
}
status = tavor_rsrc_alloc(state, TAVOR_QPHDL, 1, sleepflag, &rsrc);
if (status != DDI_SUCCESS) {
goto qpalloc_fail4;
}
qp = (tavor_qphdl_t)rsrc->tr_addr;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
status = tavor_qp_create_qpn(state, qp, qpc);
if (status != DDI_SUCCESS) {
goto qpalloc_fail5;
}
if (qp_is_umap) {
umapdb = tavor_umap_db_alloc(state->ts_instance, qp->qp_qpnum,
MLNX_UMAP_QPMEM_RSRC, (uint64_t)(uintptr_t)rsrc);
if (umapdb == NULL) {
goto qpalloc_fail6;
}
}
if (type == IBT_RC_RQP) {
max_rdb = state->ts_cfg_profile->cp_hca_max_rdma_in_qp;
status = tavor_rsrc_alloc(state, TAVOR_RDB, max_rdb,
sleepflag, &rdb);
if (status != DDI_SUCCESS) {
goto qpalloc_fail7;
}
qp->qp_rdbrsrcp = rdb;
rsrc_pool = &state->ts_rsrc_hdl[TAVOR_RDB];
qp->qp_rdb_ddraddr = (uintptr_t)rsrc_pool->rsrc_ddr_offset +
(rdb->tr_indx << TAVOR_RDB_SIZE_SHIFT);
}
attr_p->qp_sizes.cs_sq = max(attr_p->qp_sizes.cs_sq, TAVOR_QP_MIN_SIZE);
attr_p->qp_sizes.cs_rq = max(attr_p->qp_sizes.cs_rq, TAVOR_QP_MIN_SIZE);
log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq);
if (ISP2(attr_p->qp_sizes.cs_sq)) {
log_qp_sq_size = log_qp_sq_size - 1;
}
log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
if (ISP2(attr_p->qp_sizes.cs_rq)) {
log_qp_rq_size = log_qp_rq_size - 1;
}
if ((log_qp_sq_size > state->ts_cfg_profile->cp_log_max_qp_sz) ||
(!qp_srq_en && (log_qp_rq_size >
state->ts_cfg_profile->cp_log_max_qp_sz))) {
goto qpalloc_fail8;
}
max_sgl = state->ts_cfg_profile->cp_wqe_real_max_sgl;
if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
(!qp_srq_en && (attr_p->qp_sizes.cs_rq_sgl > max_sgl))) {
goto qpalloc_fail8;
}
if (qp_srq_en) {
qp->qp_rq_log_wqesz = 0;
qp->qp_rq_sgl = 0;
} else {
tavor_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
TAVOR_QP_WQ_TYPE_RECVQ, &qp->qp_rq_log_wqesz,
&qp->qp_rq_sgl);
}
tavor_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
TAVOR_QP_WQ_TYPE_SENDQ, &qp->qp_sq_log_wqesz, &qp->qp_sq_sgl);
sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
sq_size = (1 << log_qp_sq_size) * sq_wqe_size;
if (qp_srq_en) {
rq_wqe_size = 0;
rq_size = 0;
} else {
rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
rq_size = (1 << log_qp_rq_size) * rq_wqe_size;
}
qp->qp_wqinfo.qa_size = sq_size + rq_size;
qp->qp_wqinfo.qa_alloc_align = max(sq_wqe_size, rq_wqe_size);
qp->qp_wqinfo.qa_bind_align = max(sq_wqe_size, rq_wqe_size);
if (qp_is_umap) {
qp->qp_wqinfo.qa_location = TAVOR_QUEUE_LOCATION_USERLAND;
} else {
qp->qp_wqinfo.qa_location = wq_location;
}
status = tavor_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
if (status != DDI_SUCCESS) {
goto qpalloc_fail8;
}
if (sq_wqe_size > rq_wqe_size) {
sq_buf = qp->qp_wqinfo.qa_buf_aligned;
if (qp_srq_en)
rq_buf = NULL;
else
rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
} else {
rq_buf = qp->qp_wqinfo.qa_buf_aligned;
sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
}
flag = (sleepflag == TAVOR_SLEEP) ? IBT_MR_SLEEP :
IBT_MR_NOSLEEP;
mr_attr.mr_vaddr = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
mr_attr.mr_len = qp->qp_wqinfo.qa_size;
mr_attr.mr_as = NULL;
mr_attr.mr_flags = flag;
if (qp_is_umap) {
mr_op.mro_bind_type = state->ts_cfg_profile->cp_iommu_bypass;
} else {
if (wq_location == TAVOR_QUEUE_LOCATION_NORMAL) {
mr_op.mro_bind_type =
state->ts_cfg_profile->cp_iommu_bypass;
dma_xfer_mode =
state->ts_cfg_profile->cp_streaming_consistent;
if (dma_xfer_mode == DDI_DMA_STREAMING) {
mr_attr.mr_flags |= IBT_MR_NONCOHERENT;
}
} else {
mr_op.mro_bind_type = TAVOR_BINDMEM_BYPASS;
}
}
mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
mr_op.mro_bind_override_addr = 1;
status = tavor_mr_register(state, pd, &mr_attr, &mr, &mr_op);
if (status != DDI_SUCCESS) {
goto qpalloc_fail9;
}
qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
(uint64_t)mr->mr_bindinfo.bi_addr;
if (queuesz_p != NULL) {
queuesz_p->cs_sq = (1 << log_qp_sq_size);
queuesz_p->cs_sq_sgl = qp->qp_sq_sgl;
if (qp_srq_en) {
queuesz_p->cs_rq = 0;
queuesz_p->cs_rq_sgl = 0;
} else {
queuesz_p->cs_rq = (1 << log_qp_rq_size);
queuesz_p->cs_rq_sgl = qp->qp_rq_sgl;
}
}
if (qpn != NULL) {
*qpn = (ib_qpn_t)qp->qp_qpnum;
}
qp->qp_qpcrsrcp = qpc;
qp->qp_rsrcp = rsrc;
qp->qp_state = TAVOR_QP_RESET;
qp->qp_pdhdl = pd;
qp->qp_mrhdl = mr;
qp->qp_sq_sigtype = (attr_p->qp_flags & IBT_WR_SIGNALED) ?
TAVOR_QP_SQ_WR_SIGNALED : TAVOR_QP_SQ_ALL_SIGNALED;
qp->qp_is_special = 0;
qp->qp_is_umap = qp_is_umap;
qp->qp_uarpg = (qp->qp_is_umap) ? uarpg : 0;
qp->qp_umap_dhp = (devmap_cookie_t)NULL;
qp->qp_sq_cqhdl = sq_cq;
qp->qp_sq_lastwqeaddr = NULL;
qp->qp_sq_bufsz = (1 << log_qp_sq_size);
qp->qp_sq_buf = sq_buf;
qp->qp_desc_off = qp_desc_off;
qp->qp_rq_cqhdl = rq_cq;
qp->qp_rq_lastwqeaddr = NULL;
qp->qp_rq_buf = rq_buf;
if (qp_srq_en) {
qp->qp_rq_bufsz = 0;
} else {
qp->qp_rq_bufsz = (1 << log_qp_rq_size);
}
qp->qp_forward_sqd_event = 0;
qp->qp_sqd_still_draining = 0;
qp->qp_hdlrarg = (void *)ibt_qphdl;
qp->qp_mcg_refcnt = 0;
if (qp_srq_en) {
qp->qp_srqhdl = srq;
qp->qp_srq_en = TAVOR_QP_SRQ_ENABLED;
tavor_srq_refcnt_inc(qp->qp_srqhdl);
} else {
qp->qp_srqhdl = NULL;
qp->qp_srq_en = TAVOR_QP_SRQ_DISABLED;
}
qp->qp_sync = TAVOR_QP_IS_SYNC_REQ(state, qp->qp_wqinfo);
if (type == IBT_RC_RQP) {
qp->qp_serv_type = TAVOR_QP_RC;
} else if (type == IBT_UD_RQP) {
qp->qp_serv_type = TAVOR_QP_UD;
} else {
qp->qp_serv_type = TAVOR_QP_UC;
}
bzero(&qp->qpc, sizeof (tavor_hw_qpc_t));
ASSERT(state->ts_qphdl[qpc->tr_indx] == NULL);
state->ts_qphdl[qpc->tr_indx] = qp;
if (qp_is_umap) {
tavor_umap_db_add(umapdb);
}
*qphdl = qp;
return (DDI_SUCCESS);
qpalloc_fail9:
tavor_queue_free(state, &qp->qp_wqinfo);
qpalloc_fail8:
if (type == IBT_RC_RQP) {
tavor_rsrc_free(state, &rdb);
}
qpalloc_fail7:
if (qp_is_umap) {
tavor_umap_db_free(umapdb);
}
qpalloc_fail6:
tavor_qp_release_qpn(state, qp->qp_qpn_hdl, TAVOR_QPN_RELEASE);
qpc = NULL;
qpalloc_fail5:
tavor_rsrc_free(state, &rsrc);
qpalloc_fail4:
if (qpc) {
tavor_rsrc_free(state, &qpc);
}
qpalloc_fail3:
tavor_cq_refcnt_dec(rq_cq);
qpalloc_fail2:
tavor_cq_refcnt_dec(sq_cq);
qpalloc_fail1:
tavor_pd_refcnt_dec(pd);
qpalloc_fail:
return (status);
}
int
tavor_special_qp_alloc(tavor_state_t *state, tavor_qp_info_t *qpinfo,
uint_t sleepflag, tavor_qp_options_t *op)
{
tavor_rsrc_t *qpc, *rsrc;
tavor_qphdl_t qp;
ibt_qp_alloc_attr_t *attr_p;
ibt_sqp_type_t type;
uint8_t port;
ibtl_qp_hdl_t ibt_qphdl;
ibt_chan_sizes_t *queuesz_p;
tavor_qphdl_t *qphdl;
ibt_mr_attr_t mr_attr;
tavor_mr_options_t mr_op;
tavor_pdhdl_t pd;
tavor_cqhdl_t sq_cq, rq_cq;
tavor_mrhdl_t mr;
uint64_t qp_desc_off;
uint32_t *sq_buf, *rq_buf;
uint32_t log_qp_sq_size, log_qp_rq_size;
uint32_t sq_size, rq_size, max_sgl;
uint32_t sq_wqe_size, rq_wqe_size;
uint_t wq_location, dma_xfer_mode;
int status, flag;
if (op == NULL) {
wq_location = TAVOR_QUEUE_LOCATION_NORMAL;
} else {
wq_location = op->qpo_wq_loc;
}
attr_p = qpinfo->qpi_attrp;
type = qpinfo->qpi_type;
port = qpinfo->qpi_port;
ibt_qphdl = qpinfo->qpi_ibt_qphdl;
queuesz_p = qpinfo->qpi_queueszp;
qphdl = &qpinfo->qpi_qphdl;
if ((type != IBT_SMI_SQP) && (type != IBT_GSI_SQP)) {
goto spec_qpalloc_fail;
}
if (!tavor_portnum_is_valid(state, port)) {
goto spec_qpalloc_fail;
}
port = port - 1;
if (attr_p->qp_pd_hdl == NULL) {
goto spec_qpalloc_fail;
}
pd = (tavor_pdhdl_t)attr_p->qp_pd_hdl;
tavor_pd_refcnt_inc(pd);
if ((attr_p->qp_ibc_scq_hdl == NULL) ||
(attr_p->qp_ibc_rcq_hdl == NULL)) {
goto spec_qpalloc_fail1;
}
sq_cq = (tavor_cqhdl_t)attr_p->qp_ibc_scq_hdl;
rq_cq = (tavor_cqhdl_t)attr_p->qp_ibc_rcq_hdl;
status = tavor_cq_refcnt_inc(sq_cq, TAVOR_CQ_IS_SPECIAL);
if (status != DDI_SUCCESS) {
goto spec_qpalloc_fail1;
}
status = tavor_cq_refcnt_inc(rq_cq, TAVOR_CQ_IS_SPECIAL);
if (status != DDI_SUCCESS) {
goto spec_qpalloc_fail2;
}
status = tavor_special_qp_rsrc_alloc(state, type, port, &qpc);
if (status != DDI_SUCCESS) {
goto spec_qpalloc_fail3;
}
status = tavor_rsrc_alloc(state, TAVOR_QPHDL, 1, sleepflag, &rsrc);
if (status != DDI_SUCCESS) {
goto spec_qpalloc_fail4;
}
qp = (tavor_qphdl_t)rsrc->tr_addr;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
qp->qp_qpnum = qpc->tr_indx + port;
attr_p->qp_sizes.cs_sq = max(attr_p->qp_sizes.cs_sq, TAVOR_QP_MIN_SIZE);
attr_p->qp_sizes.cs_rq = max(attr_p->qp_sizes.cs_rq, TAVOR_QP_MIN_SIZE);
log_qp_sq_size = highbit(attr_p->qp_sizes.cs_sq);
if (ISP2(attr_p->qp_sizes.cs_sq)) {
log_qp_sq_size = log_qp_sq_size - 1;
}
log_qp_rq_size = highbit(attr_p->qp_sizes.cs_rq);
if (ISP2(attr_p->qp_sizes.cs_rq)) {
log_qp_rq_size = log_qp_rq_size - 1;
}
if ((log_qp_sq_size > state->ts_cfg_profile->cp_log_max_qp_sz) ||
(log_qp_rq_size > state->ts_cfg_profile->cp_log_max_qp_sz)) {
goto spec_qpalloc_fail5;
}
max_sgl = state->ts_cfg_profile->cp_wqe_real_max_sgl;
if ((attr_p->qp_sizes.cs_sq_sgl > max_sgl) ||
(attr_p->qp_sizes.cs_rq_sgl > max_sgl)) {
goto spec_qpalloc_fail5;
}
tavor_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_rq_sgl,
TAVOR_QP_WQ_TYPE_RECVQ, &qp->qp_rq_log_wqesz, &qp->qp_rq_sgl);
if (type == IBT_SMI_SQP) {
tavor_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
TAVOR_QP_WQ_TYPE_SENDMLX_QP0, &qp->qp_sq_log_wqesz,
&qp->qp_sq_sgl);
} else {
tavor_qp_sgl_to_logwqesz(state, attr_p->qp_sizes.cs_sq_sgl,
TAVOR_QP_WQ_TYPE_SENDMLX_QP1, &qp->qp_sq_log_wqesz,
&qp->qp_sq_sgl);
}
sq_wqe_size = 1 << qp->qp_sq_log_wqesz;
rq_wqe_size = 1 << qp->qp_rq_log_wqesz;
sq_size = (1 << log_qp_sq_size) * sq_wqe_size;
rq_size = (1 << log_qp_rq_size) * rq_wqe_size;
qp->qp_wqinfo.qa_size = sq_size + rq_size;
qp->qp_wqinfo.qa_alloc_align = max(sq_wqe_size, rq_wqe_size);
qp->qp_wqinfo.qa_bind_align = max(sq_wqe_size, rq_wqe_size);
qp->qp_wqinfo.qa_location = wq_location;
status = tavor_queue_alloc(state, &qp->qp_wqinfo, sleepflag);
if (status != 0) {
goto spec_qpalloc_fail5;
}
if (sq_wqe_size > rq_wqe_size) {
sq_buf = qp->qp_wqinfo.qa_buf_aligned;
rq_buf = (uint32_t *)((uintptr_t)sq_buf + sq_size);
} else {
rq_buf = qp->qp_wqinfo.qa_buf_aligned;
sq_buf = (uint32_t *)((uintptr_t)rq_buf + rq_size);
}
flag = (sleepflag == TAVOR_SLEEP) ? IBT_MR_SLEEP :
IBT_MR_NOSLEEP;
mr_attr.mr_vaddr = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
mr_attr.mr_len = qp->qp_wqinfo.qa_size;
mr_attr.mr_as = NULL;
mr_attr.mr_flags = flag;
if (wq_location == TAVOR_QUEUE_LOCATION_NORMAL) {
mr_op.mro_bind_type = state->ts_cfg_profile->cp_iommu_bypass;
dma_xfer_mode = state->ts_cfg_profile->cp_streaming_consistent;
if (dma_xfer_mode == DDI_DMA_STREAMING) {
mr_attr.mr_flags |= IBT_MR_NONCOHERENT;
}
} else {
mr_op.mro_bind_type = TAVOR_BINDMEM_BYPASS;
}
mr_op.mro_bind_dmahdl = qp->qp_wqinfo.qa_dmahdl;
mr_op.mro_bind_override_addr = 1;
status = tavor_mr_register(state, pd, &mr_attr, &mr, &mr_op);
if (status != DDI_SUCCESS) {
goto spec_qpalloc_fail6;
}
qp_desc_off = (uint64_t)(uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
(uint64_t)mr->mr_bindinfo.bi_addr;
if (queuesz_p != NULL) {
queuesz_p->cs_sq = (1 << log_qp_sq_size);
queuesz_p->cs_sq_sgl = qp->qp_sq_sgl;
queuesz_p->cs_rq = (1 << log_qp_rq_size);
queuesz_p->cs_rq_sgl = qp->qp_rq_sgl;
}
qp->qp_qpcrsrcp = qpc;
qp->qp_rsrcp = rsrc;
qp->qp_state = TAVOR_QP_RESET;
qp->qp_pdhdl = pd;
qp->qp_mrhdl = mr;
qp->qp_sq_sigtype = (attr_p->qp_flags & IBT_WR_SIGNALED) ?
TAVOR_QP_SQ_WR_SIGNALED : TAVOR_QP_SQ_ALL_SIGNALED;
qp->qp_is_special = (type == IBT_SMI_SQP) ?
TAVOR_QP_SMI : TAVOR_QP_GSI;
qp->qp_is_umap = 0;
qp->qp_uarpg = 0;
qp->qp_sq_cqhdl = sq_cq;
qp->qp_sq_lastwqeaddr = NULL;
qp->qp_sq_bufsz = (1 << log_qp_sq_size);
qp->qp_sq_buf = sq_buf;
qp->qp_desc_off = qp_desc_off;
qp->qp_rq_cqhdl = rq_cq;
qp->qp_rq_lastwqeaddr = NULL;
qp->qp_rq_bufsz = (1 << log_qp_rq_size);
qp->qp_rq_buf = rq_buf;
qp->qp_portnum = port;
qp->qp_pkeyindx = 0;
qp->qp_hdlrarg = (void *)ibt_qphdl;
qp->qp_mcg_refcnt = 0;
qp->qp_srq_en = 0;
qp->qp_srqhdl = NULL;
qp->qp_sync = TAVOR_QP_IS_SYNC_REQ(state, qp->qp_wqinfo);
qp->qp_serv_type = TAVOR_QP_UD;
bzero(&qp->qpc, sizeof (tavor_hw_qpc_t));
ASSERT(state->ts_qphdl[qpc->tr_indx + port] == NULL);
state->ts_qphdl[qpc->tr_indx + port] = qp;
*qphdl = qp;
return (DDI_SUCCESS);
spec_qpalloc_fail6:
tavor_queue_free(state, &qp->qp_wqinfo);
spec_qpalloc_fail5:
tavor_rsrc_free(state, &rsrc);
spec_qpalloc_fail4:
if (tavor_special_qp_rsrc_free(state, type, port) != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed to free special QP rsrc");
}
spec_qpalloc_fail3:
tavor_cq_refcnt_dec(rq_cq);
spec_qpalloc_fail2:
tavor_cq_refcnt_dec(sq_cq);
spec_qpalloc_fail1:
tavor_pd_refcnt_dec(pd);
spec_qpalloc_fail:
return (status);
}
int
tavor_qp_free(tavor_state_t *state, tavor_qphdl_t *qphdl,
ibc_free_qp_flags_t free_qp_flags, ibc_qpn_hdl_t *qpnh,
uint_t sleepflag)
{
tavor_rsrc_t *qpc, *rdb, *rsrc;
tavor_umap_db_entry_t *umapdb;
tavor_qpn_entry_t *entry;
tavor_pdhdl_t pd;
tavor_mrhdl_t mr;
tavor_cqhdl_t sq_cq, rq_cq;
tavor_srqhdl_t srq;
tavor_qphdl_t qp;
uint64_t value;
uint_t type, port;
uint_t maxprot;
uint_t qp_srq_en;
int status;
qp = *qphdl;
mutex_enter(&qp->qp_lock);
qpc = qp->qp_qpcrsrcp;
rsrc = qp->qp_rsrcp;
pd = qp->qp_pdhdl;
srq = qp->qp_srqhdl;
mr = qp->qp_mrhdl;
rq_cq = qp->qp_rq_cqhdl;
sq_cq = qp->qp_sq_cqhdl;
rdb = qp->qp_rdbrsrcp;
port = qp->qp_portnum;
qp_srq_en = qp->qp_srq_en;
if (qp->qp_mcg_refcnt != 0) {
mutex_exit(&qp->qp_lock);
goto qpfree_fail;
}
if (qp->qp_state != TAVOR_QP_RESET) {
if (tavor_qp_to_reset(state, qp) != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
TAVOR_WARNING(state, "failed to reset QP context");
goto qpfree_fail;
}
qp->qp_state = TAVOR_QP_RESET;
tavor_wrid_to_reset_handling(state, qp);
}
if (qp->qp_is_umap) {
status = tavor_umap_db_find(state->ts_instance, qp->qp_qpnum,
MLNX_UMAP_QPMEM_RSRC, &value, TAVOR_UMAP_DB_REMOVE,
&umapdb);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
TAVOR_WARNING(state, "failed to find in database");
return (ibc_get_ci_failure(0));
}
tavor_umap_db_free(umapdb);
if (qp->qp_umap_dhp != NULL) {
maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
status = devmap_devmem_remap(qp->qp_umap_dhp,
state->ts_dip, 0, 0, qp->qp_wqinfo.qa_size,
maxprot, DEVMAP_MAPPING_INVALID, NULL);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
TAVOR_WARNING(state, "failed in QP memory "
"devmap_devmem_remap()");
return (ibc_get_ci_failure(0));
}
qp->qp_umap_dhp = (devmap_cookie_t)NULL;
}
}
if (qp->qp_is_special) {
state->ts_qphdl[qpc->tr_indx + port] = NULL;
} else {
state->ts_qphdl[qpc->tr_indx] = NULL;
}
mutex_exit(&qp->qp_lock);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*qp))
status = tavor_mr_deregister(state, &mr, TAVOR_MR_DEREG_ALL,
sleepflag);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed to deregister QP memory");
goto qpfree_fail;
}
tavor_queue_free(state, &qp->qp_wqinfo);
if (qp->qp_is_special) {
type = (qp->qp_is_special == TAVOR_QP_SMI) ?
IBT_SMI_SQP : IBT_GSI_SQP;
status = tavor_special_qp_rsrc_free(state, type, port);
if (status != DDI_SUCCESS) {
TAVOR_WARNING(state, "failed to free special QP rsrc");
goto qpfree_fail;
}
} else {
type = qp->qp_serv_type;
if (type == TAVOR_QP_RC) {
tavor_rsrc_free(state, &rdb);
}
if (free_qp_flags == IBC_FREE_QP_ONLY) {
entry = qp->qp_qpn_hdl;
tavor_qp_release_qpn(state, qp->qp_qpn_hdl,
TAVOR_QPN_FREE_ONLY);
*qpnh = (ibc_qpn_hdl_t)entry;
} else {
tavor_qp_release_qpn(state, qp->qp_qpn_hdl,
TAVOR_QPN_RELEASE);
}
}
tavor_rsrc_free(state, &rsrc);
tavor_cq_refcnt_dec(rq_cq);
tavor_cq_refcnt_dec(sq_cq);
tavor_pd_refcnt_dec(pd);
if (qp_srq_en == TAVOR_QP_SRQ_ENABLED) {
tavor_srq_refcnt_dec(srq);
}
*qphdl = NULL;
return (DDI_SUCCESS);
qpfree_fail:
return (status);
}
int
tavor_qp_query(tavor_state_t *state, tavor_qphdl_t qp,
ibt_qp_query_attr_t *attr_p)
{
ibt_cep_state_t qp_state;
ibt_qp_ud_attr_t *ud;
ibt_qp_rc_attr_t *rc;
ibt_qp_uc_attr_t *uc;
ibt_cep_flags_t enable_flags;
tavor_hw_addr_path_t *qpc_path, *qpc_alt_path;
ibt_cep_path_t *path_ptr, *alt_path_ptr;
tavor_hw_qpc_t *qpc;
int status;
mutex_enter(&qp->qp_lock);
qpc = &qp->qpc;
switch (qp->qp_state) {
case TAVOR_QP_RESET:
qp_state = IBT_STATE_RESET;
break;
case TAVOR_QP_INIT:
qp_state = IBT_STATE_INIT;
break;
case TAVOR_QP_RTR:
qp_state = IBT_STATE_RTR;
break;
case TAVOR_QP_RTS:
qp_state = IBT_STATE_RTS;
break;
case TAVOR_QP_SQERR:
qp_state = IBT_STATE_SQE;
break;
case TAVOR_QP_SQD:
if (qp->qp_sqd_still_draining) {
qp_state = IBT_STATE_SQDRAIN;
} else {
qp_state = IBT_STATE_SQD;
}
break;
case TAVOR_QP_ERR:
qp_state = IBT_STATE_ERROR;
break;
default:
mutex_exit(&qp->qp_lock);
return (ibc_get_ci_failure(0));
}
attr_p->qp_info.qp_state = qp_state;
attr_p->qp_srq = NULL;
attr_p->qp_sq_cq = qp->qp_sq_cqhdl->cq_hdlrarg;
attr_p->qp_rq_cq = qp->qp_rq_cqhdl->cq_hdlrarg;
if (qp->qp_is_special) {
attr_p->qp_qpn = (qp->qp_is_special == TAVOR_QP_SMI) ? 0 : 1;
} else {
attr_p->qp_qpn = (ib_qpn_t)qp->qp_qpnum;
}
attr_p->qp_sq_sgl = qp->qp_sq_sgl;
attr_p->qp_rq_sgl = qp->qp_rq_sgl;
attr_p->qp_info.qp_sq_sz = qp->qp_sq_bufsz;
attr_p->qp_info.qp_rq_sz = qp->qp_rq_bufsz;
if (qp_state == IBT_STATE_RESET) {
mutex_exit(&qp->qp_lock);
return (DDI_SUCCESS);
}
status = tavor_cmn_query_cmd_post(state, QUERY_QP, qp->qp_qpnum,
qpc, sizeof (tavor_hw_qpc_t), TAVOR_CMD_NOSLEEP_SPIN);
if (status != TAVOR_CMD_SUCCESS) {
mutex_exit(&qp->qp_lock);
cmn_err(CE_CONT, "Tavor: QUERY_QP command failed: %08x\n",
status);
return (ibc_get_ci_failure(0));
}
if (qp->qp_serv_type == TAVOR_QP_UD) {
ud = &attr_p->qp_info.qp_transport.ud;
ud->ud_qkey = (ib_qkey_t)qpc->qkey;
ud->ud_sq_psn = qpc->next_snd_psn;
ud->ud_pkey_ix = qpc->pri_addr_path.pkey_indx;
ud->ud_port = qpc->pri_addr_path.portnum;
attr_p->qp_info.qp_trans = IBT_UD_SRV;
} else if (qp->qp_serv_type == TAVOR_QP_RC) {
rc = &attr_p->qp_info.qp_transport.rc;
rc->rc_sq_psn = qpc->next_snd_psn;
rc->rc_rq_psn = qpc->next_rcv_psn;
rc->rc_dst_qpn = qpc->rem_qpn;
if (qpc->pm_state == TAVOR_QP_PMSTATE_MIGRATED) {
rc->rc_mig_state = IBT_STATE_MIGRATED;
} else if (qpc->pm_state == TAVOR_QP_PMSTATE_REARM) {
rc->rc_mig_state = IBT_STATE_REARMED;
} else {
rc->rc_mig_state = IBT_STATE_ARMED;
}
rc->rc_rdma_ra_out = (1 << qpc->sra_max);
rc->rc_rdma_ra_in = (1 << qpc->rra_max);
rc->rc_min_rnr_nak = qpc->min_rnr_nak;
rc->rc_path_mtu = qpc->mtu;
rc->rc_retry_cnt = qpc->retry_cnt;
qpc_path = &qpc->pri_addr_path;
path_ptr = &rc->rc_path;
tavor_get_addr_path(state, qpc_path, &path_ptr->cep_adds_vect,
TAVOR_ADDRPATH_QP, qp);
path_ptr->cep_pkey_ix = qpc_path->pkey_indx;
path_ptr->cep_hca_port_num = qpc_path->portnum;
path_ptr->cep_timeout = qpc_path->ack_timeout;
qpc_alt_path = &qpc->alt_addr_path;
alt_path_ptr = &rc->rc_alt_path;
tavor_get_addr_path(state, qpc_alt_path,
&alt_path_ptr->cep_adds_vect, TAVOR_ADDRPATH_QP, qp);
alt_path_ptr->cep_pkey_ix = qpc_alt_path->pkey_indx;
alt_path_ptr->cep_hca_port_num = qpc_alt_path->portnum;
alt_path_ptr->cep_timeout = qpc_alt_path->ack_timeout;
rc->rc_rnr_retry_cnt = qpc_path->rnr_retry;
enable_flags = IBT_CEP_NO_FLAGS;
enable_flags |= ((qpc->rre == 0) ? 0 : IBT_CEP_RDMA_RD);
enable_flags |= ((qpc->rwe == 0) ? 0 : IBT_CEP_RDMA_WR);
enable_flags |= ((qpc->rae == 0) ? 0 : IBT_CEP_ATOMIC);
attr_p->qp_info.qp_flags = enable_flags;
attr_p->qp_info.qp_trans = IBT_RC_SRV;
} else if (qp->qp_serv_type == TAVOR_QP_UC) {
uc = &attr_p->qp_info.qp_transport.uc;
uc->uc_sq_psn = qpc->next_snd_psn;
uc->uc_rq_psn = qpc->next_rcv_psn;
uc->uc_dst_qpn = qpc->rem_qpn;
if (qpc->pm_state == TAVOR_QP_PMSTATE_MIGRATED) {
uc->uc_mig_state = IBT_STATE_MIGRATED;
} else if (qpc->pm_state == TAVOR_QP_PMSTATE_REARM) {
uc->uc_mig_state = IBT_STATE_REARMED;
} else {
uc->uc_mig_state = IBT_STATE_ARMED;
}
uc->uc_path_mtu = qpc->mtu;
qpc_path = &qpc->pri_addr_path;
path_ptr = &uc->uc_path;
tavor_get_addr_path(state, qpc_path, &path_ptr->cep_adds_vect,
TAVOR_ADDRPATH_QP, qp);
path_ptr->cep_pkey_ix = qpc_path->pkey_indx;
path_ptr->cep_hca_port_num = qpc_path->portnum;
qpc_alt_path = &qpc->alt_addr_path;
alt_path_ptr = &uc->uc_alt_path;
tavor_get_addr_path(state, qpc_alt_path,
&alt_path_ptr->cep_adds_vect, TAVOR_ADDRPATH_QP, qp);
alt_path_ptr->cep_pkey_ix = qpc_alt_path->pkey_indx;
alt_path_ptr->cep_hca_port_num = qpc_alt_path->portnum;
enable_flags = ((qpc->rwe == 0) ? 0 : IBT_CEP_RDMA_WR);
attr_p->qp_info.qp_flags = enable_flags;
attr_p->qp_info.qp_trans = IBT_UC_SRV;
} else {
TAVOR_WARNING(state, "unexpected QP transport type");
mutex_exit(&qp->qp_lock);
return (ibc_get_ci_failure(0));
}
if (qpc->state == TAVOR_QP_SQERR) {
attr_p->qp_info.qp_state = IBT_STATE_SQE;
qp->qp_state = TAVOR_QP_SQERR;
}
if (qpc->state == TAVOR_QP_ERR) {
attr_p->qp_info.qp_state = IBT_STATE_ERROR;
qp->qp_state = TAVOR_QP_ERR;
}
mutex_exit(&qp->qp_lock);
return (DDI_SUCCESS);
}
static int
tavor_qp_create_qpn(tavor_state_t *state, tavor_qphdl_t qp, tavor_rsrc_t *qpc)
{
tavor_qpn_entry_t query;
tavor_qpn_entry_t *entry;
avl_index_t where;
query.qpn_indx = qpc->tr_indx;
mutex_enter(&state->ts_qpn_avl_lock);
entry = (tavor_qpn_entry_t *)avl_find(&state->ts_qpn_avl,
&query, &where);
if (entry == NULL) {
entry = (tavor_qpn_entry_t *)kmem_zalloc(
sizeof (tavor_qpn_entry_t), KM_NOSLEEP);
if (entry == NULL) {
mutex_exit(&state->ts_qpn_avl_lock);
return (DDI_FAILURE);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
entry->qpn_indx = qpc->tr_indx;
entry->qpn_refcnt = 0;
entry->qpn_counter = 0;
avl_insert(&state->ts_qpn_avl, entry, where);
}
entry->qpn_qpc = qpc;
qp->qp_qpn_hdl = entry;
qp->qp_qpnum = ((entry->qpn_counter <<
state->ts_cfg_profile->cp_log_num_qp) | qpc->tr_indx) &
TAVOR_QP_MAXNUMBER_MSK;
entry->qpn_counter++;
entry->qpn_refcnt++;
mutex_exit(&state->ts_qpn_avl_lock);
return (DDI_SUCCESS);
}
void
tavor_qp_release_qpn(tavor_state_t *state, tavor_qpn_entry_t *entry, int flags)
{
ASSERT(entry != NULL);
mutex_enter(&state->ts_qpn_avl_lock);
if (flags == TAVOR_QPN_RELEASE) {
entry->qpn_refcnt--;
if (entry->qpn_refcnt == 0) {
if (entry->qpn_qpc != NULL) {
tavor_rsrc_free(state, &entry->qpn_qpc);
}
if (entry->qpn_counter >= (1 <<
(24 - state->ts_cfg_profile->cp_log_num_qp))) {
avl_remove(&state->ts_qpn_avl, entry);
kmem_free(entry, sizeof (tavor_qpn_entry_t));
}
}
} else if (flags == TAVOR_QPN_FREE_ONLY) {
if (entry->qpn_counter < (1 <<
(24 - state->ts_cfg_profile->cp_log_num_qp))) {
tavor_rsrc_free(state, &entry->qpn_qpc);
}
}
mutex_exit(&state->ts_qpn_avl_lock);
}
static int
tavor_qpn_avl_compare(const void *q, const void *e)
{
tavor_qpn_entry_t *entry, *query;
entry = (tavor_qpn_entry_t *)e;
query = (tavor_qpn_entry_t *)q;
if (query->qpn_indx < entry->qpn_indx) {
return (-1);
} else if (query->qpn_indx > entry->qpn_indx) {
return (+1);
} else {
return (0);
}
}
void
tavor_qpn_avl_init(tavor_state_t *state)
{
mutex_init(&state->ts_qpn_avl_lock, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(state->ts_intrmsi_pri));
avl_create(&state->ts_qpn_avl, tavor_qpn_avl_compare,
sizeof (tavor_qpn_entry_t),
offsetof(tavor_qpn_entry_t, qpn_avlnode));
}
void
tavor_qpn_avl_fini(tavor_state_t *state)
{
tavor_qpn_entry_t *entry;
void *cookie;
cookie = NULL;
while ((entry = (tavor_qpn_entry_t *)avl_destroy_nodes(
&state->ts_qpn_avl, &cookie)) != NULL) {
kmem_free(entry, sizeof (tavor_qpn_entry_t));
}
avl_destroy(&state->ts_qpn_avl);
mutex_destroy(&state->ts_qpn_avl_lock);
}
tavor_qphdl_t
tavor_qphdl_from_qpnum(tavor_state_t *state, uint_t qpnum)
{
uint_t qpindx, qpmask;
qpmask = (1 << state->ts_cfg_profile->cp_log_num_qp) - 1;
qpindx = qpnum & qpmask;
return (state->ts_qphdl[qpindx]);
}
static int
tavor_special_qp_rsrc_alloc(tavor_state_t *state, ibt_sqp_type_t type,
uint_t port, tavor_rsrc_t **qp_rsrc)
{
uint_t mask, flags;
int status;
mutex_enter(&state->ts_spec_qplock);
flags = state->ts_spec_qpflags;
if (type == IBT_SMI_SQP) {
if (state->ts_cfg_profile->cp_qp0_agents_in_fw != 0) {
mutex_exit(&state->ts_spec_qplock);
return (IBT_QP_IN_USE);
}
if ((flags & TAVOR_SPECIAL_QP0_RSRC_MASK) == 0) {
status = tavor_conf_special_qp_cmd_post(state,
state->ts_spec_qp0->tr_indx, TAVOR_CMD_QP_SMI,
TAVOR_CMD_NOSLEEP_SPIN);
if (status != TAVOR_CMD_SUCCESS) {
mutex_exit(&state->ts_spec_qplock);
cmn_err(CE_CONT, "Tavor: CONF_SPECIAL_QP "
"command failed: %08x\n", status);
return (IBT_INSUFF_RESOURCE);
}
}
mask = (1 << (TAVOR_SPECIAL_QP0_RSRC + port));
if (flags & mask) {
mutex_exit(&state->ts_spec_qplock);
return (IBT_QP_IN_USE);
}
state->ts_spec_qpflags |= mask;
*qp_rsrc = state->ts_spec_qp0;
} else {
if ((flags & TAVOR_SPECIAL_QP1_RSRC_MASK) == 0) {
status = tavor_conf_special_qp_cmd_post(state,
state->ts_spec_qp1->tr_indx, TAVOR_CMD_QP_GSI,
TAVOR_CMD_NOSLEEP_SPIN);
if (status != TAVOR_CMD_SUCCESS) {
mutex_exit(&state->ts_spec_qplock);
cmn_err(CE_CONT, "Tavor: CONF_SPECIAL_QP "
"command failed: %08x\n", status);
return (IBT_INSUFF_RESOURCE);
}
}
mask = (1 << (TAVOR_SPECIAL_QP1_RSRC + port));
if (flags & mask) {
mutex_exit(&state->ts_spec_qplock);
return (IBT_QP_IN_USE);
}
state->ts_spec_qpflags |= mask;
*qp_rsrc = state->ts_spec_qp1;
}
mutex_exit(&state->ts_spec_qplock);
return (DDI_SUCCESS);
}
static int
tavor_special_qp_rsrc_free(tavor_state_t *state, ibt_sqp_type_t type,
uint_t port)
{
uint_t mask, flags;
int status;
mutex_enter(&state->ts_spec_qplock);
if (type == IBT_SMI_SQP) {
mask = (1 << (TAVOR_SPECIAL_QP0_RSRC + port));
state->ts_spec_qpflags &= ~mask;
flags = state->ts_spec_qpflags;
if ((flags & TAVOR_SPECIAL_QP0_RSRC_MASK) == 0) {
status = tavor_conf_special_qp_cmd_post(state, 0,
TAVOR_CMD_QP_SMI, TAVOR_CMD_NOSLEEP_SPIN);
if (status != TAVOR_CMD_SUCCESS) {
mutex_exit(&state->ts_spec_qplock);
cmn_err(CE_CONT, "Tavor: CONF_SPECIAL_QP "
"command failed: %08x\n", status);
return (ibc_get_ci_failure(0));
}
}
} else {
mask = (1 << (TAVOR_SPECIAL_QP1_RSRC + port));
state->ts_spec_qpflags &= ~mask;
flags = state->ts_spec_qpflags;
if ((flags & TAVOR_SPECIAL_QP1_RSRC_MASK) == 0) {
status = tavor_conf_special_qp_cmd_post(state, 0,
TAVOR_CMD_QP_GSI, TAVOR_CMD_NOSLEEP_SPIN);
if (status != TAVOR_CMD_SUCCESS) {
mutex_exit(&state->ts_spec_qplock);
cmn_err(CE_CONT, "Tavor: CONF_SPECIAL_QP "
"command failed: %08x\n", status);
return (ibc_get_ci_failure(0));
}
}
}
mutex_exit(&state->ts_spec_qplock);
return (DDI_SUCCESS);
}
static void
tavor_qp_sgl_to_logwqesz(tavor_state_t *state, uint_t num_sgl,
tavor_qp_wq_type_t wq_type, uint_t *logwqesz, uint_t *max_sgl)
{
uint_t max_size, log2, actual_sgl;
switch (wq_type) {
case TAVOR_QP_WQ_TYPE_SENDQ:
max_size = (TAVOR_QP_WQE_MLX_SND_HDRS + (num_sgl << 4));
log2 = highbit(max_size);
if (ISP2(max_size)) {
log2 = log2 - 1;
}
log2 = max(log2, TAVOR_QP_WQE_LOG_MINIMUM);
actual_sgl = ((1 << log2) - TAVOR_QP_WQE_MLX_SND_HDRS) >> 4;
break;
case TAVOR_QP_WQ_TYPE_RECVQ:
max_size = (TAVOR_QP_WQE_MLX_RCV_HDRS + (num_sgl << 4));
log2 = highbit(max_size);
if (ISP2(max_size)) {
log2 = log2 - 1;
}
log2 = max(log2, TAVOR_QP_WQE_LOG_MINIMUM);
actual_sgl = ((1 << log2) - TAVOR_QP_WQE_MLX_RCV_HDRS) >> 4;
break;
case TAVOR_QP_WQ_TYPE_SENDMLX_QP0:
max_size = (TAVOR_QP_WQE_MLX_QP0_HDRS + (num_sgl << 4));
log2 = highbit(max_size);
if (ISP2(max_size)) {
log2 = log2 - 1;
}
log2 = max(log2, TAVOR_QP_WQE_LOG_MINIMUM);
actual_sgl = ((1 << log2) - TAVOR_QP_WQE_MLX_QP0_HDRS) >> 4;
break;
case TAVOR_QP_WQ_TYPE_SENDMLX_QP1:
max_size = (TAVOR_QP_WQE_MLX_QP1_HDRS + (num_sgl << 4));
log2 = highbit(max_size);
if (ISP2(max_size)) {
log2 = log2 - 1;
}
log2 = max(log2, TAVOR_QP_WQE_LOG_MINIMUM);
actual_sgl = ((1 << log2) - TAVOR_QP_WQE_MLX_QP1_HDRS) >> 4;
break;
default:
TAVOR_WARNING(state, "unexpected work queue type");
break;
}
*logwqesz = log2;
*max_sgl = min(state->ts_cfg_profile->cp_wqe_real_max_sgl, actual_sgl);
}