/* * siw_create_qp() * * Create QP of requested size on given device. * * @qp: Queue pait * @attrs: Initial QP attributes. * @udata: used to provide QP ID, SQ and RQ size back to user.
*/
rv = siw_qp_add(sdev, qp); if (rv) goto err_atomic;
/* All queue indices are derived from modulo operations * on a free running 'get' (consumer) and 'put' (producer) * unsigned counter. Having queue sizes at power of two * avoids handling counter wrap around.
*/
num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
num_rqe = attrs->cap.max_recv_wr; if (num_rqe)
num_rqe = roundup_pow_of_two(num_rqe);
/* * Minimum siw_query_qp() verb interface. * * @qp_attr_mask is not used but all available information is provided
*/ int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
{ struct siw_qp *qp; struct net_device *ndev;
/* * Mark QP as in process of destruction to prevent from * any async callbacks to RDMA core
*/
qp->attrs.flags |= SIW_QP_IN_DESTROY;
qp->rx_stream.rx_suspend = 1;
if (uctx) {
rdma_user_mmap_entry_remove(qp->sq_entry);
rdma_user_mmap_entry_remove(qp->rq_entry);
}
/* * siw_copy_inline_sgl() * * Prepare sgl of inlined data for sending. For userland callers * function checks if given buffer addresses and len's are within * process context bounds. * Data from all provided sge's are copied together into the wqe, * referenced by a single sge.
*/ staticint siw_copy_inline_sgl(conststruct ib_send_wr *core_wr, struct siw_sqe *sqe)
{ struct ib_sge *core_sge = core_wr->sg_list; void *kbuf = &sqe->sge[1]; int num_sge = core_wr->num_sge, bytes = 0;
while (wr) {
rqe.id = wr->wr_id;
rv = siw_rqe_complete(qp, &rqe, 0, 0, SIW_WC_WR_FLUSH_ERR); if (rv) { if (bad_wr)
*bad_wr = wr; break;
}
wr = wr->next;
} return rv;
}
/* * siw_post_send() * * Post a list of S-WR's to a SQ. * * @base_qp: Base QP contained in siw QP * @wr: Null terminated list of user WR's * @bad_wr: Points to failing WR in case of synchronous failure.
*/ int siw_post_send(struct ib_qp *base_qp, conststruct ib_send_wr *wr, conststruct ib_send_wr **bad_wr)
{ struct siw_qp *qp = to_siw_qp(base_qp); struct siw_wqe *wqe = tx_wqe(qp);
unsignedlong flags; int rv = 0, imm_err = 0;
if (wr && !rdma_is_kernel_res(&qp->base_qp.res)) {
siw_dbg_qp(qp, "wr must be empty for user mapped sq\n");
*bad_wr = wr; return -EINVAL;
}
/* * Try to acquire QP state lock. Must be non-blocking * to accommodate kernel clients needs.
*/ if (!down_read_trylock(&qp->state_lock)) { if (qp->attrs.state == SIW_QP_STATE_ERROR) { /* * ERROR state is final, so we can be sure * this state will not change as long as the QP * exists. * * This handles an ib_drain_sq() call with * a concurrent request to set the QP state * to ERROR.
*/
rv = siw_sq_flush_wr(qp, wr, bad_wr);
} else {
siw_dbg_qp(qp, "QP locked, state %d\n",
qp->attrs.state);
*bad_wr = wr;
rv = -ENOTCONN;
} return rv;
} if (unlikely(qp->attrs.state != SIW_QP_STATE_RTS)) { if (qp->attrs.state == SIW_QP_STATE_ERROR) { /* * Immediately flush this WR to CQ, if QP * is in ERROR state. SQ is guaranteed to * be empty, so WR complets in-order. * * Typically triggered by ib_drain_sq().
*/
rv = siw_sq_flush_wr(qp, wr, bad_wr);
} else {
siw_dbg_qp(qp, "QP out of state %d\n",
qp->attrs.state);
*bad_wr = wr;
rv = -ENOTCONN;
}
up_read(&qp->state_lock); return rv;
}
spin_lock_irqsave(&qp->sq_lock, flags);
case IB_WR_RDMA_READ_WITH_INV: case IB_WR_RDMA_READ: /* * iWarp restricts RREAD sink to SGL containing * 1 SGE only. we could relax to SGL with multiple * elements referring the SAME ltag or even sending * a private per-rreq tag referring to a checked * local sgl with MULTIPLE ltag's.
*/ if (unlikely(wr->num_sge != 1)) {
rv = -EINVAL; break;
}
siw_copy_sgl(wr->sg_list, &sqe->sge[0], 1); /* * NOTE: zero length RREAD is allowed!
*/
sqe->raddr = rdma_wr(wr)->remote_addr;
sqe->rkey = rdma_wr(wr)->rkey;
sqe->num_sge = 1;
/* make SQE only valid after completely written */
smp_wmb();
sqe->flags |= SIW_WQE_VALID;
qp->sq_put++;
wr = wr->next;
}
/* * Send directly if SQ processing is not in progress. * Eventual immediate errors (rv < 0) do not affect the involved * RI resources (Verbs, 8.3.1) and thus do not prevent from SQ * processing, if new work is already pending. But rv and pointer * to failed work request must be passed to caller.
*/ if (unlikely(rv < 0)) { /* * Immediate error
*/
siw_dbg_qp(qp, "Immediate error %d\n", rv);
imm_err = rv;
*bad_wr = wr;
} if (wqe->wr_status != SIW_WR_IDLE) {
spin_unlock_irqrestore(&qp->sq_lock, flags); goto skip_direct_sending;
}
rv = siw_activate_tx(qp);
spin_unlock_irqrestore(&qp->sq_lock, flags);
if (siw_qp_sq_process(qp) != 0 && !(qp->tx_ctx.tx_suspend))
siw_qp_cm_drop(qp, 0);
qp->tx_ctx.in_syscall = 0;
}
skip_direct_sending:
up_read(&qp->state_lock);
if (unlikely(imm_err)) return imm_err;
return (rv >= 0) ? 0 : rv;
}
/* * siw_post_receive() * * Post a list of R-WR's to a RQ. * * @base_qp: Base QP contained in siw QP * @wr: Null terminated list of user WR's * @bad_wr: Points to failing WR in case of synchronous failure.
*/ int siw_post_receive(struct ib_qp *base_qp, conststruct ib_recv_wr *wr, conststruct ib_recv_wr **bad_wr)
{ struct siw_qp *qp = to_siw_qp(base_qp); unsignedlong flags; int rv = 0;
if (qp->srq || qp->attrs.rq_size == 0) {
*bad_wr = wr; return -EINVAL;
} if (!rdma_is_kernel_res(&qp->base_qp.res)) {
siw_dbg_qp(qp, "no kernel post_recv for user mapped rq\n");
*bad_wr = wr; return -EINVAL;
}
/* * Try to acquire QP state lock. Must be non-blocking * to accommodate kernel clients needs.
*/ if (!down_read_trylock(&qp->state_lock)) { if (qp->attrs.state == SIW_QP_STATE_ERROR) { /* * ERROR state is final, so we can be sure * this state will not change as long as the QP * exists. * * This handles an ib_drain_rq() call with * a concurrent request to set the QP state * to ERROR.
*/
rv = siw_rq_flush_wr(qp, wr, bad_wr);
} else {
siw_dbg_qp(qp, "QP locked, state %d\n",
qp->attrs.state);
*bad_wr = wr;
rv = -ENOTCONN;
} return rv;
} if (qp->attrs.state > SIW_QP_STATE_RTS) { if (qp->attrs.state == SIW_QP_STATE_ERROR) { /* * Immediately flush this WR to CQ, if QP * is in ERROR state. RQ is guaranteed to * be empty, so WR complets in-order. * * Typically triggered by ib_drain_rq().
*/
rv = siw_rq_flush_wr(qp, wr, bad_wr);
} else {
siw_dbg_qp(qp, "QP out of state %d\n",
qp->attrs.state);
*bad_wr = wr;
rv = -ENOTCONN;
}
up_read(&qp->state_lock); return rv;
} /* * Serialize potentially multiple producers. * Not needed for single threaded consumer side.
*/
spin_lock_irqsave(&qp->rq_lock, flags);
if (cq->queue) { struct siw_ucontext *ctx =
rdma_udata_to_drv_context(udata, struct siw_ucontext,
base_ucontext); if (ctx)
rdma_user_mmap_entry_remove(cq->cq_entry);
vfree(cq->queue);
}
atomic_dec(&sdev->num_cq);
return rv;
}
/* * siw_poll_cq() * * Reap CQ entries if available and copy work completion status into * array of WC's provided by caller. Returns number of reaped CQE's. * * @base_cq: Base CQ contained in siw CQ. * @num_cqe: Maximum number of CQE's to reap. * @wc: Array of work completions to be filled by siw.
*/ int siw_poll_cq(struct ib_cq *base_cq, int num_cqe, struct ib_wc *wc)
{ struct siw_cq *cq = to_siw_cq(base_cq); int i;
for (i = 0; i < num_cqe; i++) { if (!siw_reap_cqe(cq, wc)) break;
wc++;
} return i;
}
/* * siw_req_notify_cq() * * Request notification for new CQE's added to that CQ. * Defined flags: * o SIW_CQ_NOTIFY_SOLICITED lets siw trigger a notification * event if a WQE with notification flag set enters the CQ * o SIW_CQ_NOTIFY_NEXT_COMP lets siw trigger a notification * event if a WQE enters the CQ. * o IB_CQ_REPORT_MISSED_EVENTS: return value will provide the * number of not reaped CQE's regardless of its notification * type and current or new CQ notification settings. * * @base_cq: Base CQ contained in siw CQ. * @flags: Requested notification flags.
*/ int siw_req_notify_cq(struct ib_cq *base_cq, enum ib_cq_notify_flags flags)
{ struct siw_cq *cq = to_siw_cq(base_cq);
siw_dbg_cq(cq, "flags: 0x%02x\n", flags);
if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED) /* * Enable CQ event for next solicited completion. * and make it visible to all associated producers.
*/
smp_store_mb(cq->notify->flags, SIW_NOTIFY_SOLICITED); else /* * Enable CQ event for any signalled completion. * and make it visible to all associated producers.
*/
smp_store_mb(cq->notify->flags, SIW_NOTIFY_ALL);
if (flags & IB_CQ_REPORT_MISSED_EVENTS) return cq->cq_put - cq->cq_get;
return 0;
}
/* * siw_dereg_mr() * * Release Memory Region. * * @base_mr: Base MR contained in siw MR. * @udata: points to user context, unused.
*/ int siw_dereg_mr(struct ib_mr *base_mr, struct ib_udata *udata)
{ struct siw_mr *mr = to_siw_mr(base_mr); struct siw_device *sdev = to_siw_dev(base_mr->device);
siw_dbg_mem(mr->mem, "deregister MR\n");
atomic_dec(&sdev->num_mr);
siw_mr_drop_mem(mr);
kfree_rcu(mr, rcu);
return 0;
}
/* * siw_reg_user_mr() * * Register Memory Region. * * @pd: Protection Domain * @start: starting address of MR (virtual address) * @len: len of MR * @rnic_va: not used by siw * @rights: MR access rights * @dmah: dma handle * @udata: user buffer to communicate STag and Key.
*/ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
u64 rnic_va, int rights, struct ib_dmah *dmah, struct ib_udata *udata)
{ struct siw_mr *mr = NULL; struct siw_umem *umem = NULL; struct siw_ureq_reg_mr ureq; struct siw_device *sdev = to_siw_dev(pd->device); int rv;
/* * siw_destroy_srq() * * Destroy SRQ. * It is assumed that the SRQ is not referenced by any * QP anymore - the code trusts the RDMA core environment to keep track * of QP references.
*/ int siw_destroy_srq(struct ib_srq *base_srq, struct ib_udata *udata)
{ struct siw_srq *srq = to_siw_srq(base_srq); struct siw_device *sdev = to_siw_dev(base_srq->device); struct siw_ucontext *ctx =
rdma_udata_to_drv_context(udata, struct siw_ucontext,
base_ucontext);
if (ctx)
rdma_user_mmap_entry_remove(srq->srq_entry);
vfree(srq->recvq);
atomic_dec(&sdev->num_srq); return 0;
}
/* * siw_post_srq_recv() * * Post a list of receive queue elements to SRQ. * NOTE: The function does not check or lock a certain SRQ state * during the post operation. The code simply trusts the * RDMA core environment. * * @base_srq: Base SRQ contained in siw SRQ * @wr: List of R-WR's * @bad_wr: Updated to failing WR if posting fails.
*/ int siw_post_srq_recv(struct ib_srq *base_srq, conststruct ib_recv_wr *wr, conststruct ib_recv_wr **bad_wr)
{ struct siw_srq *srq = to_siw_srq(base_srq); unsignedlong flags; int rv = 0;
if (unlikely(!srq->is_kernel_res)) {
siw_dbg_pd(base_srq->pd, "[SRQ]: no kernel post_recv for mapped srq\n");
rv = -EINVAL; goto out;
} /* * Serialize potentially multiple producers. * Also needed to serialize potentially multiple * consumers.
*/
spin_lock_irqsave(&srq->lock, flags);
/* * Do not report asynchronous errors on QP which gets * destroyed via verbs interface (siw_destroy_qp())
*/ if (qp->attrs.flags & SIW_QP_IN_DESTROY) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.