162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This software is available to you under a choice of one of two 962306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 1062306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1162306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1262306a36Sopenharmony_ci * OpenIB.org BSD license below: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1562306a36Sopenharmony_ci * without modification, are permitted provided that the following 1662306a36Sopenharmony_ci * conditions are met: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2362306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2462306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2562306a36Sopenharmony_ci * provided with the distribution. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2862306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2962306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 3062306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3162306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3262306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3362306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3462306a36Sopenharmony_ci * SOFTWARE. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <rdma/ib_smi.h> 3862306a36Sopenharmony_ci#include <rdma/ib_umem.h> 3962306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 4062306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <linux/sched.h> 4362306a36Sopenharmony_ci#include <linux/slab.h> 4462306a36Sopenharmony_ci#include <linux/stat.h> 4562306a36Sopenharmony_ci#include <linux/mm.h> 4662306a36Sopenharmony_ci#include <linux/export.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "mthca_dev.h" 4962306a36Sopenharmony_ci#include "mthca_cmd.h" 5062306a36Sopenharmony_ci#include <rdma/mthca-abi.h> 5162306a36Sopenharmony_ci#include "mthca_memfree.h" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props, 5462306a36Sopenharmony_ci struct ib_udata *uhw) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct ib_smp *in_mad; 5762306a36Sopenharmony_ci struct ib_smp *out_mad; 5862306a36Sopenharmony_ci int err = -ENOMEM; 5962306a36Sopenharmony_ci struct mthca_dev *mdev = to_mdev(ibdev); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (uhw->inlen || uhw->outlen) 6262306a36Sopenharmony_ci return -EINVAL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); 6562306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 6662306a36Sopenharmony_ci if (!in_mad || !out_mad) 6762306a36Sopenharmony_ci goto out; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci memset(props, 0, sizeof *props); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci props->fw_ver = mdev->fw_ver; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci ib_init_query_mad(in_mad); 7462306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci err = mthca_MAD_IFC(mdev, 1, 1, 7762306a36Sopenharmony_ci 1, NULL, NULL, in_mad, out_mad); 7862306a36Sopenharmony_ci if (err) 7962306a36Sopenharmony_ci goto out; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci props->device_cap_flags = mdev->device_cap_flags; 8262306a36Sopenharmony_ci props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & 8362306a36Sopenharmony_ci 0xffffff; 8462306a36Sopenharmony_ci props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); 8562306a36Sopenharmony_ci props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); 8662306a36Sopenharmony_ci memcpy(&props->sys_image_guid, out_mad->data + 4, 8); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci props->max_mr_size = ~0ull; 8962306a36Sopenharmony_ci props->page_size_cap = mdev->limits.page_size_cap; 9062306a36Sopenharmony_ci props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; 9162306a36Sopenharmony_ci props->max_qp_wr = mdev->limits.max_wqes; 9262306a36Sopenharmony_ci props->max_send_sge = mdev->limits.max_sg; 9362306a36Sopenharmony_ci props->max_recv_sge = mdev->limits.max_sg; 9462306a36Sopenharmony_ci props->max_sge_rd = mdev->limits.max_sg; 9562306a36Sopenharmony_ci props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; 9662306a36Sopenharmony_ci props->max_cqe = mdev->limits.max_cqes; 9762306a36Sopenharmony_ci props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; 9862306a36Sopenharmony_ci props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; 9962306a36Sopenharmony_ci props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; 10062306a36Sopenharmony_ci props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; 10162306a36Sopenharmony_ci props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; 10262306a36Sopenharmony_ci props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; 10362306a36Sopenharmony_ci props->max_srq_wr = mdev->limits.max_srq_wqes; 10462306a36Sopenharmony_ci props->max_srq_sge = mdev->limits.max_srq_sge; 10562306a36Sopenharmony_ci props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; 10662306a36Sopenharmony_ci props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? 10762306a36Sopenharmony_ci IB_ATOMIC_HCA : IB_ATOMIC_NONE; 10862306a36Sopenharmony_ci props->max_pkeys = mdev->limits.pkey_table_len; 10962306a36Sopenharmony_ci props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; 11062306a36Sopenharmony_ci props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; 11162306a36Sopenharmony_ci props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * 11262306a36Sopenharmony_ci props->max_mcast_grp; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci err = 0; 11562306a36Sopenharmony_ci out: 11662306a36Sopenharmony_ci kfree(in_mad); 11762306a36Sopenharmony_ci kfree(out_mad); 11862306a36Sopenharmony_ci return err; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int mthca_query_port(struct ib_device *ibdev, 12262306a36Sopenharmony_ci u32 port, struct ib_port_attr *props) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct ib_smp *in_mad; 12562306a36Sopenharmony_ci struct ib_smp *out_mad; 12662306a36Sopenharmony_ci int err = -ENOMEM; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); 12962306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 13062306a36Sopenharmony_ci if (!in_mad || !out_mad) 13162306a36Sopenharmony_ci goto out; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* props being zeroed by the caller, avoid zeroing it here */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ib_init_query_mad(in_mad); 13662306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; 13762306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(port); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, 14062306a36Sopenharmony_ci port, NULL, NULL, in_mad, out_mad); 14162306a36Sopenharmony_ci if (err) 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); 14562306a36Sopenharmony_ci props->lmc = out_mad->data[34] & 0x7; 14662306a36Sopenharmony_ci props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); 14762306a36Sopenharmony_ci props->sm_sl = out_mad->data[36] & 0xf; 14862306a36Sopenharmony_ci props->state = out_mad->data[32] & 0xf; 14962306a36Sopenharmony_ci props->phys_state = out_mad->data[33] >> 4; 15062306a36Sopenharmony_ci props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); 15162306a36Sopenharmony_ci props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; 15262306a36Sopenharmony_ci props->max_msg_sz = 0x80000000; 15362306a36Sopenharmony_ci props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; 15462306a36Sopenharmony_ci props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); 15562306a36Sopenharmony_ci props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); 15662306a36Sopenharmony_ci props->active_width = out_mad->data[31] & 0xf; 15762306a36Sopenharmony_ci props->active_speed = out_mad->data[35] >> 4; 15862306a36Sopenharmony_ci props->max_mtu = out_mad->data[41] & 0xf; 15962306a36Sopenharmony_ci props->active_mtu = out_mad->data[36] >> 4; 16062306a36Sopenharmony_ci props->subnet_timeout = out_mad->data[51] & 0x1f; 16162306a36Sopenharmony_ci props->max_vl_num = out_mad->data[37] >> 4; 16262306a36Sopenharmony_ci props->init_type_reply = out_mad->data[41] >> 4; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci out: 16562306a36Sopenharmony_ci kfree(in_mad); 16662306a36Sopenharmony_ci kfree(out_mad); 16762306a36Sopenharmony_ci return err; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int mthca_modify_device(struct ib_device *ibdev, 17162306a36Sopenharmony_ci int mask, 17262306a36Sopenharmony_ci struct ib_device_modify *props) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) 17562306a36Sopenharmony_ci return -EOPNOTSUPP; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (mask & IB_DEVICE_MODIFY_NODE_DESC) { 17862306a36Sopenharmony_ci if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) 17962306a36Sopenharmony_ci return -ERESTARTSYS; 18062306a36Sopenharmony_ci memcpy(ibdev->node_desc, props->node_desc, 18162306a36Sopenharmony_ci IB_DEVICE_NODE_DESC_MAX); 18262306a36Sopenharmony_ci mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int mthca_modify_port(struct ib_device *ibdev, 18962306a36Sopenharmony_ci u32 port, int port_modify_mask, 19062306a36Sopenharmony_ci struct ib_port_modify *props) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct mthca_set_ib_param set_ib; 19362306a36Sopenharmony_ci struct ib_port_attr attr; 19462306a36Sopenharmony_ci int err; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) 19762306a36Sopenharmony_ci return -ERESTARTSYS; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci err = ib_query_port(ibdev, port, &attr); 20062306a36Sopenharmony_ci if (err) 20162306a36Sopenharmony_ci goto out; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci set_ib.set_si_guid = 0; 20462306a36Sopenharmony_ci set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & 20762306a36Sopenharmony_ci ~props->clr_port_cap_mask; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port); 21062306a36Sopenharmony_ci if (err) 21162306a36Sopenharmony_ci goto out; 21262306a36Sopenharmony_ciout: 21362306a36Sopenharmony_ci mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); 21462306a36Sopenharmony_ci return err; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int mthca_query_pkey(struct ib_device *ibdev, 21862306a36Sopenharmony_ci u32 port, u16 index, u16 *pkey) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct ib_smp *in_mad; 22162306a36Sopenharmony_ci struct ib_smp *out_mad; 22262306a36Sopenharmony_ci int err = -ENOMEM; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); 22562306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 22662306a36Sopenharmony_ci if (!in_mad || !out_mad) 22762306a36Sopenharmony_ci goto out; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ib_init_query_mad(in_mad); 23062306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; 23162306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(index / 32); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, 23462306a36Sopenharmony_ci port, NULL, NULL, in_mad, out_mad); 23562306a36Sopenharmony_ci if (err) 23662306a36Sopenharmony_ci goto out; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci out: 24162306a36Sopenharmony_ci kfree(in_mad); 24262306a36Sopenharmony_ci kfree(out_mad); 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int mthca_query_gid(struct ib_device *ibdev, u32 port, 24762306a36Sopenharmony_ci int index, union ib_gid *gid) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct ib_smp *in_mad; 25062306a36Sopenharmony_ci struct ib_smp *out_mad; 25162306a36Sopenharmony_ci int err = -ENOMEM; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); 25462306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 25562306a36Sopenharmony_ci if (!in_mad || !out_mad) 25662306a36Sopenharmony_ci goto out; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ib_init_query_mad(in_mad); 25962306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; 26062306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(port); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, 26362306a36Sopenharmony_ci port, NULL, NULL, in_mad, out_mad); 26462306a36Sopenharmony_ci if (err) 26562306a36Sopenharmony_ci goto out; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci memcpy(gid->raw, out_mad->data + 8, 8); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ib_init_query_mad(in_mad); 27062306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; 27162306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(index / 8); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, 27462306a36Sopenharmony_ci port, NULL, NULL, in_mad, out_mad); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci goto out; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci out: 28162306a36Sopenharmony_ci kfree(in_mad); 28262306a36Sopenharmony_ci kfree(out_mad); 28362306a36Sopenharmony_ci return err; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int mthca_alloc_ucontext(struct ib_ucontext *uctx, 28762306a36Sopenharmony_ci struct ib_udata *udata) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct ib_device *ibdev = uctx->device; 29062306a36Sopenharmony_ci struct mthca_alloc_ucontext_resp uresp = {}; 29162306a36Sopenharmony_ci struct mthca_ucontext *context = to_mucontext(uctx); 29262306a36Sopenharmony_ci int err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!(to_mdev(ibdev)->active)) 29562306a36Sopenharmony_ci return -EAGAIN; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; 29862306a36Sopenharmony_ci if (mthca_is_memfree(to_mdev(ibdev))) 29962306a36Sopenharmony_ci uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci uresp.uarc_size = 0; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); 30462306a36Sopenharmony_ci if (err) 30562306a36Sopenharmony_ci return err; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); 30862306a36Sopenharmony_ci if (IS_ERR(context->db_tab)) { 30962306a36Sopenharmony_ci err = PTR_ERR(context->db_tab); 31062306a36Sopenharmony_ci mthca_uar_free(to_mdev(ibdev), &context->uar); 31162306a36Sopenharmony_ci return err; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) { 31562306a36Sopenharmony_ci mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab); 31662306a36Sopenharmony_ci mthca_uar_free(to_mdev(ibdev), &context->uar); 31762306a36Sopenharmony_ci return -EFAULT; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci context->reg_mr_warned = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void mthca_dealloc_ucontext(struct ib_ucontext *context) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar, 32862306a36Sopenharmony_ci to_mucontext(context)->db_tab); 32962306a36Sopenharmony_ci mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int mthca_mmap_uar(struct ib_ucontext *context, 33362306a36Sopenharmony_ci struct vm_area_struct *vma) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci if (vma->vm_end - vma->vm_start != PAGE_SIZE) 33662306a36Sopenharmony_ci return -EINVAL; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (io_remap_pfn_range(vma, vma->vm_start, 34162306a36Sopenharmony_ci to_mucontext(context)->uar.pfn, 34262306a36Sopenharmony_ci PAGE_SIZE, vma->vm_page_prot)) 34362306a36Sopenharmony_ci return -EAGAIN; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int mthca_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct ib_device *ibdev = ibpd->device; 35162306a36Sopenharmony_ci struct mthca_pd *pd = to_mpd(ibpd); 35262306a36Sopenharmony_ci int err; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = mthca_pd_alloc(to_mdev(ibdev), !udata, pd); 35562306a36Sopenharmony_ci if (err) 35662306a36Sopenharmony_ci return err; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (udata) { 35962306a36Sopenharmony_ci if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) { 36062306a36Sopenharmony_ci mthca_pd_free(to_mdev(ibdev), pd); 36162306a36Sopenharmony_ci return -EFAULT; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int mthca_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int mthca_ah_create(struct ib_ah *ibah, 37562306a36Sopenharmony_ci struct rdma_ah_init_attr *init_attr, 37662306a36Sopenharmony_ci struct ib_udata *udata) 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct mthca_ah *ah = to_mah(ibah); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return mthca_create_ah(to_mdev(ibah->device), to_mpd(ibah->pd), 38262306a36Sopenharmony_ci init_attr->ah_attr, ah); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int mthca_ah_destroy(struct ib_ah *ah, u32 flags) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int mthca_create_srq(struct ib_srq *ibsrq, 39262306a36Sopenharmony_ci struct ib_srq_init_attr *init_attr, 39362306a36Sopenharmony_ci struct ib_udata *udata) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct mthca_create_srq ucmd; 39662306a36Sopenharmony_ci struct mthca_ucontext *context = rdma_udata_to_drv_context( 39762306a36Sopenharmony_ci udata, struct mthca_ucontext, ibucontext); 39862306a36Sopenharmony_ci struct mthca_srq *srq = to_msrq(ibsrq); 39962306a36Sopenharmony_ci int err; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (init_attr->srq_type != IB_SRQT_BASIC) 40262306a36Sopenharmony_ci return -EOPNOTSUPP; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (udata) { 40562306a36Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) 40662306a36Sopenharmony_ci return -EFAULT; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci err = mthca_map_user_db(to_mdev(ibsrq->device), &context->uar, 40962306a36Sopenharmony_ci context->db_tab, ucmd.db_index, 41062306a36Sopenharmony_ci ucmd.db_page); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (err) 41362306a36Sopenharmony_ci return err; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci srq->mr.ibmr.lkey = ucmd.lkey; 41662306a36Sopenharmony_ci srq->db_index = ucmd.db_index; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci err = mthca_alloc_srq(to_mdev(ibsrq->device), to_mpd(ibsrq->pd), 42062306a36Sopenharmony_ci &init_attr->attr, srq, udata); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (err && udata) 42362306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar, 42462306a36Sopenharmony_ci context->db_tab, ucmd.db_index); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (err) 42762306a36Sopenharmony_ci return err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) { 43062306a36Sopenharmony_ci mthca_free_srq(to_mdev(ibsrq->device), srq); 43162306a36Sopenharmony_ci return -EFAULT; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci if (udata) { 44062306a36Sopenharmony_ci struct mthca_ucontext *context = 44162306a36Sopenharmony_ci rdma_udata_to_drv_context( 44262306a36Sopenharmony_ci udata, 44362306a36Sopenharmony_ci struct mthca_ucontext, 44462306a36Sopenharmony_ci ibucontext); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(srq->device), &context->uar, 44762306a36Sopenharmony_ci context->db_tab, to_msrq(srq)->db_index); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci mthca_free_srq(to_mdev(srq->device), to_msrq(srq)); 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic int mthca_create_qp(struct ib_qp *ibqp, 45562306a36Sopenharmony_ci struct ib_qp_init_attr *init_attr, 45662306a36Sopenharmony_ci struct ib_udata *udata) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct mthca_ucontext *context = rdma_udata_to_drv_context( 45962306a36Sopenharmony_ci udata, struct mthca_ucontext, ibucontext); 46062306a36Sopenharmony_ci struct mthca_create_qp ucmd; 46162306a36Sopenharmony_ci struct mthca_qp *qp = to_mqp(ibqp); 46262306a36Sopenharmony_ci struct mthca_dev *dev = to_mdev(ibqp->device); 46362306a36Sopenharmony_ci int err; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (init_attr->create_flags) 46662306a36Sopenharmony_ci return -EOPNOTSUPP; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci switch (init_attr->qp_type) { 46962306a36Sopenharmony_ci case IB_QPT_RC: 47062306a36Sopenharmony_ci case IB_QPT_UC: 47162306a36Sopenharmony_ci case IB_QPT_UD: 47262306a36Sopenharmony_ci { 47362306a36Sopenharmony_ci if (udata) { 47462306a36Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) 47562306a36Sopenharmony_ci return -EFAULT; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci err = mthca_map_user_db(dev, &context->uar, 47862306a36Sopenharmony_ci context->db_tab, 47962306a36Sopenharmony_ci ucmd.sq_db_index, 48062306a36Sopenharmony_ci ucmd.sq_db_page); 48162306a36Sopenharmony_ci if (err) 48262306a36Sopenharmony_ci return err; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci err = mthca_map_user_db(dev, &context->uar, 48562306a36Sopenharmony_ci context->db_tab, 48662306a36Sopenharmony_ci ucmd.rq_db_index, 48762306a36Sopenharmony_ci ucmd.rq_db_page); 48862306a36Sopenharmony_ci if (err) { 48962306a36Sopenharmony_ci mthca_unmap_user_db(dev, &context->uar, 49062306a36Sopenharmony_ci context->db_tab, 49162306a36Sopenharmony_ci ucmd.sq_db_index); 49262306a36Sopenharmony_ci return err; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci qp->mr.ibmr.lkey = ucmd.lkey; 49662306a36Sopenharmony_ci qp->sq.db_index = ucmd.sq_db_index; 49762306a36Sopenharmony_ci qp->rq.db_index = ucmd.rq_db_index; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci err = mthca_alloc_qp(dev, to_mpd(ibqp->pd), 50162306a36Sopenharmony_ci to_mcq(init_attr->send_cq), 50262306a36Sopenharmony_ci to_mcq(init_attr->recv_cq), 50362306a36Sopenharmony_ci init_attr->qp_type, init_attr->sq_sig_type, 50462306a36Sopenharmony_ci &init_attr->cap, qp, udata); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (err && udata) { 50762306a36Sopenharmony_ci mthca_unmap_user_db(dev, &context->uar, context->db_tab, 50862306a36Sopenharmony_ci ucmd.sq_db_index); 50962306a36Sopenharmony_ci mthca_unmap_user_db(dev, &context->uar, context->db_tab, 51062306a36Sopenharmony_ci ucmd.rq_db_index); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci qp->ibqp.qp_num = qp->qpn; 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci case IB_QPT_SMI: 51762306a36Sopenharmony_ci case IB_QPT_GSI: 51862306a36Sopenharmony_ci { 51962306a36Sopenharmony_ci qp->sqp = kzalloc(sizeof(struct mthca_sqp), GFP_KERNEL); 52062306a36Sopenharmony_ci if (!qp->sqp) 52162306a36Sopenharmony_ci return -ENOMEM; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci err = mthca_alloc_sqp(dev, to_mpd(ibqp->pd), 52662306a36Sopenharmony_ci to_mcq(init_attr->send_cq), 52762306a36Sopenharmony_ci to_mcq(init_attr->recv_cq), 52862306a36Sopenharmony_ci init_attr->sq_sig_type, &init_attr->cap, 52962306a36Sopenharmony_ci qp->ibqp.qp_num, init_attr->port_num, qp, 53062306a36Sopenharmony_ci udata); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci default: 53462306a36Sopenharmony_ci /* Don't support raw QPs */ 53562306a36Sopenharmony_ci return -EOPNOTSUPP; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (err) { 53962306a36Sopenharmony_ci kfree(qp->sqp); 54062306a36Sopenharmony_ci return err; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci init_attr->cap.max_send_wr = qp->sq.max; 54462306a36Sopenharmony_ci init_attr->cap.max_recv_wr = qp->rq.max; 54562306a36Sopenharmony_ci init_attr->cap.max_send_sge = qp->sq.max_gs; 54662306a36Sopenharmony_ci init_attr->cap.max_recv_sge = qp->rq.max_gs; 54762306a36Sopenharmony_ci init_attr->cap.max_inline_data = qp->max_inline_data; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic int mthca_destroy_qp(struct ib_qp *qp, struct ib_udata *udata) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci if (udata) { 55562306a36Sopenharmony_ci struct mthca_ucontext *context = 55662306a36Sopenharmony_ci rdma_udata_to_drv_context( 55762306a36Sopenharmony_ci udata, 55862306a36Sopenharmony_ci struct mthca_ucontext, 55962306a36Sopenharmony_ci ibucontext); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(qp->device), 56262306a36Sopenharmony_ci &context->uar, 56362306a36Sopenharmony_ci context->db_tab, 56462306a36Sopenharmony_ci to_mqp(qp)->sq.db_index); 56562306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(qp->device), 56662306a36Sopenharmony_ci &context->uar, 56762306a36Sopenharmony_ci context->db_tab, 56862306a36Sopenharmony_ci to_mqp(qp)->rq.db_index); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); 57162306a36Sopenharmony_ci kfree(to_mqp(qp)->sqp); 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int mthca_create_cq(struct ib_cq *ibcq, 57662306a36Sopenharmony_ci const struct ib_cq_init_attr *attr, 57762306a36Sopenharmony_ci struct ib_udata *udata) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct ib_device *ibdev = ibcq->device; 58062306a36Sopenharmony_ci int entries = attr->cqe; 58162306a36Sopenharmony_ci struct mthca_create_cq ucmd; 58262306a36Sopenharmony_ci struct mthca_cq *cq; 58362306a36Sopenharmony_ci int nent; 58462306a36Sopenharmony_ci int err; 58562306a36Sopenharmony_ci struct mthca_ucontext *context = rdma_udata_to_drv_context( 58662306a36Sopenharmony_ci udata, struct mthca_ucontext, ibucontext); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (attr->flags) 58962306a36Sopenharmony_ci return -EOPNOTSUPP; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) 59262306a36Sopenharmony_ci return -EINVAL; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (udata) { 59562306a36Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) 59662306a36Sopenharmony_ci return -EFAULT; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci err = mthca_map_user_db(to_mdev(ibdev), &context->uar, 59962306a36Sopenharmony_ci context->db_tab, ucmd.set_db_index, 60062306a36Sopenharmony_ci ucmd.set_db_page); 60162306a36Sopenharmony_ci if (err) 60262306a36Sopenharmony_ci return err; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci err = mthca_map_user_db(to_mdev(ibdev), &context->uar, 60562306a36Sopenharmony_ci context->db_tab, ucmd.arm_db_index, 60662306a36Sopenharmony_ci ucmd.arm_db_page); 60762306a36Sopenharmony_ci if (err) 60862306a36Sopenharmony_ci goto err_unmap_set; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci cq = to_mcq(ibcq); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (udata) { 61462306a36Sopenharmony_ci cq->buf.mr.ibmr.lkey = ucmd.lkey; 61562306a36Sopenharmony_ci cq->set_ci_db_index = ucmd.set_db_index; 61662306a36Sopenharmony_ci cq->arm_db_index = ucmd.arm_db_index; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (nent = 1; nent <= entries; nent <<= 1) 62062306a36Sopenharmony_ci ; /* nothing */ 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci err = mthca_init_cq(to_mdev(ibdev), nent, context, 62362306a36Sopenharmony_ci udata ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num, 62462306a36Sopenharmony_ci cq); 62562306a36Sopenharmony_ci if (err) 62662306a36Sopenharmony_ci goto err_unmap_arm; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (udata && ib_copy_to_udata(udata, &cq->cqn, sizeof(__u32))) { 62962306a36Sopenharmony_ci mthca_free_cq(to_mdev(ibdev), cq); 63062306a36Sopenharmony_ci err = -EFAULT; 63162306a36Sopenharmony_ci goto err_unmap_arm; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci cq->resize_buf = NULL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cierr_unmap_arm: 63962306a36Sopenharmony_ci if (udata) 64062306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(ibdev), &context->uar, 64162306a36Sopenharmony_ci context->db_tab, ucmd.arm_db_index); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cierr_unmap_set: 64462306a36Sopenharmony_ci if (udata) 64562306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(ibdev), &context->uar, 64662306a36Sopenharmony_ci context->db_tab, ucmd.set_db_index); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return err; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq, 65262306a36Sopenharmony_ci int entries) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci int ret; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci spin_lock_irq(&cq->lock); 65762306a36Sopenharmony_ci if (cq->resize_buf) { 65862306a36Sopenharmony_ci ret = -EBUSY; 65962306a36Sopenharmony_ci goto unlock; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); 66362306a36Sopenharmony_ci if (!cq->resize_buf) { 66462306a36Sopenharmony_ci ret = -ENOMEM; 66562306a36Sopenharmony_ci goto unlock; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci cq->resize_buf->state = CQ_RESIZE_ALLOC; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci ret = 0; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ciunlock: 67362306a36Sopenharmony_ci spin_unlock_irq(&cq->lock); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (ret) 67662306a36Sopenharmony_ci return ret; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); 67962306a36Sopenharmony_ci if (ret) { 68062306a36Sopenharmony_ci spin_lock_irq(&cq->lock); 68162306a36Sopenharmony_ci kfree(cq->resize_buf); 68262306a36Sopenharmony_ci cq->resize_buf = NULL; 68362306a36Sopenharmony_ci spin_unlock_irq(&cq->lock); 68462306a36Sopenharmony_ci return ret; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci cq->resize_buf->cqe = entries - 1; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci spin_lock_irq(&cq->lock); 69062306a36Sopenharmony_ci cq->resize_buf->state = CQ_RESIZE_READY; 69162306a36Sopenharmony_ci spin_unlock_irq(&cq->lock); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct mthca_dev *dev = to_mdev(ibcq->device); 69962306a36Sopenharmony_ci struct mthca_cq *cq = to_mcq(ibcq); 70062306a36Sopenharmony_ci struct mthca_resize_cq ucmd; 70162306a36Sopenharmony_ci u32 lkey; 70262306a36Sopenharmony_ci int ret; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (entries < 1 || entries > dev->limits.max_cqes) 70562306a36Sopenharmony_ci return -EINVAL; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci mutex_lock(&cq->mutex); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci entries = roundup_pow_of_two(entries + 1); 71062306a36Sopenharmony_ci if (entries == ibcq->cqe + 1) { 71162306a36Sopenharmony_ci ret = 0; 71262306a36Sopenharmony_ci goto out; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (cq->is_kernel) { 71662306a36Sopenharmony_ci ret = mthca_alloc_resize_buf(dev, cq, entries); 71762306a36Sopenharmony_ci if (ret) 71862306a36Sopenharmony_ci goto out; 71962306a36Sopenharmony_ci lkey = cq->resize_buf->buf.mr.ibmr.lkey; 72062306a36Sopenharmony_ci } else { 72162306a36Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { 72262306a36Sopenharmony_ci ret = -EFAULT; 72362306a36Sopenharmony_ci goto out; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci lkey = ucmd.lkey; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries)); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (ret) { 73162306a36Sopenharmony_ci if (cq->resize_buf) { 73262306a36Sopenharmony_ci mthca_free_cq_buf(dev, &cq->resize_buf->buf, 73362306a36Sopenharmony_ci cq->resize_buf->cqe); 73462306a36Sopenharmony_ci kfree(cq->resize_buf); 73562306a36Sopenharmony_ci spin_lock_irq(&cq->lock); 73662306a36Sopenharmony_ci cq->resize_buf = NULL; 73762306a36Sopenharmony_ci spin_unlock_irq(&cq->lock); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci goto out; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (cq->is_kernel) { 74362306a36Sopenharmony_ci struct mthca_cq_buf tbuf; 74462306a36Sopenharmony_ci int tcqe; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci spin_lock_irq(&cq->lock); 74762306a36Sopenharmony_ci if (cq->resize_buf->state == CQ_RESIZE_READY) { 74862306a36Sopenharmony_ci mthca_cq_resize_copy_cqes(cq); 74962306a36Sopenharmony_ci tbuf = cq->buf; 75062306a36Sopenharmony_ci tcqe = cq->ibcq.cqe; 75162306a36Sopenharmony_ci cq->buf = cq->resize_buf->buf; 75262306a36Sopenharmony_ci cq->ibcq.cqe = cq->resize_buf->cqe; 75362306a36Sopenharmony_ci } else { 75462306a36Sopenharmony_ci tbuf = cq->resize_buf->buf; 75562306a36Sopenharmony_ci tcqe = cq->resize_buf->cqe; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci kfree(cq->resize_buf); 75962306a36Sopenharmony_ci cq->resize_buf = NULL; 76062306a36Sopenharmony_ci spin_unlock_irq(&cq->lock); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci mthca_free_cq_buf(dev, &tbuf, tcqe); 76362306a36Sopenharmony_ci } else 76462306a36Sopenharmony_ci ibcq->cqe = entries - 1; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ciout: 76762306a36Sopenharmony_ci mutex_unlock(&cq->mutex); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci return ret; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci if (udata) { 77562306a36Sopenharmony_ci struct mthca_ucontext *context = 77662306a36Sopenharmony_ci rdma_udata_to_drv_context( 77762306a36Sopenharmony_ci udata, 77862306a36Sopenharmony_ci struct mthca_ucontext, 77962306a36Sopenharmony_ci ibucontext); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(cq->device), 78262306a36Sopenharmony_ci &context->uar, 78362306a36Sopenharmony_ci context->db_tab, 78462306a36Sopenharmony_ci to_mcq(cq)->arm_db_index); 78562306a36Sopenharmony_ci mthca_unmap_user_db(to_mdev(cq->device), 78662306a36Sopenharmony_ci &context->uar, 78762306a36Sopenharmony_ci context->db_tab, 78862306a36Sopenharmony_ci to_mcq(cq)->set_ci_db_index); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic inline u32 convert_access(int acc) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) | 79762306a36Sopenharmony_ci (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) | 79862306a36Sopenharmony_ci (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) | 79962306a36Sopenharmony_ci (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) | 80062306a36Sopenharmony_ci MTHCA_MPT_FLAG_LOCAL_READ; 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct mthca_mr *mr; 80662306a36Sopenharmony_ci int err; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci mr = kmalloc(sizeof *mr, GFP_KERNEL); 80962306a36Sopenharmony_ci if (!mr) 81062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci err = mthca_mr_alloc_notrans(to_mdev(pd->device), 81362306a36Sopenharmony_ci to_mpd(pd)->pd_num, 81462306a36Sopenharmony_ci convert_access(acc), mr); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (err) { 81762306a36Sopenharmony_ci kfree(mr); 81862306a36Sopenharmony_ci return ERR_PTR(err); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci mr->umem = NULL; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return &mr->ibmr; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, 82762306a36Sopenharmony_ci u64 virt, int acc, struct ib_udata *udata) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct mthca_dev *dev = to_mdev(pd->device); 83062306a36Sopenharmony_ci struct ib_block_iter biter; 83162306a36Sopenharmony_ci struct mthca_ucontext *context = rdma_udata_to_drv_context( 83262306a36Sopenharmony_ci udata, struct mthca_ucontext, ibucontext); 83362306a36Sopenharmony_ci struct mthca_mr *mr; 83462306a36Sopenharmony_ci struct mthca_reg_mr ucmd; 83562306a36Sopenharmony_ci u64 *pages; 83662306a36Sopenharmony_ci int n, i; 83762306a36Sopenharmony_ci int err = 0; 83862306a36Sopenharmony_ci int write_mtt_size; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (udata->inlen < sizeof ucmd) { 84162306a36Sopenharmony_ci if (!context->reg_mr_warned) { 84262306a36Sopenharmony_ci mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", 84362306a36Sopenharmony_ci current->comm); 84462306a36Sopenharmony_ci mthca_warn(dev, " Update libmthca to fix this.\n"); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci ++context->reg_mr_warned; 84762306a36Sopenharmony_ci ucmd.mr_attrs = 0; 84862306a36Sopenharmony_ci } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) 84962306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci mr = kmalloc(sizeof *mr, GFP_KERNEL); 85262306a36Sopenharmony_ci if (!mr) 85362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci mr->umem = ib_umem_get(pd->device, start, length, acc); 85662306a36Sopenharmony_ci if (IS_ERR(mr->umem)) { 85762306a36Sopenharmony_ci err = PTR_ERR(mr->umem); 85862306a36Sopenharmony_ci goto err; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci n = ib_umem_num_dma_blocks(mr->umem, PAGE_SIZE); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci mr->mtt = mthca_alloc_mtt(dev, n); 86462306a36Sopenharmony_ci if (IS_ERR(mr->mtt)) { 86562306a36Sopenharmony_ci err = PTR_ERR(mr->mtt); 86662306a36Sopenharmony_ci goto err_umem; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci pages = (u64 *) __get_free_page(GFP_KERNEL); 87062306a36Sopenharmony_ci if (!pages) { 87162306a36Sopenharmony_ci err = -ENOMEM; 87262306a36Sopenharmony_ci goto err_mtt; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci i = n = 0; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci rdma_umem_for_each_dma_block(mr->umem, &biter, PAGE_SIZE) { 88062306a36Sopenharmony_ci pages[i++] = rdma_block_iter_dma_address(&biter); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* 88362306a36Sopenharmony_ci * Be friendly to write_mtt and pass it chunks 88462306a36Sopenharmony_ci * of appropriate size. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci if (i == write_mtt_size) { 88762306a36Sopenharmony_ci err = mthca_write_mtt(dev, mr->mtt, n, pages, i); 88862306a36Sopenharmony_ci if (err) 88962306a36Sopenharmony_ci goto mtt_done; 89062306a36Sopenharmony_ci n += i; 89162306a36Sopenharmony_ci i = 0; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (i) 89662306a36Sopenharmony_ci err = mthca_write_mtt(dev, mr->mtt, n, pages, i); 89762306a36Sopenharmony_cimtt_done: 89862306a36Sopenharmony_ci free_page((unsigned long) pages); 89962306a36Sopenharmony_ci if (err) 90062306a36Sopenharmony_ci goto err_mtt; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, PAGE_SHIFT, virt, length, 90362306a36Sopenharmony_ci convert_access(acc), mr); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (err) 90662306a36Sopenharmony_ci goto err_mtt; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return &mr->ibmr; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cierr_mtt: 91162306a36Sopenharmony_ci mthca_free_mtt(dev, mr->mtt); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cierr_umem: 91462306a36Sopenharmony_ci ib_umem_release(mr->umem); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cierr: 91762306a36Sopenharmony_ci kfree(mr); 91862306a36Sopenharmony_ci return ERR_PTR(err); 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistatic int mthca_dereg_mr(struct ib_mr *mr, struct ib_udata *udata) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct mthca_mr *mmr = to_mmr(mr); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci mthca_free_mr(to_mdev(mr->device), mmr); 92662306a36Sopenharmony_ci ib_umem_release(mmr->umem); 92762306a36Sopenharmony_ci kfree(mmr); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic ssize_t hw_rev_show(struct device *device, 93362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct mthca_dev *dev = 93662306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return sysfs_emit(buf, "%x\n", dev->rev_id); 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hw_rev); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic const char *hca_type_string(int hca_type) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci switch (hca_type) { 94562306a36Sopenharmony_ci case PCI_DEVICE_ID_MELLANOX_TAVOR: 94662306a36Sopenharmony_ci return "MT23108"; 94762306a36Sopenharmony_ci case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT: 94862306a36Sopenharmony_ci return "MT25208 (MT23108 compat mode)"; 94962306a36Sopenharmony_ci case PCI_DEVICE_ID_MELLANOX_ARBEL: 95062306a36Sopenharmony_ci return "MT25208"; 95162306a36Sopenharmony_ci case PCI_DEVICE_ID_MELLANOX_SINAI: 95262306a36Sopenharmony_ci case PCI_DEVICE_ID_MELLANOX_SINAI_OLD: 95362306a36Sopenharmony_ci return "MT25204"; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return "unknown"; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic ssize_t hca_type_show(struct device *device, 96062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct mthca_dev *dev = 96362306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", hca_type_string(dev->pdev->device)); 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hca_type); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic ssize_t board_id_show(struct device *device, 97062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct mthca_dev *dev = 97362306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci return sysfs_emit(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(board_id); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic struct attribute *mthca_dev_attributes[] = { 98062306a36Sopenharmony_ci &dev_attr_hw_rev.attr, 98162306a36Sopenharmony_ci &dev_attr_hca_type.attr, 98262306a36Sopenharmony_ci &dev_attr_board_id.attr, 98362306a36Sopenharmony_ci NULL 98462306a36Sopenharmony_ci}; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic const struct attribute_group mthca_attr_group = { 98762306a36Sopenharmony_ci .attrs = mthca_dev_attributes, 98862306a36Sopenharmony_ci}; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic int mthca_init_node_data(struct mthca_dev *dev) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct ib_smp *in_mad; 99362306a36Sopenharmony_ci struct ib_smp *out_mad; 99462306a36Sopenharmony_ci int err = -ENOMEM; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); 99762306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 99862306a36Sopenharmony_ci if (!in_mad || !out_mad) 99962306a36Sopenharmony_ci goto out; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci ib_init_query_mad(in_mad); 100262306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci err = mthca_MAD_IFC(dev, 1, 1, 100562306a36Sopenharmony_ci 1, NULL, NULL, in_mad, out_mad); 100662306a36Sopenharmony_ci if (err) 100762306a36Sopenharmony_ci goto out; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci err = mthca_MAD_IFC(dev, 1, 1, 101462306a36Sopenharmony_ci 1, NULL, NULL, in_mad, out_mad); 101562306a36Sopenharmony_ci if (err) 101662306a36Sopenharmony_ci goto out; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (mthca_is_memfree(dev)) 101962306a36Sopenharmony_ci dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); 102062306a36Sopenharmony_ci memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ciout: 102362306a36Sopenharmony_ci kfree(in_mad); 102462306a36Sopenharmony_ci kfree(out_mad); 102562306a36Sopenharmony_ci return err; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int mthca_port_immutable(struct ib_device *ibdev, u32 port_num, 102962306a36Sopenharmony_ci struct ib_port_immutable *immutable) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct ib_port_attr attr; 103262306a36Sopenharmony_ci int err; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci err = ib_query_port(ibdev, port_num, &attr); 103762306a36Sopenharmony_ci if (err) 103862306a36Sopenharmony_ci return err; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci immutable->pkey_tbl_len = attr.pkey_tbl_len; 104162306a36Sopenharmony_ci immutable->gid_tbl_len = attr.gid_tbl_len; 104262306a36Sopenharmony_ci immutable->max_mad_size = IB_MGMT_MAD_SIZE; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci return 0; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic void get_dev_fw_str(struct ib_device *device, char *str) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci struct mthca_dev *dev = 105062306a36Sopenharmony_ci container_of(device, struct mthca_dev, ib_dev); 105162306a36Sopenharmony_ci snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d", 105262306a36Sopenharmony_ci (int) (dev->fw_ver >> 32), 105362306a36Sopenharmony_ci (int) (dev->fw_ver >> 16) & 0xffff, 105462306a36Sopenharmony_ci (int) dev->fw_ver & 0xffff); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic const struct ib_device_ops mthca_dev_ops = { 105862306a36Sopenharmony_ci .owner = THIS_MODULE, 105962306a36Sopenharmony_ci .driver_id = RDMA_DRIVER_MTHCA, 106062306a36Sopenharmony_ci .uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION, 106162306a36Sopenharmony_ci .uverbs_no_driver_id_binding = 1, 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci .alloc_pd = mthca_alloc_pd, 106462306a36Sopenharmony_ci .alloc_ucontext = mthca_alloc_ucontext, 106562306a36Sopenharmony_ci .attach_mcast = mthca_multicast_attach, 106662306a36Sopenharmony_ci .create_ah = mthca_ah_create, 106762306a36Sopenharmony_ci .create_cq = mthca_create_cq, 106862306a36Sopenharmony_ci .create_qp = mthca_create_qp, 106962306a36Sopenharmony_ci .dealloc_pd = mthca_dealloc_pd, 107062306a36Sopenharmony_ci .dealloc_ucontext = mthca_dealloc_ucontext, 107162306a36Sopenharmony_ci .dereg_mr = mthca_dereg_mr, 107262306a36Sopenharmony_ci .destroy_ah = mthca_ah_destroy, 107362306a36Sopenharmony_ci .destroy_cq = mthca_destroy_cq, 107462306a36Sopenharmony_ci .destroy_qp = mthca_destroy_qp, 107562306a36Sopenharmony_ci .detach_mcast = mthca_multicast_detach, 107662306a36Sopenharmony_ci .device_group = &mthca_attr_group, 107762306a36Sopenharmony_ci .get_dev_fw_str = get_dev_fw_str, 107862306a36Sopenharmony_ci .get_dma_mr = mthca_get_dma_mr, 107962306a36Sopenharmony_ci .get_port_immutable = mthca_port_immutable, 108062306a36Sopenharmony_ci .mmap = mthca_mmap_uar, 108162306a36Sopenharmony_ci .modify_device = mthca_modify_device, 108262306a36Sopenharmony_ci .modify_port = mthca_modify_port, 108362306a36Sopenharmony_ci .modify_qp = mthca_modify_qp, 108462306a36Sopenharmony_ci .poll_cq = mthca_poll_cq, 108562306a36Sopenharmony_ci .process_mad = mthca_process_mad, 108662306a36Sopenharmony_ci .query_ah = mthca_ah_query, 108762306a36Sopenharmony_ci .query_device = mthca_query_device, 108862306a36Sopenharmony_ci .query_gid = mthca_query_gid, 108962306a36Sopenharmony_ci .query_pkey = mthca_query_pkey, 109062306a36Sopenharmony_ci .query_port = mthca_query_port, 109162306a36Sopenharmony_ci .query_qp = mthca_query_qp, 109262306a36Sopenharmony_ci .reg_user_mr = mthca_reg_user_mr, 109362306a36Sopenharmony_ci .resize_cq = mthca_resize_cq, 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ah, mthca_ah, ibah), 109662306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, mthca_cq, ibcq), 109762306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, mthca_pd, ibpd), 109862306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_qp, mthca_qp, ibqp), 109962306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, mthca_ucontext, ibucontext), 110062306a36Sopenharmony_ci}; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic const struct ib_device_ops mthca_dev_arbel_srq_ops = { 110362306a36Sopenharmony_ci .create_srq = mthca_create_srq, 110462306a36Sopenharmony_ci .destroy_srq = mthca_destroy_srq, 110562306a36Sopenharmony_ci .modify_srq = mthca_modify_srq, 110662306a36Sopenharmony_ci .post_srq_recv = mthca_arbel_post_srq_recv, 110762306a36Sopenharmony_ci .query_srq = mthca_query_srq, 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq), 111062306a36Sopenharmony_ci}; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic const struct ib_device_ops mthca_dev_tavor_srq_ops = { 111362306a36Sopenharmony_ci .create_srq = mthca_create_srq, 111462306a36Sopenharmony_ci .destroy_srq = mthca_destroy_srq, 111562306a36Sopenharmony_ci .modify_srq = mthca_modify_srq, 111662306a36Sopenharmony_ci .post_srq_recv = mthca_tavor_post_srq_recv, 111762306a36Sopenharmony_ci .query_srq = mthca_query_srq, 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq), 112062306a36Sopenharmony_ci}; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic const struct ib_device_ops mthca_dev_arbel_ops = { 112362306a36Sopenharmony_ci .post_recv = mthca_arbel_post_receive, 112462306a36Sopenharmony_ci .post_send = mthca_arbel_post_send, 112562306a36Sopenharmony_ci .req_notify_cq = mthca_arbel_arm_cq, 112662306a36Sopenharmony_ci}; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic const struct ib_device_ops mthca_dev_tavor_ops = { 112962306a36Sopenharmony_ci .post_recv = mthca_tavor_post_receive, 113062306a36Sopenharmony_ci .post_send = mthca_tavor_post_send, 113162306a36Sopenharmony_ci .req_notify_cq = mthca_tavor_arm_cq, 113262306a36Sopenharmony_ci}; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ciint mthca_register_device(struct mthca_dev *dev) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci int ret; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = mthca_init_node_data(dev); 113962306a36Sopenharmony_ci if (ret) 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci dev->ib_dev.node_type = RDMA_NODE_IB_CA; 114362306a36Sopenharmony_ci dev->ib_dev.phys_port_cnt = dev->limits.num_ports; 114462306a36Sopenharmony_ci dev->ib_dev.num_comp_vectors = 1; 114562306a36Sopenharmony_ci dev->ib_dev.dev.parent = &dev->pdev->dev; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (dev->mthca_flags & MTHCA_FLAG_SRQ) { 114862306a36Sopenharmony_ci if (mthca_is_memfree(dev)) 114962306a36Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, 115062306a36Sopenharmony_ci &mthca_dev_arbel_srq_ops); 115162306a36Sopenharmony_ci else 115262306a36Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, 115362306a36Sopenharmony_ci &mthca_dev_tavor_srq_ops); 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, &mthca_dev_ops); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (mthca_is_memfree(dev)) 115962306a36Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, &mthca_dev_arbel_ops); 116062306a36Sopenharmony_ci else 116162306a36Sopenharmony_ci ib_set_device_ops(&dev->ib_dev, &mthca_dev_tavor_ops); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci mutex_init(&dev->cap_mask_mutex); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci ret = ib_register_device(&dev->ib_dev, "mthca%d", &dev->pdev->dev); 116662306a36Sopenharmony_ci if (ret) 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci mthca_start_catas_poll(dev); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci return 0; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_civoid mthca_unregister_device(struct mthca_dev *dev) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci mthca_stop_catas_poll(dev); 117762306a36Sopenharmony_ci ib_unregister_device(&dev->ib_dev); 117862306a36Sopenharmony_ci} 1179