in hw/irdma/verbs.c [1451:1679]
int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
struct ib_udata *udata)
{
struct irdma_qp *iwqp = to_iwqp(ibqp);
struct irdma_device *iwdev = iwqp->iwdev;
struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
struct irdma_qp_host_ctx_info *ctx_info;
struct irdma_tcp_offload_info *tcp_info;
struct irdma_iwarp_offload_info *offload_info;
struct irdma_modify_qp_info info = {};
struct irdma_modify_qp_resp uresp = {};
struct irdma_modify_qp_req ureq = {};
u8 issue_modify_qp = 0;
u8 dont_wait = 0;
int err;
unsigned long flags;
if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
return -EOPNOTSUPP;
ctx_info = &iwqp->ctx_info;
offload_info = &iwqp->iwarp_info;
tcp_info = &iwqp->tcp_info;
wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
ibdev_dbg(&iwdev->ibdev,
"VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d last_aeq=%d hw_tcp_state=%d hw_iwarp_state=%d attr_mask=0x%x\n",
__builtin_return_address(0), ibqp->qp_num, attr->qp_state,
iwqp->ibqp_state, iwqp->iwarp_state, iwqp->last_aeq,
iwqp->hw_tcp_state, iwqp->hw_iwarp_state, attr_mask);
spin_lock_irqsave(&iwqp->lock, flags);
if (attr_mask & IB_QP_STATE) {
info.curr_iwarp_state = iwqp->iwarp_state;
switch (attr->qp_state) {
case IB_QPS_INIT:
case IB_QPS_RTR:
if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
err = -EINVAL;
goto exit;
}
if (iwqp->iwarp_state == IRDMA_QP_STATE_INVALID) {
info.next_iwarp_state = IRDMA_QP_STATE_IDLE;
issue_modify_qp = 1;
}
if (iwdev->push_mode && udata &&
iwqp->sc_qp.push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX &&
dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
spin_unlock_irqrestore(&iwqp->lock, flags);
irdma_alloc_push_page(iwqp);
spin_lock_irqsave(&iwqp->lock, flags);
}
break;
case IB_QPS_RTS:
if (iwqp->iwarp_state > IRDMA_QP_STATE_RTS ||
!iwqp->cm_id) {
err = -EINVAL;
goto exit;
}
issue_modify_qp = 1;
iwqp->hw_tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
iwqp->hte_added = 1;
info.next_iwarp_state = IRDMA_QP_STATE_RTS;
info.tcp_ctx_valid = true;
info.ord_valid = true;
info.arp_cache_idx_valid = true;
info.cq_num_valid = true;
break;
case IB_QPS_SQD:
if (iwqp->hw_iwarp_state > IRDMA_QP_STATE_RTS) {
err = 0;
goto exit;
}
if (iwqp->iwarp_state == IRDMA_QP_STATE_CLOSING ||
iwqp->iwarp_state < IRDMA_QP_STATE_RTS) {
err = 0;
goto exit;
}
if (iwqp->iwarp_state > IRDMA_QP_STATE_CLOSING) {
err = -EINVAL;
goto exit;
}
info.next_iwarp_state = IRDMA_QP_STATE_CLOSING;
issue_modify_qp = 1;
break;
case IB_QPS_SQE:
if (iwqp->iwarp_state >= IRDMA_QP_STATE_TERMINATE) {
err = -EINVAL;
goto exit;
}
info.next_iwarp_state = IRDMA_QP_STATE_TERMINATE;
issue_modify_qp = 1;
break;
case IB_QPS_ERR:
case IB_QPS_RESET:
if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata) {
if (ib_copy_from_udata(&ureq, udata,
min(sizeof(ureq), udata->inlen)))
return -EINVAL;
irdma_flush_wqes(iwqp,
(ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
(ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
IRDMA_REFLUSH);
}
return 0;
}
if (iwqp->sc_qp.term_flags) {
spin_unlock_irqrestore(&iwqp->lock, flags);
irdma_terminate_del_timer(&iwqp->sc_qp);
spin_lock_irqsave(&iwqp->lock, flags);
}
info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
if (iwqp->hw_tcp_state > IRDMA_TCP_STATE_CLOSED &&
iwdev->iw_status &&
iwqp->hw_tcp_state != IRDMA_TCP_STATE_TIME_WAIT)
info.reset_tcp_conn = true;
else
dont_wait = 1;
issue_modify_qp = 1;
info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
break;
default:
err = -EINVAL;
goto exit;
}
iwqp->ibqp_state = attr->qp_state;
}
if (attr_mask & IB_QP_ACCESS_FLAGS) {
ctx_info->iwarp_info_valid = true;
if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
offload_info->wr_rdresp_en = true;
if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
offload_info->wr_rdresp_en = true;
if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
offload_info->rd_en = true;
}
if (ctx_info->iwarp_info_valid) {
ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
}
spin_unlock_irqrestore(&iwqp->lock, flags);
if (attr_mask & IB_QP_STATE) {
if (issue_modify_qp) {
ctx_info->rem_endpoint_idx = tcp_info->arp_idx;
if (irdma_hw_modify_qp(iwdev, iwqp, &info, true))
return -EINVAL;
}
spin_lock_irqsave(&iwqp->lock, flags);
if (iwqp->iwarp_state == info.curr_iwarp_state) {
iwqp->iwarp_state = info.next_iwarp_state;
iwqp->ibqp_state = attr->qp_state;
}
spin_unlock_irqrestore(&iwqp->lock, flags);
}
if (issue_modify_qp && iwqp->ibqp_state > IB_QPS_RTS) {
if (dont_wait) {
if (iwqp->cm_id && iwqp->hw_tcp_state) {
spin_lock_irqsave(&iwqp->lock, flags);
iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSED;
iwqp->last_aeq = IRDMA_AE_RESET_SENT;
spin_unlock_irqrestore(&iwqp->lock, flags);
irdma_cm_disconn(iwqp);
}
} else {
int close_timer_started;
spin_lock_irqsave(&iwdev->cm_core.ht_lock, flags);
if (iwqp->cm_node) {
refcount_inc(&iwqp->cm_node->refcnt);
spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
close_timer_started = atomic_inc_return(&iwqp->close_timer_started);
if (iwqp->cm_id && close_timer_started == 1)
irdma_schedule_cm_timer(iwqp->cm_node,
(struct irdma_puda_buf *)iwqp,
IRDMA_TIMER_TYPE_CLOSE, 1, 0);
irdma_rem_ref_cm_node(iwqp->cm_node);
} else {
spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
}
}
}
if (attr_mask & IB_QP_STATE && udata &&
dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
struct irdma_ucontext *ucontext;
ucontext = rdma_udata_to_drv_context(udata,
struct irdma_ucontext, ibucontext);
if (iwqp->sc_qp.push_idx != IRDMA_INVALID_PUSH_PAGE_INDEX &&
!iwqp->push_wqe_mmap_entry &&
!irdma_setup_push_mmap_entries(ucontext, iwqp,
&uresp.push_wqe_mmap_key, &uresp.push_db_mmap_key)) {
uresp.push_valid = 1;
uresp.push_offset = iwqp->sc_qp.push_offset;
}
err = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp),
udata->outlen));
if (err) {
irdma_remove_push_mmap_entries(iwqp);
ibdev_dbg(&iwdev->ibdev,
"VERBS: copy_to_udata failed\n");
return err;
}
}
return 0;
exit:
spin_unlock_irqrestore(&iwqp->lock, flags);
return err;
}