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