ipath_verbs.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,205 行 · 第 1/3 页
C
1,205 行
/* * 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_mad.h>#include <rdma/ib_user_verbs.h>#include <linux/utsname.h>#include "ipath_kernel.h"#include "ipath_verbs.h"#include "ips_common.h"/* Not static, because we don't want the compiler removing it */const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR;static unsigned int ib_ipath_qp_table_size = 251;module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO);MODULE_PARM_DESC(qp_table_size, "QP table size");unsigned int ib_ipath_lkey_table_size = 12;module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint, S_IRUGO);MODULE_PARM_DESC(lkey_table_size, "LKEY table size in bits (2^n, 1 <= n <= 23)");unsigned int ib_ipath_debug; /* debug mask */module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(debug, "Verbs debug mask");MODULE_LICENSE("GPL");MODULE_AUTHOR("PathScale <support@pathscale.com>");MODULE_DESCRIPTION("Pathscale InfiniPath driver");const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { [IB_QPS_RESET] = 0, [IB_QPS_INIT] = IPATH_POST_RECV_OK, [IB_QPS_RTR] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, [IB_QPS_RTS] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK, [IB_QPS_SQD] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | IPATH_POST_SEND_OK, [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, [IB_QPS_ERR] = 0,};/* * Translate ib_wr_opcode into ib_wc_opcode. */const enum ib_wc_opcode ib_ipath_wc_opcode[] = { [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, [IB_WR_SEND] = IB_WC_SEND, [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD};/* * System image GUID. */static __be64 sys_image_guid;/** * ipath_copy_sge - copy data to SGE memory * @ss: the SGE state * @data: the data to copy * @length: the length of the data */void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length){ struct ipath_sge *sge = &ss->sge; while (length) { u32 len = sge->length; BUG_ON(len == 0); if (len > length) len = length; memcpy(sge->vaddr, data, 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; } data += len; length -= len; }}/** * ipath_skip_sge - skip over SGE memory - XXX almost dup of prev func * @ss: the SGE state * @length: the number of bytes to skip */void ipath_skip_sge(struct ipath_sge_state *ss, u32 length){ struct ipath_sge *sge = &ss->sge; while (length > sge->sge_length) { length -= sge->sge_length; ss->sge = *ss->sg_list++; } while (length) { u32 len = sge->length; BUG_ON(len == 0); if (len > length) len = length; 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; }}/** * ipath_post_send - post a send on a QP * @ibqp: the QP to post the send on * @wr: the list of work requests to post * @bad_wr: the first bad WR is put here * * This may be called from interrupt context. */static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_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_rc_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; } if (err) { *bad_wr = wr; break; } }bail: return err;}/** * ipath_post_receive - post a receive on a QP * @ibqp: the QP to post the receive on * @wr: the WR to post * @bad_wr: the first bad WR is put here * * This may be called from interrupt context. */static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, struct ib_recv_wr **bad_wr){ struct ipath_qp *qp = to_iqp(ibqp); unsigned long flags; int ret; /* Check that state is OK to post receive. */ if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) { *bad_wr = wr; ret = -EINVAL; goto bail; } for (; wr; wr = wr->next) { struct ipath_rwqe *wqe; u32 next; int i, j; if (wr->num_sge > qp->r_rq.max_sge) { *bad_wr = wr; ret = -ENOMEM; goto bail; } spin_lock_irqsave(&qp->r_rq.lock, flags); next = qp->r_rq.head + 1; if (next >= qp->r_rq.size) next = 0; if (next == qp->r_rq.tail) { spin_unlock_irqrestore(&qp->r_rq.lock, flags); *bad_wr = wr; ret = -ENOMEM; goto bail; } wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head); wqe->wr_id = wr->wr_id; 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; for (i = 0, j = 0; i < wr->num_sge; i++) { /* Check LKEY */ if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { spin_unlock_irqrestore(&qp->r_rq.lock, flags); *bad_wr = wr; ret = -EINVAL; goto bail; } if (wr->sg_list[i].length == 0) continue; if (!ipath_lkey_ok( &to_idev(qp->ibqp.device)->lk_table, &wqe->sg_list[j], &wr->sg_list[i], IB_ACCESS_LOCAL_WRITE)) { spin_unlock_irqrestore(&qp->r_rq.lock, flags); *bad_wr = wr; ret = -EINVAL; goto bail; } wqe->length += wr->sg_list[i].length; j++; } wqe->num_sge = j; qp->r_rq.head = next; spin_unlock_irqrestore(&qp->r_rq.lock, flags); } ret = 0;bail: return ret;}/** * ipath_qp_rcv - processing an incoming packet on a QP * @dev: the device the packet came on * @hdr: the packet header * @has_grh: true if the packet has a GRH * @data: the packet data * @tlen: the packet length * @qp: the QP the packet came on * * This is called from ipath_ib_rcv() to process an incoming packet * for the given QP. * Called at interrupt level. */static void ipath_qp_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, int has_grh, void *data, u32 tlen, struct ipath_qp *qp){ /* Check for valid receive state. */ if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) { dev->n_pkt_drops++; return; } switch (qp->ibqp.qp_type) { case IB_QPT_SMI: case IB_QPT_GSI: case IB_QPT_UD: ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); break; case IB_QPT_RC: ipath_rc_rcv(dev, hdr, has_grh, data, tlen, qp); break; case IB_QPT_UC: ipath_uc_rcv(dev, hdr, has_grh, data, tlen, qp); break; default: break; }}/** * ipath_ib_rcv - process and incoming packet * @arg: the device pointer * @rhdr: the header of the packet * @data: the packet data * @tlen: the packet length * * This is called from ipath_kreceive() to process an incoming packet at * interrupt level. Tlen is the length of the header + data + CRC in bytes. */static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen){ struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; struct ipath_ib_header *hdr = rhdr; struct ipath_other_headers *ohdr; struct ipath_qp *qp; u32 qp_num; int lnh; u8 opcode; u16 lid; if (unlikely(dev == NULL)) goto bail; if (unlikely(tlen < 24)) { /* LRH+BTH+CRC */ dev->rcv_errors++; goto bail; } /* Check for a valid destination LID (see ch. 7.11.1). */ lid = be16_to_cpu(hdr->lrh[1]); if (lid < IPS_MULTICAST_LID_BASE) { lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); if (unlikely(lid != ipath_layer_get_lid(dev->dd))) { dev->rcv_errors++; goto bail; } } /* Check for GRH */ lnh = be16_to_cpu(hdr->lrh[0]) & 3; if (lnh == IPS_LRH_BTH) ohdr = &hdr->u.oth; else if (lnh == IPS_LRH_GRH) ohdr = &hdr->u.l.oth; else { dev->rcv_errors++; goto bail; } opcode = be32_to_cpu(ohdr->bth[0]) >> 24; dev->opstats[opcode].n_bytes += tlen; dev->opstats[opcode].n_packets++; /* Get the destination QP number. */ qp_num = be32_to_cpu(ohdr->bth[1]) & IPS_QPN_MASK;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?