ipath_verbs.c
来自「linux 内核源代码」· C语言 代码 · 共 1,887 行 · 第 1/4 页
C
1,887 行
/* * 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_mad.h>#include <rdma/ib_user_verbs.h>#include <linux/io.h>#include <linux/utsname.h>#include "ipath_kernel.h"#include "ipath_verbs.h"#include "ipath_common.h"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)");static unsigned int ib_ipath_max_pds = 0xFFFF;module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_pds, "Maximum number of protection domains to support");static unsigned int ib_ipath_max_ahs = 0xFFFF;module_param_named(max_ahs, ib_ipath_max_ahs, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_ahs, "Maximum number of address handles to support");unsigned int ib_ipath_max_cqes = 0x2FFFF;module_param_named(max_cqes, ib_ipath_max_cqes, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_cqes, "Maximum number of completion queue entries to support");unsigned int ib_ipath_max_cqs = 0x1FFFF;module_param_named(max_cqs, ib_ipath_max_cqs, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_cqs, "Maximum number of completion queues to support");unsigned int ib_ipath_max_qp_wrs = 0x3FFF;module_param_named(max_qp_wrs, ib_ipath_max_qp_wrs, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support");unsigned int ib_ipath_max_qps = 16384;module_param_named(max_qps, ib_ipath_max_qps, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support");unsigned int ib_ipath_max_sges = 0x60;module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support");unsigned int ib_ipath_max_mcast_grps = 16384;module_param_named(max_mcast_grps, ib_ipath_max_mcast_grps, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_mcast_grps, "Maximum number of multicast groups to support");unsigned int ib_ipath_max_mcast_qp_attached = 16;module_param_named(max_mcast_qp_attached, ib_ipath_max_mcast_qp_attached, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_mcast_qp_attached, "Maximum number of attached QPs to support");unsigned int ib_ipath_max_srqs = 1024;module_param_named(max_srqs, ib_ipath_max_srqs, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_srqs, "Maximum number of SRQs to support");unsigned int ib_ipath_max_srq_sges = 128;module_param_named(max_srq_sges, ib_ipath_max_srq_sges, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_srq_sges, "Maximum number of SRQ SGEs to support");unsigned int ib_ipath_max_srq_wrs = 0x1FFFF;module_param_named(max_srq_wrs, ib_ipath_max_srq_wrs, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support");static unsigned int ib_ipath_disable_sma;module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(ib_ipath_disable_sma, "Disable the SMA");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,};struct ipath_ucontext { struct ib_ucontext ibucontext;};static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext *ibucontext){ return container_of(ibucontext, struct ipath_ucontext, ibucontext);}/* * 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; if (len > length) len = length; if (len > sge->sge_length) len = sge->sge_length; BUG_ON(len == 0); 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) { u32 len = sge->length; if (len > length) len = length; if (len > sge->sge_length) len = sge->sge_length; BUG_ON(len == 0); 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; }}static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr){ struct ib_wc wc; memset(&wc, 0, sizeof(wc)); wc.wr_id = wr->wr_id; wc.status = IB_WC_WR_FLUSH_ERR; wc.opcode = ib_ipath_wc_opcode[wr->opcode]; wc.qp = &qp->ibqp; ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);}/** * 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 (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) { if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR) goto bail_inval; /* C10-96 says generate a flushed completion entry. */ ipath_flush_wqe(qp, wr); ret = 0; goto bail; } /* 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) { ret = -ENOMEM; goto bail; } 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 * @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; for (; wr; wr = wr->next) { err = ipath_post_one_send(qp, wr); if (err) { *bad_wr = wr; goto bail; } } /* Try to do the send work in the caller's context. */ ipath_do_send((unsigned long) qp);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); struct ipath_rwq *wq = qp->r_rq.wq; unsigned long flags; int ret; /* Check that state is OK to post receive. */ if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK) || !wq) { *bad_wr = wr; ret = -EINVAL; goto bail; } for (; wr; wr = wr->next) { struct ipath_rwqe *wqe; u32 next; int i; if ((unsigned) wr->num_sge > qp->r_rq.max_sge) { *bad_wr = wr; ret = -EINVAL; goto bail; } spin_lock_irqsave(&qp->r_rq.lock, flags); next = wq->head + 1; if (next >= qp->r_rq.size) next = 0; if (next == wq->tail) { spin_unlock_irqrestore(&qp->r_rq.lock, flags); *bad_wr = wr; ret = -ENOMEM; goto bail; } wqe = get_rwqe_ptr(&qp->r_rq, wq->head); wqe->wr_id = wr->wr_id; wqe->num_sge = wr->num_sge; for (i = 0; i < wr->num_sge; i++) wqe->sg_list[i] = wr->sg_list[i]; /* Make sure queue entry is written before the head index. */ smp_wmb(); wq->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: if (ib_ipath_disable_sma) break; /* FALLTHROUGH */ case IB_QPT_UD: ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?