ipath_ud.c

来自「linux 内核源代码」· C语言 代码 · 共 563 行 · 第 1/2 页

C
563
字号
/* * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. * 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 "ipath_kernel.h"/** * ipath_ud_loopback - handle send on loopback QPs * @sqp: the sending QP * @swqe: the send work request * * 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_swqe *swqe){	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_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, 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).	 * 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) 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 drop;	}	/*	 * A GRH is expected to preceed the data even if not	 * present on the wire.	 */	length = swqe->length;	wc.byte_len = length + sizeof(struct ib_grh);	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;	}	/*	 * 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);		handler = srq->ibsrq.event_handler;		rq = &srq->rq;	} else {		srq = NULL;		handler = NULL;		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;	/* 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 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;	if (handler) {		u32 n;		/*		 * validate head pointer value and compute		 * the number of remaining WQEs.		 */		n = wq->head;		if (n >= rq->size)			n = 0;		if (n < tail)			n += rq->size - tail;		else			n -= 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;			handler(&ev, srq->ibsrq.srq_context);		} else			spin_unlock_irqrestore(&rq->lock, flags);	} else		spin_unlock_irqrestore(&rq->lock, flags);	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;	} else		ipath_skip_sge(&rsge, sizeof(struct ib_grh));	sge = swqe->sg_list;	while (length) {		u32 len = sge->length;		if (len > length)			len = length;		if (len > sge->sge_length)			len = sge->sge_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 (--swqe->wr.num_sge)				sge++;		} 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 = &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 |		(ah_attr->src_path_bits &		 ((1 << dev->dd->ipath_lmc) - 1));	wc.sl = ah_attr->sl;	wc.dlid_path_bits =		ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1);	wc.port_num = 1;	/* Signal completion event if the solicited bit is set. */	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,		       swqe->wr.send_flags & IB_SEND_SOLICITED);drop:	kfree(rsge.sg_list);	if (atomic_dec_and_test(&qp->refcount))		wake_up(&qp->wait);send_comp:	ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);}/** * ipath_make_ud_req - construct a UD request packet * @qp: the QP * * Return 1 if constructed; otherwise, return 0. */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_swqe *wqe;	u32 nwords;	u32 extra_bytes;	u32 bth0;	u16 lrh0;	u16 lid;	int ret = 0;	if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))		goto bail;	if (qp->s_cur == qp->s_head)		goto bail;	wqe = get_swqe_ptr(qp, qp->s_cur);	/* Construct the header. */

⌨️ 快捷键说明

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