IB/ipath: Change UD to queue work requests like RC & UC
The code to post UD sends tried to process work requests at the time ib_post_send() is called without using a WQE queue. This was fine as long as HW resources were available for sending a packet. This patch changes UD to be handled more like RC and UC and shares more code. Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
210d6ca3db
commit
4ee97180ac
|
@ -338,6 +338,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
|
|||
qp->s_busy = 0;
|
||||
qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
|
||||
qp->s_hdrwords = 0;
|
||||
qp->s_wqe = NULL;
|
||||
qp->s_psn = 0;
|
||||
qp->r_psn = 0;
|
||||
qp->r_msn = 0;
|
||||
|
@ -751,6 +752,9 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
|
|||
switch (init_attr->qp_type) {
|
||||
case IB_QPT_UC:
|
||||
case IB_QPT_RC:
|
||||
case IB_QPT_UD:
|
||||
case IB_QPT_SMI:
|
||||
case IB_QPT_GSI:
|
||||
sz = sizeof(struct ipath_sge) *
|
||||
init_attr->cap.max_send_sge +
|
||||
sizeof(struct ipath_swqe);
|
||||
|
@ -759,10 +763,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
|
|||
ret = ERR_PTR(-ENOMEM);
|
||||
goto bail;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case IB_QPT_UD:
|
||||
case IB_QPT_SMI:
|
||||
case IB_QPT_GSI:
|
||||
sz = sizeof(*qp);
|
||||
if (init_attr->srq) {
|
||||
struct ipath_srq *srq = to_isrq(init_attr->srq);
|
||||
|
@ -805,8 +805,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
|
|||
spin_lock_init(&qp->r_rq.lock);
|
||||
atomic_set(&qp->refcount, 0);
|
||||
init_waitqueue_head(&qp->wait);
|
||||
tasklet_init(&qp->s_task, ipath_do_ruc_send,
|
||||
(unsigned long)qp);
|
||||
tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
|
||||
INIT_LIST_HEAD(&qp->piowait);
|
||||
INIT_LIST_HEAD(&qp->timerwait);
|
||||
qp->state = IB_QPS_RESET;
|
||||
|
|
|
@ -81,9 +81,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
|
|||
* Note that we are in the responder's side of the QP context.
|
||||
* Note the QP s_lock must be held.
|
||||
*/
|
||||
static int ipath_make_rc_ack(struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr,
|
||||
u32 pmtu, u32 *bth0p, u32 *bth2p)
|
||||
static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr, u32 pmtu)
|
||||
{
|
||||
struct ipath_ack_entry *e;
|
||||
u32 hwords;
|
||||
|
@ -192,8 +191,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
|
|||
}
|
||||
qp->s_hdrwords = hwords;
|
||||
qp->s_cur_size = len;
|
||||
*bth0p = bth0 | (1 << 22); /* Set M bit */
|
||||
*bth2p = bth2;
|
||||
ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
|
||||
return 1;
|
||||
|
||||
bail:
|
||||
|
@ -203,32 +201,39 @@ bail:
|
|||
/**
|
||||
* ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
|
||||
* @qp: a pointer to the QP
|
||||
* @ohdr: a pointer to the IB header being constructed
|
||||
* @pmtu: the path MTU
|
||||
* @bth0p: pointer to the BTH opcode word
|
||||
* @bth2p: pointer to the BTH PSN word
|
||||
*
|
||||
* Return 1 if constructed; otherwise, return 0.
|
||||
* Note the QP s_lock must be held and interrupts disabled.
|
||||
*/
|
||||
int ipath_make_rc_req(struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr,
|
||||
u32 pmtu, u32 *bth0p, u32 *bth2p)
|
||||
int ipath_make_rc_req(struct ipath_qp *qp)
|
||||
{
|
||||
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
|
||||
struct ipath_other_headers *ohdr;
|
||||
struct ipath_sge_state *ss;
|
||||
struct ipath_swqe *wqe;
|
||||
u32 hwords;
|
||||
u32 len;
|
||||
u32 bth0;
|
||||
u32 bth2;
|
||||
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
|
||||
char newreq;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
ohdr = &qp->s_hdr.u.oth;
|
||||
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
|
||||
ohdr = &qp->s_hdr.u.l.oth;
|
||||
|
||||
/*
|
||||
* The lock is needed to synchronize between the sending tasklet,
|
||||
* the receive interrupt handler, and timeout resends.
|
||||
*/
|
||||
spin_lock_irqsave(&qp->s_lock, flags);
|
||||
|
||||
/* Sending responses has higher priority over sending requests. */
|
||||
if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
|
||||
(qp->s_flags & IPATH_S_ACK_PENDING) ||
|
||||
qp->s_ack_state != OP(ACKNOWLEDGE)) &&
|
||||
ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
|
||||
ipath_make_rc_ack(dev, qp, ohdr, pmtu))
|
||||
goto done;
|
||||
|
||||
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
|
||||
|
@ -560,13 +565,12 @@ int ipath_make_rc_req(struct ipath_qp *qp,
|
|||
qp->s_hdrwords = hwords;
|
||||
qp->s_cur_sge = ss;
|
||||
qp->s_cur_size = len;
|
||||
*bth0p = bth0 | (qp->s_state << 24);
|
||||
*bth2p = bth2;
|
||||
ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
|
||||
done:
|
||||
return 1;
|
||||
|
||||
ret = 1;
|
||||
bail:
|
||||
return 0;
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -627,7 +631,7 @@ static void send_rc_ack(struct ipath_qp *qp)
|
|||
/*
|
||||
* If we can send the ACK, clear the ACK state.
|
||||
*/
|
||||
if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
|
||||
if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) {
|
||||
dev->n_unicast_xmit++;
|
||||
goto done;
|
||||
}
|
||||
|
@ -757,7 +761,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
|
|||
wc->vendor_err = 0;
|
||||
wc->byte_len = 0;
|
||||
wc->qp = &qp->ibqp;
|
||||
wc->imm_data = 0;
|
||||
wc->src_qp = qp->remote_qpn;
|
||||
wc->wc_flags = 0;
|
||||
wc->pkey_index = 0;
|
||||
wc->slid = qp->remote_ah_attr.dlid;
|
||||
wc->sl = qp->remote_ah_attr.sl;
|
||||
|
@ -1041,7 +1047,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
|
|||
wc.vendor_err = 0;
|
||||
wc.byte_len = 0;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.imm_data = 0;
|
||||
wc.src_qp = qp->remote_qpn;
|
||||
wc.wc_flags = 0;
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = qp->remote_ah_attr.dlid;
|
||||
wc.sl = qp->remote_ah_attr.sl;
|
||||
|
@ -1453,6 +1461,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
|
|||
qp->r_ack_psn = qp->r_psn - 1;
|
||||
goto send_ack;
|
||||
}
|
||||
/*
|
||||
* Try to send a simple ACK to work around a Mellanox bug
|
||||
* which doesn't accept a RDMA read response or atomic
|
||||
* response as an ACK for earlier SENDs or RDMA writes.
|
||||
*/
|
||||
if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
|
||||
!(qp->s_flags & IPATH_S_ACK_PENDING) &&
|
||||
qp->s_ack_state == OP(ACKNOWLEDGE)) {
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
qp->r_nak_state = 0;
|
||||
qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
|
||||
goto send_ack;
|
||||
}
|
||||
/*
|
||||
* Resend the RDMA read or atomic op which
|
||||
* ACKs this duplicate request.
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "ipath_verbs.h"
|
||||
#include "ipath_kernel.h"
|
||||
|
||||
|
@ -106,27 +108,30 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
|
|||
spin_unlock_irqrestore(&dev->pending_lock, flags);
|
||||
}
|
||||
|
||||
static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
|
||||
/**
|
||||
* ipath_init_sge - Validate a RWQE and fill in the SGE state
|
||||
* @qp: the QP
|
||||
*
|
||||
* Return 1 if OK.
|
||||
*/
|
||||
int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
|
||||
u32 *lengthp, struct ipath_sge_state *ss)
|
||||
{
|
||||
int user = to_ipd(qp->ibqp.pd)->user;
|
||||
int i, j, ret;
|
||||
struct ib_wc wc;
|
||||
|
||||
qp->r_len = 0;
|
||||
*lengthp = 0;
|
||||
for (i = j = 0; i < wqe->num_sge; i++) {
|
||||
if (wqe->sg_list[i].length == 0)
|
||||
continue;
|
||||
/* Check LKEY */
|
||||
if ((user && wqe->sg_list[i].lkey == 0) ||
|
||||
!ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
|
||||
IB_ACCESS_LOCAL_WRITE))
|
||||
if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
|
||||
&wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
|
||||
goto bad_lkey;
|
||||
qp->r_len += wqe->sg_list[i].length;
|
||||
*lengthp += wqe->sg_list[i].length;
|
||||
j++;
|
||||
}
|
||||
qp->r_sge.sge = qp->r_sg_list[0];
|
||||
qp->r_sge.sg_list = qp->r_sg_list + 1;
|
||||
qp->r_sge.num_sge = j;
|
||||
ss->num_sge = j;
|
||||
ret = 1;
|
||||
goto bail;
|
||||
|
||||
|
@ -172,6 +177,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
|
|||
u32 tail;
|
||||
int ret;
|
||||
|
||||
qp->r_sge.sg_list = qp->r_sg_list;
|
||||
|
||||
if (qp->ibqp.srq) {
|
||||
srq = to_isrq(qp->ibqp.srq);
|
||||
handler = srq->ibsrq.event_handler;
|
||||
|
@ -199,7 +206,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
|
|||
wqe = get_rwqe_ptr(rq, tail);
|
||||
if (++tail >= rq->size)
|
||||
tail = 0;
|
||||
} while (!wr_id_only && !init_sge(qp, wqe));
|
||||
} while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len,
|
||||
&qp->r_sge));
|
||||
qp->r_wr_id = wqe->wr_id;
|
||||
wq->tail = tail;
|
||||
|
||||
|
@ -239,9 +247,9 @@ bail:
|
|||
|
||||
/**
|
||||
* ipath_ruc_loopback - handle UC and RC lookback requests
|
||||
* @sqp: the loopback QP
|
||||
* @sqp: the sending QP
|
||||
*
|
||||
* This is called from ipath_do_uc_send() or ipath_do_rc_send() to
|
||||
* This is called from ipath_do_send() to
|
||||
* forward a WQE addressed to the same HCA.
|
||||
* Note that although we are single threaded due to the tasklet, we still
|
||||
* have to protect against post_send(). We don't have to worry about
|
||||
|
@ -450,40 +458,18 @@ again:
|
|||
wc.byte_len = wqe->length;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.src_qp = qp->remote_qpn;
|
||||
/* XXX do we know which pkey matched? Only needed for GSI. */
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = qp->remote_ah_attr.dlid;
|
||||
wc.sl = qp->remote_ah_attr.sl;
|
||||
wc.dlid_path_bits = 0;
|
||||
wc.port_num = 1;
|
||||
/* Signal completion event if the solicited bit is set. */
|
||||
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
|
||||
wqe->wr.send_flags & IB_SEND_SOLICITED);
|
||||
|
||||
send_comp:
|
||||
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
|
||||
|
||||
if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
|
||||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
|
||||
wc.wr_id = wqe->wr.wr_id;
|
||||
wc.status = IB_WC_SUCCESS;
|
||||
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
|
||||
wc.vendor_err = 0;
|
||||
wc.byte_len = wqe->length;
|
||||
wc.qp = &sqp->ibqp;
|
||||
wc.src_qp = 0;
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = 0;
|
||||
wc.sl = 0;
|
||||
wc.dlid_path_bits = 0;
|
||||
wc.port_num = 0;
|
||||
ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0);
|
||||
}
|
||||
|
||||
/* Update s_last now that we are finished with the SWQE */
|
||||
spin_lock_irqsave(&sqp->s_lock, flags);
|
||||
if (++sqp->s_last >= sqp->s_size)
|
||||
sqp->s_last = 0;
|
||||
spin_unlock_irqrestore(&sqp->s_lock, flags);
|
||||
ipath_send_complete(sqp, wqe, IB_WC_SUCCESS);
|
||||
goto again;
|
||||
|
||||
done:
|
||||
|
@ -491,13 +477,11 @@ done:
|
|||
wake_up(&qp->wait);
|
||||
}
|
||||
|
||||
static int want_buffer(struct ipath_devdata *dd)
|
||||
static void want_buffer(struct ipath_devdata *dd)
|
||||
{
|
||||
set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
|
||||
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
|
||||
dd->ipath_sendctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -507,14 +491,11 @@ static int want_buffer(struct ipath_devdata *dd)
|
|||
*
|
||||
* Called when we run out of PIO buffers.
|
||||
*/
|
||||
static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
|
||||
static void ipath_no_bufs_available(struct ipath_qp *qp,
|
||||
struct ipath_ibdev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->pending_lock, flags);
|
||||
if (list_empty(&qp->piowait))
|
||||
list_add_tail(&qp->piowait, &dev->piowait);
|
||||
spin_unlock_irqrestore(&dev->pending_lock, flags);
|
||||
/*
|
||||
* Note that as soon as want_buffer() is called and
|
||||
* possibly before it returns, ipath_ib_piobufavail()
|
||||
|
@ -524,100 +505,13 @@ static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev
|
|||
* We leave the busy flag set so that another post send doesn't
|
||||
* try to put the same QP on the piowait list again.
|
||||
*/
|
||||
spin_lock_irqsave(&dev->pending_lock, flags);
|
||||
list_add_tail(&qp->piowait, &dev->piowait);
|
||||
spin_unlock_irqrestore(&dev->pending_lock, flags);
|
||||
want_buffer(dev->dd);
|
||||
dev->n_piowait++;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_post_ruc_send - post RC and UC sends
|
||||
* @qp: the QP to post on
|
||||
* @wr: the work request to send
|
||||
*/
|
||||
int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
||||
{
|
||||
struct ipath_swqe *wqe;
|
||||
unsigned long flags;
|
||||
u32 next;
|
||||
int i, j;
|
||||
int acc;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Don't allow RDMA reads or atomic operations on UC or
|
||||
* undefined operations.
|
||||
* Make sure buffer is large enough to hold the result for atomics.
|
||||
*/
|
||||
if (qp->ibqp.qp_type == IB_QPT_UC) {
|
||||
if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
} else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
} else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
|
||||
(wr->num_sge == 0 ||
|
||||
wr->sg_list[0].length < sizeof(u64) ||
|
||||
wr->sg_list[0].addr & (sizeof(u64) - 1))) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
} else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
/* IB spec says that num_sge == 0 is OK. */
|
||||
if (wr->num_sge > qp->s_max_sge) {
|
||||
ret = -ENOMEM;
|
||||
goto bail;
|
||||
}
|
||||
spin_lock_irqsave(&qp->s_lock, flags);
|
||||
next = qp->s_head + 1;
|
||||
if (next >= qp->s_size)
|
||||
next = 0;
|
||||
if (next == qp->s_last) {
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
wqe = get_swqe_ptr(qp, qp->s_head);
|
||||
wqe->wr = *wr;
|
||||
wqe->ssn = qp->s_ssn++;
|
||||
wqe->sg_list[0].mr = NULL;
|
||||
wqe->sg_list[0].vaddr = NULL;
|
||||
wqe->sg_list[0].length = 0;
|
||||
wqe->sg_list[0].sge_length = 0;
|
||||
wqe->length = 0;
|
||||
acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0;
|
||||
for (i = 0, j = 0; i < wr->num_sge; i++) {
|
||||
if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
if (wr->sg_list[i].length == 0)
|
||||
continue;
|
||||
if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
|
||||
acc)) {
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
wqe->length += wr->sg_list[i].length;
|
||||
j++;
|
||||
}
|
||||
wqe->wr.num_sge = j;
|
||||
qp->s_head = next;
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
|
||||
ipath_do_ruc_send((unsigned long) qp);
|
||||
|
||||
ret = 0;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_make_grh - construct a GRH header
|
||||
* @dev: a pointer to the ipath device
|
||||
|
@ -648,81 +542,16 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
|
|||
return sizeof(struct ib_grh) / sizeof(u32);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_do_ruc_send - perform a send on an RC or UC QP
|
||||
* @data: contains a pointer to the QP
|
||||
*
|
||||
* Process entries in the send work queue until credit or queue is
|
||||
* exhausted. Only allow one CPU to send a packet per QP (tasklet).
|
||||
* Otherwise, after we drop the QP s_lock, two threads could send
|
||||
* packets out of order.
|
||||
*/
|
||||
void ipath_do_ruc_send(unsigned long data)
|
||||
void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr,
|
||||
u32 bth0, u32 bth2)
|
||||
{
|
||||
struct ipath_qp *qp = (struct ipath_qp *)data;
|
||||
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
|
||||
unsigned long flags;
|
||||
u16 lrh0;
|
||||
u32 nwords;
|
||||
u32 extra_bytes;
|
||||
u32 bth0;
|
||||
u32 bth2;
|
||||
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
|
||||
struct ipath_other_headers *ohdr;
|
||||
|
||||
if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
|
||||
goto bail;
|
||||
|
||||
if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
|
||||
ipath_ruc_loopback(qp);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
ohdr = &qp->s_hdr.u.oth;
|
||||
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
|
||||
ohdr = &qp->s_hdr.u.l.oth;
|
||||
|
||||
again:
|
||||
/* Check for a constructed packet to be sent. */
|
||||
if (qp->s_hdrwords != 0) {
|
||||
/*
|
||||
* If no PIO bufs are available, return. An interrupt will
|
||||
* call ipath_ib_piobufavail() when one is available.
|
||||
*/
|
||||
if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
|
||||
(u32 *) &qp->s_hdr, qp->s_cur_size,
|
||||
qp->s_cur_sge)) {
|
||||
ipath_no_bufs_available(qp, dev);
|
||||
goto bail;
|
||||
}
|
||||
dev->n_unicast_xmit++;
|
||||
/* Record that we sent the packet and s_hdr is empty. */
|
||||
qp->s_hdrwords = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The lock is needed to synchronize between setting
|
||||
* qp->s_ack_state, resend timer, and post_send().
|
||||
*/
|
||||
spin_lock_irqsave(&qp->s_lock, flags);
|
||||
|
||||
if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
|
||||
ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
|
||||
ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
|
||||
/*
|
||||
* Clear the busy bit before unlocking to avoid races with
|
||||
* adding new work queue items and then failing to process
|
||||
* them.
|
||||
*/
|
||||
clear_bit(IPATH_S_BUSY, &qp->s_busy);
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
|
||||
/* Construct the header. */
|
||||
extra_bytes = (4 - qp->s_cur_size) & 3;
|
||||
extra_bytes = -qp->s_cur_size & 3;
|
||||
nwords = (qp->s_cur_size + extra_bytes) >> 2;
|
||||
lrh0 = IPATH_LRH_BTH;
|
||||
if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
|
||||
|
@ -734,20 +563,99 @@ again:
|
|||
lrh0 |= qp->remote_ah_attr.sl << 4;
|
||||
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
|
||||
qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
|
||||
qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
|
||||
SIZE_OF_CRC);
|
||||
qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
|
||||
qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
|
||||
bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
|
||||
bth0 |= extra_bytes << 20;
|
||||
ohdr->bth[0] = cpu_to_be32(bth0);
|
||||
ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
|
||||
ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
|
||||
ohdr->bth[2] = cpu_to_be32(bth2);
|
||||
}
|
||||
|
||||
/* Check for more work to do. */
|
||||
goto again;
|
||||
/**
|
||||
* ipath_do_send - perform a send on a QP
|
||||
* @data: contains a pointer to the QP
|
||||
*
|
||||
* Process entries in the send work queue until credit or queue is
|
||||
* exhausted. Only allow one CPU to send a packet per QP (tasklet).
|
||||
* Otherwise, two threads could send packets out of order.
|
||||
*/
|
||||
void ipath_do_send(unsigned long data)
|
||||
{
|
||||
struct ipath_qp *qp = (struct ipath_qp *)data;
|
||||
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
|
||||
int (*make_req)(struct ipath_qp *qp);
|
||||
|
||||
if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
|
||||
goto bail;
|
||||
|
||||
if ((qp->ibqp.qp_type == IB_QPT_RC ||
|
||||
qp->ibqp.qp_type == IB_QPT_UC) &&
|
||||
qp->remote_ah_attr.dlid == dev->dd->ipath_lid) {
|
||||
ipath_ruc_loopback(qp);
|
||||
goto clear;
|
||||
}
|
||||
|
||||
if (qp->ibqp.qp_type == IB_QPT_RC)
|
||||
make_req = ipath_make_rc_req;
|
||||
else if (qp->ibqp.qp_type == IB_QPT_UC)
|
||||
make_req = ipath_make_uc_req;
|
||||
else
|
||||
make_req = ipath_make_ud_req;
|
||||
|
||||
again:
|
||||
/* Check for a constructed packet to be sent. */
|
||||
if (qp->s_hdrwords != 0) {
|
||||
/*
|
||||
* If no PIO bufs are available, return. An interrupt will
|
||||
* call ipath_ib_piobufavail() when one is available.
|
||||
*/
|
||||
if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
|
||||
qp->s_cur_sge, qp->s_cur_size)) {
|
||||
ipath_no_bufs_available(qp, dev);
|
||||
goto bail;
|
||||
}
|
||||
dev->n_unicast_xmit++;
|
||||
/* Record that we sent the packet and s_hdr is empty. */
|
||||
qp->s_hdrwords = 0;
|
||||
}
|
||||
|
||||
if (make_req(qp))
|
||||
goto again;
|
||||
clear:
|
||||
clear_bit(IPATH_S_BUSY, &qp->s_busy);
|
||||
bail:
|
||||
return;
|
||||
bail:;
|
||||
}
|
||||
|
||||
void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
|
||||
enum ib_wc_status status)
|
||||
{
|
||||
u32 last = qp->s_last;
|
||||
|
||||
if (++last == qp->s_size)
|
||||
last = 0;
|
||||
qp->s_last = last;
|
||||
|
||||
/* See ch. 11.2.4.1 and 10.7.3.1 */
|
||||
if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
|
||||
(wqe->wr.send_flags & IB_SEND_SIGNALED) ||
|
||||
status != IB_WC_SUCCESS) {
|
||||
struct ib_wc wc;
|
||||
|
||||
wc.wr_id = wqe->wr.wr_id;
|
||||
wc.status = status;
|
||||
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
|
||||
wc.vendor_err = 0;
|
||||
wc.byte_len = wqe->length;
|
||||
wc.imm_data = 0;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.src_qp = 0;
|
||||
wc.wc_flags = 0;
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = 0;
|
||||
wc.sl = 0;
|
||||
wc.dlid_path_bits = 0;
|
||||
wc.port_num = 0;
|
||||
ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,72 +37,40 @@
|
|||
/* cut down ridiculously long IB macro names */
|
||||
#define OP(x) IB_OPCODE_UC_##x
|
||||
|
||||
static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
|
||||
struct ib_wc *wc)
|
||||
{
|
||||
if (++qp->s_last == qp->s_size)
|
||||
qp->s_last = 0;
|
||||
if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
|
||||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
|
||||
wc->wr_id = wqe->wr.wr_id;
|
||||
wc->status = IB_WC_SUCCESS;
|
||||
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
|
||||
wc->vendor_err = 0;
|
||||
wc->byte_len = wqe->length;
|
||||
wc->qp = &qp->ibqp;
|
||||
wc->src_qp = qp->remote_qpn;
|
||||
wc->pkey_index = 0;
|
||||
wc->slid = qp->remote_ah_attr.dlid;
|
||||
wc->sl = qp->remote_ah_attr.sl;
|
||||
wc->dlid_path_bits = 0;
|
||||
wc->port_num = 0;
|
||||
ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_make_uc_req - construct a request packet (SEND, RDMA write)
|
||||
* @qp: a pointer to the QP
|
||||
* @ohdr: a pointer to the IB header being constructed
|
||||
* @pmtu: the path MTU
|
||||
* @bth0p: pointer to the BTH opcode word
|
||||
* @bth2p: pointer to the BTH PSN word
|
||||
*
|
||||
* Return 1 if constructed; otherwise, return 0.
|
||||
* Note the QP s_lock must be held and interrupts disabled.
|
||||
*/
|
||||
int ipath_make_uc_req(struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr,
|
||||
u32 pmtu, u32 *bth0p, u32 *bth2p)
|
||||
int ipath_make_uc_req(struct ipath_qp *qp)
|
||||
{
|
||||
struct ipath_other_headers *ohdr;
|
||||
struct ipath_swqe *wqe;
|
||||
u32 hwords;
|
||||
u32 bth0;
|
||||
u32 len;
|
||||
struct ib_wc wc;
|
||||
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
|
||||
int ret = 0;
|
||||
|
||||
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
|
||||
goto done;
|
||||
|
||||
ohdr = &qp->s_hdr.u.oth;
|
||||
if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
|
||||
ohdr = &qp->s_hdr.u.l.oth;
|
||||
|
||||
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
|
||||
hwords = 5;
|
||||
bth0 = 1 << 22; /* Set M bit */
|
||||
|
||||
/* Get the next send request. */
|
||||
wqe = get_swqe_ptr(qp, qp->s_last);
|
||||
wqe = get_swqe_ptr(qp, qp->s_cur);
|
||||
qp->s_wqe = NULL;
|
||||
switch (qp->s_state) {
|
||||
default:
|
||||
/*
|
||||
* Signal the completion of the last send
|
||||
* (if there is one).
|
||||
*/
|
||||
if (qp->s_last != qp->s_tail) {
|
||||
complete_last_send(qp, wqe, &wc);
|
||||
wqe = get_swqe_ptr(qp, qp->s_last);
|
||||
}
|
||||
|
||||
/* Check if send work queue is empty. */
|
||||
if (qp->s_tail == qp->s_head)
|
||||
if (qp->s_cur == qp->s_head)
|
||||
goto done;
|
||||
/*
|
||||
* Start a new request.
|
||||
|
@ -131,6 +99,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
|
|||
}
|
||||
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
|
||||
bth0 |= 1 << 23;
|
||||
qp->s_wqe = wqe;
|
||||
if (++qp->s_cur >= qp->s_size)
|
||||
qp->s_cur = 0;
|
||||
break;
|
||||
|
||||
case IB_WR_RDMA_WRITE:
|
||||
|
@ -157,13 +128,14 @@ int ipath_make_uc_req(struct ipath_qp *qp,
|
|||
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
|
||||
bth0 |= 1 << 23;
|
||||
}
|
||||
qp->s_wqe = wqe;
|
||||
if (++qp->s_cur >= qp->s_size)
|
||||
qp->s_cur = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
if (++qp->s_tail >= qp->s_size)
|
||||
qp->s_tail = 0;
|
||||
break;
|
||||
|
||||
case OP(SEND_FIRST):
|
||||
|
@ -185,6 +157,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
|
|||
}
|
||||
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
|
||||
bth0 |= 1 << 23;
|
||||
qp->s_wqe = wqe;
|
||||
if (++qp->s_cur >= qp->s_size)
|
||||
qp->s_cur = 0;
|
||||
break;
|
||||
|
||||
case OP(RDMA_WRITE_FIRST):
|
||||
|
@ -207,18 +182,22 @@ int ipath_make_uc_req(struct ipath_qp *qp,
|
|||
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
|
||||
bth0 |= 1 << 23;
|
||||
}
|
||||
qp->s_wqe = wqe;
|
||||
if (++qp->s_cur >= qp->s_size)
|
||||
qp->s_cur = 0;
|
||||
break;
|
||||
}
|
||||
qp->s_len -= len;
|
||||
qp->s_hdrwords = hwords;
|
||||
qp->s_cur_sge = &qp->s_sge;
|
||||
qp->s_cur_size = len;
|
||||
*bth0p = bth0 | (qp->s_state << 24);
|
||||
*bth2p = qp->s_next_psn++ & IPATH_PSN_MASK;
|
||||
return 1;
|
||||
ipath_make_ruc_header(to_idev(qp->ibqp.device),
|
||||
qp, ohdr, bth0 | (qp->s_state << 24),
|
||||
qp->s_next_psn++ & IPATH_PSN_MASK);
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,68 +36,17 @@
|
|||
#include "ipath_verbs.h"
|
||||
#include "ipath_kernel.h"
|
||||
|
||||
static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
|
||||
u32 *lengthp, struct ipath_sge_state *ss)
|
||||
{
|
||||
int user = to_ipd(qp->ibqp.pd)->user;
|
||||
int i, j, ret;
|
||||
struct ib_wc wc;
|
||||
|
||||
*lengthp = 0;
|
||||
for (i = j = 0; i < wqe->num_sge; i++) {
|
||||
if (wqe->sg_list[i].length == 0)
|
||||
continue;
|
||||
/* Check LKEY */
|
||||
if ((user && wqe->sg_list[i].lkey == 0) ||
|
||||
!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
|
||||
&wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
|
||||
goto bad_lkey;
|
||||
*lengthp += wqe->sg_list[i].length;
|
||||
j++;
|
||||
}
|
||||
ss->num_sge = j;
|
||||
ret = 1;
|
||||
goto bail;
|
||||
|
||||
bad_lkey:
|
||||
wc.wr_id = wqe->wr_id;
|
||||
wc.status = IB_WC_LOC_PROT_ERR;
|
||||
wc.opcode = IB_WC_RECV;
|
||||
wc.vendor_err = 0;
|
||||
wc.byte_len = 0;
|
||||
wc.imm_data = 0;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.src_qp = 0;
|
||||
wc.wc_flags = 0;
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = 0;
|
||||
wc.sl = 0;
|
||||
wc.dlid_path_bits = 0;
|
||||
wc.port_num = 0;
|
||||
/* Signal solicited completion event. */
|
||||
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
|
||||
ret = 0;
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_ud_loopback - handle send on loopback QPs
|
||||
* @sqp: the QP
|
||||
* @ss: the SGE state
|
||||
* @length: the length of the data to send
|
||||
* @wr: the work request
|
||||
* @wc: the work completion entry
|
||||
* @sqp: the sending QP
|
||||
* @swqe: the send work request
|
||||
*
|
||||
* This is called from ipath_post_ud_send() to forward a WQE addressed
|
||||
* This is called from ipath_make_ud_req() to forward a WQE addressed
|
||||
* to the same HCA.
|
||||
* Note that the receive interrupt handler may be calling ipath_ud_rcv()
|
||||
* while this is being called.
|
||||
*/
|
||||
static void ipath_ud_loopback(struct ipath_qp *sqp,
|
||||
struct ipath_sge_state *ss,
|
||||
u32 length, struct ib_send_wr *wr,
|
||||
struct ib_wc *wc)
|
||||
static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
|
||||
{
|
||||
struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
|
||||
struct ipath_qp *qp;
|
||||
|
@ -110,12 +59,18 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
struct ipath_rwq *wq;
|
||||
struct ipath_rwqe *wqe;
|
||||
void (*handler)(struct ib_event *, void *);
|
||||
struct ib_wc wc;
|
||||
u32 tail;
|
||||
u32 rlen;
|
||||
u32 length;
|
||||
|
||||
qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
|
||||
if (!qp)
|
||||
return;
|
||||
qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
|
||||
if (!qp) {
|
||||
dev->n_pkt_drops++;
|
||||
goto send_comp;
|
||||
}
|
||||
|
||||
rsge.sg_list = NULL;
|
||||
|
||||
/*
|
||||
* Check that the qkey matches (except for QP0, see 9.6.1.4.1).
|
||||
|
@ -123,39 +78,34 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
* qkey from the QP context instead of the WR (see 10.2.5).
|
||||
*/
|
||||
if (unlikely(qp->ibqp.qp_num &&
|
||||
((int) wr->wr.ud.remote_qkey < 0
|
||||
? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) {
|
||||
((int) swqe->wr.wr.ud.remote_qkey < 0 ?
|
||||
sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) {
|
||||
/* XXX OK to lose a count once in a while. */
|
||||
dev->qkey_violations++;
|
||||
dev->n_pkt_drops++;
|
||||
goto done;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/*
|
||||
* A GRH is expected to preceed the data even if not
|
||||
* present on the wire.
|
||||
*/
|
||||
wc->byte_len = length + sizeof(struct ib_grh);
|
||||
length = swqe->length;
|
||||
wc.byte_len = length + sizeof(struct ib_grh);
|
||||
|
||||
if (wr->opcode == IB_WR_SEND_WITH_IMM) {
|
||||
wc->wc_flags = IB_WC_WITH_IMM;
|
||||
wc->imm_data = wr->imm_data;
|
||||
if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
|
||||
wc.wc_flags = IB_WC_WITH_IMM;
|
||||
wc.imm_data = swqe->wr.imm_data;
|
||||
} else {
|
||||
wc->wc_flags = 0;
|
||||
wc->imm_data = 0;
|
||||
wc.wc_flags = 0;
|
||||
wc.imm_data = 0;
|
||||
}
|
||||
|
||||
if (wr->num_sge > 1) {
|
||||
rsge.sg_list = kmalloc((wr->num_sge - 1) *
|
||||
sizeof(struct ipath_sge),
|
||||
GFP_ATOMIC);
|
||||
} else
|
||||
rsge.sg_list = NULL;
|
||||
|
||||
/*
|
||||
* Get the next work request entry to find where to put the data.
|
||||
* Note that it is safe to drop the lock after changing rq->tail
|
||||
* since ipath_post_receive() won't fill the empty slot.
|
||||
* This would be a lot simpler if we could call ipath_get_rwqe()
|
||||
* but that uses state that the receive interrupt handler uses
|
||||
* so we would need to lock out receive interrupts while doing
|
||||
* local loopback.
|
||||
*/
|
||||
if (qp->ibqp.srq) {
|
||||
srq = to_isrq(qp->ibqp.srq);
|
||||
|
@ -167,32 +117,53 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
rq = &qp->r_rq;
|
||||
}
|
||||
|
||||
if (rq->max_sge > 1) {
|
||||
/*
|
||||
* XXX We could use GFP_KERNEL if ipath_do_send()
|
||||
* was always called from the tasklet instead of
|
||||
* from ipath_post_send().
|
||||
*/
|
||||
rsge.sg_list = kmalloc((rq->max_sge - 1) *
|
||||
sizeof(struct ipath_sge),
|
||||
GFP_ATOMIC);
|
||||
if (!rsge.sg_list) {
|
||||
dev->n_pkt_drops++;
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next work request entry to find where to put the data.
|
||||
* Note that it is safe to drop the lock after changing rq->tail
|
||||
* since ipath_post_receive() won't fill the empty slot.
|
||||
*/
|
||||
spin_lock_irqsave(&rq->lock, flags);
|
||||
wq = rq->wq;
|
||||
tail = wq->tail;
|
||||
while (1) {
|
||||
if (unlikely(tail == wq->head)) {
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
dev->n_pkt_drops++;
|
||||
goto bail_sge;
|
||||
}
|
||||
/* Make sure entry is read after head index is read. */
|
||||
smp_rmb();
|
||||
wqe = get_rwqe_ptr(rq, tail);
|
||||
if (++tail >= rq->size)
|
||||
tail = 0;
|
||||
if (init_sge(qp, wqe, &rlen, &rsge))
|
||||
break;
|
||||
wq->tail = tail;
|
||||
}
|
||||
/* Silently drop packets which are too big. */
|
||||
if (wc->byte_len > rlen) {
|
||||
/* Validate tail before using it since it is user writable. */
|
||||
if (tail >= rq->size)
|
||||
tail = 0;
|
||||
if (unlikely(tail == wq->head)) {
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
dev->n_pkt_drops++;
|
||||
goto bail_sge;
|
||||
goto drop;
|
||||
}
|
||||
wqe = get_rwqe_ptr(rq, tail);
|
||||
if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
dev->n_pkt_drops++;
|
||||
goto drop;
|
||||
}
|
||||
/* Silently drop packets which are too big. */
|
||||
if (wc.byte_len > rlen) {
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
dev->n_pkt_drops++;
|
||||
goto drop;
|
||||
}
|
||||
if (++tail >= rq->size)
|
||||
tail = 0;
|
||||
wq->tail = tail;
|
||||
wc->wr_id = wqe->wr_id;
|
||||
wc.wr_id = wqe->wr_id;
|
||||
if (handler) {
|
||||
u32 n;
|
||||
|
||||
|
@ -221,13 +192,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
} else
|
||||
spin_unlock_irqrestore(&rq->lock, flags);
|
||||
|
||||
ah_attr = &to_iah(wr->wr.ud.ah)->attr;
|
||||
ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
|
||||
if (ah_attr->ah_flags & IB_AH_GRH) {
|
||||
ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
|
||||
wc->wc_flags |= IB_WC_GRH;
|
||||
wc.wc_flags |= IB_WC_GRH;
|
||||
} else
|
||||
ipath_skip_sge(&rsge, sizeof(struct ib_grh));
|
||||
sge = &ss->sge;
|
||||
sge = swqe->sg_list;
|
||||
while (length) {
|
||||
u32 len = sge->length;
|
||||
|
||||
|
@ -241,8 +212,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
sge->length -= len;
|
||||
sge->sge_length -= len;
|
||||
if (sge->sge_length == 0) {
|
||||
if (--ss->num_sge)
|
||||
*sge = *ss->sg_list++;
|
||||
if (--swqe->wr.num_sge)
|
||||
sge++;
|
||||
} else if (sge->length == 0 && sge->mr != NULL) {
|
||||
if (++sge->n >= IPATH_SEGSZ) {
|
||||
if (++sge->m >= sge->mr->mapsz)
|
||||
|
@ -256,123 +227,60 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
|
|||
}
|
||||
length -= len;
|
||||
}
|
||||
wc->status = IB_WC_SUCCESS;
|
||||
wc->opcode = IB_WC_RECV;
|
||||
wc->vendor_err = 0;
|
||||
wc->qp = &qp->ibqp;
|
||||
wc->src_qp = sqp->ibqp.qp_num;
|
||||
wc.status = IB_WC_SUCCESS;
|
||||
wc.opcode = IB_WC_RECV;
|
||||
wc.vendor_err = 0;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.src_qp = sqp->ibqp.qp_num;
|
||||
/* XXX do we know which pkey matched? Only needed for GSI. */
|
||||
wc->pkey_index = 0;
|
||||
wc->slid = dev->dd->ipath_lid |
|
||||
wc.pkey_index = 0;
|
||||
wc.slid = dev->dd->ipath_lid |
|
||||
(ah_attr->src_path_bits &
|
||||
((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
|
||||
wc->sl = ah_attr->sl;
|
||||
wc->dlid_path_bits =
|
||||
wc.sl = ah_attr->sl;
|
||||
wc.dlid_path_bits =
|
||||
ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
|
||||
wc.port_num = 1;
|
||||
/* Signal completion event if the solicited bit is set. */
|
||||
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
|
||||
wr->send_flags & IB_SEND_SOLICITED);
|
||||
|
||||
bail_sge:
|
||||
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
|
||||
swqe->wr.send_flags & IB_SEND_SOLICITED);
|
||||
drop:
|
||||
kfree(rsge.sg_list);
|
||||
done:
|
||||
if (atomic_dec_and_test(&qp->refcount))
|
||||
wake_up(&qp->wait);
|
||||
send_comp:
|
||||
ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_post_ud_send - post a UD send on QP
|
||||
* ipath_make_ud_req - construct a UD request packet
|
||||
* @qp: the QP
|
||||
* @wr: the work request
|
||||
*
|
||||
* Note that we actually send the data as it is posted instead of putting
|
||||
* the request into a ring buffer. If we wanted to use a ring buffer,
|
||||
* we would need to save a reference to the destination address in the SWQE.
|
||||
* Return 1 if constructed; otherwise, return 0.
|
||||
*/
|
||||
int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
||||
int ipath_make_ud_req(struct ipath_qp *qp)
|
||||
{
|
||||
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
|
||||
struct ipath_other_headers *ohdr;
|
||||
struct ib_ah_attr *ah_attr;
|
||||
struct ipath_sge_state ss;
|
||||
struct ipath_sge *sg_list;
|
||||
struct ib_wc wc;
|
||||
u32 hwords;
|
||||
struct ipath_swqe *wqe;
|
||||
u32 nwords;
|
||||
u32 len;
|
||||
u32 extra_bytes;
|
||||
u32 bth0;
|
||||
u16 lrh0;
|
||||
u16 lid;
|
||||
int i;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
|
||||
ret = 0;
|
||||
if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (wr->wr.ud.ah->pd != qp->ibqp.pd) {
|
||||
ret = -EPERM;
|
||||
if (qp->s_cur == qp->s_head)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* IB spec says that num_sge == 0 is OK. */
|
||||
if (wr->num_sge > qp->s_max_sge) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (wr->num_sge > 1) {
|
||||
sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list),
|
||||
GFP_ATOMIC);
|
||||
if (!sg_list) {
|
||||
ret = -ENOMEM;
|
||||
goto bail;
|
||||
}
|
||||
} else
|
||||
sg_list = NULL;
|
||||
|
||||
/* Check the buffer to send. */
|
||||
ss.sg_list = sg_list;
|
||||
ss.sge.mr = NULL;
|
||||
ss.sge.vaddr = NULL;
|
||||
ss.sge.length = 0;
|
||||
ss.sge.sge_length = 0;
|
||||
ss.num_sge = 0;
|
||||
len = 0;
|
||||
for (i = 0; i < wr->num_sge; i++) {
|
||||
/* Check LKEY */
|
||||
if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (wr->sg_list[i].length == 0)
|
||||
continue;
|
||||
if (!ipath_lkey_ok(qp, ss.num_sge ?
|
||||
sg_list + ss.num_sge - 1 : &ss.sge,
|
||||
&wr->sg_list[i], 0)) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
len += wr->sg_list[i].length;
|
||||
ss.num_sge++;
|
||||
}
|
||||
/* Check for invalid packet size. */
|
||||
if (len > dev->dd->ipath_ibmtu) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
extra_bytes = (4 - len) & 3;
|
||||
nwords = (len + extra_bytes) >> 2;
|
||||
wqe = get_swqe_ptr(qp, qp->s_cur);
|
||||
|
||||
/* Construct the header. */
|
||||
ah_attr = &to_iah(wr->wr.ud.ah)->attr;
|
||||
if (ah_attr->dlid == 0) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
|
||||
if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
|
||||
if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
|
||||
dev->n_multicast_xmit++;
|
||||
|
@ -383,64 +291,53 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
|||
lid = ah_attr->dlid &
|
||||
~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
|
||||
if (unlikely(lid == dev->dd->ipath_lid)) {
|
||||
/*
|
||||
* Pass in an uninitialized ib_wc to save stack
|
||||
* space.
|
||||
*/
|
||||
ipath_ud_loopback(qp, &ss, len, wr, &wc);
|
||||
ipath_ud_loopback(qp, wqe);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
extra_bytes = -wqe->length & 3;
|
||||
nwords = (wqe->length + extra_bytes) >> 2;
|
||||
|
||||
/* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
|
||||
qp->s_hdrwords = 7;
|
||||
if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
|
||||
qp->s_hdrwords++;
|
||||
qp->s_cur_size = wqe->length;
|
||||
qp->s_cur_sge = &qp->s_sge;
|
||||
qp->s_wqe = wqe;
|
||||
qp->s_sge.sge = wqe->sg_list[0];
|
||||
qp->s_sge.sg_list = wqe->sg_list + 1;
|
||||
qp->s_sge.num_sge = wqe->wr.num_sge;
|
||||
|
||||
if (ah_attr->ah_flags & IB_AH_GRH) {
|
||||
/* Header size in 32-bit words. */
|
||||
hwords = 17;
|
||||
qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
|
||||
&ah_attr->grh,
|
||||
qp->s_hdrwords, nwords);
|
||||
lrh0 = IPATH_LRH_GRH;
|
||||
ohdr = &qp->s_hdr.u.l.oth;
|
||||
qp->s_hdr.u.l.grh.version_tclass_flow =
|
||||
cpu_to_be32((6 << 28) |
|
||||
(ah_attr->grh.traffic_class << 20) |
|
||||
ah_attr->grh.flow_label);
|
||||
qp->s_hdr.u.l.grh.paylen =
|
||||
cpu_to_be16(((wr->opcode ==
|
||||
IB_WR_SEND_WITH_IMM ? 6 : 5) +
|
||||
nwords + SIZE_OF_CRC) << 2);
|
||||
/* next_hdr is defined by C8-7 in ch. 8.4.1 */
|
||||
qp->s_hdr.u.l.grh.next_hdr = 0x1B;
|
||||
qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit;
|
||||
/* The SGID is 32-bit aligned. */
|
||||
qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
|
||||
dev->gid_prefix;
|
||||
qp->s_hdr.u.l.grh.sgid.global.interface_id =
|
||||
dev->dd->ipath_guid;
|
||||
qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
|
||||
/*
|
||||
* Don't worry about sending to locally attached multicast
|
||||
* QPs. It is unspecified by the spec. what happens.
|
||||
*/
|
||||
} else {
|
||||
/* Header size in 32-bit words. */
|
||||
hwords = 7;
|
||||
lrh0 = IPATH_LRH_BTH;
|
||||
ohdr = &qp->s_hdr.u.oth;
|
||||
}
|
||||
if (wr->opcode == IB_WR_SEND_WITH_IMM) {
|
||||
ohdr->u.ud.imm_data = wr->imm_data;
|
||||
wc.imm_data = wr->imm_data;
|
||||
hwords += 1;
|
||||
if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
|
||||
ohdr->u.ud.imm_data = wqe->wr.imm_data;
|
||||
bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
|
||||
} else if (wr->opcode == IB_WR_SEND) {
|
||||
wc.imm_data = 0;
|
||||
} else
|
||||
bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
lrh0 |= ah_attr->sl << 4;
|
||||
if (qp->ibqp.qp_type == IB_QPT_SMI)
|
||||
lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
|
||||
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
|
||||
qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
|
||||
qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
|
||||
qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
|
||||
SIZE_OF_CRC);
|
||||
lid = dev->dd->ipath_lid;
|
||||
if (lid) {
|
||||
lid |= ah_attr->src_path_bits &
|
||||
|
@ -448,7 +345,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
|||
qp->s_hdr.lrh[3] = cpu_to_be16(lid);
|
||||
} else
|
||||
qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
|
||||
if (wr->send_flags & IB_SEND_SOLICITED)
|
||||
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
|
||||
bth0 |= 1 << 23;
|
||||
bth0 |= extra_bytes << 20;
|
||||
bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
|
||||
|
@ -460,38 +357,20 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
|||
ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
|
||||
ah_attr->dlid != IPATH_PERMISSIVE_LID ?
|
||||
__constant_cpu_to_be32(IPATH_MULTICAST_QPN) :
|
||||
cpu_to_be32(wr->wr.ud.remote_qpn);
|
||||
/* XXX Could lose a PSN count but not worth locking */
|
||||
cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
|
||||
ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
|
||||
/*
|
||||
* Qkeys with the high order bit set mean use the
|
||||
* qkey from the QP context instead of the WR (see 10.2.5).
|
||||
*/
|
||||
ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ?
|
||||
qp->qkey : wr->wr.ud.remote_qkey);
|
||||
ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
|
||||
qp->qkey : wqe->wr.wr.ud.remote_qkey);
|
||||
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
|
||||
if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr,
|
||||
len, &ss))
|
||||
dev->n_no_piobuf++;
|
||||
|
||||
done:
|
||||
/* Queue the completion status entry. */
|
||||
if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
|
||||
(wr->send_flags & IB_SEND_SIGNALED)) {
|
||||
wc.wr_id = wr->wr_id;
|
||||
wc.status = IB_WC_SUCCESS;
|
||||
wc.vendor_err = 0;
|
||||
wc.opcode = IB_WC_SEND;
|
||||
wc.byte_len = len;
|
||||
wc.qp = &qp->ibqp;
|
||||
wc.src_qp = 0;
|
||||
wc.wc_flags = 0;
|
||||
/* XXX initialize other fields? */
|
||||
ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
|
||||
}
|
||||
kfree(sg_list);
|
||||
|
||||
ret = 0;
|
||||
if (++qp->s_cur >= qp->s_size)
|
||||
qp->s_cur = 0;
|
||||
ret = 1;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
|
@ -673,6 +552,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
|
|||
*/
|
||||
wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
|
||||
dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
|
||||
wc.port_num = 1;
|
||||
/* Signal completion event if the solicited bit is set. */
|
||||
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
|
||||
(ohdr->bth[0] &
|
||||
|
|
|
@ -230,6 +230,103 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_post_one_send - post one RC, UC, or UD send work request
|
||||
* @qp: the QP to post on
|
||||
* @wr: the work request to send
|
||||
*/
|
||||
static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
|
||||
{
|
||||
struct ipath_swqe *wqe;
|
||||
u32 next;
|
||||
int i;
|
||||
int j;
|
||||
int acc;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&qp->s_lock, flags);
|
||||
|
||||
/* Check that state is OK to post send. */
|
||||
if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))
|
||||
goto bail_inval;
|
||||
|
||||
/* IB spec says that num_sge == 0 is OK. */
|
||||
if (wr->num_sge > qp->s_max_sge)
|
||||
goto bail_inval;
|
||||
|
||||
/*
|
||||
* Don't allow RDMA reads or atomic operations on UC or
|
||||
* undefined operations.
|
||||
* Make sure buffer is large enough to hold the result for atomics.
|
||||
*/
|
||||
if (qp->ibqp.qp_type == IB_QPT_UC) {
|
||||
if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
|
||||
goto bail_inval;
|
||||
} else if (qp->ibqp.qp_type == IB_QPT_UD) {
|
||||
/* Check UD opcode */
|
||||
if (wr->opcode != IB_WR_SEND &&
|
||||
wr->opcode != IB_WR_SEND_WITH_IMM)
|
||||
goto bail_inval;
|
||||
/* Check UD destination address PD */
|
||||
if (qp->ibqp.pd != wr->wr.ud.ah->pd)
|
||||
goto bail_inval;
|
||||
} else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
|
||||
goto bail_inval;
|
||||
else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
|
||||
(wr->num_sge == 0 ||
|
||||
wr->sg_list[0].length < sizeof(u64) ||
|
||||
wr->sg_list[0].addr & (sizeof(u64) - 1)))
|
||||
goto bail_inval;
|
||||
else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
|
||||
goto bail_inval;
|
||||
|
||||
next = qp->s_head + 1;
|
||||
if (next >= qp->s_size)
|
||||
next = 0;
|
||||
if (next == qp->s_last)
|
||||
goto bail_inval;
|
||||
|
||||
wqe = get_swqe_ptr(qp, qp->s_head);
|
||||
wqe->wr = *wr;
|
||||
wqe->ssn = qp->s_ssn++;
|
||||
wqe->length = 0;
|
||||
if (wr->num_sge) {
|
||||
acc = wr->opcode >= IB_WR_RDMA_READ ?
|
||||
IB_ACCESS_LOCAL_WRITE : 0;
|
||||
for (i = 0, j = 0; i < wr->num_sge; i++) {
|
||||
u32 length = wr->sg_list[i].length;
|
||||
int ok;
|
||||
|
||||
if (length == 0)
|
||||
continue;
|
||||
ok = ipath_lkey_ok(qp, &wqe->sg_list[j],
|
||||
&wr->sg_list[i], acc);
|
||||
if (!ok)
|
||||
goto bail_inval;
|
||||
wqe->length += length;
|
||||
j++;
|
||||
}
|
||||
wqe->wr.num_sge = j;
|
||||
}
|
||||
if (qp->ibqp.qp_type == IB_QPT_UC ||
|
||||
qp->ibqp.qp_type == IB_QPT_RC) {
|
||||
if (wqe->length > 0x80000000U)
|
||||
goto bail_inval;
|
||||
} else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
|
||||
goto bail_inval;
|
||||
qp->s_head = next;
|
||||
|
||||
ret = 0;
|
||||
goto bail;
|
||||
|
||||
bail_inval:
|
||||
ret = -EINVAL;
|
||||
bail:
|
||||
spin_unlock_irqrestore(&qp->s_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_post_send - post a send on a QP
|
||||
* @ibqp: the QP to post the send on
|
||||
|
@ -244,35 +341,17 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
|
|||
struct ipath_qp *qp = to_iqp(ibqp);
|
||||
int err = 0;
|
||||
|
||||
/* Check that state is OK to post send. */
|
||||
if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) {
|
||||
*bad_wr = wr;
|
||||
err = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
for (; wr; wr = wr->next) {
|
||||
switch (qp->ibqp.qp_type) {
|
||||
case IB_QPT_UC:
|
||||
case IB_QPT_RC:
|
||||
err = ipath_post_ruc_send(qp, wr);
|
||||
break;
|
||||
|
||||
case IB_QPT_SMI:
|
||||
case IB_QPT_GSI:
|
||||
case IB_QPT_UD:
|
||||
err = ipath_post_ud_send(qp, wr);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
err = ipath_post_one_send(qp, wr);
|
||||
if (err) {
|
||||
*bad_wr = wr;
|
||||
break;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to do the send work in the caller's context. */
|
||||
ipath_do_send((unsigned long) qp);
|
||||
|
||||
bail:
|
||||
return err;
|
||||
}
|
||||
|
@ -641,11 +720,11 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
|
|||
u32 len = ss->sge.length;
|
||||
u32 off;
|
||||
|
||||
BUG_ON(len == 0);
|
||||
if (len > length)
|
||||
len = length;
|
||||
if (len > ss->sge.sge_length)
|
||||
len = ss->sge.sge_length;
|
||||
BUG_ON(len == 0);
|
||||
/* If the source address is not aligned, try to align it. */
|
||||
off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
|
||||
if (off) {
|
||||
|
@ -767,30 +846,15 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
|
|||
__raw_writel(last, piobuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_verbs_send - send a packet
|
||||
* @dd: the infinipath device
|
||||
* @hdrwords: the number of words in the header
|
||||
* @hdr: the packet header
|
||||
* @len: the length of the packet in bytes
|
||||
* @ss: the SGE to send
|
||||
*/
|
||||
int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
|
||||
u32 *hdr, u32 len, struct ipath_sge_state *ss)
|
||||
static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords,
|
||||
struct ipath_sge_state *ss, u32 len,
|
||||
u32 plen, u32 dwords)
|
||||
{
|
||||
struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
|
||||
u32 __iomem *piobuf;
|
||||
unsigned flush_wc;
|
||||
u32 plen;
|
||||
int ret;
|
||||
|
||||
/* +1 is for the qword padding of pbc */
|
||||
plen = hdrwords + ((len + 3) >> 2) + 1;
|
||||
if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Get a PIO buffer to use. */
|
||||
piobuf = ipath_getpiobuf(dd, NULL);
|
||||
if (unlikely(piobuf == NULL)) {
|
||||
ret = -EBUSY;
|
||||
|
@ -831,13 +895,10 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
|
|||
/* The common case is aligned and contained in one segment. */
|
||||
if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
|
||||
!((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
|
||||
u32 dwords;
|
||||
u32 *addr = (u32 *) ss->sge.vaddr;
|
||||
|
||||
/* Update address before sending packet. */
|
||||
update_sge(ss, len);
|
||||
/* Need to round up for the last dword in the packet. */
|
||||
dwords = (len + 3) >> 2;
|
||||
if (flush_wc) {
|
||||
__iowrite32_copy(piobuf, addr, dwords - 1);
|
||||
/* must flush early everything before trigger word */
|
||||
|
@ -851,11 +912,37 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
|
|||
}
|
||||
copy_io(piobuf, ss, len, flush_wc);
|
||||
done:
|
||||
if (qp->s_wqe)
|
||||
ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
|
||||
ret = 0;
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipath_verbs_send - send a packet
|
||||
* @qp: the QP to send on
|
||||
* @hdr: the packet header
|
||||
* @hdrwords: the number of words in the header
|
||||
* @ss: the SGE to send
|
||||
* @len: the length of the packet in bytes
|
||||
*/
|
||||
int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
|
||||
u32 hdrwords, struct ipath_sge_state *ss, u32 len)
|
||||
{
|
||||
u32 plen;
|
||||
int ret;
|
||||
u32 dwords = (len + 3) >> 2;
|
||||
|
||||
/* +1 is for the qword padding of pbc */
|
||||
plen = hdrwords + dwords + 1;
|
||||
|
||||
ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords,
|
||||
ss, len, plen, dwords);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
|
||||
u64 *rwords, u64 *spkts, u64 *rpkts,
|
||||
u64 *xmit_wait)
|
||||
|
@ -864,7 +951,6 @@ int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
|
|||
|
||||
if (!(dd->ipath_flags & IPATH_INITTED)) {
|
||||
/* no hardware, freeze, etc. */
|
||||
ipath_dbg("unit %u not usable\n", dd->ipath_unit);
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
@ -890,48 +976,44 @@ bail:
|
|||
int ipath_get_counters(struct ipath_devdata *dd,
|
||||
struct ipath_verbs_counters *cntrs)
|
||||
{
|
||||
struct ipath_cregs const *crp = dd->ipath_cregs;
|
||||
int ret;
|
||||
|
||||
if (!(dd->ipath_flags & IPATH_INITTED)) {
|
||||
/* no hardware, freeze, etc. */
|
||||
ipath_dbg("unit %u not usable\n", dd->ipath_unit);
|
||||
ret = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
cntrs->symbol_error_counter =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
|
||||
ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt);
|
||||
cntrs->link_error_recovery_counter =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
|
||||
ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt);
|
||||
/*
|
||||
* The link downed counter counts when the other side downs the
|
||||
* connection. We add in the number of times we downed the link
|
||||
* due to local link integrity errors to compensate.
|
||||
*/
|
||||
cntrs->link_downed_counter =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
|
||||
ipath_snap_cntr(dd, crp->cr_iblinkdowncnt);
|
||||
cntrs->port_rcv_errors =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_rcvovflcnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_portovflcnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_err_rlencnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_invalidrlencnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_errlinkcnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_erricrccnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_errvcrccnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_errlpcrccnt) +
|
||||
ipath_snap_cntr(dd, crp->cr_badformatcnt) +
|
||||
dd->ipath_rxfc_unsupvl_errs;
|
||||
cntrs->port_rcv_remphys_errors =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
|
||||
cntrs->port_xmit_discards =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
|
||||
cntrs->port_xmit_data =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
|
||||
cntrs->port_rcv_data =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
|
||||
cntrs->port_xmit_packets =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
|
||||
cntrs->port_rcv_packets =
|
||||
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
|
||||
ipath_snap_cntr(dd, crp->cr_rcvebpcnt);
|
||||
cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt);
|
||||
cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt);
|
||||
cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt);
|
||||
cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt);
|
||||
cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt);
|
||||
cntrs->local_link_integrity_errors =
|
||||
(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
|
||||
dd->ipath_lli_errs : dd->ipath_lli_errors;
|
||||
|
@ -1045,8 +1127,9 @@ static int ipath_query_port(struct ib_device *ibdev,
|
|||
u8 port, struct ib_port_attr *props)
|
||||
{
|
||||
struct ipath_ibdev *dev = to_idev(ibdev);
|
||||
struct ipath_devdata *dd = dev->dd;
|
||||
enum ib_mtu mtu;
|
||||
u16 lid = dev->dd->ipath_lid;
|
||||
u16 lid = dd->ipath_lid;
|
||||
u64 ibcstat;
|
||||
|
||||
memset(props, 0, sizeof(*props));
|
||||
|
@ -1054,16 +1137,16 @@ static int ipath_query_port(struct ib_device *ibdev,
|
|||
props->lmc = dev->mkeyprot_resv_lmc & 7;
|
||||
props->sm_lid = dev->sm_lid;
|
||||
props->sm_sl = dev->sm_sl;
|
||||
ibcstat = dev->dd->ipath_lastibcstat;
|
||||
ibcstat = dd->ipath_lastibcstat;
|
||||
props->state = ((ibcstat >> 4) & 0x3) + 1;
|
||||
/* See phys_state_show() */
|
||||
props->phys_state = ipath_cvt_physportstate[
|
||||
dev->dd->ipath_lastibcstat & 0xf];
|
||||
dd->ipath_lastibcstat & 0xf];
|
||||
props->port_cap_flags = dev->port_cap_flags;
|
||||
props->gid_tbl_len = 1;
|
||||
props->max_msg_sz = 0x80000000;
|
||||
props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
|
||||
props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
|
||||
props->pkey_tbl_len = ipath_get_npkeys(dd);
|
||||
props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) -
|
||||
dev->z_pkey_violations;
|
||||
props->qkey_viol_cntr = dev->qkey_violations;
|
||||
props->active_width = IB_WIDTH_4X;
|
||||
|
@ -1073,12 +1156,12 @@ static int ipath_query_port(struct ib_device *ibdev,
|
|||
props->init_type_reply = 0;
|
||||
|
||||
/*
|
||||
* Note: the chips support a maximum MTU of 4096, but the driver
|
||||
* Note: the chip supports a maximum MTU of 4096, but the driver
|
||||
* hasn't implemented this feature yet, so set the maximum value
|
||||
* to 2048.
|
||||
*/
|
||||
props->max_mtu = IB_MTU_2048;
|
||||
switch (dev->dd->ipath_ibmtu) {
|
||||
switch (dd->ipath_ibmtu) {
|
||||
case 4096:
|
||||
mtu = IB_MTU_4096;
|
||||
break;
|
||||
|
@ -1427,9 +1510,7 @@ static int disable_timer(struct ipath_devdata *dd)
|
|||
{
|
||||
/* Disable GPIO bit 2 interrupt */
|
||||
if (dd->ipath_flags & IPATH_GPIO_INTR) {
|
||||
u64 val;
|
||||
/* Disable GPIO bit 2 interrupt */
|
||||
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
|
||||
dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
|
||||
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
|
||||
dd->ipath_gpio_mask);
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include <rdma/ib_pack.h>
|
||||
#include <rdma/ib_user_verbs.h>
|
||||
|
||||
#include "ipath_kernel.h"
|
||||
|
||||
#define IPATH_MAX_RDMA_ATOMIC 4
|
||||
|
||||
#define QPN_MAX (1 << 24)
|
||||
|
@ -59,6 +61,7 @@
|
|||
*/
|
||||
#define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1)
|
||||
|
||||
/* AETH NAK opcode values */
|
||||
#define IB_RNR_NAK 0x20
|
||||
#define IB_NAK_PSN_ERROR 0x60
|
||||
#define IB_NAK_INVALID_REQUEST 0x61
|
||||
|
@ -66,6 +69,7 @@
|
|||
#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
|
||||
#define IB_NAK_INVALID_RD_REQUEST 0x64
|
||||
|
||||
/* Flags for checking QP state (see ib_ipath_state_ops[]) */
|
||||
#define IPATH_POST_SEND_OK 0x01
|
||||
#define IPATH_POST_RECV_OK 0x02
|
||||
#define IPATH_PROCESS_RECV_OK 0x04
|
||||
|
@ -239,7 +243,7 @@ struct ipath_mregion {
|
|||
*/
|
||||
struct ipath_sge {
|
||||
struct ipath_mregion *mr;
|
||||
void *vaddr; /* current pointer into the segment */
|
||||
void *vaddr; /* kernel virtual address of segment */
|
||||
u32 sge_length; /* length of the SGE */
|
||||
u32 length; /* remaining length of the segment */
|
||||
u16 m; /* current index: mr->map[m] */
|
||||
|
@ -407,6 +411,7 @@ struct ipath_qp {
|
|||
u32 s_ssn; /* SSN of tail entry */
|
||||
u32 s_lsn; /* limit sequence number (credit) */
|
||||
struct ipath_swqe *s_wq; /* send work queue */
|
||||
struct ipath_swqe *s_wqe;
|
||||
struct ipath_rq r_rq; /* receive work queue */
|
||||
struct ipath_sge r_sg_list[0]; /* verified SGEs */
|
||||
};
|
||||
|
@ -683,8 +688,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc);
|
|||
|
||||
void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
|
||||
|
||||
int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
|
||||
u32 *hdr, u32 len, struct ipath_sge_state *ss);
|
||||
int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
|
||||
u32 hdrwords, struct ipath_sge_state *ss, u32 len);
|
||||
|
||||
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
|
||||
|
||||
|
@ -692,8 +697,6 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
|
|||
|
||||
void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
|
||||
|
||||
int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
|
||||
|
||||
void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
|
||||
int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
|
||||
|
||||
|
@ -733,6 +736,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
|
|||
|
||||
int ipath_destroy_srq(struct ib_srq *ibsrq);
|
||||
|
||||
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
|
||||
|
||||
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
|
||||
|
||||
struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
|
||||
|
@ -782,18 +787,28 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
|
|||
|
||||
void ipath_insert_rnr_queue(struct ipath_qp *qp);
|
||||
|
||||
int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
|
||||
u32 *lengthp, struct ipath_sge_state *ss);
|
||||
|
||||
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
|
||||
|
||||
u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
|
||||
struct ib_global_route *grh, u32 hwords, u32 nwords);
|
||||
|
||||
void ipath_do_ruc_send(unsigned long data);
|
||||
void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
|
||||
struct ipath_other_headers *ohdr,
|
||||
u32 bth0, u32 bth2);
|
||||
|
||||
int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
|
||||
u32 pmtu, u32 *bth0p, u32 *bth2p);
|
||||
void ipath_do_send(unsigned long data);
|
||||
|
||||
int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
|
||||
u32 pmtu, u32 *bth0p, u32 *bth2p);
|
||||
void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
|
||||
enum ib_wc_status status);
|
||||
|
||||
int ipath_make_rc_req(struct ipath_qp *qp);
|
||||
|
||||
int ipath_make_uc_req(struct ipath_qp *qp);
|
||||
|
||||
int ipath_make_ud_req(struct ipath_qp *qp);
|
||||
|
||||
int ipath_register_ib_device(struct ipath_devdata *);
|
||||
|
||||
|
|
Loading…
Reference in New Issue