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