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 + -
显示快捷键?