ipath_ud.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 624 行 · 第 1/2 页

C
624
字号
/* * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */#include <rdma/ib_smi.h>#include "ipath_verbs.h"#include "ips_common.h"/** * 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 * * This is called from ipath_post_ud_send() to forward a WQE addressed * to the same HCA. */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){	struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);	struct ipath_qp *qp;	struct ib_ah_attr *ah_attr;	unsigned long flags;	struct ipath_rq *rq;	struct ipath_srq *srq;	struct ipath_sge_state rsge;	struct ipath_sge *sge;	struct ipath_rwqe *wqe;	qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);	if (!qp)		return;	/*	 * Check that the qkey matches (except for QP0, see 9.6.1.4.1).	 * Qkeys with the high order bit set mean use the	 * 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)) {		/* XXX OK to lose a count once in a while. */		dev->qkey_violations++;		dev->n_pkt_drops++;		goto done;	}	/*	 * A GRH is expected to preceed the data even if not	 * present on the wire.	 */	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;	} else {		wc->wc_flags = 0;		wc->imm_data = 0;	}	/*	 * 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.	 */	if (qp->ibqp.srq) {		srq = to_isrq(qp->ibqp.srq);		rq = &srq->rq;	} else {		srq = NULL;		rq = &qp->r_rq;	}	spin_lock_irqsave(&rq->lock, flags);	if (rq->tail == rq->head) {		spin_unlock_irqrestore(&rq->lock, flags);		dev->n_pkt_drops++;		goto done;	}	/* Silently drop packets which are too big. */	wqe = get_rwqe_ptr(rq, rq->tail);	if (wc->byte_len > wqe->length) {		spin_unlock_irqrestore(&rq->lock, flags);		dev->n_pkt_drops++;		goto done;	}	wc->wr_id = wqe->wr_id;	rsge.sge = wqe->sg_list[0];	rsge.sg_list = wqe->sg_list + 1;	rsge.num_sge = wqe->num_sge;	if (++rq->tail >= rq->size)		rq->tail = 0;	if (srq && srq->ibsrq.event_handler) {		u32 n;		if (rq->head < rq->tail)			n = rq->size + rq->head - rq->tail;		else			n = rq->head - rq->tail;		if (n < srq->limit) {			struct ib_event ev;			srq->limit = 0;			spin_unlock_irqrestore(&rq->lock, flags);			ev.device = qp->ibqp.device;			ev.element.srq = qp->ibqp.srq;			ev.event = IB_EVENT_SRQ_LIMIT_REACHED;			srq->ibsrq.event_handler(&ev,						 srq->ibsrq.srq_context);		} else			spin_unlock_irqrestore(&rq->lock, flags);	} else		spin_unlock_irqrestore(&rq->lock, flags);	ah_attr = &to_iah(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;	} else		ipath_skip_sge(&rsge, sizeof(struct ib_grh));	sge = &ss->sge;	while (length) {		u32 len = sge->length;		if (len > length)			len = length;		BUG_ON(len == 0);		ipath_copy_sge(&rsge, sge->vaddr, len);		sge->vaddr += len;		sge->length -= len;		sge->sge_length -= len;		if (sge->sge_length == 0) {			if (--ss->num_sge)				*sge = *ss->sg_list++;		} else if (sge->length == 0 && sge->mr != NULL) {			if (++sge->n >= IPATH_SEGSZ) {				if (++sge->m >= sge->mr->mapsz)					break;				sge->n = 0;			}			sge->vaddr =				sge->mr->map[sge->m]->segs[sge->n].vaddr;			sge->length =				sge->mr->map[sge->m]->segs[sge->n].length;		}		length -= len;	}	wc->status = IB_WC_SUCCESS;	wc->opcode = IB_WC_RECV;	wc->vendor_err = 0;	wc->qp_num = qp->ibqp.qp_num;	wc->src_qp = sqp->ibqp.qp_num;	/* XXX do we know which pkey matched? Only needed for GSI. */	wc->pkey_index = 0;	wc->slid = ipath_layer_get_lid(dev->dd) |		(ah_attr->src_path_bits &		 ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));	wc->sl = ah_attr->sl;	wc->dlid_path_bits =		ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 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);done:	if (atomic_dec_and_test(&qp->refcount))		wake_up(&qp->wait);}/** * ipath_post_ud_send - post a UD send on QP * @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. */int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr){	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;	u32 nwords;	u32 len;	u32 extra_bytes;	u32 bth0;	u16 lrh0;	u16 lid;	int i;	int ret;	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {		ret = 0;		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(&dev->lk_table, 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++;	}	extra_bytes = (4 - len) & 3;	nwords = (len + extra_bytes) >> 2;	/* Construct the header. */	ah_attr = &to_iah(wr->wr.ud.ah)->attr;	if (ah_attr->dlid == 0) {		ret = -EINVAL;		goto bail;	}	if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE) {		if (ah_attr->dlid != IPS_PERMISSIVE_LID)			dev->n_multicast_xmit++;		else			dev->n_unicast_xmit++;	} else {		dev->n_unicast_xmit++;		lid = ah_attr->dlid &			~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);		if (unlikely(lid == ipath_layer_get_lid(dev->dd))) {			/*			 * Pass in an uninitialized ib_wc to save stack			 * space.			 */			ipath_ud_loopback(qp, &ss, len, wr, &wc);			goto done;		}	}	if (ah_attr->ah_flags & IB_AH_GRH) {		/* Header size in 32-bit words. */		hwords = 17;		lrh0 = IPS_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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?