📄 ehca_qp.c
字号:
/* * 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 + -