📄 hcp_if.c
字号:
/* * IBM eServer eHCA Infiniband device driver for Linux on POWER * * Firmware Infiniband Interface code for POWER * * Authors: Christoph Raisch <raisch@de.ibm.com> * Hoang-Nam Nguyen <hnguyen@de.ibm.com> * Joachim Fenkes <fenkes@de.ibm.com> * Gerd Bayer <gerd.bayer@de.ibm.com> * Waleri Fomin <fomin@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/hvcall.h>#include "ehca_tools.h"#include "hcp_if.h"#include "hcp_phyp.h"#include "hipz_fns.h"#include "ipz_pt_fn.h"#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)#define H_ALL_RES_QP_STORAGE EHCA_BMASK_IBM(16, 17)#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)#define H_ALL_RES_QP_MAX_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31)#define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32, 39)#define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40, 47)#define H_ALL_RES_QP_UD_AV_LKEY EHCA_BMASK_IBM(32, 63)#define H_ALL_RES_QP_SRQ_QP_TOKEN EHCA_BMASK_IBM(0, 31)#define H_ALL_RES_QP_SRQ_QP_HANDLE EHCA_BMASK_IBM(0, 64)#define H_ALL_RES_QP_SRQ_LIMIT EHCA_BMASK_IBM(48, 63)#define H_ALL_RES_QP_SRQ_QPN EHCA_BMASK_IBM(40, 63)#define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)#define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48, 63)#define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8, 15)#define H_ALL_RES_QP_ACT_RECV_SGE EHCA_BMASK_IBM(24, 31)#define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0, 31)#define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32, 63)#define H_MP_INIT_TYPE EHCA_BMASK_IBM(44, 47)#define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48)#define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49)#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx"#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx"#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx"static DEFINE_SPINLOCK(hcall_lock);static u32 get_longbusy_msecs(int longbusy_rc){ switch (longbusy_rc) { case H_LONG_BUSY_ORDER_1_MSEC: return 1; case H_LONG_BUSY_ORDER_10_MSEC: return 10; case H_LONG_BUSY_ORDER_100_MSEC: return 100; case H_LONG_BUSY_ORDER_1_SEC: return 1000; case H_LONG_BUSY_ORDER_10_SEC: return 10000; case H_LONG_BUSY_ORDER_100_SEC: return 100000; default: return 1; }}static long ehca_plpar_hcall_norets(unsigned long opcode, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7){ long ret; int i, sleep_msecs; unsigned long flags = 0; ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); for (i = 0; i < 5; i++) { /* serialize hCalls to work around firmware issue */ if (ehca_lock_hcalls) spin_lock_irqsave(&hcall_lock, flags); ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7); if (ehca_lock_hcalls) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); continue; } if (ret < H_SUCCESS) ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT, opcode, ret, arg1, arg2, arg3, arg4, arg5, arg6, arg7); else ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret); return ret; } return H_BUSY;}static long ehca_plpar_hcall9(unsigned long opcode, unsigned long *outs, /* array of 9 outputs */ unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, unsigned long arg8, unsigned long arg9){ long ret; int i, sleep_msecs; unsigned long flags = 0; ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); for (i = 0; i < 5; i++) { /* serialize hCalls to work around firmware issue */ if (ehca_lock_hcalls) spin_lock_irqsave(&hcall_lock, flags); ret = plpar_hcall9(opcode, outs, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); if (ehca_lock_hcalls) spin_unlock_irqrestore(&hcall_lock, flags); if (H_IS_LONG_BUSY(ret)) { sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); continue; } if (ret < H_SUCCESS) { ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, ret, outs[0], outs[1], outs[2], outs[3], outs[4], outs[5], outs[6], outs[7], outs[8]); } else ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT, ret, outs[0], outs[1], outs[2], outs[3], outs[4], outs[5], outs[6], outs[7], outs[8]); return ret; } return H_BUSY;}u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle, struct ehca_pfeq *pfeq, const u32 neq_control, const u32 number_of_entries, struct ipz_eq_handle *eq_handle, u32 *act_nr_of_entries, u32 *act_pages, u32 *eq_ist){ u64 ret; u64 outs[PLPAR_HCALL9_BUFSIZE]; u64 allocate_controls; /* resource type */ allocate_controls = 3ULL; /* ISN is associated */ if (neq_control != 1) allocate_controls = (1ULL << (63 - 7)) | allocate_controls; else /* notification event queue */ allocate_controls = (1ULL << 63) | allocate_controls; ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, adapter_handle.handle, /* r4 */ allocate_controls, /* r5 */ number_of_entries, /* r6 */ 0, 0, 0, 0, 0, 0); eq_handle->handle = outs[0]; *act_nr_of_entries = (u32)outs[3]; *act_pages = (u32)outs[4]; *eq_ist = (u32)outs[5]; if (ret == H_NOT_ENOUGH_RESOURCES) ehca_gen_err("Not enough resource - ret=%li ", ret); return ret;}u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle, struct ipz_eq_handle eq_handle, const u64 event_mask){ return ehca_plpar_hcall_norets(H_RESET_EVENTS, adapter_handle.handle, /* r4 */ eq_handle.handle, /* r5 */ event_mask, /* r6 */ 0, 0, 0, 0);}u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle, struct ehca_cq *cq, struct ehca_alloc_cq_parms *param){ u64 ret; u64 outs[PLPAR_HCALL9_BUFSIZE]; ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, adapter_handle.handle, /* r4 */ 2, /* r5 */ param->eq_handle.handle, /* r6 */ cq->token, /* r7 */ param->nr_cqe, /* r8 */ 0, 0, 0, 0); cq->ipz_cq_handle.handle = outs[0]; param->act_nr_of_entries = (u32)outs[3]; param->act_pages = (u32)outs[4]; if (ret == H_SUCCESS) hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) ehca_gen_err("Not enough resources. ret=%li", ret); return ret;}u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle, struct ehca_alloc_qp_parms *parms){ u64 ret; u64 allocate_controls, max_r10_reg, r11, r12; u64 outs[PLPAR_HCALL9_BUFSIZE]; allocate_controls = EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS, parms->ext_type) | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0) | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype) | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype) | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage) | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE, parms->squeue.page_size) | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE, parms->rqueue.page_size) | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING, !!(parms->ll_comp_flags & LLQP_RECV_COMP)) | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING, !!(parms->ll_comp_flags & LLQP_SEND_COMP)) | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL, parms->ud_av_l_key_ctl) | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1); max_r10_reg = EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR, parms->squeue.max_wr + 1) | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR, parms->rqueue.max_wr + 1) | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE, parms->squeue.max_sge) | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE, parms->rqueue.max_sge); r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token); if (parms->ext_type == EQPT_SRQ) r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_LIMIT, parms->srq_limit); else r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QPN, parms->srq_qpn); ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs, adapter_handle.handle, /* r4 */ allocate_controls, /* r5 */ parms->send_cq_handle.handle, parms->recv_cq_handle.handle, parms->eq_handle.handle, ((u64)parms->token << 32) | parms->pd.value, max_r10_reg, r11, r12); parms->qp_handle.handle = outs[0]; parms->real_qp_num = (u32)outs[1]; parms->squeue.act_nr_wqes = (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]); parms->rqueue.act_nr_wqes = (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]); parms->squeue.act_nr_sges = (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]); parms->rqueue.act_nr_sges = (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]); parms->squeue.queue_size = (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]); parms->rqueue.queue_size = (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]); if (ret == H_SUCCESS) hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]); if (ret == H_NOT_ENOUGH_RESOURCES) ehca_gen_err("Not enough resources. ret=%li", ret); return ret;}u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, const u8 port_id, struct hipz_query_port *query_port_response_block){ u64 ret; u64 r_cb = virt_to_abs(query_port_response_block); if (r_cb & (EHCA_PAGESIZE-1)) { ehca_gen_err("response block not page aligned"); return H_PARAMETER; } ret = ehca_plpar_hcall_norets(H_QUERY_PORT, adapter_handle.handle, /* r4 */ port_id, /* r5 */ r_cb, /* r6 */ 0, 0, 0, 0); if (ehca_debug_level) ehca_dmp(query_port_response_block, 64, "response_block"); return ret;}u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle, const u8 port_id, const u32 port_cap, const u8 init_type, const int modify_mask){ u64 port_attributes = port_cap; if (modify_mask & IB_PORT_SHUTDOWN) port_attributes |= EHCA_BMASK_SET(H_MP_SHUTDOWN, 1); if (modify_mask & IB_PORT_INIT_TYPE) port_attributes |= EHCA_BMASK_SET(H_MP_INIT_TYPE, init_type); if (modify_mask & IB_PORT_RESET_QKEY_CNTR) port_attributes |= EHCA_BMASK_SET(H_MP_RESET_QKEY_CTR, 1); return ehca_plpar_hcall_norets(H_MODIFY_PORT, adapter_handle.handle, /* r4 */ port_id, /* r5 */ port_attributes, /* r6 */ 0, 0, 0, 0);}u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, struct hipz_query_hca *query_hca_rblock){ u64 r_cb = virt_to_abs(query_hca_rblock); if (r_cb & (EHCA_PAGESIZE-1)) { ehca_gen_err("response_block=%p not page aligned", query_hca_rblock); return H_PARAMETER; } return ehca_plpar_hcall_norets(H_QUERY_HCA, adapter_handle.handle, /* r4 */ r_cb, /* r5 */ 0, 0, 0, 0, 0);}u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle, const u8 pagesize, const u8 queue_type, const u64 resource_handle, const u64 logical_address_of_page, u64 count){ return ehca_plpar_hcall_norets(H_REGISTER_RPAGES, adapter_handle.handle, /* r4 */ (u64)queue_type | ((u64)pagesize) << 8, /* r5 */ resource_handle, /* r6 */ logical_address_of_page, /* r7 */ count, /* r8 */ 0, 0);}u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle, const struct ipz_eq_handle eq_handle, struct ehca_pfeq *pfeq, const u8 pagesize, const u8 queue_type, const u64 logical_address_of_page, const u64 count){ if (count != 1) { ehca_gen_err("Ppage counter=%lx", count); return H_PARAMETER; } return hipz_h_register_rpage(adapter_handle, pagesize, queue_type, eq_handle.handle, logical_address_of_page, count);}u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle, u32 ist){ u64 ret; ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE, adapter_handle.handle, /* r4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -