#include "dapl.h"
#include "dapl_tavor_hw.h"
#include "dapl_tavor_wr.h"
#include "dapl_tavor_ibtf_impl.h"
extern uint64_t dapls_tavor_wrid_get_entry(ib_cq_handle_t, tavor_hw_cqe_t *,
uint_t, uint_t, dapls_tavor_wrid_entry_t *);
extern void dapls_tavor_wrid_cq_reap(ib_cq_handle_t);
extern DAPL_OS_LOCK g_tavor_uar_lock;
#ifndef _LP64
extern void dapls_atomic_assign_64(uint64_t, uint64_t *);
#endif
static int dapli_tavor_wqe_send_build(ib_qp_handle_t, ibt_send_wr_t *,
uint64_t *, uint_t *);
static void dapli_tavor_wqe_send_linknext(ibt_send_wr_t *, uint64_t *,
boolean_t, uint32_t, uint_t, uint64_t *, tavor_sw_wqe_dbinfo_t *);
static DAT_RETURN dapli_tavor_wqe_recv_build(ib_qp_handle_t, ibt_recv_wr_t *,
uint64_t *, uint_t *);
static void dapli_tavor_wqe_recv_linknext(uint64_t *, boolean_t, uint32_t,
uint_t, uint64_t *);
static int dapli_tavor_cq_cqe_consume(ib_cq_handle_t, tavor_hw_cqe_t *,
ibt_wc_t *);
static int dapli_tavor_cq_errcqe_consume(ib_cq_handle_t, tavor_hw_cqe_t *,
ibt_wc_t *);
extern void dapli_tavor_wrid_add_entry(dapls_tavor_workq_hdr_t *, uint64_t,
uint32_t, uint_t);
extern void dapli_tavor_wrid_add_entry_srq(ib_srq_handle_t, uint64_t, uint32_t);
#if defined(_LP64) || defined(__lint)
#define dapli_tavor_cq_doorbell(ia_uar, cq_cmd, cqn, cq_param) \
((tavor_hw_uar_t *)ia_uar)->cq = HTOBE_64( \
((uint64_t)cq_cmd << TAVOR_CQDB_CMD_SHIFT) | \
((uint64_t)cqn << TAVOR_CQDB_CQN_SHIFT) | cq_param)
#else
static void
dapli_tavor_cq_doorbell(dapls_hw_uar_t ia_uar, uint32_t cq_cmd, uint32_t cqn,
uint32_t cq_param)
{
uint64_t doorbell;
doorbell = ((uint64_t)cq_cmd << TAVOR_CQDB_CMD_SHIFT) |
((uint64_t)cqn << TAVOR_CQDB_CQN_SHIFT) | cq_param;
#ifdef _LP64
((tavor_hw_uar_t *)ia_uar)->cq = HTOBE_64(doorbell);
#elif defined(i386)
dapl_os_lock(&g_tavor_uar_lock);
((tavor_hw_uar32_t *)ia_uar)->cq[0] =
(uint32_t)HTOBE_32(doorbell >> 32);
((tavor_hw_uar32_t *)ia_uar)->cq[1] =
(uint32_t)HTOBE_32(doorbell & 0x00000000ffffffff);
dapl_os_unlock(&g_tavor_uar_lock);
#else
dapls_atomic_assign_64(HTOBE_64(doorbell),
&((tavor_hw_uar_t *)ia_uar)->cq);
#endif
}
#endif
#if defined(_LP64) || defined(__lint)
#define dapli_tavor_qp_send_doorbell(ia_uar, nda, nds, qpn, fence, nopcode) \
((tavor_hw_uar_t *)ia_uar)->send = HTOBE_64( \
(((uint64_t)nda & TAVOR_QPSNDDB_NDA_MASK) << \
TAVOR_QPSNDDB_NDA_SHIFT) | \
((uint64_t)fence << TAVOR_QPSNDDB_F_SHIFT) | \
((uint64_t)nopcode << TAVOR_QPSNDDB_NOPCODE_SHIFT) | \
((uint64_t)qpn << TAVOR_QPSNDDB_QPN_SHIFT) | nds)
#else
static void
dapli_tavor_qp_send_doorbell(dapls_hw_uar_t ia_uar, uint32_t nda,
uint32_t nds, uint32_t qpn, uint32_t fence, uint32_t nopcode)
{
uint64_t doorbell;
doorbell = (((uint64_t)nda & TAVOR_QPSNDDB_NDA_MASK) <<
TAVOR_QPSNDDB_NDA_SHIFT) |
((uint64_t)fence << TAVOR_QPSNDDB_F_SHIFT) |
((uint64_t)nopcode << TAVOR_QPSNDDB_NOPCODE_SHIFT) |
((uint64_t)qpn << TAVOR_QPSNDDB_QPN_SHIFT) | nds;
#ifdef _LP64
((tavor_hw_uar_t *)ia_uar)->send = HTOBE_64(doorbell);
#else
#if defined(i386)
dapl_os_lock(&g_tavor_uar_lock);
((tavor_hw_uar32_t *)ia_uar)->send[0] =
(uint32_t)HTOBE_32(doorbell >> 32);
((tavor_hw_uar32_t *)ia_uar)->send[1] =
(uint32_t)HTOBE_32(doorbell & 0x00000000ffffffff);
dapl_os_unlock(&g_tavor_uar_lock);
#else
dapls_atomic_assign_64(HTOBE_64(doorbell),
&((tavor_hw_uar_t *)ia_uar)->send);
#endif
#endif
}
#endif
#if defined(_LP64) || defined(__lint)
#define dapli_tavor_qp_recv_doorbell(ia_uar, nda, nds, qpn, credits) \
((tavor_hw_uar_t *)ia_uar)->recv = HTOBE_64( \
(((uint64_t)nda & TAVOR_QPRCVDB_NDA_MASK) << \
TAVOR_QPRCVDB_NDA_SHIFT) | \
((uint64_t)nds << TAVOR_QPRCVDB_NDS_SHIFT) | \
((uint64_t)qpn << TAVOR_QPRCVDB_QPN_SHIFT) | credits)
#else
static void
dapli_tavor_qp_recv_doorbell(dapls_hw_uar_t ia_uar, uint32_t nda,
uint32_t nds, uint32_t qpn, uint32_t credits)
{
uint64_t doorbell;
doorbell = (((uint64_t)nda & TAVOR_QPRCVDB_NDA_MASK) <<
TAVOR_QPRCVDB_NDA_SHIFT) |
((uint64_t)nds << TAVOR_QPRCVDB_NDS_SHIFT) |
((uint64_t)qpn << TAVOR_QPRCVDB_QPN_SHIFT) | credits;
#ifdef _LP64
((tavor_hw_uar_t *)ia_uar)->recv = HTOBE_64(doorbell);
#else
#if defined(i386)
dapl_os_lock(&g_tavor_uar_lock);
((tavor_hw_uar32_t *)ia_uar)->recv[0] =
(uint32_t)HTOBE_32(doorbell >> 32);
((tavor_hw_uar32_t *)ia_uar)->recv[1] =
(uint32_t)HTOBE_32(doorbell & 0x00000000ffffffff);
dapl_os_unlock(&g_tavor_uar_lock);
#else
dapls_atomic_assign_64(HTOBE_64(doorbell),
&((tavor_hw_uar_t *)ia_uar)->recv);
#endif
#endif
}
#endif
int
dapls_tavor_max_inline(void)
{
static int max_inline_env = -2;
if (max_inline_env != -2)
return (max_inline_env);
max_inline_env = dapl_os_get_env_val("DAPL_MAX_INLINE", -1);
if (max_inline_env != -1)
if (max_inline_env <= 0)
max_inline_env = 0;
return (max_inline_env);
}
int
dapls_ib_max_request_iov(int iovs, int wqes, int max_iovs,
int max_inline_bytes)
{
int ret_iovs;
if (max_inline_bytes > 0) {
ret_iovs = max_inline_bytes / sizeof (tavor_hw_wqe_sgl_t);
} else if (wqes < 128) {
max_inline_bytes = 256 - TAVOR_INLINE_HEADER_SIZE_MAX;
ret_iovs = max_inline_bytes / sizeof (tavor_hw_wqe_sgl_t);
} else if (wqes < 256) {
max_inline_bytes = 128 - TAVOR_INLINE_HEADER_SIZE_MAX;
ret_iovs = max_inline_bytes / sizeof (tavor_hw_wqe_sgl_t);
} else {
ret_iovs = iovs;
}
if (ret_iovs > max_iovs)
ret_iovs = max_iovs;
if (iovs > ret_iovs)
ret_iovs = iovs;
return (ret_iovs);
}
static int
dapli_tavor_wqe_send_build(ib_qp_handle_t qp, ibt_send_wr_t *wr,
uint64_t *addr, uint_t *size)
{
tavor_hw_snd_wqe_remaddr_t *rc;
tavor_hw_snd_wqe_bind_t *bn;
tavor_hw_wqe_sgl_t *ds;
ibt_wr_ds_t *sgl;
uint32_t nds;
uint32_t len, total_len;
uint32_t tavor_num_mpt_mask;
uint32_t new_rkey;
uint32_t old_rkey;
int i, num_ds;
int max_inline_bytes = -1;
nds = wr->wr_nds;
sgl = wr->wr_sgl;
num_ds = 0;
switch (wr->wr_opcode) {
case IBT_WRC_SEND:
ds = (tavor_hw_wqe_sgl_t *)((uintptr_t)addr +
sizeof (tavor_hw_snd_wqe_nextctrl_t));
if (qp->qp_sq_inline != 0)
max_inline_bytes =
qp->qp_sq_wqesz - TAVOR_INLINE_HEADER_SIZE_SEND;
break;
case IBT_WRC_RDMAW:
if (qp->qp_sq_inline != 0)
max_inline_bytes =
qp->qp_sq_wqesz - TAVOR_INLINE_HEADER_SIZE_RDMAW;
case IBT_WRC_RDMAR:
if (qp->qp_sq_inline < 0 && wr->wr_opcode == IBT_WRC_RDMAR)
qp->qp_sq_inline = 0;
rc = (tavor_hw_snd_wqe_remaddr_t *)((uintptr_t)addr +
sizeof (tavor_hw_snd_wqe_nextctrl_t));
TAVOR_WQE_BUILD_REMADDR(rc, &wr->wr.rc.rcwr.rdma);
ds = (tavor_hw_wqe_sgl_t *)((uintptr_t)rc +
sizeof (tavor_hw_snd_wqe_remaddr_t));
break;
case IBT_WRC_BIND:
old_rkey = wr->wr.rc.rcwr.bind->bind_rkey;
tavor_num_mpt_mask = (uint32_t)(1 << qp->qp_num_mpt_shift) - 1;
new_rkey = (old_rkey >> qp->qp_num_mpt_shift);
new_rkey++;
new_rkey = ((new_rkey << qp->qp_num_mpt_shift) |
(old_rkey & tavor_num_mpt_mask));
wr->wr.rc.rcwr.bind->bind_rkey_out = new_rkey;
bn = (tavor_hw_snd_wqe_bind_t *)((uintptr_t)addr +
sizeof (tavor_hw_snd_wqe_nextctrl_t));
TAVOR_WQE_BUILD_BIND(bn, wr->wr.rc.rcwr.bind);
ds = (tavor_hw_wqe_sgl_t *)((uintptr_t)bn +
sizeof (tavor_hw_snd_wqe_bind_t));
break;
default:
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"dapli_tavor_wqe_send_build: invalid wr_opcode=%d\n",
wr->wr_opcode);
return (DAT_INTERNAL_ERROR);
}
if (nds > qp->qp_sq_sgl) {
return (DAT_INVALID_PARAMETER);
}
if (max_inline_bytes != -1) {
total_len = 0;
for (i = 0; i < nds; i++)
total_len += sgl[i].ds_len;
if (total_len > max_inline_bytes)
max_inline_bytes = -1;
}
if (max_inline_bytes != -1) {
uint8_t *dst = (uint8_t *)((uint32_t *)ds + 1);
*(uint32_t *)ds =
HTOBE_32(total_len | TAVOR_WQE_SGL_INLINE_MASK);
for (i = 0; i < nds; i++) {
if ((len = sgl[i].ds_len) == 0) {
continue;
}
(void) dapl_os_memcpy(dst,
(void *)(uintptr_t)sgl[i].ds_va, len);
dst += len;
}
*size = ((uintptr_t)dst - (uintptr_t)addr + 15) >> 4;
} else {
for (i = 0; i < nds; i++) {
if (sgl[i].ds_len == 0) {
continue;
}
TAVOR_WQE_BUILD_DATA_SEG(&ds[num_ds], &sgl[i]);
num_ds++;
}
*size = ((uintptr_t)&ds[num_ds] - (uintptr_t)addr) >> 4;
}
return (DAT_SUCCESS);
}
static void
dapli_tavor_wqe_send_linknext(ibt_send_wr_t *curr_wr, uint64_t *curr_addr,
boolean_t ns, uint32_t curr_desc, uint_t curr_descsz, uint64_t *prev_addr,
tavor_sw_wqe_dbinfo_t *dbinfo)
{
uint64_t next, ctrl;
uint32_t nopcode, fence;
next = 0;
ctrl = 0;
if (curr_wr->wr_flags & IBT_WR_SEND_SIGNAL) {
ctrl = ctrl | TAVOR_WQE_SEND_SIGNALED_MASK;
}
if (curr_wr->wr_flags & IBT_WR_SEND_SOLICIT) {
ctrl = ctrl | TAVOR_WQE_SEND_SOLICIT_MASK;
}
if (!ns) {
ctrl = ctrl | TAVOR_WQE_RCV_EVENT_MASK;
}
TAVOR_WQE_LINKNEXT(curr_addr, ctrl, next);
switch (curr_wr->wr_opcode) {
case IBT_WRC_RDMAW:
nopcode = TAVOR_WQE_SEND_NOPCODE_RDMAW;
break;
case IBT_WRC_SEND:
nopcode = TAVOR_WQE_SEND_NOPCODE_SEND;
break;
case IBT_WRC_RDMAR:
nopcode = TAVOR_WQE_SEND_NOPCODE_RDMAR;
break;
case IBT_WRC_BIND:
nopcode = TAVOR_WQE_SEND_NOPCODE_BIND;
break;
default:
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"dapli_tavor_wqe_send_linknext: invalid nopcode=%d\n",
nopcode);
return;
}
next = ((uint64_t)curr_desc & TAVOR_WQE_NDA_MASK) << 32;
next = next | ((uint64_t)nopcode << 32);
fence = (curr_wr->wr_flags & IBT_WR_SEND_FENCE) ? 1 : 0;
if (fence) {
next = next | TAVOR_WQE_SEND_FENCE_MASK;
}
next = next | (curr_descsz & TAVOR_WQE_NDS_MASK);
next = next | TAVOR_WQE_DBD_MASK;
dbinfo->db_nopcode = nopcode;
dbinfo->db_fence = fence;
if (prev_addr != NULL) {
TAVOR_WQE_LINKFIRST(prev_addr, next);
}
}
static DAT_RETURN
dapli_tavor_wqe_recv_build(ib_qp_handle_t qp, ibt_recv_wr_t *wr,
uint64_t *addr, uint_t *size)
{
tavor_hw_wqe_sgl_t *ds;
int i;
int num_ds;
ds = (tavor_hw_wqe_sgl_t *)((uintptr_t)addr +
sizeof (tavor_hw_rcv_wqe_nextctrl_t));
num_ds = 0;
if (wr->wr_nds > qp->qp_rq_sgl) {
return (DAT_INVALID_PARAMETER);
}
for (i = 0; i < wr->wr_nds; i++) {
if (wr->wr_sgl[i].ds_len == 0) {
continue;
}
TAVOR_WQE_BUILD_DATA_SEG(&ds[num_ds], &wr->wr_sgl[i]);
num_ds++;
}
*size = ((uintptr_t)&ds[num_ds] - (uintptr_t)addr) >> 0x4;
return (DAT_SUCCESS);
}
static void
dapli_tavor_wqe_recv_linknext(uint64_t *curr_addr, boolean_t ns,
uint32_t curr_desc, uint_t curr_descsz, uint64_t *prev_addr)
{
uint64_t next;
uint64_t ctrl = 0;
next = TAVOR_WQE_DBD_MASK | TAVOR_RCV_WQE_NDA0_WA_MASK;
if (!ns) {
ctrl = TAVOR_WQE_RCV_EVENT_MASK;
}
TAVOR_WQE_LINKNEXT(curr_addr, ctrl, next);
if (prev_addr != NULL) {
next = ((uint64_t)curr_desc & TAVOR_WQE_NDA_MASK) << 32;
next = next | (curr_descsz & TAVOR_WQE_NDS_MASK) |
TAVOR_WQE_DBD_MASK | TAVOR_RCV_WQE_NDA0_WA_MASK;
TAVOR_WQE_LINKFIRST(prev_addr, next);
}
}
static DAT_RETURN
dapli_tavor_wqe_srq_build(ib_srq_handle_t srq, ibt_recv_wr_t *wr,
uint64_t *addr)
{
tavor_hw_wqe_sgl_t *ds;
ibt_wr_ds_t end_sgl;
int i;
int num_ds;
ds = (tavor_hw_wqe_sgl_t *)((uintptr_t)addr +
sizeof (tavor_hw_rcv_wqe_nextctrl_t));
num_ds = 0;
if (wr->wr_nds > srq->srq_wq_sgl) {
return (DAT_INVALID_PARAMETER);
}
for (i = 0; i < wr->wr_nds; i++) {
if (wr->wr_sgl[i].ds_len == 0) {
continue;
}
TAVOR_WQE_BUILD_DATA_SEG(&ds[num_ds], &wr->wr_sgl[i]);
num_ds++;
}
if (num_ds < srq->srq_wq_sgl) {
end_sgl.ds_va = (ib_vaddr_t)0;
end_sgl.ds_len = (ib_msglen_t)0;
end_sgl.ds_key = (ibt_lkey_t)1;
TAVOR_WQE_BUILD_DATA_SEG(&ds[num_ds], &end_sgl);
}
return (DAT_SUCCESS);
}
static void
dapli_tavor_wqe_srq_linknext(uint64_t *curr_addr, boolean_t ns,
uint32_t curr_desc, uint64_t *prev_addr)
{
uint64_t next;
uint64_t ctrl = 0;
next = TAVOR_RCV_WQE_NDA0_WA_MASK;
if (!ns) {
ctrl = TAVOR_WQE_RCV_EVENT_MASK;
}
TAVOR_WQE_LINKNEXT(curr_addr, ctrl, next);
if (prev_addr != NULL) {
next = ((uint64_t)curr_desc & TAVOR_WQE_NDA_MASK) << 32;
next = next | TAVOR_WQE_DBD_MASK | TAVOR_RCV_WQE_NDA0_WA_MASK;
TAVOR_WQE_LINKFIRST(prev_addr, next);
}
}
static void
dapli_tavor_cq_peek(ib_cq_handle_t cq, int *num_cqe)
{
tavor_hw_cqe_t *cqe;
uint32_t imm_eth_pkey_cred;
uint32_t cons_indx;
uint32_t wrap_around_mask;
uint32_t polled_cnt;
uint_t doorbell_cnt;
uint_t opcode;
cons_indx = cq->cq_consindx;
wrap_around_mask = (cq->cq_size - 1);
cqe = &cq->cq_addr[cons_indx];
polled_cnt = 0;
while (TAVOR_CQE_OWNER_IS_SW(cqe)) {
opcode = TAVOR_CQE_OPCODE_GET(cqe);
if ((opcode == TAVOR_CQE_SEND_ERR_OPCODE) ||
(opcode == TAVOR_CQE_RECV_ERR_OPCODE)) {
imm_eth_pkey_cred =
TAVOR_CQE_IMM_ETH_PKEY_CRED_GET(cqe);
doorbell_cnt =
imm_eth_pkey_cred & TAVOR_CQE_ERR_DBDCNT_MASK;
polled_cnt += (doorbell_cnt + 1);
} else {
polled_cnt++;
}
cons_indx = (cons_indx + 1) & wrap_around_mask;
cqe = &cq->cq_addr[cons_indx];
}
*num_cqe = polled_cnt;
}
static DAT_RETURN
dapli_tavor_cq_poll(ib_cq_handle_t cq, ibt_wc_t *wc_p, uint_t num_wc,
uint_t *num_polled)
{
tavor_hw_cqe_t *cqe;
uint32_t cons_indx;
uint32_t wrap_around_mask;
uint32_t polled_cnt;
uint32_t num_to_increment;
DAT_RETURN dat_status;
int status;
cons_indx = cq->cq_consindx;
wrap_around_mask = (cq->cq_size - 1);
cqe = &cq->cq_addr[cons_indx];
polled_cnt = 0;
while (TAVOR_CQE_OWNER_IS_SW(cqe)) {
status = dapli_tavor_cq_cqe_consume(cq, cqe,
&wc_p[polled_cnt++]);
if (status == TAVOR_CQ_SYNC_AND_DB) {
TAVOR_CQE_OWNER_SET_HW(cqe);
cons_indx = (cons_indx + 1) & wrap_around_mask;
cqe = &cq->cq_addr[cons_indx];
}
if (polled_cnt >= num_wc) {
break;
}
}
dat_status = DAT_SUCCESS;
if ((polled_cnt != 0) && (cq->cq_consindx != cons_indx)) {
if (cons_indx > cq->cq_consindx) {
num_to_increment = (cons_indx - cq->cq_consindx) - 1;
} else {
num_to_increment = ((cons_indx + cq->cq_size) -
cq->cq_consindx) - 1;
}
cq->cq_consindx = cons_indx;
dapli_tavor_cq_doorbell(cq->cq_iauar, TAVOR_CQDB_INCR_CONSINDX,
cq->cq_num, num_to_increment);
} else if (polled_cnt == 0) {
if (cq->cq_wrid_reap_head)
dapls_tavor_wrid_cq_reap(cq);
dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0);
}
if (num_polled != NULL) {
*num_polled = polled_cnt;
}
return (dat_status);
}
static DAT_RETURN
dapli_tavor_cq_poll_one(ib_cq_handle_t cq, ibt_wc_t *wc_p)
{
tavor_hw_cqe_t *cqe;
uint32_t cons_indx;
DAT_RETURN dat_status;
int status;
cons_indx = cq->cq_consindx;
cqe = &cq->cq_addr[cons_indx];
if (TAVOR_CQE_OWNER_IS_SW(cqe)) {
status = dapli_tavor_cq_cqe_consume(cq, cqe, wc_p);
if (status == TAVOR_CQ_SYNC_AND_DB) {
TAVOR_CQE_OWNER_SET_HW(cqe);
cq->cq_consindx =
(cons_indx + 1) & (cq->cq_size - 1);
dapli_tavor_cq_doorbell(cq->cq_iauar,
TAVOR_CQDB_INCR_CONSINDX,
cq->cq_num, 0);
}
dat_status = DAT_SUCCESS;
} else {
if (cq->cq_wrid_reap_head)
dapls_tavor_wrid_cq_reap(cq);
dat_status = DAT_ERROR(DAT_QUEUE_EMPTY, 0);
}
return (dat_status);
}
static int
dapli_tavor_cq_cqe_consume(ib_cq_handle_t cqhdl, tavor_hw_cqe_t *cqe,
ibt_wc_t *wc)
{
uint_t flags;
uint_t type;
uint_t opcode;
int status;
opcode = TAVOR_CQE_OPCODE_GET(cqe);
if ((opcode == TAVOR_CQE_SEND_ERR_OPCODE) ||
(opcode == TAVOR_CQE_RECV_ERR_OPCODE)) {
status = dapli_tavor_cq_errcqe_consume(cqhdl, cqe, wc);
return (status);
}
wc->wc_id = dapls_tavor_wrid_get_entry(cqhdl, cqe,
TAVOR_CQE_SENDRECV_GET(cqe), 0, NULL);
wc->wc_qpn = TAVOR_CQE_QPNUM_GET(cqe);
flags = IBT_WC_NO_FLAGS;
if (TAVOR_CQE_SENDRECV_GET(cqe) != TAVOR_COMPLETION_RECV) {
switch (opcode) {
case TAVOR_CQE_SND_RDMAWR:
type = IBT_WRC_RDMAW;
break;
case TAVOR_CQE_SND_SEND:
type = IBT_WRC_SEND;
break;
case TAVOR_CQE_SND_RDMARD:
type = IBT_WRC_RDMAR;
wc->wc_bytes_xfer = TAVOR_CQE_BYTECNT_GET(cqe);
break;
case TAVOR_CQE_SND_BIND_MW:
type = IBT_WRC_BIND;
break;
default:
wc->wc_status = IBT_WC_LOCAL_CHAN_OP_ERR;
return (TAVOR_CQ_SYNC_AND_DB);
}
} else {
switch (opcode & 0x1F) {
case TAVOR_CQE_RCV_RECV:
case TAVOR_CQE_RCV_RECV2:
type = IBT_WRC_RECV;
wc->wc_bytes_xfer = TAVOR_CQE_BYTECNT_GET(cqe);
break;
default:
wc->wc_status = IBT_WC_LOCAL_CHAN_OP_ERR;
return (TAVOR_CQ_SYNC_AND_DB);
}
}
wc->wc_type = type;
wc->wc_flags = flags;
wc->wc_status = IBT_WC_SUCCESS;
return (TAVOR_CQ_SYNC_AND_DB);
}
static int
dapli_tavor_cq_errcqe_consume(ib_cq_handle_t cqhdl, tavor_hw_cqe_t *cqe,
ibt_wc_t *wc)
{
dapls_tavor_wrid_entry_t wre;
uint32_t next_wqeaddr;
uint32_t imm_eth_pkey_cred;
uint_t nextwqesize, dbd;
uint_t doorbell_cnt, status;
uint_t opcode = TAVOR_CQE_OPCODE_GET(cqe);
dapl_dbg_log(DAPL_DBG_TYPE_EVD, "errcqe_consume:cqe.eth=%x, wqe=%x\n",
TAVOR_CQE_IMM_ETH_PKEY_CRED_GET(cqe),
TAVOR_CQE_WQEADDRSZ_GET(cqe));
wc->wc_id = dapls_tavor_wrid_get_entry(cqhdl, cqe,
(opcode == TAVOR_CQE_SEND_ERR_OPCODE) ? TAVOR_COMPLETION_SEND :
TAVOR_COMPLETION_RECV, 1, &wre);
wc->wc_qpn = TAVOR_CQE_QPNUM_GET(cqe);
imm_eth_pkey_cred = TAVOR_CQE_IMM_ETH_PKEY_CRED_GET(cqe);
status = imm_eth_pkey_cred >> TAVOR_CQE_ERR_STATUS_SHIFT;
switch (status) {
case TAVOR_CQE_LOC_LEN_ERR:
status = IBT_WC_LOCAL_LEN_ERR;
break;
case TAVOR_CQE_LOC_OP_ERR:
status = IBT_WC_LOCAL_CHAN_OP_ERR;
break;
case TAVOR_CQE_LOC_PROT_ERR:
status = IBT_WC_LOCAL_PROTECT_ERR;
break;
case TAVOR_CQE_WR_FLUSHED_ERR:
status = IBT_WC_WR_FLUSHED_ERR;
break;
case TAVOR_CQE_MW_BIND_ERR:
status = IBT_WC_MEM_WIN_BIND_ERR;
break;
case TAVOR_CQE_BAD_RESPONSE_ERR:
status = IBT_WC_BAD_RESPONSE_ERR;
break;
case TAVOR_CQE_LOCAL_ACCESS_ERR:
status = IBT_WC_LOCAL_ACCESS_ERR;
break;
case TAVOR_CQE_REM_INV_REQ_ERR:
status = IBT_WC_REMOTE_INVALID_REQ_ERR;
break;
case TAVOR_CQE_REM_ACC_ERR:
status = IBT_WC_REMOTE_ACCESS_ERR;
break;
case TAVOR_CQE_REM_OP_ERR:
status = IBT_WC_REMOTE_OP_ERR;
break;
case TAVOR_CQE_TRANS_TO_ERR:
status = IBT_WC_TRANS_TIMEOUT_ERR;
break;
case TAVOR_CQE_RNRNAK_TO_ERR:
status = IBT_WC_RNR_NAK_TIMEOUT_ERR;
break;
default:
status = IBT_WC_LOCAL_CHAN_OP_ERR;
break;
}
wc->wc_status = status;
wc->wc_type = 0;
dbd = (wre.wr_signaled_dbd & TAVOR_WRID_ENTRY_DOORBELLED) ? 1 : 0;
next_wqeaddr = wre.wr_wqeaddrsz;
nextwqesize = wre.wr_wqeaddrsz & TAVOR_WQE_NDS_MASK;
doorbell_cnt = imm_eth_pkey_cred & TAVOR_CQE_ERR_DBDCNT_MASK;
if ((nextwqesize == 0) || ((doorbell_cnt == 0) && (dbd == 1))) {
return (TAVOR_CQ_SYNC_AND_DB);
} else {
doorbell_cnt = doorbell_cnt - dbd;
TAVOR_CQE_IMM_ETH_PKEY_CRED_SET(cqe,
((TAVOR_CQE_WR_FLUSHED_ERR << TAVOR_CQE_ERR_STATUS_SHIFT) |
(doorbell_cnt & TAVOR_CQE_ERR_DBDCNT_MASK)));
TAVOR_CQE_WQEADDRSZ_SET(cqe,
TAVOR_QP_WQEADDRSZ(next_wqeaddr, nextwqesize));
dapl_dbg_log(DAPL_DBG_TYPE_EVD,
"errcqe_consume: recycling cqe.eth=%x, wqe=%x\n",
TAVOR_CQE_IMM_ETH_PKEY_CRED_GET(cqe),
TAVOR_CQE_WQEADDRSZ_GET(cqe));
return (TAVOR_CQ_RECYCLE_ENTRY);
}
}
static DAT_RETURN
dapli_tavor_cq_notify(ib_cq_handle_t cq, int flags, uint32_t param)
{
uint32_t cqnum;
cqnum = cq->cq_num;
if (flags == IB_NOTIFY_ON_NEXT_COMP) {
dapli_tavor_cq_doorbell(cq->cq_iauar, TAVOR_CQDB_NOTIFY_CQ,
cqnum, TAVOR_CQDB_DEFAULT_PARAM);
} else if (flags == IB_NOTIFY_ON_NEXT_SOLICITED) {
dapli_tavor_cq_doorbell(cq->cq_iauar,
TAVOR_CQDB_NOTIFY_CQ_SOLICIT, cqnum,
TAVOR_CQDB_DEFAULT_PARAM);
} else if (flags == IB_NOTIFY_ON_NEXT_NCOMP) {
dapli_tavor_cq_doorbell(cq->cq_iauar, TAVOR_CQDB_NOTIFY_NCQ,
cqnum, param);
} else {
return (DAT_INVALID_PARAMETER);
}
return (DAT_SUCCESS);
}
static DAT_RETURN
dapli_tavor_post_send(DAPL_EP *ep, ibt_send_wr_t *wr, boolean_t ns)
{
tavor_sw_wqe_dbinfo_t dbinfo;
dapls_tavor_wrid_list_hdr_t *wridlist;
dapls_tavor_wrid_entry_t *wre_last;
uint32_t desc;
uint64_t *wqe_addr;
uint32_t desc_sz;
uint32_t wqeaddrsz, signaled_dbd;
uint32_t head, tail, next_tail, qsize_msk;
int status;
ib_qp_handle_t qp;
if ((ep->qp_state == IBT_STATE_RESET) ||
(ep->qp_state == IBT_STATE_INIT) ||
(ep->qp_state == IBT_STATE_RTR)) {
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"post_send: invalid qp_state %d\n", ep->qp_state);
return (DAT_INVALID_STATE);
}
qp = ep->qp_handle;
dapl_os_lock(&qp->qp_sq_wqhdr->wq_wrid_lock->wrl_lock);
wridlist = qp->qp_sq_wqhdr->wq_wrid_post;
qsize_msk = qp->qp_sq_wqhdr->wq_size - 1;
tail = qp->qp_sq_wqhdr->wq_tail;
head = qp->qp_sq_wqhdr->wq_head;
if (qp->qp_sq_wqhdr->wq_full != 0) {
dapl_os_unlock(&qp->qp_sq_wqhdr->wq_wrid_lock->wrl_lock);
return (DAT_INSUFFICIENT_RESOURCES);
}
next_tail = (tail + 1) & qsize_msk;
if (next_tail == head) {
qp->qp_sq_wqhdr->wq_full = 1;
}
wqe_addr = TAVOR_QP_SQ_ENTRY(qp, tail);
status = dapli_tavor_wqe_send_build(qp, wr, wqe_addr, &desc_sz);
if (status != DAT_SUCCESS) {
dapl_os_unlock(&qp->qp_sq_wqhdr->wq_wrid_lock->wrl_lock);
return (status);
}
desc = TAVOR_QP_SQ_DESC(qp, tail);
dapl_os_assert(desc >= qp->qp_sq_desc_addr &&
desc <= (qp->qp_sq_desc_addr +
qp->qp_sq_numwqe*qp->qp_sq_wqesz));
wqeaddrsz = TAVOR_QP_WQEADDRSZ(desc, desc_sz);
if (wr->wr_flags & IBT_WR_SEND_SIGNAL) {
signaled_dbd = TAVOR_WRID_ENTRY_SIGNALED;
}
dapli_tavor_wrid_add_entry(qp->qp_sq_wqhdr, wr->wr_id, wqeaddrsz,
signaled_dbd);
dapli_tavor_wqe_send_linknext(wr, wqe_addr, ns, desc, desc_sz,
qp->qp_sq_lastwqeaddr, &dbinfo);
wre_last = wridlist->wl_wre_old_tail;
if (wre_last != NULL) {
wre_last->wr_signaled_dbd |= TAVOR_WRID_ENTRY_DOORBELLED;
}
qp->qp_sq_lastwqeaddr = wqe_addr;
qp->qp_sq_wqhdr->wq_tail = next_tail;
dapli_tavor_qp_send_doorbell(qp->qp_iauar, desc, desc_sz,
qp->qp_num, dbinfo.db_fence, dbinfo.db_nopcode);
dapl_os_unlock(&qp->qp_sq_wqhdr->wq_wrid_lock->wrl_lock);
return (DAT_SUCCESS);
}
static DAT_RETURN
dapli_tavor_post_recv(DAPL_EP *ep, ibt_recv_wr_t *wr, boolean_t ns)
{
dapls_tavor_wrid_list_hdr_t *wridlist;
dapls_tavor_wrid_entry_t *wre_last;
ib_qp_handle_t qp;
DAT_RETURN status;
uint32_t desc;
uint64_t *wqe_addr;
uint32_t desc_sz;
uint32_t wqeaddrsz;
uint32_t head, tail, next_tail, qsize_msk;
if (ep->qp_state == IBT_STATE_RESET) {
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
"post_recv: invalid qp_state %d\n", ep->qp_state);
return (DAT_INVALID_STATE);
}
qp = ep->qp_handle;
dapl_os_lock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock);
wridlist = qp->qp_rq_wqhdr->wq_wrid_post;
qsize_msk = qp->qp_rq_wqhdr->wq_size - 1;
tail = qp->qp_rq_wqhdr->wq_tail;
head = qp->qp_rq_wqhdr->wq_head;
if (qp->qp_rq_wqhdr->wq_full != 0) {
dapl_os_unlock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock);
return (DAT_INSUFFICIENT_RESOURCES);
}
next_tail = (tail + 1) & qsize_msk;
if (next_tail == head) {
qp->qp_rq_wqhdr->wq_full = 1;
}
desc = TAVOR_QP_RQ_DESC(qp, tail);
wqe_addr = TAVOR_QP_RQ_ENTRY(qp, tail);
status = dapli_tavor_wqe_recv_build(qp, wr, wqe_addr, &desc_sz);
if (status != DAT_SUCCESS) {
dapl_os_unlock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock);
return (DAT_INTERNAL_ERROR);
}
wqeaddrsz = TAVOR_QP_WQEADDRSZ(desc, desc_sz);
dapli_tavor_wrid_add_entry(qp->qp_rq_wqhdr, wr->wr_id, wqeaddrsz,
(uint32_t)TAVOR_WRID_ENTRY_SIGNALED);
dapli_tavor_wqe_recv_linknext(wqe_addr, ns, desc, desc_sz,
qp->qp_rq_lastwqeaddr);
wre_last = wridlist->wl_wre_old_tail;
if (wre_last != NULL) {
wre_last->wr_signaled_dbd |= TAVOR_WRID_ENTRY_DOORBELLED;
}
qp->qp_rq_lastwqeaddr = wqe_addr;
qp->qp_rq_wqhdr->wq_tail = next_tail;
dapli_tavor_qp_recv_doorbell(qp->qp_iauar, desc, desc_sz,
qp->qp_num, 1);
dapl_os_unlock(&qp->qp_rq_wqhdr->wq_wrid_lock->wrl_lock);
return (DAT_SUCCESS);
}
static DAT_RETURN
dapli_tavor_post_srq(DAPL_SRQ *srqp, ibt_recv_wr_t *wr, boolean_t ns)
{
ib_srq_handle_t srq;
DAT_RETURN status;
uint32_t desc;
uint64_t *wqe_addr;
uint64_t *last_wqe_addr;
uint32_t head, next_head, qsize_msk;
uint32_t wqe_index;
srq = srqp->srq_handle;
dapl_os_lock(&srq->srq_wridlist->wl_lock->wrl_lock);
if (srq->srq_wridlist->wl_freel_entries == 0) {
dapl_os_unlock(&srq->srq_wridlist->wl_lock->wrl_lock);
return (DAT_INSUFFICIENT_RESOURCES);
}
qsize_msk = srq->srq_wridlist->wl_size - 1;
head = srq->srq_wridlist->wl_freel_head;
next_head = (head + 1) & qsize_msk;
desc = srq->srq_wridlist->wl_free_list[head];
wqe_index = TAVOR_SRQ_WQ_INDEX(srq->srq_wq_desc_addr, desc,
srq->srq_wq_wqesz);
wqe_addr = TAVOR_SRQ_WQ_ENTRY(srq, wqe_index);
status = dapli_tavor_wqe_srq_build(srq, wr, wqe_addr);
if (status != DAT_SUCCESS) {
dapl_os_unlock(&srq->srq_wridlist->wl_lock->wrl_lock);
return (status);
}
dapli_tavor_wrid_add_entry_srq(srq, wr->wr_id, wqe_index);
if (srq->srq_wq_lastwqeindex == -1) {
last_wqe_addr = NULL;
} else {
last_wqe_addr = TAVOR_SRQ_WQ_ENTRY(srq,
srq->srq_wq_lastwqeindex);
}
dapli_tavor_wqe_srq_linknext(wqe_addr, ns, desc, last_wqe_addr);
srq->srq_wq_lastwqeindex = wqe_index;
srq->srq_wridlist->wl_freel_head = next_head;
srq->srq_wridlist->wl_freel_entries--;
dapl_os_assert(srq->srq_wridlist->wl_freel_entries <=
srq->srq_wridlist->wl_size);
dapli_tavor_qp_recv_doorbell(srq->srq_iauar, desc, 0,
srq->srq_num, 1);
dapl_os_unlock(&srq->srq_wridlist->wl_lock->wrl_lock);
return (DAT_SUCCESS);
}
extern void
dapli_tavor_wrid_add_entry(dapls_tavor_workq_hdr_t *wq, uint64_t wrid,
uint32_t wqeaddrsz, uint_t signaled_dbd)
{
dapls_tavor_wrid_entry_t *wre_tmp;
uint32_t head, tail, size;
head = wq->wq_wrid_post->wl_head;
tail = wq->wq_wrid_post->wl_tail;
size = wq->wq_wrid_post->wl_size;
wre_tmp = &wq->wq_wrid_post->wl_wre[tail];
wre_tmp->wr_wrid = wrid;
wre_tmp->wr_wqeaddrsz = wqeaddrsz;
wre_tmp->wr_signaled_dbd = signaled_dbd;
wq->wq_wrid_post->wl_wre_old_tail = wre_tmp;
tail = ((tail + 1) & (size - 1));
wq->wq_wrid_post->wl_tail = tail;
if (head == tail) {
wq->wq_wrid_post->wl_full = 1;
}
}
extern void
dapli_tavor_wrid_add_entry_srq(ib_srq_handle_t srq, uint64_t wrid,
uint32_t wqe_index)
{
dapls_tavor_wrid_entry_t *wre;
dapl_os_assert(wqe_index < srq->srq_wq_numwqe);
wre = &srq->srq_wridlist->wl_wre[wqe_index];
wre->wr_wrid = wrid;
wre->wr_signaled_dbd = (uint32_t)TAVOR_WRID_ENTRY_SIGNALED;
}
static void
dapli_tavor_cq_srq_entries_flush(ib_qp_handle_t qp)
{
ib_cq_handle_t cq;
dapls_tavor_workq_hdr_t *wqhdr;
tavor_hw_cqe_t *cqe;
tavor_hw_cqe_t *next_cqe;
uint32_t cons_indx, tail_cons_indx, wrap_around_mask;
uint32_t new_indx, check_indx, indx;
uint32_t num_to_increment;
int cqe_qpnum, cqe_type;
int outstanding_cqes, removed_cqes;
int i;
cq = qp->qp_rq_cqhdl;
wqhdr = qp->qp_rq_wqhdr;
dapl_os_assert(wqhdr->wq_wrid_post != NULL);
dapl_os_assert(wqhdr->wq_wrid_post->wl_srq_en != 0);
cons_indx = cq->cq_consindx;
wrap_around_mask = (cq->cq_size - 1);
cqe = &cq->cq_addr[cons_indx];
outstanding_cqes = 0;
tail_cons_indx = cons_indx;
while (TAVOR_CQE_OWNER_IS_SW(cqe)) {
outstanding_cqes++;
tail_cons_indx = (tail_cons_indx + 1) & wrap_around_mask;
cqe = &cq->cq_addr[tail_cons_indx];
}
check_indx = new_indx = (tail_cons_indx - 1) & wrap_around_mask;
for (i = 0; i < outstanding_cqes; i++) {
cqe = &cq->cq_addr[check_indx];
cqe_qpnum = TAVOR_CQE_QPNUM_GET(cqe);
cqe_type = TAVOR_CQE_SENDRECV_GET(cqe);
if (cqe_qpnum == qp->qp_num &&
cqe_type == TAVOR_COMPLETION_RECV) {
(void) dapli_tavor_wrid_find_match_srq(
wqhdr->wq_wrid_post, cqe);
} else {
if (check_indx != new_indx) {
next_cqe = &cq->cq_addr[new_indx];
(void) dapl_os_memcpy(next_cqe, cqe,
sizeof (tavor_hw_cqe_t));
}
new_indx = (new_indx - 1) & wrap_around_mask;
}
check_indx = (check_indx - 1) & wrap_around_mask;
}
removed_cqes = 0;
if (check_indx != new_indx) {
for (indx = cons_indx; indx <= new_indx;
indx = (indx + 1) & wrap_around_mask) {
removed_cqes++;
cqe = &cq->cq_addr[indx];
TAVOR_CQE_OWNER_SET_HW(cqe);
}
}
cons_indx = (new_indx + 1) & wrap_around_mask;
if ((removed_cqes != 0) && (cq->cq_consindx != cons_indx)) {
if (cons_indx > cq->cq_consindx) {
num_to_increment = (cons_indx - cq->cq_consindx) - 1;
} else {
num_to_increment = ((cons_indx + cq->cq_size) -
cq->cq_consindx) - 1;
}
cq->cq_consindx = cons_indx;
dapli_tavor_cq_doorbell(cq->cq_iauar, TAVOR_CQDB_INCR_CONSINDX,
cq->cq_num, num_to_increment);
}
}
static void
dapli_tavor_qp_init(ib_qp_handle_t qp)
{
}
static void
dapli_tavor_cq_init(ib_cq_handle_t cq)
{
}
static void
dapli_tavor_srq_init(ib_srq_handle_t srq)
{
}
void
dapls_init_funcs_tavor(DAPL_HCA *hca_ptr)
{
hca_ptr->post_send = dapli_tavor_post_send;
hca_ptr->post_recv = dapli_tavor_post_recv;
hca_ptr->post_srq = dapli_tavor_post_srq;
hca_ptr->cq_peek = dapli_tavor_cq_peek;
hca_ptr->cq_poll = dapli_tavor_cq_poll;
hca_ptr->cq_poll_one = dapli_tavor_cq_poll_one;
hca_ptr->cq_notify = dapli_tavor_cq_notify;
hca_ptr->srq_flush = dapli_tavor_cq_srq_entries_flush;
hca_ptr->qp_init = dapli_tavor_qp_init;
hca_ptr->cq_init = dapli_tavor_cq_init;
hca_ptr->srq_init = dapli_tavor_srq_init;
hca_ptr->hermon_resize_cq = 0;
}