/* * Copyright (c) 2009 Voltaire, Inc. All rights reserved. * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. * Copyright (c) 1996-2003 Intel Corporation. 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. * */ #ifdef OSM_VENDOR_INTF_MTL /* - Mellanox Confidential and Proprietary - * * Copyright (C) Jul. 2001, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. * * Except as specifically permitted herein, no portion of the information, * including but not limited to object code and source code, may be reproduced, * modified, distributed, republished or otherwise exploited in any form or by * any means for any purpose without the prior written permission of Mellanox * Technologies Ltd. Use of software subject to the terms and conditions * detailed in the file "LICENSE.txt". * * End of legal section ...................................................... * * osmt_mtl_regular_qp.c - * Provide Simple Interface for Sending and Receiving MADS through a regular QP * * Creation date: * * Version: $Id$ * * Authors: * Eitan Zahavi * * Changes: */ #include #include #include #include #include #include #include #include #include #include #include #include /* * Initialize the QP etc. * Given in res: port_num, max_outs_sq, max_outs_rq */ VAPI_ret_t osmt_mtl_get_qp_resources(IN OUT osmt_mtl_mad_res_t * res) { VAPI_ret_t ret; VAPI_hca_port_t hca_port_info; VAPI_qp_init_attr_t qp_init_attr; VAPI_qp_prop_t qp_prop; VAPI_cqe_num_t act_num; /* Get HCA LID */ ret = VAPI_query_hca_port_prop(res->hca_hndl, res->port_num, &hca_port_info); VAPI_CHECK_RET; res->slid = hca_port_info.lid; /* Get a PD */ ret = VAPI_alloc_pd(res->hca_hndl, &(res->pd_hndl)); VAPI_CHECK_RET; /* Create CQ for RQ and SQ *//* TBD - Check we have enough act nums */ ret = VAPI_create_cq(res->hca_hndl, res->max_outs_sq + 1, &(res->sq_cq_hndl), &act_num); VAPI_CHECK_RET; ret = VAPI_create_cq(res->hca_hndl, res->max_outs_rq + 1, &(res->rq_cq_hndl), &act_num); VAPI_CHECK_RET; /* register event handlers for polling(block mode) internal use */ /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->rq_cq_hndl, */ /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->rq_cq_eventh)); */ /* VAPI_CHECK_RET; */ /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->sq_cq_hndl, */ /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->sq_cq_eventh)); */ /* VAPI_CHECK_RET; */ /* Create QP */ qp_init_attr.cap.max_oust_wr_sq = res->max_outs_sq + 1; qp_init_attr.cap.max_oust_wr_rq = res->max_outs_rq + 1; qp_init_attr.cap.max_sg_size_sq = 4; qp_init_attr.cap.max_sg_size_rq = 4; qp_init_attr.pd_hndl = res->pd_hndl; qp_init_attr.rdd_hndl = 0; qp_init_attr.rq_cq_hndl = res->rq_cq_hndl; qp_init_attr.rq_sig_type = VAPI_SIGNAL_ALL_WR; /* That's default for IB */ qp_init_attr.sq_cq_hndl = res->sq_cq_hndl; qp_init_attr.sq_sig_type = VAPI_SIGNAL_REQ_WR; qp_init_attr.ts_type = VAPI_TS_UD; ret = VAPI_create_qp(res->hca_hndl, &qp_init_attr, &(res->qp_hndl), &qp_prop); VAPI_CHECK_RET; res->qp_id.qp_num = qp_prop.qp_num; return (VAPI_OK); } VAPI_ret_t osmt_mtl_qp_init(osmt_mtl_mad_res_t * res) { VAPI_ret_t ret; VAPI_qp_attr_t qp_attr; VAPI_qp_attr_mask_t qp_attr_mask; VAPI_qp_cap_t qp_cap; /* * Change QP to INIT * */ QP_ATTR_MASK_CLR_ALL(qp_attr_mask); qp_attr.qp_state = VAPI_INIT; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); qp_attr.pkey_ix = 0; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PKEY_IX); qp_attr.port = res->port_num; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PORT); qp_attr.qkey = res->qkey; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QKEY); /* If I do not set this mask, I get an error from HH. QPM should catch it */ ret = VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, &qp_cap); VAPI_CHECK_RET; return (ret); } VAPI_ret_t osmt_mtl_qp_2_rtr_rts(osmt_mtl_mad_res_t * res) { VAPI_ret_t ret; VAPI_qp_attr_t qp_attr; VAPI_qp_attr_mask_t qp_attr_mask; VAPI_qp_cap_t qp_cap; /* * Change QP to RTR * */ QP_ATTR_MASK_CLR_ALL(qp_attr_mask); qp_attr.qp_state = VAPI_RTR; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); /* qp_attr.rq_psn = 0; */ /* QP_ATTR_MASK_SET(qp_attr_mask,QP_ATTR_RQ_PSN); */ ret = VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, &qp_cap); VAPI_CHECK_RET; /* * Change QP to RTS * */ QP_ATTR_MASK_CLR_ALL(qp_attr_mask); qp_attr.qp_state = VAPI_RTS; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); qp_attr.sq_psn = 0; QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_SQ_PSN); ret = VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, &qp_cap); VAPI_CHECK_RET; return (ret); } VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res) { VAPI_ret_t ret; VAPI_mrw_t mr_in, mr_out; res->buf_size = (MAD_SIZE + GRH_LEN) * (res->max_outs_sq + res->max_outs_rq + 1); /* Register single memory address region for all buffers */ res->buf_ptr = VMALLOC(res->buf_size); if (res->buf_ptr == ((VAPI_virt_addr_t) NULL)) { ret = VAPI_EAGAIN; VAPI_CHECK_RET; } /* Enable local and remote access to memory region */ mr_in.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE; mr_in.l_key = 0; mr_in.pd_hndl = res->pd_hndl; mr_in.r_key = 0; mr_in.size = res->buf_size; ASSERT_VOIDP2UINTN(res->buf_ptr); mr_in.start = (VAPI_virt_addr_t) (res->buf_ptr); mr_in.type = VAPI_MR; ret = VAPI_register_mr(res->hca_hndl, &mr_in, &(res->mr_hndl), &mr_out); VAPI_CHECK_RET; res->l_key = mr_out.l_key; return (ret); } VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res) { VAPI_ret_t ret; res->pd_hndl = VAPI_INVAL_HNDL; res->rq_cq_hndl = VAPI_INVAL_HNDL; res->sq_cq_hndl = VAPI_INVAL_HNDL; res->sq_cq_eventh = VAPI_INVAL_HNDL; res->rq_cq_eventh = VAPI_INVAL_HNDL; res->qp_hndl = VAPI_INVAL_HNDL; res->mr_hndl = VAPI_INVAL_HNDL; /* * Create QP * */ ret = osmt_mtl_get_qp_resources(res); if (ret != VAPI_OK) { return ret; } /* * Move to init * */ ret = osmt_mtl_qp_init(res); if (ret != VAPI_OK) { return ret; } /* * Initialize memory regions * */ ret = osmt_mtl_mad_create_mr(res); if (ret != VAPI_OK) { return ret; } /* only now move to RTR and RTS */ ret = osmt_mtl_qp_2_rtr_rts(res); if (ret != VAPI_OK) { return ret; } return VAPI_OK; } VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res) { if (res->qp_hndl != VAPI_INVAL_HNDL) { VAPI_destroy_qp(res->hca_hndl, res->qp_hndl); } if (res->sq_cq_eventh != VAPI_INVAL_HNDL) { EVAPI_clear_comp_eventh(res->hca_hndl, res->sq_cq_eventh); } if (res->rq_cq_eventh != VAPI_INVAL_HNDL) { EVAPI_clear_comp_eventh(res->hca_hndl, res->rq_cq_eventh); } if (res->rq_cq_hndl != VAPI_INVAL_HNDL) { VAPI_destroy_cq(res->hca_hndl, res->rq_cq_hndl); } if (res->sq_cq_hndl != VAPI_INVAL_HNDL) { VAPI_destroy_cq(res->hca_hndl, res->sq_cq_hndl); } if (res->mr_hndl != VAPI_INVAL_HNDL) { VAPI_deregister_mr(res->hca_hndl, res->mr_hndl); } if (res->pd_hndl != VAPI_INVAL_HNDL) { VAPI_dealloc_pd(res->hca_hndl, res->pd_hndl); } #if 0 /* open/close of HCA should be done system wide - not per application */ if (res->hca_hndl != VAPI_INVAL_HNDL) { VAPI_close_hca(res->hca_hndl); /* TBD: HCA_open/close should be done on a system wide basis */ } #endif return VAPI_OK; } VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, int16_t dlid, VAPI_ud_av_hndl_t * avh_p) { VAPI_ud_av_t av; VAPI_ret_t ret; av.dlid = dlid; av.port = res->port_num; av.sl = 0; /* dest->sl; */ av.src_path_bits = 0; /* dest->ee_dlid.dst_path_bits; */ av.static_rate = 0; /* GRH ? */ av.grh_flag = 0; ret = VAPI_create_addr_hndl(res->hca_hndl, res->pd_hndl, &av, avh_p); if (ret != VAPI_OK) { MTL_ERROR1("%s: failed VAPI_create_addr_hndl (%s)\n", __func__, VAPI_strerror_sym(ret)); return ret; } return VAPI_OK; } VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, VAPI_wr_id_t id, void *mad, VAPI_qp_num_t dest_qp, IB_sl_t sl, u_int32_t dest_qkey, VAPI_ud_av_hndl_t avh) { VAPI_sr_desc_t sr; VAPI_sg_lst_entry_t sg_entry; VAPI_ret_t ret; /* building SEND request */ sr.opcode = VAPI_SEND; sr.remote_ah = avh; sr.remote_qp = dest_qp; sr.remote_qkey = dest_qkey; sr.id = id; sr.set_se = FALSE; sr.fence = FALSE; sr.comp_type = VAPI_SIGNALED; sr.sg_lst_len = 1; sr.sg_lst_p = &sg_entry; ASSERT_VOIDP2UINTN(mad); sg_entry.addr = (VAPI_virt_addr_t) (mad); sg_entry.len = MAD_SIZE; sg_entry.lkey = res->l_key; ret = VAPI_post_sr(res->hca_hndl, res->qp_hndl, &sr); if (ret != VAPI_OK) { MTL_ERROR1(__FUNCTION__ ": failed VAPI_post_sr (%s)\n", VAPI_strerror_sym(ret)); return ret; } return VAPI_OK; } int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, void *buf_array, u_int32_t num_o_bufs, u_int32_t size, VAPI_wr_id_t start_id) { uint32_t i; void *cur_buf; VAPI_rr_desc_t rr; VAPI_sg_lst_entry_t sg_entry; VAPI_ret_t ret; rr.opcode = VAPI_RECEIVE; rr.comp_type = VAPI_SIGNALED; /* All with CQE (IB compliant) */ rr.sg_lst_len = 1; /* single buffers */ rr.sg_lst_p = &sg_entry; sg_entry.lkey = res->l_key; cur_buf = buf_array; for (i = 0; i < num_o_bufs; i++) { rr.id = start_id + i; /* WQE id used is the index to buffers ptr array */ ASSERT_VOIDP2UINTN(cur_buf); sg_entry.addr = (VAPI_virt_addr_t) cur_buf; sg_entry.len = size; memset(cur_buf, 0x00, size); /* fill with 0 */ ret = VAPI_post_rr(res->hca_hndl, res->qp_hndl, &rr); if (ret != VAPI_OK) { MTL_ERROR1(__FUNCTION__ ": failed posting RQ WQE (%s)\n", VAPI_strerror_sym(ret)); return i; } MTL_DEBUG4(__FUNCTION__ ": posted buf at %p\n", cur_buf); cur_buf += size; } return i; /* num of buffers posted */ } VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, VAPI_cq_hndl_t cq, VAPI_wc_desc_t * wc_desc_p, u_int32_t max_poll, u_int32_t poll_sleep, VAPI_ud_av_hndl_t * avh_p) { VAPI_ret_t ret = VAPI_CQ_EMPTY; u_int32_t poll_cnt = 0; /* wait for something to arrive */ while ((ret == VAPI_CQ_EMPTY) && (poll_cnt < max_poll)) { ret = VAPI_poll_cq(hca, cq, wc_desc_p); /* don't sleep if we already succeeded) */ if (ret != VAPI_CQ_EMPTY) { break; } usleep(poll_sleep); poll_cnt++; } /* if passed an AVH to destory - do it */ if (avh_p != NULL) { VAPI_destroy_addr_hndl(hca, *avh_p); } if ((poll_cnt == max_poll) && (ret == VAPI_CQ_EMPTY)) { MTL_DEBUG1(__FUNCTION__ ": Failed to get completion on wq after %d polls.\n", max_poll); return VAPI_CQ_EMPTY; } if (ret != VAPI_OK) { MTL_DEBUG1(__FUNCTION__ ": VAPI_poll_cq failed with ret=%s on sq_cq\n", mtl_strerror_sym(ret)); return ret; } if (wc_desc_p->status != VAPI_SUCCESS) { MTL_DEBUG1(__FUNCTION__ ": completion error (%d) detected\n", wc_desc_p->status); } return VAPI_OK; } #endif /* OSM_VENDOR_INTF_MTL */