162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 562306a36Sopenharmony_ci * modify it under the terms of EITHER the GNU General Public License 662306a36Sopenharmony_ci * version 2 as published by the Free Software Foundation or the BSD 762306a36Sopenharmony_ci * 2-Clause License. This program is distributed in the hope that it 862306a36Sopenharmony_ci * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 962306a36Sopenharmony_ci * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1062306a36Sopenharmony_ci * See the GNU General Public License version 2 for more details at 1162306a36Sopenharmony_ci * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 1462306a36Sopenharmony_ci * along with this program available in the file COPYING in the main 1562306a36Sopenharmony_ci * directory of this source tree. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * The BSD 2-Clause License 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 2062306a36Sopenharmony_ci * without modification, are permitted provided that the following 2162306a36Sopenharmony_ci * conditions are met: 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * - Redistributions of source code must retain the above 2462306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2562306a36Sopenharmony_ci * disclaimer. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2862306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2962306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 3062306a36Sopenharmony_ci * provided with the distribution. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3362306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3462306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 3562306a36Sopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 3662306a36Sopenharmony_ci * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 3762306a36Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3962306a36Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4062306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4162306a36Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4262306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4362306a36Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <asm/page.h> 4762306a36Sopenharmony_ci#include <linux/inet.h> 4862306a36Sopenharmony_ci#include <linux/io.h> 4962306a36Sopenharmony_ci#include <rdma/ib_addr.h> 5062306a36Sopenharmony_ci#include <rdma/ib_smi.h> 5162306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 5262306a36Sopenharmony_ci#include <rdma/vmw_pvrdma-abi.h> 5362306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#include "pvrdma.h" 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * pvrdma_query_device - query device 5962306a36Sopenharmony_ci * @ibdev: the device to query 6062306a36Sopenharmony_ci * @props: the device properties 6162306a36Sopenharmony_ci * @uhw: user data 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * @return: 0 on success, otherwise negative errno 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ciint pvrdma_query_device(struct ib_device *ibdev, 6662306a36Sopenharmony_ci struct ib_device_attr *props, 6762306a36Sopenharmony_ci struct ib_udata *uhw) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibdev); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (uhw->inlen || uhw->outlen) 7262306a36Sopenharmony_ci return -EINVAL; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci props->fw_ver = dev->dsr->caps.fw_ver; 7562306a36Sopenharmony_ci props->sys_image_guid = dev->dsr->caps.sys_image_guid; 7662306a36Sopenharmony_ci props->max_mr_size = dev->dsr->caps.max_mr_size; 7762306a36Sopenharmony_ci props->page_size_cap = dev->dsr->caps.page_size_cap; 7862306a36Sopenharmony_ci props->vendor_id = dev->dsr->caps.vendor_id; 7962306a36Sopenharmony_ci props->vendor_part_id = dev->pdev->device; 8062306a36Sopenharmony_ci props->hw_ver = dev->dsr->caps.hw_ver; 8162306a36Sopenharmony_ci props->max_qp = dev->dsr->caps.max_qp; 8262306a36Sopenharmony_ci props->max_qp_wr = dev->dsr->caps.max_qp_wr; 8362306a36Sopenharmony_ci props->device_cap_flags = dev->dsr->caps.device_cap_flags; 8462306a36Sopenharmony_ci props->max_send_sge = dev->dsr->caps.max_sge; 8562306a36Sopenharmony_ci props->max_recv_sge = dev->dsr->caps.max_sge; 8662306a36Sopenharmony_ci props->max_sge_rd = PVRDMA_GET_CAP(dev, dev->dsr->caps.max_sge, 8762306a36Sopenharmony_ci dev->dsr->caps.max_sge_rd); 8862306a36Sopenharmony_ci props->max_srq = dev->dsr->caps.max_srq; 8962306a36Sopenharmony_ci props->max_srq_wr = dev->dsr->caps.max_srq_wr; 9062306a36Sopenharmony_ci props->max_srq_sge = dev->dsr->caps.max_srq_sge; 9162306a36Sopenharmony_ci props->max_cq = dev->dsr->caps.max_cq; 9262306a36Sopenharmony_ci props->max_cqe = dev->dsr->caps.max_cqe; 9362306a36Sopenharmony_ci props->max_mr = dev->dsr->caps.max_mr; 9462306a36Sopenharmony_ci props->max_pd = dev->dsr->caps.max_pd; 9562306a36Sopenharmony_ci props->max_qp_rd_atom = dev->dsr->caps.max_qp_rd_atom; 9662306a36Sopenharmony_ci props->max_qp_init_rd_atom = dev->dsr->caps.max_qp_init_rd_atom; 9762306a36Sopenharmony_ci props->atomic_cap = 9862306a36Sopenharmony_ci dev->dsr->caps.atomic_ops & 9962306a36Sopenharmony_ci (PVRDMA_ATOMIC_OP_COMP_SWAP | PVRDMA_ATOMIC_OP_FETCH_ADD) ? 10062306a36Sopenharmony_ci IB_ATOMIC_HCA : IB_ATOMIC_NONE; 10162306a36Sopenharmony_ci props->masked_atomic_cap = props->atomic_cap; 10262306a36Sopenharmony_ci props->max_ah = dev->dsr->caps.max_ah; 10362306a36Sopenharmony_ci props->max_pkeys = dev->dsr->caps.max_pkeys; 10462306a36Sopenharmony_ci props->local_ca_ack_delay = dev->dsr->caps.local_ca_ack_delay; 10562306a36Sopenharmony_ci if ((dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_LOCAL_INV) && 10662306a36Sopenharmony_ci (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_REMOTE_INV) && 10762306a36Sopenharmony_ci (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_FAST_REG_WR)) { 10862306a36Sopenharmony_ci props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; 10962306a36Sopenharmony_ci props->max_fast_reg_page_list_len = PVRDMA_GET_CAP(dev, 11062306a36Sopenharmony_ci PVRDMA_MAX_FAST_REG_PAGES, 11162306a36Sopenharmony_ci dev->dsr->caps.max_fast_reg_page_list_len); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci props->device_cap_flags |= IB_DEVICE_PORT_ACTIVE_EVENT | 11562306a36Sopenharmony_ci IB_DEVICE_RC_RNR_NAK_GEN; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * pvrdma_query_port - query device port attributes 12262306a36Sopenharmony_ci * @ibdev: the device to query 12362306a36Sopenharmony_ci * @port: the port number 12462306a36Sopenharmony_ci * @props: the device properties 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * @return: 0 on success, otherwise negative errno 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ciint pvrdma_query_port(struct ib_device *ibdev, u32 port, 12962306a36Sopenharmony_ci struct ib_port_attr *props) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibdev); 13262306a36Sopenharmony_ci union pvrdma_cmd_req req; 13362306a36Sopenharmony_ci union pvrdma_cmd_resp rsp; 13462306a36Sopenharmony_ci struct pvrdma_cmd_query_port *cmd = &req.query_port; 13562306a36Sopenharmony_ci struct pvrdma_cmd_query_port_resp *resp = &rsp.query_port_resp; 13662306a36Sopenharmony_ci int err; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 13962306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_QUERY_PORT; 14062306a36Sopenharmony_ci cmd->port_num = port; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci err = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_PORT_RESP); 14362306a36Sopenharmony_ci if (err < 0) { 14462306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 14562306a36Sopenharmony_ci "could not query port, error: %d\n", err); 14662306a36Sopenharmony_ci return err; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* props being zeroed by the caller, avoid zeroing it here */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci props->state = pvrdma_port_state_to_ib(resp->attrs.state); 15262306a36Sopenharmony_ci props->max_mtu = pvrdma_mtu_to_ib(resp->attrs.max_mtu); 15362306a36Sopenharmony_ci props->active_mtu = pvrdma_mtu_to_ib(resp->attrs.active_mtu); 15462306a36Sopenharmony_ci props->gid_tbl_len = resp->attrs.gid_tbl_len; 15562306a36Sopenharmony_ci props->port_cap_flags = 15662306a36Sopenharmony_ci pvrdma_port_cap_flags_to_ib(resp->attrs.port_cap_flags); 15762306a36Sopenharmony_ci props->port_cap_flags |= IB_PORT_CM_SUP; 15862306a36Sopenharmony_ci props->ip_gids = true; 15962306a36Sopenharmony_ci props->max_msg_sz = resp->attrs.max_msg_sz; 16062306a36Sopenharmony_ci props->bad_pkey_cntr = resp->attrs.bad_pkey_cntr; 16162306a36Sopenharmony_ci props->qkey_viol_cntr = resp->attrs.qkey_viol_cntr; 16262306a36Sopenharmony_ci props->pkey_tbl_len = resp->attrs.pkey_tbl_len; 16362306a36Sopenharmony_ci props->lid = resp->attrs.lid; 16462306a36Sopenharmony_ci props->sm_lid = resp->attrs.sm_lid; 16562306a36Sopenharmony_ci props->lmc = resp->attrs.lmc; 16662306a36Sopenharmony_ci props->max_vl_num = resp->attrs.max_vl_num; 16762306a36Sopenharmony_ci props->sm_sl = resp->attrs.sm_sl; 16862306a36Sopenharmony_ci props->subnet_timeout = resp->attrs.subnet_timeout; 16962306a36Sopenharmony_ci props->init_type_reply = resp->attrs.init_type_reply; 17062306a36Sopenharmony_ci props->active_width = pvrdma_port_width_to_ib(resp->attrs.active_width); 17162306a36Sopenharmony_ci props->active_speed = pvrdma_port_speed_to_ib(resp->attrs.active_speed); 17262306a36Sopenharmony_ci props->phys_state = resp->attrs.phys_state; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * pvrdma_query_gid - query device gid 17962306a36Sopenharmony_ci * @ibdev: the device to query 18062306a36Sopenharmony_ci * @port: the port number 18162306a36Sopenharmony_ci * @index: the index 18262306a36Sopenharmony_ci * @gid: the device gid value 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * @return: 0 on success, otherwise negative errno 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ciint pvrdma_query_gid(struct ib_device *ibdev, u32 port, int index, 18762306a36Sopenharmony_ci union ib_gid *gid) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibdev); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (index >= dev->dsr->caps.gid_tbl_len) 19262306a36Sopenharmony_ci return -EINVAL; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci memcpy(gid, &dev->sgid_tbl[index], sizeof(union ib_gid)); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/** 20062306a36Sopenharmony_ci * pvrdma_query_pkey - query device port's P_Key table 20162306a36Sopenharmony_ci * @ibdev: the device to query 20262306a36Sopenharmony_ci * @port: the port number 20362306a36Sopenharmony_ci * @index: the index 20462306a36Sopenharmony_ci * @pkey: the device P_Key value 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * @return: 0 on success, otherwise negative errno 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ciint pvrdma_query_pkey(struct ib_device *ibdev, u32 port, u16 index, 20962306a36Sopenharmony_ci u16 *pkey) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int err = 0; 21262306a36Sopenharmony_ci union pvrdma_cmd_req req; 21362306a36Sopenharmony_ci union pvrdma_cmd_resp rsp; 21462306a36Sopenharmony_ci struct pvrdma_cmd_query_pkey *cmd = &req.query_pkey; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 21762306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_QUERY_PKEY; 21862306a36Sopenharmony_ci cmd->port_num = port; 21962306a36Sopenharmony_ci cmd->index = index; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci err = pvrdma_cmd_post(to_vdev(ibdev), &req, &rsp, 22262306a36Sopenharmony_ci PVRDMA_CMD_QUERY_PKEY_RESP); 22362306a36Sopenharmony_ci if (err < 0) { 22462306a36Sopenharmony_ci dev_warn(&to_vdev(ibdev)->pdev->dev, 22562306a36Sopenharmony_ci "could not query pkey, error: %d\n", err); 22662306a36Sopenharmony_ci return err; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci *pkey = rsp.query_pkey_resp.pkey; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cienum rdma_link_layer pvrdma_port_link_layer(struct ib_device *ibdev, 23562306a36Sopenharmony_ci u32 port) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci return IB_LINK_LAYER_ETHERNET; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciint pvrdma_modify_device(struct ib_device *ibdev, int mask, 24162306a36Sopenharmony_ci struct ib_device_modify *props) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci unsigned long flags; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | 24662306a36Sopenharmony_ci IB_DEVICE_MODIFY_NODE_DESC)) { 24762306a36Sopenharmony_ci dev_warn(&to_vdev(ibdev)->pdev->dev, 24862306a36Sopenharmony_ci "unsupported device modify mask %#x\n", mask); 24962306a36Sopenharmony_ci return -EOPNOTSUPP; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (mask & IB_DEVICE_MODIFY_NODE_DESC) { 25362306a36Sopenharmony_ci spin_lock_irqsave(&to_vdev(ibdev)->desc_lock, flags); 25462306a36Sopenharmony_ci memcpy(ibdev->node_desc, props->node_desc, 64); 25562306a36Sopenharmony_ci spin_unlock_irqrestore(&to_vdev(ibdev)->desc_lock, flags); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) { 25962306a36Sopenharmony_ci mutex_lock(&to_vdev(ibdev)->port_mutex); 26062306a36Sopenharmony_ci to_vdev(ibdev)->sys_image_guid = 26162306a36Sopenharmony_ci cpu_to_be64(props->sys_image_guid); 26262306a36Sopenharmony_ci mutex_unlock(&to_vdev(ibdev)->port_mutex); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/** 26962306a36Sopenharmony_ci * pvrdma_modify_port - modify device port attributes 27062306a36Sopenharmony_ci * @ibdev: the device to modify 27162306a36Sopenharmony_ci * @port: the port number 27262306a36Sopenharmony_ci * @mask: attributes to modify 27362306a36Sopenharmony_ci * @props: the device properties 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * @return: 0 on success, otherwise negative errno 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ciint pvrdma_modify_port(struct ib_device *ibdev, u32 port, int mask, 27862306a36Sopenharmony_ci struct ib_port_modify *props) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct ib_port_attr attr; 28162306a36Sopenharmony_ci struct pvrdma_dev *vdev = to_vdev(ibdev); 28262306a36Sopenharmony_ci int ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (mask & ~IB_PORT_SHUTDOWN) { 28562306a36Sopenharmony_ci dev_warn(&vdev->pdev->dev, 28662306a36Sopenharmony_ci "unsupported port modify mask %#x\n", mask); 28762306a36Sopenharmony_ci return -EOPNOTSUPP; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mutex_lock(&vdev->port_mutex); 29162306a36Sopenharmony_ci ret = ib_query_port(ibdev, port, &attr); 29262306a36Sopenharmony_ci if (ret) 29362306a36Sopenharmony_ci goto out; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci vdev->port_cap_mask |= props->set_port_cap_mask; 29662306a36Sopenharmony_ci vdev->port_cap_mask &= ~props->clr_port_cap_mask; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (mask & IB_PORT_SHUTDOWN) 29962306a36Sopenharmony_ci vdev->ib_active = false; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciout: 30262306a36Sopenharmony_ci mutex_unlock(&vdev->port_mutex); 30362306a36Sopenharmony_ci return ret; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * pvrdma_alloc_ucontext - allocate ucontext 30862306a36Sopenharmony_ci * @uctx: the uverbs countext 30962306a36Sopenharmony_ci * @udata: user data 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * @return: zero on success, otherwise errno. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ciint pvrdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct ib_device *ibdev = uctx->device; 31662306a36Sopenharmony_ci struct pvrdma_dev *vdev = to_vdev(ibdev); 31762306a36Sopenharmony_ci struct pvrdma_ucontext *context = to_vucontext(uctx); 31862306a36Sopenharmony_ci union pvrdma_cmd_req req = {}; 31962306a36Sopenharmony_ci union pvrdma_cmd_resp rsp = {}; 32062306a36Sopenharmony_ci struct pvrdma_cmd_create_uc *cmd = &req.create_uc; 32162306a36Sopenharmony_ci struct pvrdma_cmd_create_uc_resp *resp = &rsp.create_uc_resp; 32262306a36Sopenharmony_ci struct pvrdma_alloc_ucontext_resp uresp = {}; 32362306a36Sopenharmony_ci int ret; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!vdev->ib_active) 32662306a36Sopenharmony_ci return -EAGAIN; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci context->dev = vdev; 32962306a36Sopenharmony_ci ret = pvrdma_uar_alloc(vdev, &context->uar); 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci return -ENOMEM; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* get ctx_handle from host */ 33462306a36Sopenharmony_ci if (vdev->dsr_version < PVRDMA_PPN64_VERSION) 33562306a36Sopenharmony_ci cmd->pfn = context->uar.pfn; 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci cmd->pfn64 = context->uar.pfn; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_CREATE_UC; 34062306a36Sopenharmony_ci ret = pvrdma_cmd_post(vdev, &req, &rsp, PVRDMA_CMD_CREATE_UC_RESP); 34162306a36Sopenharmony_ci if (ret < 0) { 34262306a36Sopenharmony_ci dev_warn(&vdev->pdev->dev, 34362306a36Sopenharmony_ci "could not create ucontext, error: %d\n", ret); 34462306a36Sopenharmony_ci goto err; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci context->ctx_handle = resp->ctx_handle; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* copy back to user */ 35062306a36Sopenharmony_ci uresp.qp_tab_size = vdev->dsr->caps.max_qp; 35162306a36Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 35262306a36Sopenharmony_ci if (ret) { 35362306a36Sopenharmony_ci pvrdma_uar_free(vdev, &context->uar); 35462306a36Sopenharmony_ci pvrdma_dealloc_ucontext(&context->ibucontext); 35562306a36Sopenharmony_ci return -EFAULT; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cierr: 36162306a36Sopenharmony_ci pvrdma_uar_free(vdev, &context->uar); 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/** 36662306a36Sopenharmony_ci * pvrdma_dealloc_ucontext - deallocate ucontext 36762306a36Sopenharmony_ci * @ibcontext: the ucontext 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_civoid pvrdma_dealloc_ucontext(struct ib_ucontext *ibcontext) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct pvrdma_ucontext *context = to_vucontext(ibcontext); 37262306a36Sopenharmony_ci union pvrdma_cmd_req req = {}; 37362306a36Sopenharmony_ci struct pvrdma_cmd_destroy_uc *cmd = &req.destroy_uc; 37462306a36Sopenharmony_ci int ret; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_DESTROY_UC; 37762306a36Sopenharmony_ci cmd->ctx_handle = context->ctx_handle; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = pvrdma_cmd_post(context->dev, &req, NULL, 0); 38062306a36Sopenharmony_ci if (ret < 0) 38162306a36Sopenharmony_ci dev_warn(&context->dev->pdev->dev, 38262306a36Sopenharmony_ci "destroy ucontext failed, error: %d\n", ret); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Free the UAR even if the device command failed */ 38562306a36Sopenharmony_ci pvrdma_uar_free(to_vdev(ibcontext->device), &context->uar); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * pvrdma_mmap - create mmap region 39062306a36Sopenharmony_ci * @ibcontext: the user context 39162306a36Sopenharmony_ci * @vma: the VMA 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * @return: 0 on success, otherwise errno. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ciint pvrdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct pvrdma_ucontext *context = to_vucontext(ibcontext); 39862306a36Sopenharmony_ci unsigned long start = vma->vm_start; 39962306a36Sopenharmony_ci unsigned long size = vma->vm_end - vma->vm_start; 40062306a36Sopenharmony_ci unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci dev_dbg(&context->dev->pdev->dev, "create mmap region\n"); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if ((size != PAGE_SIZE) || (offset & ~PAGE_MASK)) { 40562306a36Sopenharmony_ci dev_warn(&context->dev->pdev->dev, 40662306a36Sopenharmony_ci "invalid params for mmap region\n"); 40762306a36Sopenharmony_ci return -EINVAL; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Map UAR to kernel space, VM_LOCKED? */ 41162306a36Sopenharmony_ci vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND); 41262306a36Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 41362306a36Sopenharmony_ci if (io_remap_pfn_range(vma, start, context->uar.pfn, size, 41462306a36Sopenharmony_ci vma->vm_page_prot)) 41562306a36Sopenharmony_ci return -EAGAIN; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * pvrdma_alloc_pd - allocate protection domain 42262306a36Sopenharmony_ci * @ibpd: PD pointer 42362306a36Sopenharmony_ci * @udata: user data 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * @return: the ib_pd protection domain pointer on success, otherwise errno. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ciint pvrdma_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct ib_device *ibdev = ibpd->device; 43062306a36Sopenharmony_ci struct pvrdma_pd *pd = to_vpd(ibpd); 43162306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibdev); 43262306a36Sopenharmony_ci union pvrdma_cmd_req req = {}; 43362306a36Sopenharmony_ci union pvrdma_cmd_resp rsp = {}; 43462306a36Sopenharmony_ci struct pvrdma_cmd_create_pd *cmd = &req.create_pd; 43562306a36Sopenharmony_ci struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp; 43662306a36Sopenharmony_ci struct pvrdma_alloc_pd_resp pd_resp = {0}; 43762306a36Sopenharmony_ci int ret; 43862306a36Sopenharmony_ci struct pvrdma_ucontext *context = rdma_udata_to_drv_context( 43962306a36Sopenharmony_ci udata, struct pvrdma_ucontext, ibucontext); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Check allowed max pds */ 44262306a36Sopenharmony_ci if (!atomic_add_unless(&dev->num_pds, 1, dev->dsr->caps.max_pd)) 44362306a36Sopenharmony_ci return -ENOMEM; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_CREATE_PD; 44662306a36Sopenharmony_ci cmd->ctx_handle = context ? context->ctx_handle : 0; 44762306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_PD_RESP); 44862306a36Sopenharmony_ci if (ret < 0) { 44962306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 45062306a36Sopenharmony_ci "failed to allocate protection domain, error: %d\n", 45162306a36Sopenharmony_ci ret); 45262306a36Sopenharmony_ci goto err; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci pd->privileged = !udata; 45662306a36Sopenharmony_ci pd->pd_handle = resp->pd_handle; 45762306a36Sopenharmony_ci pd->pdn = resp->pd_handle; 45862306a36Sopenharmony_ci pd_resp.pdn = resp->pd_handle; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (udata) { 46162306a36Sopenharmony_ci if (ib_copy_to_udata(udata, &pd_resp, sizeof(pd_resp))) { 46262306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 46362306a36Sopenharmony_ci "failed to copy back protection domain\n"); 46462306a36Sopenharmony_ci pvrdma_dealloc_pd(&pd->ibpd, udata); 46562306a36Sopenharmony_ci return -EFAULT; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* u32 pd handle */ 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cierr: 47362306a36Sopenharmony_ci atomic_dec(&dev->num_pds); 47462306a36Sopenharmony_ci return ret; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/** 47862306a36Sopenharmony_ci * pvrdma_dealloc_pd - deallocate protection domain 47962306a36Sopenharmony_ci * @pd: the protection domain to be released 48062306a36Sopenharmony_ci * @udata: user data or null for kernel object 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci * @return: Always 0 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ciint pvrdma_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(pd->device); 48762306a36Sopenharmony_ci union pvrdma_cmd_req req = {}; 48862306a36Sopenharmony_ci struct pvrdma_cmd_destroy_pd *cmd = &req.destroy_pd; 48962306a36Sopenharmony_ci int ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_DESTROY_PD; 49262306a36Sopenharmony_ci cmd->pd_handle = to_vpd(pd)->pd_handle; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, NULL, 0); 49562306a36Sopenharmony_ci if (ret) 49662306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 49762306a36Sopenharmony_ci "could not dealloc protection domain, error: %d\n", 49862306a36Sopenharmony_ci ret); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci atomic_dec(&dev->num_pds); 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/** 50562306a36Sopenharmony_ci * pvrdma_create_ah - create an address handle 50662306a36Sopenharmony_ci * @ibah: the IB address handle 50762306a36Sopenharmony_ci * @init_attr: the attributes of the AH 50862306a36Sopenharmony_ci * @udata: pointer to user data 50962306a36Sopenharmony_ci * 51062306a36Sopenharmony_ci * @return: 0 on success, otherwise errno. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ciint pvrdma_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, 51362306a36Sopenharmony_ci struct ib_udata *udata) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr = init_attr->ah_attr; 51662306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibah->device); 51762306a36Sopenharmony_ci struct pvrdma_ah *ah = to_vah(ibah); 51862306a36Sopenharmony_ci const struct ib_global_route *grh; 51962306a36Sopenharmony_ci u32 port_num = rdma_ah_get_port_num(ah_attr); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!(rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH)) 52262306a36Sopenharmony_ci return -EINVAL; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci grh = rdma_ah_read_grh(ah_attr); 52562306a36Sopenharmony_ci if ((ah_attr->type != RDMA_AH_ATTR_TYPE_ROCE) || 52662306a36Sopenharmony_ci rdma_is_multicast_addr((struct in6_addr *)grh->dgid.raw)) 52762306a36Sopenharmony_ci return -EINVAL; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!atomic_add_unless(&dev->num_ahs, 1, dev->dsr->caps.max_ah)) 53062306a36Sopenharmony_ci return -ENOMEM; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ah->av.port_pd = to_vpd(ibah->pd)->pd_handle | (port_num << 24); 53362306a36Sopenharmony_ci ah->av.src_path_bits = rdma_ah_get_path_bits(ah_attr); 53462306a36Sopenharmony_ci ah->av.src_path_bits |= 0x80; 53562306a36Sopenharmony_ci ah->av.gid_index = grh->sgid_index; 53662306a36Sopenharmony_ci ah->av.hop_limit = grh->hop_limit; 53762306a36Sopenharmony_ci ah->av.sl_tclass_flowlabel = (grh->traffic_class << 20) | 53862306a36Sopenharmony_ci grh->flow_label; 53962306a36Sopenharmony_ci memcpy(ah->av.dgid, grh->dgid.raw, 16); 54062306a36Sopenharmony_ci memcpy(ah->av.dmac, ah_attr->roce.dmac, ETH_ALEN); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/** 54662306a36Sopenharmony_ci * pvrdma_destroy_ah - destroy an address handle 54762306a36Sopenharmony_ci * @ah: the address handle to destroyed 54862306a36Sopenharmony_ci * @flags: destroy address handle flags (see enum rdma_destroy_ah_flags) 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ciint pvrdma_destroy_ah(struct ib_ah *ah, u32 flags) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ah->device); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci atomic_dec(&dev->num_ahs); 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 558