⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehca_qp.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  IBM eServer eHCA Infiniband device driver for Linux on POWER * *  QP functions * *  Authors: Joachim Fenkes <fenkes@de.ibm.com> *           Stefan Roscher <stefan.roscher@de.ibm.com> *           Waleri Fomin <fomin@de.ibm.com> *           Hoang-Nam Nguyen <hnguyen@de.ibm.com> *           Reinhard Ernst <rernst@de.ibm.com> *           Heiko J Schick <schickhj@de.ibm.com> * *  Copyright (c) 2005 IBM Corporation * *  All rights reserved. * *  This source code is distributed under a dual license of GPL v2.0 and OpenIB *  BSD. * * OpenIB BSD License * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <asm/current.h>#include "ehca_classes.h"#include "ehca_tools.h"#include "ehca_qes.h"#include "ehca_iverbs.h"#include "hcp_if.h"#include "hipz_fns.h"static struct kmem_cache *qp_cache;/* * attributes not supported by query qp */#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \				     IB_QP_MAX_QP_RD_ATOMIC   | \				     IB_QP_ACCESS_FLAGS       | \				     IB_QP_EN_SQD_ASYNC_NOTIFY)/* * ehca (internal) qp state values */enum ehca_qp_state {	EHCA_QPS_RESET = 1,	EHCA_QPS_INIT = 2,	EHCA_QPS_RTR = 3,	EHCA_QPS_RTS = 5,	EHCA_QPS_SQD = 6,	EHCA_QPS_SQE = 8,	EHCA_QPS_ERR = 128};/* * qp state transitions as defined by IB Arch Rel 1.1 page 431 */enum ib_qp_statetrans {	IB_QPST_ANY2RESET,	IB_QPST_ANY2ERR,	IB_QPST_RESET2INIT,	IB_QPST_INIT2RTR,	IB_QPST_INIT2INIT,	IB_QPST_RTR2RTS,	IB_QPST_RTS2SQD,	IB_QPST_RTS2RTS,	IB_QPST_SQD2RTS,	IB_QPST_SQE2RTS,	IB_QPST_SQD2SQD,	IB_QPST_MAX	/* nr of transitions, this must be last!!! */};/* * ib2ehca_qp_state maps IB to ehca qp_state * returns ehca qp state corresponding to given ib qp state */static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state){	switch (ib_qp_state) {	case IB_QPS_RESET:		return EHCA_QPS_RESET;	case IB_QPS_INIT:		return EHCA_QPS_INIT;	case IB_QPS_RTR:		return EHCA_QPS_RTR;	case IB_QPS_RTS:		return EHCA_QPS_RTS;	case IB_QPS_SQD:		return EHCA_QPS_SQD;	case IB_QPS_SQE:		return EHCA_QPS_SQE;	case IB_QPS_ERR:		return EHCA_QPS_ERR;	default:		ehca_gen_err("invalid ib_qp_state=%x", ib_qp_state);		return -EINVAL;	}}/* * ehca2ib_qp_state maps ehca to IB qp_state * returns ib qp state corresponding to given ehca qp state */static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state						ehca_qp_state){	switch (ehca_qp_state) {	case EHCA_QPS_RESET:		return IB_QPS_RESET;	case EHCA_QPS_INIT:		return IB_QPS_INIT;	case EHCA_QPS_RTR:		return IB_QPS_RTR;	case EHCA_QPS_RTS:		return IB_QPS_RTS;	case EHCA_QPS_SQD:		return IB_QPS_SQD;	case EHCA_QPS_SQE:		return IB_QPS_SQE;	case EHCA_QPS_ERR:		return IB_QPS_ERR;	default:		ehca_gen_err("invalid ehca_qp_state=%x", ehca_qp_state);		return -EINVAL;	}}/* * ehca_qp_type used as index for req_attr and opt_attr of * struct ehca_modqp_statetrans */enum ehca_qp_type {	QPT_RC = 0,	QPT_UC = 1,	QPT_UD = 2,	QPT_SQP = 3,	QPT_MAX};/* * ib2ehcaqptype maps Ib to ehca qp_type * returns ehca qp type corresponding to ib qp type */static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype){	switch (ibqptype) {	case IB_QPT_SMI:	case IB_QPT_GSI:		return QPT_SQP;	case IB_QPT_RC:		return QPT_RC;	case IB_QPT_UC:		return QPT_UC;	case IB_QPT_UD:		return QPT_UD;	default:		ehca_gen_err("Invalid ibqptype=%x", ibqptype);		return -EINVAL;	}}static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,							 int ib_tostate){	int index = -EINVAL;	switch (ib_tostate) {	case IB_QPS_RESET:		index = IB_QPST_ANY2RESET;		break;	case IB_QPS_INIT:		switch (ib_fromstate) {		case IB_QPS_RESET:			index = IB_QPST_RESET2INIT;			break;		case IB_QPS_INIT:			index = IB_QPST_INIT2INIT;			break;		}		break;	case IB_QPS_RTR:		if (ib_fromstate == IB_QPS_INIT)			index = IB_QPST_INIT2RTR;		break;	case IB_QPS_RTS:		switch (ib_fromstate) {		case IB_QPS_RTR:			index = IB_QPST_RTR2RTS;			break;		case IB_QPS_RTS:			index = IB_QPST_RTS2RTS;			break;		case IB_QPS_SQD:			index = IB_QPST_SQD2RTS;			break;		case IB_QPS_SQE:			index = IB_QPST_SQE2RTS;			break;		}		break;	case IB_QPS_SQD:		if (ib_fromstate == IB_QPS_RTS)			index = IB_QPST_RTS2SQD;		break;	case IB_QPS_SQE:		break;	case IB_QPS_ERR:		index = IB_QPST_ANY2ERR;		break;	default:		break;	}	return index;}/* * ibqptype2servicetype returns hcp service type corresponding to given * ib qp type used by create_qp() */static inline int ibqptype2servicetype(enum ib_qp_type ibqptype){	switch (ibqptype) {	case IB_QPT_SMI:	case IB_QPT_GSI:		return ST_UD;	case IB_QPT_RC:		return ST_RC;	case IB_QPT_UC:		return ST_UC;	case IB_QPT_UD:		return ST_UD;	case IB_QPT_RAW_IPV6:		return -EINVAL;	case IB_QPT_RAW_ETY:		return -EINVAL;	default:		ehca_gen_err("Invalid ibqptype=%x", ibqptype);		return -EINVAL;	}}/* * init userspace queue info from ipz_queue data */static inline void queue2resp(struct ipzu_queue_resp *resp,			      struct ipz_queue *queue){	resp->qe_size = queue->qe_size;	resp->act_nr_of_sg = queue->act_nr_of_sg;	resp->queue_length = queue->queue_length;	resp->pagesize = queue->pagesize;	resp->toggle_state = queue->toggle_state;	resp->offset = queue->offset;}/* * init_qp_queue initializes/constructs r/squeue and registers queue pages. */static inline int init_qp_queue(struct ehca_shca *shca,				struct ehca_pd *pd,				struct ehca_qp *my_qp,				struct ipz_queue *queue,				int q_type,				u64 expected_hret,				struct ehca_alloc_queue_parms *parms,				int wqe_size){	int ret, cnt, ipz_rc, nr_q_pages;	void *vpage;	u64 rpage, h_ret;	struct ib_device *ib_dev = &shca->ib_device;	struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;	if (!parms->queue_size)		return 0;	if (parms->is_small) {		nr_q_pages = 1;		ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,					128 << parms->page_size,					wqe_size, parms->act_nr_sges, 1);	} else {		nr_q_pages = parms->queue_size;		ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,					EHCA_PAGESIZE, wqe_size,					parms->act_nr_sges, 0);	}	if (!ipz_rc) {		ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i",			 ipz_rc);		return -EBUSY;	}	/* register queue pages */	for (cnt = 0; cnt < nr_q_pages; cnt++) {		vpage = ipz_qpageit_get_inc(queue);		if (!vpage) {			ehca_err(ib_dev, "ipz_qpageit_get_inc() "				 "failed p_vpage= %p", vpage);			ret = -EINVAL;			goto init_qp_queue1;		}		rpage = virt_to_abs(vpage);		h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,						 my_qp->ipz_qp_handle,						 NULL, 0, q_type,						 rpage, parms->is_small ? 0 : 1,						 my_qp->galpas.kernel);		if (cnt == (nr_q_pages - 1)) {	/* last page! */			if (h_ret != expected_hret) {				ehca_err(ib_dev, "hipz_qp_register_rpage() "					 "h_ret=%li", h_ret);				ret = ehca2ib_return_code(h_ret);				goto init_qp_queue1;			}			vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);			if (vpage) {				ehca_err(ib_dev, "ipz_qpageit_get_inc() "					 "should not succeed vpage=%p", vpage);				ret = -EINVAL;				goto init_qp_queue1;			}		} else {			if (h_ret != H_PAGE_REGISTERED) {				ehca_err(ib_dev, "hipz_qp_register_rpage() "					 "h_ret=%li", h_ret);				ret = ehca2ib_return_code(h_ret);				goto init_qp_queue1;			}		}	}	ipz_qeit_reset(queue);	return 0;init_qp_queue1:	ipz_queue_dtor(pd, queue);	return ret;}static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp){	if (is_llqp)		return 128 << act_nr_sge;	else		return offsetof(struct ehca_wqe,				u.nud.sg_list[act_nr_sge]);}static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,				       int req_nr_sge, int is_llqp){	u32 wqe_size, q_size;	int act_nr_sge = req_nr_sge;	if (!is_llqp)		/* round up #SGEs so WQE size is a power of 2 */		for (act_nr_sge = 4; act_nr_sge <= 252;		     act_nr_sge = 4 + 2 * act_nr_sge)			if (act_nr_sge >= req_nr_sge)				break;	wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);	q_size = wqe_size * (queue->max_wr + 1);	if (q_size <= 512)		queue->page_size = 2;	else if (q_size <= 1024)		queue->page_size = 3;	else		queue->page_size = 0;	queue->is_small = (queue->page_size != 0);}/* * Create an ib_qp struct that is either a QP or an SRQ, depending on * the value of the is_srq parameter. If init_attr and srq_init_attr share * fields, the field out of init_attr is used. */static struct ehca_qp *internal_create_qp(	struct ib_pd *pd,	struct ib_qp_init_attr *init_attr,	struct ib_srq_init_attr *srq_init_attr,	struct ib_udata *udata, int is_srq){	struct ehca_qp *my_qp;	struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);	struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,					      ib_device);	struct ib_ucontext *context = NULL;	u64 h_ret;	int is_llqp = 0, has_srq = 0;	int qp_type, max_send_sge, max_recv_sge, ret;	/* h_call's out parameters */	struct ehca_alloc_qp_parms parms;	u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;	unsigned long flags;	memset(&parms, 0, sizeof(parms));	qp_type = init_attr->qp_type;	if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&		init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {		ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",			 init_attr->sq_sig_type);		return ERR_PTR(-EINVAL);	}	/* save LLQP info */	if (qp_type & 0x80) {		is_llqp = 1;		parms.ext_type = EQPT_LLQP;		parms.ll_comp_flags = qp_type & LLQP_COMP_MASK;	}	qp_type &= 0x1F;	init_attr->qp_type &= 0x1F;	/* handle SRQ base QPs */	if (init_attr->srq) {		struct ehca_qp *my_srq =			container_of(init_attr->srq, struct ehca_qp, ib_srq);		has_srq = 1;		parms.ext_type = EQPT_SRQBASE;		parms.srq_qpn = my_srq->real_qp_num;	}	if (is_llqp && has_srq) {		ehca_err(pd->device, "LLQPs can't have an SRQ");		return ERR_PTR(-EINVAL);	}	/* handle SRQs */	if (is_srq) {		parms.ext_type = EQPT_SRQ;		parms.srq_limit = srq_init_attr->attr.srq_limit;		if (init_attr->cap.max_recv_sge > 3) {			ehca_err(pd->device, "no more than three SGEs "				 "supported for SRQ  pd=%p  max_sge=%x",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -